diff --git a/src/enrich/enrichment.service.ts b/src/enrich/enrichment.service.ts index a8303f2..2514f78 100644 --- a/src/enrich/enrichment.service.ts +++ b/src/enrich/enrichment.service.ts @@ -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 { 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 (