feat(now-playing): ГУСЬ (radiogoose) — now-playing + обложки, починка потоков
Сеть ГУСЬ (16 каналов) на AzuraCast (radiogoose.ru). Потоки в каталоге были многострочными (url1\nurl2) → клиент рвал воспроизведение, health-check метил offline, станции скрывались. Почищены на канонический https://radiogoose.ru/listen/{slug}/play. GooseNowPlayingService (@Interval 30с): AzuraCast API /api/nowplaying/{slug} → now_playing.song {artist,title,art}, ingest + isOnline=true. Исключён из ICY-поллера. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -6636,7 +6636,7 @@
|
||||
"name": "Радио Гусь",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/radiogoose/play\nhttp://stream4.radiogoose.ru/listen/radiogoose/play",
|
||||
"stream": "https://radiogoose.ru/listen/radiogoose/play",
|
||||
"type": "mp3",
|
||||
"iconText": "",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6651,7 +6651,7 @@
|
||||
"name": "ГУСЬ.Бигрум",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/bigroom/play\nhttp://stream5.radiogoose.ru/listen/bigroom/play",
|
||||
"stream": "https://radiogoose.ru/listen/bigroom/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Бигрум",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6666,7 +6666,7 @@
|
||||
"name": "ГУСЬ.Рус",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/rus/play\nhttp://stream1.radiogoose.ru/listen/rus/play",
|
||||
"stream": "https://radiogoose.ru/listen/rus/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Рус",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6681,7 +6681,7 @@
|
||||
"name": "ГУСЬ.Олдскул",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/oldschool/play\nhttp://stream1.radiogoose.ru/listen/oldschool/play",
|
||||
"stream": "https://radiogoose.ru/listen/oldschool/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Олдскул",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6696,7 +6696,7 @@
|
||||
"name": "ГУСЬ.Рок",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/rock/play\nhttp://stream3.radiogoose.ru/listen/rock/play",
|
||||
"stream": "https://radiogoose.ru/listen/rock/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Рок",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6711,7 +6711,7 @@
|
||||
"name": "ГУСЬ.Мидтемпо",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/midtempo/play\nhttp://stream1.radiogoose.ru/listen/midtempo/play",
|
||||
"stream": "https://radiogoose.ru/listen/midtempo/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Мидтемпо",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6726,7 +6726,7 @@
|
||||
"name": "ГУСЬ.Транс",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/trance/play\nhttp://stream5.radiogoose.ru/listen/trance/play",
|
||||
"stream": "https://radiogoose.ru/listen/trance/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Транс",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6741,7 +6741,7 @@
|
||||
"name": "ГУСЬ.Фонк",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/phonk/play\nhttp://stream3.radiogoose.ru/listen/phonk/play",
|
||||
"stream": "https://radiogoose.ru/listen/phonk/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Фонк",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6756,7 +6756,7 @@
|
||||
"name": "ГУСЬ.Электро",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/electro/play\nhttp://stream4.radiogoose.ru/listen/electro/play",
|
||||
"stream": "https://radiogoose.ru/listen/electro/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Электро",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6771,7 +6771,7 @@
|
||||
"name": "ГУСЬ.Дипхаус",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/deep/play\nhttp://stream2.radiogoose.ru/listen/deep/play",
|
||||
"stream": "https://radiogoose.ru/listen/deep/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Дипхаус",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6786,7 +6786,7 @@
|
||||
"name": "ГУСЬ.Драм",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/dnb/play\nhttp://stream3.radiogoose.ru/listen/dnb/play",
|
||||
"stream": "https://radiogoose.ru/listen/dnb/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Драм",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6801,7 +6801,7 @@
|
||||
"name": "ГУСЬ.Денскор",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/dancecore/play\nhttp://stream5.radiogoose.ru/listen/dancecore/play",
|
||||
"stream": "https://radiogoose.ru/listen/dancecore/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Денскор",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6816,7 +6816,7 @@
|
||||
"name": "ГУСЬ.Технорейв",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/harddance/play\nhttp://stream1.radiogoose.ru/listen/harddance/play",
|
||||
"stream": "https://radiogoose.ru/listen/harddance/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Технорейв",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6831,7 +6831,7 @@
|
||||
"name": "ГУСЬ.Хардстайл",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/hardstyle/play\nhttp://stream3.radiogoose.ru/listen/hardstyle/play",
|
||||
"stream": "https://radiogoose.ru/listen/hardstyle/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Хардстайл",
|
||||
"textColor": "#FF834B",
|
||||
@@ -6846,7 +6846,7 @@
|
||||
"name": "ГУСЬ.Хардкор",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/hardcore/play\nhttp://stream3.radiogoose.ru/listen/hardcore/play",
|
||||
"stream": "https://radiogoose.ru/listen/hardcore/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Хардкор",
|
||||
"textColor": "#E74E5D",
|
||||
@@ -6861,7 +6861,7 @@
|
||||
"name": "ГУСЬ.Новогодний",
|
||||
"bitrate": "320",
|
||||
"site": "https://radiogoose.ru/",
|
||||
"stream": "http://stream.radiogoose.ru/listen/newyear/play\nhttp://stream4.radiogoose.ru/listen/newyear/play",
|
||||
"stream": "https://radiogoose.ru/listen/newyear/play",
|
||||
"type": "mp3",
|
||||
"iconText": "ГУСЬ\\Новогодний",
|
||||
"textColor": "#4D8080",
|
||||
|
||||
89
src/now-playing/goose-now-playing.service.ts
Normal file
89
src/now-playing/goose-now-playing.service.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Interval } from '@nestjs/schedule';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { NowPlayingService } from './now-playing.service';
|
||||
|
||||
// Ответ AzuraCast https://radiogoose.ru/api/nowplaying/{slug}
|
||||
interface AzuraNowPlaying {
|
||||
is_online?: boolean;
|
||||
now_playing?: {
|
||||
song?: {
|
||||
artist?: string;
|
||||
title?: string;
|
||||
art?: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Now-playing для сети ГУСЬ (radiogoose.ru) — это AzuraCast, у него штатный
|
||||
* публичный API текущего трека с обложкой:
|
||||
* GET https://radiogoose.ru/api/nowplaying/{slug} → now_playing.song {artist,title,art}.
|
||||
* slug = сегмент потока /listen/{slug}/play. is_online из ответа поправляет
|
||||
* ошибочный offline-флаг (health-check ранее спотыкался о многострочный URL).
|
||||
*/
|
||||
@Injectable()
|
||||
export class GooseNowPlayingService {
|
||||
private readonly logger = new Logger(GooseNowPlayingService.name);
|
||||
private readonly headers = { 'User-Agent': 'Mozilla/5.0' };
|
||||
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly nowPlayingService: NowPlayingService,
|
||||
) {}
|
||||
|
||||
@Interval(30000)
|
||||
async pollGooseNowPlaying() {
|
||||
const stations = await this.prisma.station.findMany({
|
||||
where: { streamUrl: { contains: 'radiogoose.ru' } },
|
||||
});
|
||||
if (stations.length === 0) return;
|
||||
|
||||
let updated = 0;
|
||||
|
||||
await Promise.allSettled(
|
||||
stations.map(async (station) => {
|
||||
const slug = this.extractSlug(station.streamUrl);
|
||||
if (!slug) return;
|
||||
|
||||
const res = await fetch(
|
||||
`https://radiogoose.ru/api/nowplaying/${slug}`,
|
||||
{ headers: this.headers },
|
||||
);
|
||||
if (!res.ok) return;
|
||||
|
||||
const data = (await res.json()) as AzuraNowPlaying;
|
||||
if (data.is_online === false) return;
|
||||
|
||||
const song = data.now_playing?.song;
|
||||
const artist = (song?.artist ?? '').trim();
|
||||
const title = (song?.title ?? '').trim();
|
||||
if (!artist || !title) return;
|
||||
|
||||
await this.nowPlayingService.ingest({
|
||||
stationDbId: station.id,
|
||||
stationNumericId: station.stationId,
|
||||
artist,
|
||||
song: title,
|
||||
coverUrl: song?.art?.trim() || null,
|
||||
});
|
||||
|
||||
if (!station.isOnline) {
|
||||
await this.prisma.station.update({
|
||||
where: { id: station.id },
|
||||
data: { isOnline: true },
|
||||
});
|
||||
}
|
||||
updated++;
|
||||
}),
|
||||
);
|
||||
|
||||
this.logger.log(`Goose poll: ${updated}/${stations.length} обновлено`);
|
||||
}
|
||||
|
||||
// https://radiogoose.ru/listen/bigroom/play → bigroom
|
||||
private extractSlug(streamUrl: string): string | null {
|
||||
const m = streamUrl.match(/\/listen\/([a-z0-9]+)\/play/i);
|
||||
return m ? m[1].toLowerCase() : null;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ export class IcyNowPlayingService {
|
||||
'Radio ROKS',
|
||||
'Unistar',
|
||||
'Zaicev FM',
|
||||
'Гусь',
|
||||
],
|
||||
},
|
||||
NOT: { streamUrl: { contains: 'emgsound.ru' } },
|
||||
|
||||
@@ -10,6 +10,7 @@ import { LoveNowPlayingService } from './love-now-playing.service';
|
||||
import { RoksNowPlayingService } from './roks-now-playing.service';
|
||||
import { UnistarNowPlayingService } from './unistar-now-playing.service';
|
||||
import { ZaycevNowPlayingService } from './zaycev-now-playing.service';
|
||||
import { GooseNowPlayingService } from './goose-now-playing.service';
|
||||
import { ChartsModule } from '../charts/charts.module';
|
||||
|
||||
@Module({
|
||||
@@ -26,6 +27,7 @@ import { ChartsModule } from '../charts/charts.module';
|
||||
RoksNowPlayingService,
|
||||
UnistarNowPlayingService,
|
||||
ZaycevNowPlayingService,
|
||||
GooseNowPlayingService,
|
||||
],
|
||||
exports: [NowPlayingService],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user