import { Injectable, Logger } from '@nestjs/common'; import { Interval } from '@nestjs/schedule'; import { PrismaService } from '../prisma/prisma.service'; import { NowPlayingService } from './now-playing.service'; interface Radio101Resp { result?: { short?: { titleTrack?: string; titleExecutorFull?: string; cover?: { coverOriginal?: string }; }; }; } /** * Now-playing для станций на платформе 101.ru (Comedy Radio, Радио Energy/NRJ). * Потоки pub*.101.ru/stream/.../{channelId} — id канала = последний сегмент. * Трек: `https://101.ru/api/channel/getTrackOnAir/{id}/?dataFormat=json&idcity=1` * → result.short {titleExecutorFull, titleTrack, cover.coverOriginal}. Обложка — * cdn0.101.ru + coverOriginal. (Comedy: «комик - реприза» — это их «в эфире».) */ @Injectable() export class Radio101NowPlayingService { private readonly logger = new Logger(Radio101NowPlayingService.name); private readonly coverBase = 'https://cdn0.101.ru'; private readonly headers = { 'User-Agent': 'Mozilla/5.0' }; constructor( private readonly prisma: PrismaService, private readonly nowPlayingService: NowPlayingService, ) {} @Interval(30000) async pollRadio101NowPlaying() { const stations = await this.prisma.station.findMany({ where: { streamUrl: { contains: '.101.ru' } }, }); if (stations.length === 0) return; let updated = 0; await Promise.allSettled( stations.map(async (station) => { const id = this.extractChannelId(station.streamUrl); if (!id) return; const res = await fetch( `https://101.ru/api/channel/getTrackOnAir/${id}/?dataFormat=json&idcity=1`, { headers: this.headers, redirect: 'follow' }, ); if (!res.ok) return; const short = ((await res.json()) as Radio101Resp).result?.short; const artist = (short?.titleExecutorFull ?? '').trim(); const song = (short?.titleTrack ?? '').trim(); if (!artist || !song) return; const coverPath = short?.cover?.coverOriginal; const coverUrl = coverPath ? this.coverBase + coverPath : null; await this.nowPlayingService.ingest({ stationDbId: station.id, stationNumericId: station.stationId, artist, song, coverUrl, }); if (!station.isOnline) { await this.prisma.station.update({ where: { id: station.id }, data: { isOnline: true }, }); } updated++; }), ); this.logger.log(`Radio101 poll: ${updated}/${stations.length} обновлено`); } // https://pub0302.101.ru:8000/stream/pro/aac/64/446 → 446 private extractChannelId(streamUrl: string): string | null { const m = streamUrl.match(/\/(\d+)\/?$/); return m ? m[1] : null; } }