fix(charts): отсекать джинглы/шоу/названия станций из сбора чартов
Record API при эфире шоу/джингла возвращает название станции/сети как трек (пустой artist/song или совпадение с названием станции). Такие записи накапливали проигрывания и забивали топ. Теперь recordPlay их пропускает (кэш названий станций).
This commit is contained in:
@@ -85,15 +85,45 @@ export class ChartsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Кэш названий станций — чтобы отсеивать джинглы/шоу из чарта
|
||||||
|
private stationNames = new Set<string>();
|
||||||
|
private stationNamesAt = 0;
|
||||||
|
|
||||||
|
private async getStationNames(): Promise<Set<string>> {
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - this.stationNamesAt > 10 * 60 * 1000 || this.stationNames.size === 0) {
|
||||||
|
const rows = await this.prisma.station.findMany({ select: { name: true } });
|
||||||
|
this.stationNames = new Set(
|
||||||
|
rows.map((r) => r.name.trim().toLowerCase()).filter((n) => n.length > 0),
|
||||||
|
);
|
||||||
|
this.stationNamesAt = now;
|
||||||
|
}
|
||||||
|
return this.stationNames;
|
||||||
|
}
|
||||||
|
|
||||||
// Записывает факт смены трека на станции (вызывается из NowPlayingService)
|
// Записывает факт смены трека на станции (вызывается из NowPlayingService)
|
||||||
async recordPlay(params: RecordPlayParams): Promise<void> {
|
async recordPlay(params: RecordPlayParams): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { artist, song, coverUrl, stationDbId } = params;
|
const artist = (params.artist ?? '').trim();
|
||||||
|
const song = (params.song ?? '').trim();
|
||||||
|
const { coverUrl, stationDbId } = params;
|
||||||
|
|
||||||
|
// Отсекаем не-музыкальные записи: пустые поля, либо когда артист/песня
|
||||||
|
// совпадает с названием станции (это джинглы, шоу, сетевые промо).
|
||||||
|
if (!artist || !song) return;
|
||||||
|
const stationNames = await this.getStationNames();
|
||||||
|
if (
|
||||||
|
stationNames.has(artist.toLowerCase()) ||
|
||||||
|
stationNames.has(song.toLowerCase())
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Нормализованный ключ: нижний регистр, схлопнуть пробелы
|
// Нормализованный ключ: нижний регистр, схлопнуть пробелы
|
||||||
const normKey =
|
const normKey =
|
||||||
artist.trim().toLowerCase().replace(/\s+/g, ' ') +
|
artist.toLowerCase().replace(/\s+/g, ' ') +
|
||||||
'|' +
|
'|' +
|
||||||
song.trim().toLowerCase().replace(/\s+/g, ' ');
|
song.toLowerCase().replace(/\s+/g, ' ');
|
||||||
|
|
||||||
const track = await this.prisma.track.upsert({
|
const track = await this.prisma.track.upsert({
|
||||||
where: { normKey },
|
where: { normKey },
|
||||||
|
|||||||
Reference in New Issue
Block a user