dizquetv/src/api.js
2020-10-10 09:10:15 -04:00

632 lines
19 KiB
JavaScript

const express = require('express')
const path = require('path')
const databaseMigration = require('./database-migration');
const channelCache = require('./channel-cache')
const constants = require('./constants');
const FFMPEGInfo = require('./ffmpeg-info');
const PlexServerDB = require('./dao/plex-server-db');
const Plex = require("./plex.js");
const FillerDB = require('./dao/filler-db');
const timeSlotsService = require('./services/time-slots-service');
module.exports = { router: api }
function api(db, channelDB, fillerDB, xmltvInterval, guideService ) {
let router = express.Router()
let plexServerDB = new PlexServerDB(channelDB, channelCache, db);
router.get('/api/version', async (req, res) => {
try {
let ffmpegSettings = db['ffmpeg-settings'].find()[0];
let v = await (new FFMPEGInfo(ffmpegSettings)).getVersion();
res.send( {
"dizquetv" : constants.VERSION_NAME,
"ffmpeg" : v,
} );
} catch(err) {
console.error(err);
res.status(500).send("error");
}
});
// Plex Servers
router.get('/api/plex-servers', (req, res) => {
try {
let servers = db['plex-servers'].find()
servers.sort( (a,b) => { return a.index - b.index } );
res.send(servers)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post("/api/plex-servers/status", async (req, res) => {
try {
let servers = db['plex-servers'].find( {
name: req.body.name,
});
if (servers.length != 1) {
return res.status(404).send("Plex server not found.");
}
let plex = new Plex(servers[0]);
let s = await Promise.race( [
(async() => {
return await plex.checkServerStatus();
})(),
new Promise( (resolve, reject) => {
setTimeout( () => { resolve(-1); }, 60000);
}),
]);
res.send( {
status: s,
});
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post("/api/plex-servers/foreignstatus", async (req, res) => {
try {
let server = req.body;
let plex = new Plex(server);
let s = await Promise.race( [
(async() => {
return await plex.checkServerStatus();
})(),
new Promise( (resolve, reject) => {
setTimeout( () => { resolve(-1); }, 60000);
}),
]);
res.send( {
status: s,
});
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.delete('/api/plex-servers', async (req, res) => {
try {
let name = req.body.name;
if (typeof(name) === 'undefined') {
return res.status(400).send("Missing name");
}
let report = await plexServerDB.deleteServer(name);
res.send(report)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post('/api/plex-servers', async (req, res) => {
try {
await plexServerDB.updateServer(req.body);
res.status(204).send("Plex server updated.");;
} catch (err) {
console.error("Could not add plex server.", err);
res.status(400).send("Could not add plex server.");
}
})
router.put('/api/plex-servers', async (req, res) => {
try {
await plexServerDB.addServer(req.body);
res.status(201).send("Plex server added.");;
} catch (err) {
console.error("Could not add plex server.", err);
res.status(400).send("Could not add plex server.");
}
})
// Channels
router.get('/api/channels', async (req, res) => {
try {
let channels = await channelDB.getAllChannels();
channels.sort((a, b) => { return a.number < b.number ? -1 : 1 })
res.send(channels)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.get('/api/channel/:number', async (req, res) => {
try {
let number = parseInt(req.params.number, 10);
let channel = await channelCache.getChannelConfig(channelDB, number);
if (channel.length == 1) {
channel = channel[0];
res.send( channel );
} else {
return res.status(404).send("Channel not found");
}
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.get('/api/channel/description/:number', async (req, res) => {
try {
let number = parseInt(req.params.number, 10);
let channel = await channelCache.getChannelConfig(channelDB, number);
if (channel.length == 1) {
channel = channel[0];
res.send( {
number: channel.number,
icon: channel.icon,
name: channel.name,
stealth: channel.stealth,
});
} else {
return res.status(404).send("Channel not found");
}
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.get('/api/channelNumbers', async (req, res) => {
try {
let channels = await channelDB.getAllChannelNumbers();
channels.sort( (a,b) => { return parseInt(a) - parseInt(b) } );
res.send(channels)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post('/api/channel', async (req, res) => {
try {
cleanUpChannel(req.body);
await channelDB.saveChannel( req.body.number, req.body );
channelCache.clear();
res.send( { number: req.body.number} )
updateXmltv()
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.put('/api/channel', async (req, res) => {
try {
cleanUpChannel(req.body);
await channelDB.saveChannel( req.body.number, req.body );
channelCache.clear();
res.send( { number: req.body.number} )
updateXmltv()
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.delete('/api/channel', async (req, res) => {
try {
await channelDB.deleteChannel( req.body.number );
channelCache.clear();
res.send( { number: req.body.number} )
updateXmltv()
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
// Filler
router.get('/api/fillers', async (req, res) => {
try {
let fillers = await fillerDB.getAllFillersInfo();
res.send(fillers);
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.get('/api/filler/:id', async (req, res) => {
try {
let id = req.params.id;
if (typeof(id) === 'undefined') {
return res.status(400).send("Missing id");
}
let filler = await fillerDB.getFiller(id);
if (filler == null) {
return res.status(404).send("Filler not found");
}
res.send(filler);
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post('/api/filler/:id', async (req, res) => {
try {
let id = req.params.id;
if (typeof(id) === 'undefined') {
return res.status(400).send("Missing id");
}
await fillerDB.saveFiller(id, req.body );
return res.status(204).send({});
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.put('/api/filler', async (req, res) => {
try {
let uuid = await fillerDB.createFiller(req.body );
return res.status(201).send({id: uuid});
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.delete('/api/filler/:id', async (req, res) => {
try {
let id = req.params.id;
if (typeof(id) === 'undefined') {
return res.status(400).send("Missing id");
}
await fillerDB.deleteFiller(id);
return res.status(204).send({});
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.get('/api/filler/:id/channels', async(req, res) => {
try {
let id = req.params.id;
if (typeof(id) === 'undefined') {
return res.status(400).send("Missing id");
}
let channels = await fillerDB.getFillerChannels(id);
if (channels == null) {
return res.status(404).send("Filler not found");
}
res.send(channels);
} catch(err) {
console.error(err);
res.status(500).send("error");
}
} );
// FFMPEG SETTINGS
router.get('/api/ffmpeg-settings', (req, res) => {
try {
let ffmpeg = db['ffmpeg-settings'].find()[0]
res.send(ffmpeg)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.put('/api/ffmpeg-settings', (req, res) => {
try {
db['ffmpeg-settings'].update({ _id: req.body._id }, req.body)
let ffmpeg = db['ffmpeg-settings'].find()[0]
let err = fixupFFMPEGSettings(ffmpeg);
if (typeof(err) !== 'undefined') {
return res.status(400).send(err);
}
res.send(ffmpeg)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post('/api/ffmpeg-settings', (req, res) => { // RESET
try {
let ffmpeg = databaseMigration.defaultFFMPEG() ;
ffmpeg.ffmpegPath = req.body.ffmpegPath;
db['ffmpeg-settings'].update({ _id: req.body._id }, ffmpeg)
ffmpeg = db['ffmpeg-settings'].find()[0]
res.send(ffmpeg)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
function fixupFFMPEGSettings(ffmpeg) {
if (typeof(ffmpeg.maxFPS) === 'undefined') {
ffmpeg.maxFPS = 60;
} else if ( isNaN(ffmpeg.maxFPS) ) {
return "maxFPS should be a number";
}
}
// PLEX SETTINGS
router.get('/api/plex-settings', (req, res) => {
try {
let plex = db['plex-settings'].find()[0]
res.send(plex)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.put('/api/plex-settings', (req, res) => {
try {
db['plex-settings'].update({ _id: req.body._id }, req.body)
let plex = db['plex-settings'].find()[0]
res.send(plex)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post('/api/plex-settings', (req, res) => { // RESET
try {
db['plex-settings'].update({ _id: req.body._id }, {
streamPath: 'plex',
debugLogging: true,
directStreamBitrate: '20000',
transcodeBitrate: '2000',
mediaBufferSize: 1000,
transcodeMediaBufferSize: 20000,
maxPlayableResolution: "1920x1080",
maxTranscodeResolution: "1920x1080",
videoCodecs: 'h264,hevc,mpeg2video,av1',
audioCodecs: 'ac3',
maxAudioChannels: '2',
audioBoost: '100',
enableSubtitles: false,
subtitleSize: '100',
updatePlayStatus: false,
streamProtocol: 'http',
forceDirectPlay: false,
pathReplace: '',
pathReplaceWith: ''
})
let plex = db['plex-settings'].find()[0]
res.send(plex)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.get('/api/xmltv-last-refresh', (req, res) => {
try {
res.send(JSON.stringify({ value: xmltvInterval.lastUpdated.valueOf() }))
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
// XMLTV SETTINGS
router.get('/api/xmltv-settings', (req, res) => {
try {
let xmltv = db['xmltv-settings'].find()[0]
res.send(xmltv)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.put('/api/xmltv-settings', (req, res) => {
try {
let xmltv = db['xmltv-settings'].find()[0]
db['xmltv-settings'].update(
{ _id: req.body._id },
{
_id: req.body._id,
cache: req.body.cache,
refresh: req.body.refresh,
file: xmltv.file,
}
);
xmltv = db['xmltv-settings'].find()[0]
res.send(xmltv)
updateXmltv()
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post('/api/xmltv-settings', (req, res) => {
try {
db['xmltv-settings'].update({ _id: req.body._id }, {
_id: req.body._id,
cache: 12,
refresh: 4,
file: process.env.DATABASE + '/xmltv.xml'
})
var xmltv = db['xmltv-settings'].find()[0]
res.send(xmltv)
updateXmltv()
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.get('/api/guide/status', async (req, res) => {
try {
let s = await guideService.getStatus();
res.send(s);
} catch(err) {
console.error(err);
res.status(500).send("error");
}
});
router.get('/api/guide/debug', async (req, res) => {
try {
let s = await guideService.get();
res.send(s);
} catch(err) {
console.error(err);
res.status(500).send("error");
}
});
router.get('/api/guide/channels/:number', async (req, res) => {
try {
let dateFrom = new Date(req.query.dateFrom);
let dateTo = new Date(req.query.dateTo);
let lineup = await guideService.getChannelLineup( req.params.number , dateFrom, dateTo );
if (lineup == null) {
console.log(`GET /api/guide/channels/${req.params.number} : 404 Not Found`);
res.status(404).send("Channel not found in TV guide");
} else {
res.send( lineup );
}
} catch (err) {
console.error(err);
res.status(500).send("error");
}
});
//HDHR SETTINGS
router.get('/api/hdhr-settings', (req, res) => {
try {
let hdhr = db['hdhr-settings'].find()[0]
res.send(hdhr)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.put('/api/hdhr-settings', (req, res) => {
try {
db['hdhr-settings'].update({ _id: req.body._id }, req.body)
let hdhr = db['hdhr-settings'].find()[0]
res.send(hdhr)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
router.post('/api/hdhr-settings', (req, res) => {
try {
db['hdhr-settings'].update({ _id: req.body._id }, {
_id: req.body._id,
tunerCount: 1,
autoDiscovery: true,
})
var hdhr = db['hdhr-settings'].find()[0]
res.send(hdhr)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
// XMLTV.XML Download
router.get('/api/xmltv.xml', (req, res) => {
try {
res.set('Cache-Control', 'no-store')
res.type('text')
let xmltvSettings = db['xmltv-settings'].find()[0]
let f = path.resolve(xmltvSettings.file);
res.sendFile(f)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
//tool services
router.post('/api/channel-tools/time-slots', async (req, res) => {
try {
let toolRes = await timeSlotsService(req.body.programs, req.body.schedule);
if ( typeof(toolRes.userError) !=='undefined') {
return res.status(400).send(toolRes.userError);
}
res.status(200).send(toolRes);
} catch(err) {
console.error(err);
res.status(500).send("Internal error");
}
});
// CHANNELS.M3U Download
router.get('/api/channels.m3u', async (req, res) => {
try {
res.type('text')
let channels = await channelDB.getAllChannels();
channels.sort((a, b) => { return a.number < b.number ? -1 : 1 })
let tvg = `${req.protocol}://${req.get('host')}/api/xmltv.xml`
var data = `#EXTM3U url-tvg="${tvg}" x-tvg-url="${tvg}"\n`;
for (var i = 0; i < channels.length; i++) {
if (channels[i].stealth!==true) {
data += `#EXTINF:0 tvg-id="${channels[i].number}" tvg-chno="${channels[i].number}" tvg-name="${channels[i].name}" tvg-logo="${channels[i].icon}" group-title="dizqueTV",${channels[i].name}\n`
data += `${req.protocol}://${req.get('host')}/video?channel=${channels[i].number}\n`
}
}
if (channels.length === 0) {
data += `#EXTINF:0 tvg-id="1" tvg-chno="1" tvg-name="dizqueTV" tvg-logo="https://raw.githubusercontent.com/vexorian/dizquetv/main/resources/dizquetv.png" group-title="dizqueTV",dizqueTV\n`
data += `${req.protocol}://${req.get('host')}/setup\n`
}
res.send(data)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
// hls.m3u Download is not really working correctly right now
router.get('/api/hls.m3u', async (req, res) => {
try {
res.type('text')
let channels = await channelDB.getAllChannels();
channels.sort((a, b) => { return a.number < b.number ? -1 : 1 })
var data = "#EXTM3U\n"
for (var i = 0; i < channels.length; i++) {
data += `#EXTINF:0 tvg-id="${channels[i].number}" tvg-chno="${channels[i].number}" tvg-name="${channels[i].name}" tvg-logo="${channels[i].icon}" group-title="dizqueTV",${channels[i].name}\n`
data += `${req.protocol}://${req.get('host')}/m3u8?channel=${channels[i].number}\n`
}
if (channels.length === 0) {
data += `#EXTINF:0 tvg-id="1" tvg-chno="1" tvg-name="dizqueTV" tvg-logo="https://raw.githubusercontent.com/vexorian/dizquetv/main/resources/dizquetv.png" group-title="dizqueTV",dizqueTV\n`
data += `${req.protocol}://${req.get('host')}/setup\n`
}
res.send(data)
} catch(err) {
console.error(err);
res.status(500).send("error");
}
})
function updateXmltv() {
xmltvInterval.updateXML()
xmltvInterval.restartInterval()
}
function cleanUpProgram(program) {
delete program.start
delete program.stop
delete program.streams;
delete program.durationStr;
delete program.commercials;
}
function cleanUpChannel(channel) {
channel.programs.forEach( cleanUpProgram );
delete channel.fillerContent;
delete channel.filler;
channel.fallback.forEach( cleanUpProgram );
}
return router
}