From 3c4f349f7107134d99e186ff355139a7585cd84f Mon Sep 17 00:00:00 2001 From: nk Date: Sat, 6 Jun 2026 09:01:03 +0300 Subject: [PATCH] =?UTF-8?q?fix(now-playing):=20=D0=9E=D1=80=D1=84=D0=B5?= =?UTF-8?q?=D0=B9=20=E2=80=94=20=D1=87=D0=B8=D0=BD=D0=B8=D0=BC=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D1=83=20(=D0=B4?= =?UTF-8?q?=D0=B2=D0=BE=D0=B9=D0=BD=D0=B0=D1=8F=20=D0=BC=D0=BE=D0=B9=D0=B8?= =?UTF-8?q?=D0=B1=D0=B5=D0=B9=D0=BA=20cp1251)=20+=20=D1=80=D0=B5=D0=B6?= =?UTF-8?q?=D0=B5=D0=BC=20=D1=85=D0=B5=D0=BA=D1=81-=D1=85=D0=B2=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit status-json смешанной кодировки: часть тайтлов нормальный UTF-8, часть — cp1251- байты, прочитанные как latin1 и завёрнутые в UTF-8 (мойибейк «Íèêîëà»→«Никола»). fixEncoding: реальную кириллицу не трогаем, мойибейк (À-ÿ) восстанавливаем latin1→windows-1251. Срезаем приклеенный служебный id трека (- f0098627), фильтр hex/числовых плейсхолдеров усилен. Каналы без реального произведения — без подписи. Co-Authored-By: Claude Opus 4.8 --- .../orpheus-now-playing.service.ts | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) 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 }; } }