Files

79 lines
3.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function (root) {
'use strict';
const modes = ['default', 'newest', 'oldest', 'heat', 'views', 'title'];
const collator = new Intl.Collator('zh-Hans-CN', {numeric: true, sensitivity: 'base'});
function chineseNumber(text) {
const digits = {零:0,〇:0,一:1,二:2,两:2,兩:2,三:3,四:4,五:5,六:6,七:7,八:8,九:9};
const units = {十:10,百:100,千:1000,万:10000,萬:10000};
if ([...text].every(character => character in digits)) return Number([...text].map(character => digits[character]).join(''));
let total=0, section=0, digit=0;
for (const character of text) {
if (character in digits) digit=digits[character];
else if (units[character]===10000) {total+=(section+digit||1)*10000;section=0;digit=0;}
else {section+=(digit||1)*units[character];digit=0;}
}
return total+section+digit;
}
function titleKey(drama) {
return String(drama.title || drama.name || '').normalize('NFKC').trim()
.replace(/第\s*([零〇一二两兩三四五六七八九十百千万萬]+)\s*(?=[季部集章卷篇册冊辑輯])/g, (_, number) => '第'+chineseNumber(number));
}
function metricValue(value) {
if (typeof value === 'number') return Number.isFinite(value) && value >= 0 ? value : null;
const text = String(value ?? '').replace(/[,,\s]/g, '');
const match = /^(\d+(?:\.\d+)?)(亿|万|千|w|k|m|b)?\+?(?:次播放|次观看|人看过|热度|播放|观看|次)?\+?$/i.exec(text);
if (!match) return null;
const unit = (match[2] || '').toLowerCase();
const number = Number(match[1]) * ({亿: 1e8, 万: 1e4, 千: 1e3, w: 1e4, k: 1e3, m: 1e6, b: 1e9}[unit] || 1);
return Number.isFinite(number) ? number : null;
}
function dateValue(value) {
const match = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(String(value || '').trim());
if (!match) return null;
const year = Number(match[1]), month = Number(match[2]), day = Number(match[3]);
const date = new Date(Date.UTC(year, month - 1, day));
if (year < 2000 || year > 2100 || date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) return null;
return date.getTime();
}
function sortValue(drama, mode) {
if (mode === 'newest' || mode === 'oldest') return dateValue(drama.onlineDate);
if (mode === 'heat') return metricValue(drama.heat);
if (mode === 'views') return metricValue(drama.views);
return null;
}
function sortDramas(list, mode) {
if (!modes.includes(mode) || mode === 'default') return list.slice();
return list.map((drama, index) => ({drama, index, title: titleKey(drama), value: sortValue(drama, mode)})).sort((left, right) => {
if (mode !== 'title') {
if (left.value === null && right.value === null) return left.index - right.index;
if (left.value === null && right.value !== null) return 1;
if (left.value !== null && right.value === null) return -1;
if (left.value !== right.value) return mode === 'oldest' ? left.value - right.value : right.value - left.value;
}
return collator.compare(left.title, right.title) || left.index - right.index;
}).map(item => item.drama);
}
function summary(list, mode) {
if (!['newest', 'oldest', 'heat', 'views'].includes(mode)) return '';
const label = {newest: '上线日期', oldest: '上线日期', heat: '热度', views: '播放量'}[mode];
const known = list.filter(drama => sortValue(drama, mode) !== null).length;
if (!list.length) return '';
if (!known) return '当前结果缺少' + label + ',无法按此排序';
return known < list.length ? label + '未知 ' + (list.length - known) + ' 部,已置后' : '';
}
const librarySort = {modes, metricValue, dateValue, sortDramas, summary, titleKey};
if (typeof module !== 'undefined' && module.exports) module.exports = librarySort;
if (root) root.JukuLibrarySort = librarySort;
})(typeof window !== 'undefined' ? window : null);