105 lines
3.1 KiB
JavaScript
105 lines
3.1 KiB
JavaScript
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}`);
|
|
});
|