const axios = require('axios'); const logger = require('./logger'); /** * Radio station metadata providers * Maps station names/URLs to their API endpoints or scraping methods */ // Europa FM API async function getEuropaFMMetadata() { try { const response = await axios.get('https://www.europafm.ro/now-playing/', { timeout: 5000, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } }); // Parse the HTML or JSON response const html = response.data; // Look for common patterns in Europa FM's page const titleMatch = html.match(/
([^<]+)<\/div>/i) || html.match(/([^<]+)<\/span>/i) || html.match(/"title":"([^"]+)"/); const artistMatch = html.match(/
([^<]+)<\/div>/i) || html.match(/([^<]+)<\/span>/i) || html.match(/"artist":"([^"]+)"/); if (titleMatch || artistMatch) { return { title: titleMatch ? titleMatch[1].trim() : null, artist: artistMatch ? artistMatch[1].trim() : null, source: 'Europa FM Website' }; } // Try API endpoint try { const apiResponse = await axios.get('https://www.europafm.ro/api/now-playing', { timeout: 3000, headers: { 'User-Agent': 'Mozilla/5.0' } }); if (apiResponse.data && apiResponse.data.title) { return { title: apiResponse.data.title, artist: apiResponse.data.artist || null, source: 'Europa FM API' }; } } catch (apiError) { // API might not exist, continue } return null; } catch (error) { logger.error('Europa FM metadata fetch error:', error.message); return null; } } // Radio Romania (various stations) async function getRadioRomaniaMetadata(stationId = 'actualitati') { try { const response = await axios.get(`https://www.radioromania.ro/live/${stationId}/`, { timeout: 5000, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } }); const html = response.data; const titleMatch = html.match(/"currentSong":"([^"]+)"/); const artistMatch = html.match(/"currentArtist":"([^"]+)"/); if (titleMatch || artistMatch) { return { title: titleMatch ? titleMatch[1].trim() : null, artist: artistMatch ? artistMatch[1].trim() : null, source: 'Radio Romania' }; } return null; } catch (error) { logger.error('Radio Romania metadata fetch error:', error.message); return null; } } // Magic FM async function getMagicFMMetadata() { try { const response = await axios.get('https://www.magicfm.ro/now-playing/', { timeout: 5000, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } }); const html = response.data; const titleMatch = html.match(/"title":"([^"]+)"/); const artistMatch = html.match(/"artist":"([^"]+)"/); if (titleMatch || artistMatch) { return { title: titleMatch ? titleMatch[1].trim() : null, artist: artistMatch ? artistMatch[1].trim() : null, source: 'Magic FM' }; } return null; } catch (error) { logger.error('Magic FM metadata fetch error:', error.message); return null; } } // Kiss FM async function getKissFMMetadata() { try { const response = await axios.get('https://www.kissfm.ro/now-playing/', { timeout: 5000, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } }); const html = response.data; const titleMatch = html.match(/"title":"([^"]+)"/); const artistMatch = html.match(/"artist":"([^"]+)"/); if (titleMatch || artistMatch) { return { title: titleMatch ? titleMatch[1].trim() : null, artist: artistMatch ? artistMatch[1].trim() : null, source: 'Kiss FM' }; } return null; } catch (error) { logger.error('Kiss FM metadata fetch error:', error.message); return null; } } // Pro FM async function getProFMMetadata() { try { const response = await axios.get('https://www.profm.ro/now-playing/', { timeout: 5000, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } }); const html = response.data; const titleMatch = html.match(/"title":"([^"]+)"/); const artistMatch = html.match(/"artist":"([^"]+)"/); if (titleMatch || artistMatch) { return { title: titleMatch ? titleMatch[1].trim() : null, artist: artistMatch ? artistMatch[1].trim() : null, source: 'Pro FM' }; } return null; } catch (error) { logger.error('Pro FM metadata fetch error:', error.message); return null; } } // Generic RadioBrowser API fallback async function getRadioBrowserMetadata(stationName) { try { // Search for station const searchResponse = await axios.get('https://de1.api.radio-browser.info/json/stations/search', { params: { name: stationName, limit: 1 }, timeout: 5000, headers: { 'User-Agent': 'StreamFlow/1.0' } }); if (searchResponse.data && searchResponse.data.length > 0) { const station = searchResponse.data[0]; // Radio Browser doesn't provide real-time metadata, but we can try the station's homepage if (station.homepage) { try { const homepageResponse = await axios.get(station.homepage, { timeout: 3000, headers: { 'User-Agent': 'Mozilla/5.0' } }); const html = homepageResponse.data; // Try common patterns const patterns = [ /"nowPlaying":"([^"]+)"/, /"current_track":"([^"]+)"/, /]*class="[^"]*now-playing[^"]*"[^>]*>([^<]+)= 2) { return { artist: parts[0].trim(), title: parts.slice(1).join(' - ').trim(), source: 'Radio Browser + Website' }; } return { title: match[1].trim(), artist: null, source: 'Radio Browser + Website' }; } } } catch (homepageError) { // Homepage fetch failed, ignore } } } return null; } catch (error) { logger.error('Radio Browser metadata fetch error:', error.message); return null; } } /** * Main function to get metadata for a radio station * Tries to identify the station and use the appropriate provider */ async function getRadioStationMetadata(channelName, channelUrl) { const nameLower = channelName.toLowerCase(); const urlLower = channelUrl ? channelUrl.toLowerCase() : ''; logger.info(`[RadioMetadata] Fetching metadata for: ${channelName}`); // Try specific providers based on station name or URL try { // Europa FM if (nameLower.includes('europa') && nameLower.includes('fm')) { const metadata = await getEuropaFMMetadata(); if (metadata) { logger.info(`[RadioMetadata] Found metadata from ${metadata.source}`); return metadata; } } // Radio Romania if (nameLower.includes('radio') && nameLower.includes('romania')) { let stationId = 'actualitati'; if (nameLower.includes('muzical')) stationId = 'muzical'; if (nameLower.includes('cultural')) stationId = 'cultural'; if (nameLower.includes('Cluj')) stationId = 'cluj'; const metadata = await getRadioRomaniaMetadata(stationId); if (metadata) { logger.info(`[RadioMetadata] Found metadata from ${metadata.source}`); return metadata; } } // Magic FM if (nameLower.includes('magic') && nameLower.includes('fm')) { const metadata = await getMagicFMMetadata(); if (metadata) { logger.info(`[RadioMetadata] Found metadata from ${metadata.source}`); return metadata; } } // Kiss FM if (nameLower.includes('kiss') && nameLower.includes('fm')) { const metadata = await getKissFMMetadata(); if (metadata) { logger.info(`[RadioMetadata] Found metadata from ${metadata.source}`); return metadata; } } // Pro FM if (nameLower.includes('pro') && nameLower.includes('fm')) { const metadata = await getProFMMetadata(); if (metadata) { logger.info(`[RadioMetadata] Found metadata from ${metadata.source}`); return metadata; } } // Fallback to RadioBrowser const metadata = await getRadioBrowserMetadata(channelName); if (metadata) { logger.info(`[RadioMetadata] Found metadata from ${metadata.source}`); return metadata; } } catch (error) { logger.error(`[RadioMetadata] Error fetching metadata: ${error.message}`); } logger.info(`[RadioMetadata] No external metadata found for ${channelName}`); return null; } module.exports = { getRadioStationMetadata };