Spaces:
Paused
Paused
| const axios = require('axios'); | |
| const moment = require('moment-timezone'); | |
| function unixTimestampToSpecifiedTimezone(timestamp, timezone) { | |
| // The timestamp is already in UTC, so we just need to format it for the specified timezone | |
| return moment(timestamp, 'YYYYMMDDHHmmss ZZ').tz(timezone).format('ddd, DD MMM YYYY HH:mm:ss z'); | |
| } | |
| async function fetchAndProcessXMLTV(baseUrl, username, password) { | |
| const xmltvUrl = `${baseUrl}/xmltv.php?username=${username}&password=${password}`; | |
| const response = await axios.get(xmltvUrl); | |
| const xmlData = response.data; | |
| function getElements(xml, tag) { | |
| const regex = new RegExp(`<${tag}[^>]*>(.*?)<\/${tag}>`, 'gs'); | |
| return Array.from(xml.matchAll(regex)).map(match => match[0]); | |
| } | |
| function getAttribute(element, attr) { | |
| const match = element.match(new RegExp(`${attr}="([^"]*)"`, 'i')); | |
| return match ? match[1] : null; | |
| } | |
| function getTextContent(element) { | |
| const match = element.match(/>([^<]*)</s); | |
| return match ? match[1].trim() : ''; | |
| } | |
| // Process channels | |
| const channels = getElements(xmlData, 'channel') | |
| .map(channel => ({ | |
| id: getAttribute(channel, 'id'), | |
| name: getTextContent(getElements(channel, 'display-name')[0] || ''), | |
| icon: getAttribute(getElements(channel, 'icon')[0] || '', 'src') || '' | |
| })) | |
| .sort((a, b) => a.name.localeCompare(b.name)); | |
| // Process programmes | |
| const programmes = getElements(xmlData, 'programme') | |
| .map(programme => ({ | |
| channelId: getAttribute(programme, 'channel'), | |
| start: getAttribute(programme, 'start'), | |
| stop: getAttribute(programme, 'stop'), | |
| title: getTextContent(getElements(programme, 'title')[0] || ''), | |
| description: getTextContent(getElements(programme, 'desc')[0] || '') | |
| })) | |
| .sort((a, b) => a.start.localeCompare(b.start)); | |
| return { channels, programmes }; | |
| } | |
| function getCurrentAndNextProgram(programmes, timezone) { | |
| const now = moment().tz(timezone); | |
| let currentProgram = null; | |
| let nextProgram = null; | |
| for (let i = 0; i < programmes.length; i++) { | |
| const programStart = moment(programmes[i].start, 'YYYYMMDDHHmmss ZZ'); | |
| const programStop = moment(programmes[i].stop, 'YYYYMMDDHHmmss ZZ'); | |
| if (programStart.isSameOrBefore(now) && programStop.isAfter(now)) { | |
| currentProgram = programmes[i]; | |
| nextProgram = programmes[i + 1] || null; | |
| break; | |
| } | |
| if (programStart.isAfter(now)) { | |
| nextProgram = programmes[i]; | |
| break; | |
| } | |
| } | |
| return { | |
| currentProgram: currentProgram ? { | |
| ...currentProgram, | |
| start: unixTimestampToSpecifiedTimezone(currentProgram.start, timezone), | |
| stop: unixTimestampToSpecifiedTimezone(currentProgram.stop, timezone) | |
| } : null, | |
| nextProgram: nextProgram ? { | |
| ...nextProgram, | |
| start: unixTimestampToSpecifiedTimezone(nextProgram.start, timezone), | |
| stop: unixTimestampToSpecifiedTimezone(nextProgram.stop, timezone) | |
| } : null | |
| }; | |
| } | |
| async function handleChannelRequest(epgChannelId, baseUrl, username, password, timezone) { | |
| try { | |
| const { channels, programmes } = await fetchAndProcessXMLTV(baseUrl, username, password); | |
| const channelInfo = channels.find(channel => channel.id === epgChannelId); | |
| if (!channelInfo) { | |
| return null; | |
| } | |
| const channelProgrammes = programmes.filter(programme => programme.channelId === epgChannelId); | |
| const { currentProgram, nextProgram } = getCurrentAndNextProgram(channelProgrammes, timezone); | |
| return { | |
| channel: channelInfo, | |
| currentProgram: currentProgram, | |
| nextProgram: nextProgram | |
| }; | |
| } catch (error) { | |
| console.error("Error in handleChannelRequest:", error); | |
| return null; | |
| } | |
| } | |
| async function handleMultiChannelRequest(channelIdsString, baseUrl, username, password, timezone) { | |
| try { | |
| const { channels, programmes } = await fetchAndProcessXMLTV(baseUrl, username, password); | |
| const channelIds = channelIdsString.split(','); | |
| const uniqueChannelIds = [...new Set(channelIds)]; // Remove duplicates | |
| const responseData = uniqueChannelIds.map(channelId => { | |
| const channelInfo = channels.find(channel => channel.id === channelId); | |
| if (!channelInfo) { | |
| return { channelId, error: 'Channel not found' }; | |
| } | |
| const channelProgrammes = programmes.filter(programme => programme.channelId === channelId); | |
| const { currentProgram, nextProgram } = getCurrentAndNextProgram(channelProgrammes, timezone); | |
| return { | |
| channel: channelInfo, | |
| currentProgram: currentProgram, | |
| nextProgram: nextProgram | |
| }; | |
| }); | |
| return responseData; | |
| } catch (error) { | |
| console.error("Error in handleMultiChannelRequest:", error); | |
| throw new Error('Error processing XMLTV data: ' + error.message); | |
| } | |
| } | |
| async function handleChannelsListRequest(baseUrl, username, password) { | |
| try { | |
| const { channels } = await fetchAndProcessXMLTV(baseUrl, username, password); | |
| return channels; | |
| } catch (error) { | |
| console.error("Error in handleChannelsListRequest:", error); | |
| throw new Error('Error fetching channels list: ' + error.message); | |
| } | |
| } | |
| async function getEpgInfoBatch(channelIds, baseUrl, username, password, timezone) { | |
| try { | |
| const { channels, programmes } = await fetchAndProcessXMLTV(baseUrl, username, password); | |
| const results = {}; | |
| for (const channel of channelIds) { | |
| if (!channel.epg_channel_id) { | |
| continue; | |
| } | |
| const channelInfo = channels.find(c => c.id === channel.epg_channel_id); | |
| if (!channelInfo) { | |
| continue; | |
| } | |
| const channelProgrammes = programmes.filter(programme => programme.channelId === channel.epg_channel_id); | |
| const { currentProgram, nextProgram } = getCurrentAndNextProgram(channelProgrammes, timezone); | |
| results[channel.stream_id] = { | |
| channel: channelInfo, | |
| currentProgram: currentProgram, | |
| nextProgram: nextProgram | |
| }; | |
| } | |
| return results; | |
| } catch (error) { | |
| console.error("Error in getEpgInfoBatch:", error); | |
| throw new Error('Error processing XMLTV data: ' + error.message); | |
| } | |
| } | |
| module.exports = { | |
| handleChannelRequest, | |
| handleChannelsListRequest, | |
| handleMultiChannelRequest, | |
| getEpgInfoBatch | |
| }; | |