const express = require('express'); const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); let channelsPath = path.resolve(__dirname, 'channels.json'); let channels = JSON.parse(fs.readFileSync(channelsPath, 'utf8')); fs.watch(channelsPath, (eventType, filename) => { if (eventType === 'change') { console.log(`channels.json was updated, reloading...`); channels = JSON.parse(fs.readFileSync(channelsPath, 'utf8')); } }); const app = express(); const port = 8080; const tmp_folder = '/tmp/ramdisk/mpegts' async function startStreamlink(channel) { const useragent = channel.useragent; const authorization = channel.authorization; const proxy = channel.proxy; const key1 = channel.key1; const key2 = channel.key2; const key3 = channel.key3; let resolution = channel.resolution; resolution = 'res=' + resolution; let args = [ channel.url, '--header', `User-Agent:${useragent}`, '--use-shaka-packager', '--log-level', 'INFO', '--live-real-time-merge', '--live-pipe-mux', '--live-keep-segments', 'false', '-sv', 'best', '-sa', 'best2', '--tmp-dir', tmp_folder, '--del-after-done', 'true' ]; if (authorization) { args.splice(2, 0, '--header', `Authorization=${authorization}`); } if (proxy) { args.splice(2, 0, '--custom-proxy', proxy); } if (key1) { args.splice(4, 0, '--key', key1); } if (key2) { args.splice(6, 0, '--key', key2); } if (key3) { args.splice(6, 0, '--key', key3); } return spawn('N_m3u8DL-RE', args); } app.get('/stream/:channelName', async (req, res) => { const channelName = req.params.channelName; console.log(`Received request for /stream/${channelName}`); const channel = channels[channelName]; if (!channel) { res.status(404).send('Channel not found'); return; } console.log(`Starting Streamlink command for channel: ${channelName}`); try { let streamlinkProcess = await startStreamlink(channel); res.setHeader('Content-Type', 'video/MP2T'); streamlinkProcess.stdout.pipe(res); streamlinkProcess.stderr.on('data', data => { console.error(`Streamlink: ${data}`); }); streamlinkProcess.on('close', code => { console.log(`Streamlink process exited with code ${code}`); res.end(); }); res.on('close', () => { console.log(`Response closed, killing Streamlink process`); streamlinkProcess.kill(); if (fs.existsSync(tmp_folder)) { fs.rmSync(tmp_folder, { recursive: true }); } }); req.on('abort', () => { console.log(`Request aborted, killing Streamlink process`); streamlinkProcess.kill(); }); } catch (error) { console.error(`Streamlink failed: ${error}`); res.status(500).send('Streamlink failed'); } }); app.listen(port, () => { console.log(`Server listening on port ${port}`); });