fix(enrich): coverFast — очищенный iTunes + Deezer (не множить лимит)
Прошлый вариант делал 2 запроса iTunes на каждый now-playing-трек без обложки (170+ играющих) → упирался в лимит iTunes ~20/мин, обложки не наливались. coverFast теперь: 1 запрос iTunes по ОЧИЩЕННОМУ названию (чаще матчит ремиксы/ «(Original Mix)») → на промахе/429 фолбэк Deezer (отдельный лимит). Полный fetchItunes (full→clean→deezer) остаётся для фонового enrichOne. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -103,7 +103,10 @@ export class EnrichmentService {
|
||||
}
|
||||
}
|
||||
|
||||
// Только обложка через iTunes (без Discogs) — для быстрого покрытия эфира
|
||||
// Только обложка — для быстрого покрытия эфира. Чтобы не множить нагрузку на
|
||||
// iTunes (лимит ~20/мин на 170+ играющих треков), делаем ОДИН запрос iTunes по
|
||||
// очищенному названию (он чаще матчит ремиксы/«(Original Mix)»), а на промахе/
|
||||
// лимите идём в Deezer (отдельный лимит, хорошее покрытие электроники).
|
||||
private async coverFast(t: {
|
||||
id: string;
|
||||
artist: string;
|
||||
@@ -111,24 +114,42 @@ export class EnrichmentService {
|
||||
normKey: string;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
const itunes = await this.fetchItunes(t.artist, t.song);
|
||||
const candidate = itunes?.coverUrl;
|
||||
if (!candidate) return;
|
||||
const stored = await this.covers.store(candidate, t.normKey);
|
||||
const cover = await this.fetchCover(t.artist, t.song);
|
||||
if (!cover?.coverUrl) return;
|
||||
const stored = await this.covers.store(cover.coverUrl, t.normKey);
|
||||
if (!stored) return;
|
||||
await this.prisma.track.update({
|
||||
where: { id: t.id },
|
||||
data: {
|
||||
coverUrl: stored,
|
||||
genre: itunes?.genre ?? undefined,
|
||||
album: itunes?.album ?? undefined,
|
||||
genre: cover.genre ?? undefined,
|
||||
album: cover.album ?? undefined,
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
// сбой iTunes (429/сеть) — добёрём на следующем тике
|
||||
// сбой — добёрём на следующем тике
|
||||
}
|
||||
}
|
||||
|
||||
/** Только обложка: один iTunes (очищенный) → Deezer. Не бросает. */
|
||||
private async fetchCover(
|
||||
artist: string,
|
||||
song: string,
|
||||
): Promise<{ coverUrl: string | null; genre: string | null; album: string | null } | null> {
|
||||
const cleaned =
|
||||
`${this.stripNoise(artist)} ${this.stripNoise(song)}`.replace(/\s+/g, ' ').trim() ||
|
||||
`${artist} ${song}`;
|
||||
try {
|
||||
const r = await this.itunesSearch(cleaned);
|
||||
if (r?.coverUrl) return { coverUrl: r.coverUrl, genre: r.genre, album: r.album };
|
||||
} catch {
|
||||
// iTunes 429/сеть — попробуем Deezer
|
||||
}
|
||||
const dz = await this.fetchDeezerCover(artist, song);
|
||||
if (dz) return { coverUrl: dz, genre: null, album: null };
|
||||
return null;
|
||||
}
|
||||
|
||||
// Нормализованный ключ — как в ChartsService.recordPlay
|
||||
private buildNormKey(artist: string, song: string): string {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user