This commit is contained in:
2026-09-13 04:54:24 +02:00
parent 340c825019
commit 33c6d0e76d
15 changed files with 425 additions and 104 deletions
+44 -7
View File
@@ -468,7 +468,13 @@ export default new class queue {
this._lastCoverExtracted = false; // Reset state for this call
if (link && typeof link === 'string' && link.match(/soundcloud/)) {
const proxyArgs = (cfg.main.socks && cfg.main.socks !== 'undefined' && cfg.main.socks !== '') ? ['--proxy', cfg.main.socks.includes('://') ? cfg.main.socks : `socks5h://${cfg.main.socks}`] : [];
let cover = (await this.spawn('yt-dlp', [...proxyArgs, '-f', 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w', '--get-thumbnail', link])).stdout.trim().split('\n').map(l => l.trim()).filter(l => l.length > 0).pop();
let cover = null;
try {
const ytRes = await this.spawn('yt-dlp', [...proxyArgs, '--get-thumbnail', link], { quiet: true });
cover = ytRes.stdout.trim().split('\n').map(l => l.trim()).filter(l => l.length > 0).pop();
} catch (err) {
console.warn(`[QUEUE] yt-dlp thumbnail fetch failed for SoundCloud track (${link}):`, err.message || err);
}
if (cover && !cover.match(/default_avatar/)) {
cover = cover.replace(/-(large|original)\./, '-t500x500.');
try {
@@ -517,13 +523,9 @@ export default new class queue {
}
} catch (_) { }
}
// If no cover art found, use audio.webp as the thumbnail
// If no cover art found, generate audio placeholder matching .sidebar-media-placeholder.audio
if (!coverExtracted) {
const audioFallback = path.join(cfg.paths.s, 'img', 'audio.webp');
await fs.promises.copyFile(audioFallback, tmpFile).catch(async () => {
// If copy fails, fall back to generated placeholder
await this.spawn('magick', ['-size', thumbSpec, 'xc:#1a1a1a', '-gravity', 'center', '-fill', '#666', '-pointsize', '40', '-annotate', '0', '♪', tmpFile]).catch(() => {});
});
await this.genAudioPlaceholder(tmpFile, thumbSpec, thumbSize);
}
// Store extraction result for caller
this._lastCoverExtracted = coverExtracted;
@@ -647,6 +649,13 @@ export default new class queue {
// Cleanup temp files
await fs.promises.unlink(tmpFile).catch(() => {});
await fs.promises.unlink(tmpJpg).catch(() => {});
if (mime && mime.startsWith('audio/')) {
try {
await this.genAudioPlaceholder(outPath, thumbSpec, thumbSize);
console.warn(`[QUEUE] Used audio placeholder thumbnail for item ${itemid}`);
return false;
} catch (_) {}
}
// Fallback: copy 404.gif as the thumbnail
const fallback404 = path.join(cfg.paths.s, 'img', '404.gif');
try {
@@ -659,6 +668,34 @@ export default new class queue {
}
};
async genAudioPlaceholder(targetFile, thumbSpec = '512x512', thumbSize = 512) {
const faFont = path.join(cfg.paths.s, 'fa', 'webfonts', 'fa-solid-900.ttf');
const ptSize = String(Math.round(thumbSize * 0.35));
try {
await this.spawn('magick', [
'-size', thumbSpec, 'radial-gradient:#334a15-#1e1e1e',
'(', '+clone', '-font', faFont, '-pointsize', ptSize, '-gravity', 'center', '-fill', 'rgba(153,255,0,0.5)', '-annotate', '0', '\uf001', '-blur', '0x12', ')',
'-composite',
'-font', faFont, '-pointsize', ptSize, '-gravity', 'center', '-fill', '#99ff00', '-annotate', '0', '\uf001',
targetFile
]);
return true;
} catch (_) {
const audioFallback = path.join(cfg.paths.s, 'img', 'audio.webp');
try {
await fs.promises.copyFile(audioFallback, targetFile);
return true;
} catch (copyErr) {
await this.spawn('magick', [
'-size', thumbSpec, 'radial-gradient:#334a15-#1e1e1e',
'-gravity', 'center', '-fill', '#99ff00', '-pointsize', '60', '-annotate', '0', '♪',
targetFile
]).catch(() => {});
return false;
}
}
};
async genBlurredThumbnail(itemid, pending = false) {
let tDir = pending ? path.join(cfg.paths.pending, 't') : cfg.paths.t;