初始提交:短剧库源码(含转码优化 ultrafast)
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { $, api } from './ui-core.js';
|
||||
|
||||
export function createRecommendations({merge, changed, switched, allowed = () => true}) {
|
||||
const feeds = new Map();
|
||||
let enabled = false, genre = 'short_play', controller, sequence = 0, busy = false;
|
||||
function current() {
|
||||
if (!feeds.has(genre)) feeds.set(genre, {items: [], offset: 0, sessionId: '', hasMore: true, loaded: false, error: '', saved: true});
|
||||
return feeds.get(genre);
|
||||
}
|
||||
function cancel() {
|
||||
sequence++;
|
||||
controller?.abort();
|
||||
controller = null;
|
||||
busy = false;
|
||||
}
|
||||
function render() {
|
||||
const feed = current();
|
||||
$('recommendFooter').hidden = !enabled;
|
||||
$('recommendMoreBtn').hidden = !feed.hasMore && !feed.error;
|
||||
$('recommendMoreBtn').disabled = busy;
|
||||
$('recommendMoreBtn').textContent = busy ? '读取中…' : feed.error ? '重试' : feed.loaded ? '继续推荐' : '获取推荐';
|
||||
$('recommendRefreshBtn').disabled = busy;
|
||||
$('recommendRefreshBtn').setAttribute('aria-busy', String(busy));
|
||||
$('recommendStatus').textContent = busy ? '正在读取红果分类推荐…' : feed.error || (feed.loaded ? '已显示 ' + feed.items.length + ' 部' + (feed.hasMore ? ',按红果默认推荐顺序' : ',本轮已读完') + (feed.saved ? '' : ';缓存暂未保存') : '选择分类获取推荐');
|
||||
$('recommendStatus').classList.toggle('error', Boolean(feed.error));
|
||||
}
|
||||
async function load(reset = Boolean(current().retryReset)) {
|
||||
if (!allowed() || !enabled || busy) return;
|
||||
const feed = current();
|
||||
if (!reset && !feed.hasMore && !feed.error) return;
|
||||
cancel();
|
||||
const token = sequence, requestGenre = genre;
|
||||
controller = new AbortController();
|
||||
const signal = controller.signal;
|
||||
busy = true;
|
||||
feed.error = '';
|
||||
render();
|
||||
try {
|
||||
const result = await api('/api/ui/recommendations', {
|
||||
method: 'POST', signal,
|
||||
body: JSON.stringify({genre, offset: reset ? 0 : feed.offset, sessionId: reset ? '' : feed.sessionId, seen: reset ? [] : feed.items.slice(-540).map(item => item.id)})
|
||||
});
|
||||
if (signal.aborted || token !== sequence || genre !== requestGenre || !enabled) return;
|
||||
if (!Array.isArray(result.data) || typeof result.hasMore !== 'boolean' || !Number.isInteger(result.nextOffset) || typeof result.sessionId !== 'string') throw new Error('推荐数据格式无效');
|
||||
const known = new Set(reset ? [] : feed.items.map(item => item.id));
|
||||
const rows = result.data.filter(item => /^hongguo:[0-9]{1,32}$/.test(item.id) && item.source === 'hongguo').filter(item => {
|
||||
if (known.has(item.id)) return false;
|
||||
known.add(item.id);
|
||||
return true;
|
||||
});
|
||||
if (result.hasMore && (result.nextOffset <= (reset ? 0 : feed.offset) || !rows.length)) throw new Error('推荐分页未前进,请重新获取');
|
||||
feed.items = reset ? rows : feed.items.concat(rows);
|
||||
feed.offset = result.nextOffset;
|
||||
feed.sessionId = result.sessionId;
|
||||
feed.hasMore = result.hasMore;
|
||||
feed.loaded = true;
|
||||
feed.retryReset = false;
|
||||
feed.saved = result.saved !== false;
|
||||
merge(rows);
|
||||
changed();
|
||||
} catch (error) {
|
||||
if (token === sequence && !signal.aborted) {feed.error = error.message; feed.retryReset = reset;}
|
||||
} finally {
|
||||
if (token === sequence) {
|
||||
busy = false;
|
||||
controller = null;
|
||||
render();
|
||||
}
|
||||
}
|
||||
}
|
||||
function setEnabled(value) {
|
||||
if (value && !allowed()) return;
|
||||
cancel();
|
||||
enabled = value;
|
||||
$('librarySearch').hidden = enabled;
|
||||
$('libraryFilters').hidden = enabled;
|
||||
$('recommendToolbar').hidden = !enabled;
|
||||
$('recentSearches').hidden = true;
|
||||
$('libraryModeBtn').setAttribute('aria-pressed', String(!enabled));
|
||||
$('recommendModeBtn').setAttribute('aria-pressed', String(enabled));
|
||||
document.body.classList.toggle('show-recommendations', enabled);
|
||||
switched();
|
||||
render();
|
||||
if (enabled && !current().loaded) load();
|
||||
}
|
||||
function init() {
|
||||
$('recommendModeBtn').hidden = !allowed();
|
||||
$('libraryModeBtn').addEventListener('click', () => setEnabled(false));
|
||||
$('recommendModeBtn').addEventListener('click', () => setEnabled(true));
|
||||
$('recommendGenre').addEventListener('change', () => {
|
||||
cancel();
|
||||
genre = $('recommendGenre').value;
|
||||
changed();
|
||||
render();
|
||||
if (!current().loaded) load();
|
||||
});
|
||||
$('recommendMoreBtn').addEventListener('click', () => load());
|
||||
$('recommendRefreshBtn').addEventListener('click', () => load(true));
|
||||
}
|
||||
return {init, get enabled() {return enabled;}, items: () => current().items, all: () => Array.from(feeds.values()).flatMap(feed => feed.items)};
|
||||
}
|
||||
Reference in New Issue
Block a user