Add a paged lyrics quality queue
This commit is contained in:
54
server/admin-tools.js
Normal file
54
server/admin-tools.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import { audit } from './audit-log.js';
|
||||
|
||||
const clientOf = db => typeof db?.execute === 'function' ? db : db?.db;
|
||||
const parse = value => { try { return JSON.parse(value || '{}'); } catch { return {}; } };
|
||||
const number = value => Number(value) || 0;
|
||||
|
||||
export function registerAdminToolsRoutes(app, { db, adminAuth, media = null, backupDir = null }) {
|
||||
const sql = clientOf(db);
|
||||
|
||||
app.get('/api/admin/lyrics/quality', adminAuth, async c => {
|
||||
const minLines = Math.max(1, Math.min(200, Number(c.req.query('minLines')) || 8));
|
||||
const offset = Math.max(0, Math.min(1_000_000, Number(c.req.query('offset')) || 0));
|
||||
const limit = Math.max(1, Math.min(100, Number(c.req.query('limit')) || 50));
|
||||
const category = ['all', 'missing', 'short', 'automatic', 'untimed', 'reports'].includes(c.req.query('category')) ? c.req.query('category') : 'all';
|
||||
const conditions = {
|
||||
missing: 'n.video_id IS NULL',
|
||||
short: 'n.video_id IS NOT NULL AND COALESCE(json_array_length(json_extract(n.data,\'$.lines\')),0) < ?',
|
||||
automatic: "n.source='auto'",
|
||||
untimed: "EXISTS (SELECT 1 FROM json_each(n.data,'$.lines') line WHERE json_extract(line.value,'$.t') IS NULL)",
|
||||
reports: "EXISTS (SELECT 1 FROM lyric_flags f WHERE f.video_id=m.id AND f.status='open')",
|
||||
};
|
||||
const parts = category === 'all'
|
||||
? [conditions.missing, conditions.short, conditions.automatic, conditions.untimed, conditions.reports]
|
||||
: [conditions[category]];
|
||||
const where = `WHERE (${parts.join(' OR ')})`;
|
||||
const args = category === 'short' ? [minLines] : category === 'all' ? [minLines] : [];
|
||||
const query = `SELECT m.id,m.card,m.updated_at,n.data AS lyrics,n.source AS lyricSource,n.updated_at AS lyricUpdated,
|
||||
COALESCE(json_array_length(json_extract(n.data,'$.lines')),0) AS lineCount,
|
||||
EXISTS(SELECT 1 FROM json_each(n.data,'$.lines') line WHERE json_extract(line.value,'$.t') IS NULL) AS untimed,
|
||||
(SELECT COUNT(*) FROM lyric_flags f WHERE f.video_id=m.id AND f.status='open') AS openReports
|
||||
FROM video_meta m LEFT JOIN video_notes n ON n.video_id=m.id AND n.kind='lyrics'
|
||||
${where} ORDER BY openReports DESC,lyricUpdated ASC,m.updated_at DESC LIMIT ? OFFSET ?`;
|
||||
const rows = await sql.execute({ sql: query, args: [...args, limit, offset] });
|
||||
const count = await sql.execute({ sql: `SELECT COUNT(*) AS total FROM video_meta m LEFT JOIN video_notes n ON n.video_id=m.id AND n.kind='lyrics' ${where}`, args });
|
||||
const songs = rows.rows.map(row => {
|
||||
const card = parse(row.card);
|
||||
let untimed = !!row.untimed;
|
||||
let lines = number(row.lineCount);
|
||||
if (row.lyrics) {
|
||||
const data = parse(row.lyrics); lines ||= Array.isArray(data.lines) ? data.lines.length : 0;
|
||||
if (Array.isArray(data.lines)) untimed ||= data.lines.some(line => line.t == null);
|
||||
}
|
||||
const reasons = [];
|
||||
if (!row.lyrics) reasons.push('missing');
|
||||
else if (lines < minLines) reasons.push('short');
|
||||
if (row.lyricSource === 'auto') reasons.push('automatic');
|
||||
if (untimed) reasons.push('untimed');
|
||||
if (number(row.openReports)) reasons.push('reports');
|
||||
return { id: row.id, title: card.title || row.id, channel: card.channel || '', lines, source: row.lyricSource || null, untimed, openReports: number(row.openReports), reasons, updatedAt: number(row.lyricUpdated) };
|
||||
});
|
||||
return c.json({ ok: true, minLines, category, offset, limit, total: number(count.rows[0]?.total), songs }, 200, { 'Cache-Control': 'no-store' });
|
||||
});
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user