diff --git a/src/now-playing/orpheus-now-playing.service.ts b/src/now-playing/orpheus-now-playing.service.ts index 980f9b8..3047037 100644 --- a/src/now-playing/orpheus-now-playing.service.ts +++ b/src/now-playing/orpheus-now-playing.service.ts @@ -89,22 +89,52 @@ export class OrpheusNowPlayingService { return m ? m[1] : null; } - /** Разбирает title «Артист — Произведение», отсекая мусор. */ + /** + * Чинит кодировку: реальную кириллицу (U+0400-04FF) не трогаем; «двойную + * мойибейк» (cp1251-байты, прочитанные как latin1 и завёрнутые в UTF-8 — + * признак латиницы-1 À-ÿ) восстанавливаем latin1→windows-1251. + */ + private fixEncoding(s: string): string { + if (/[Ѐ-ӿ]/.test(s)) return s; // уже корректная кириллица + if (/[À-ÿ]/.test(s)) { + try { + return new TextDecoder('windows-1251').decode(Buffer.from(s, 'latin1')); + } catch { + return s; + } + } + return s; + } + + /** Разбирает title «Артист — Произведение», чиня кодировку и отсекая мусор/служебные id. */ private parseTitle(title?: string): { artist: string; song: string } | null { if (!title) return null; - const t = title.trim(); - if (!t || t === 'undefined') return null; - // hex-плейсхолдеры (0003b6d2), URL-источники (http://fonotron.ru), JSON - if (/^[0-9a-f]{6,}$/i.test(t) || t.startsWith('http') || t.startsWith('{')) { + let t = this.fixEncoding(title).replace(/\s+/g, ' ').trim(); + if (!t || t.toLowerCase() === 'undefined') return null; + // Срезаем хвостовой служебный id трека: « - f0098627», « - 147-1-10», « - 263-2-01» + t = t + .replace(/\s*[-—]\s*[0-9a-f]{6,}\s*$/i, '') + .replace(/\s*[-—]\s*\d+-\d+(?:-\d+)?\s*$/, '') + .trim(); + if (!t) return null; + // Целиком мусор: hex-плейсхолдер, числовой код, URL, JSON + if ( + /^[0-9a-f]{4,}$/i.test(t) || + /^\d+-\d+/.test(t) || + t.startsWith('http') || + t.startsWith('{') + ) { return null; } - // Разделитель — длинное тире или дефис с пробелами - const idx = t.indexOf(' — ') >= 0 ? t.indexOf(' — ') : t.indexOf(' - '); + // Разделитель — длинное тире или дефис с пробелами (оба длиной 3 символа: « X ») + const emIdx = t.indexOf(' — '); + const idx = emIdx >= 0 ? emIdx : t.indexOf(' - '); if (idx < 0) return null; - const sepLen = t.indexOf(' — ') >= 0 ? 3 : 3; const artist = t.slice(0, idx).trim(); - const song = t.slice(idx + sepLen).trim(); + const song = t.slice(idx + 3).trim(); if (!artist || !song) return null; + // Часть после чистки всё ещё мусорная + if (/^[0-9a-f]{4,}$/i.test(song) || /^[0-9a-f]{4,}$/i.test(artist)) return null; return { artist, song }; } }