From 7daad9e33f9ad5f6220142534d04ae8eed737bd4 Mon Sep 17 00:00:00 2001 From: vexorian Date: Mon, 8 Dec 2025 10:23:47 -0400 Subject: [PATCH] When adding media from plex, the UI will now use dizqueTV as a proxy to connect to Plex. Thanks to this the 'ui route' is no longer necessary. Connection to plex through UI is still in use for authenticating with plex when adding the servers. --- index.js | 36 ++++++++++++++++++++++++- src/api.js | 13 ++++++--- src/dao/plex-server-db.js | 11 ++++++++ src/services/plex-proxy-service.js | 30 +++++++++++++++++++++ web/directives/plex-library.js | 27 +++++++++++-------- web/directives/plex-settings.js | 28 ------------------- web/public/locales/en/main.json | 6 ++--- web/public/templates/plex-library.html | 10 +++++-- web/public/templates/plex-settings.html | 13 +-------- web/services/dizquetv.js | 9 +++++++ web/services/plex.js | 22 +++++++-------- 11 files changed, 132 insertions(+), 73 deletions(-) create mode 100644 src/services/plex-proxy-service.js diff --git a/index.js b/index.js index 5805ef7..9f614e6 100644 --- a/index.js +++ b/index.js @@ -32,6 +32,8 @@ const ProgrammingService = require("./src/services/programming-service"); const ActiveChannelService = require('./src/services/active-channel-service') const ProgramPlayTimeDB = require('./src/dao/program-play-time-db') const FfmpegSettingsService = require('./src/services/ffmpeg-settings-service') +const PlexProxyService = require('./src/services/plex-proxy-service') +const PlexServerDB = require('./src/dao/plex-server-db'); const onShutdown = require("node-graceful-shutdown").onShutdown; @@ -107,6 +109,9 @@ fillerDB = new FillerDB( path.join(process.env.DATABASE, 'filler') , channelServ customShowDB = new CustomShowDB( path.join(process.env.DATABASE, 'custom-shows') ); let programPlayTimeDB = new ProgramPlayTimeDB( path.join(process.env.DATABASE, 'play-cache') ); let ffmpegSettingsService = new FfmpegSettingsService(db, unlockPath); +let plexServerDB = new PlexServerDB(channelService, fillerDB, customShowDB, db); +let plexProxyService = new PlexProxyService(plexServerDB); + async function initializeProgramPlayTimeDB() { try { @@ -251,6 +256,35 @@ channelService.on("channel-update", (data) => { let hdhr = HDHR(db, channelDB) let app = express() + +const responseInterceptor = ( + req, + res, + next +) => { + + let t0 = new Date().getTime(); + + const originalSend = res.send; + let responseSent = false; + console.log(`${req.method} ${req.url} ...`); + + res.send = function (body) { + + if (!responseSent) { + let t1 = new Date().getTime(); + let dt = t1 - t0; + console.log(`${req.method} ${req.url} ${res.statusCode} in ${dt}ms`); + responseSent = true; + } + + return originalSend.call(this, body); + }; + + next(); +}; +app.use(responseInterceptor); + eventService.setup(app); app.use( @@ -290,7 +324,7 @@ app.use('/favicon.svg', express.static( app.use('/custom.css', express.static(path.join(process.env.DATABASE, 'custom.css'))) // API Routers -app.use(api.router(db, channelService, fillerDB, customShowDB, xmltvInterval, guideService, m3uService, eventService, ffmpegSettingsService)) +app.use(api.router(db, channelService, fillerDB, customShowDB, xmltvInterval, guideService, m3uService, eventService, ffmpegSettingsService, plexServerDB, plexProxyService)) app.use('/api/cache/images', cacheImageService.apiRouters()) app.use('/' + fontAwesome, express.static(path.join(process.env.DATABASE, fontAwesome))) app.use('/' + bootstrap, express.static(path.join(process.env.DATABASE, bootstrap))) diff --git a/src/api.js b/src/api.js index 7d21f4d..904574a 100644 --- a/src/api.js +++ b/src/api.js @@ -24,10 +24,9 @@ function safeString(object) { } module.exports = { router: api } -function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideService, _m3uService, eventService, ffmpegSettingsService ) { +function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideService, _m3uService, eventService, ffmpegSettingsService, plexServerDB, plexProxyService ) { let m3uService = _m3uService; const router = express.Router() - const plexServerDB = new PlexServerDB(channelService, fillerDB, customShowDB, db); router.get('/api/version', async (req, res) => { try { @@ -216,7 +215,15 @@ function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideSe ); } }) - + router.get('/api/plex-server/:serverName64/:path(*)', async (req, res) => { + try { + let result = await plexProxyService.get(req.params.serverName64, req.params.path); + res.status(200).send(result); + } catch (err) { + console.error("Could not use plex proxy.", err); + res.status(404).send("Could not call plex server."); + } + }); // Channels router.get('/api/channels', async (req, res) => { diff --git a/src/dao/plex-server-db.js b/src/dao/plex-server-db.js index cd35d4c..a3a7000 100644 --- a/src/dao/plex-server-db.js +++ b/src/dao/plex-server-db.js @@ -15,6 +15,17 @@ class PlexServerDB this.showDB = showDB; } + async getPlexServerByName(name) { + let servers = this.db['plex-servers'].find() + let server = servers.sort( (a,b) => { return a.index - b.index } ) + .filter( (server) => name === server.name ) + [0]; + if (typeof(server) === "undefined") { + return null; + } + return server; + } + async fixupAllChannels(name, newServer) { let channelNumbers = await this.channelService.getAllChannelNumbers(); let report = await Promise.all( channelNumbers.map( async (i) => { diff --git a/src/services/plex-proxy-service.js b/src/services/plex-proxy-service.js new file mode 100644 index 0000000..8a14ba1 --- /dev/null +++ b/src/services/plex-proxy-service.js @@ -0,0 +1,30 @@ +const Plex = require('../plex.js') +const events = require('events') + +class PlexProxyService extends events.EventEmitter { + + constructor(plexServerDB) { + super(); + this.plexServerDB = plexServerDB; + } + + async get(serverName64, path) { + let plexServer = await getPlexServer(this.plexServerDB, serverName64); + let client = new Plex(plexServer); + return { MediaContainer: await client.Get("/" + path) }; + } +} + + + +async function getPlexServer(plexServerDB, serverName64) { + let serverKey = Buffer.from(serverName64, 'base64').toString('utf-8'); + let server = await plexServerDB.getPlexServerByName(serverKey); + if (server == null) { + throw Error("server not found"); + } + return server; + +} + +module.exports = PlexProxyService \ No newline at end of file diff --git a/web/directives/plex-library.js b/web/directives/plex-library.js index 153b2e2..0406d89 100644 --- a/web/directives/plex-library.js +++ b/web/directives/plex-library.js @@ -31,13 +31,7 @@ module.exports = function (plex, dizquetv, $timeout, commonProgramTools) { }); } scope.selectOrigin = function (origin) { - if ( origin.type === 'plex' ) { - scope.plexServer = origin.server; - updateLibrary(scope.plexServer); - } else { - scope.plexServer = undefined; - updateCustomShows(); - } + updateLibrary(origin); } scope._onFinish = (s, insertPoint) => { if (s.length > scope.limit) { @@ -99,20 +93,31 @@ module.exports = function (plex, dizquetv, $timeout, commonProgramTools) { "type" : "plex", "name" : `Plex - ${s.name}`, "server": s, + "loaded" : false, } } ); - scope.currentOrigin = scope.origins[0]; - scope.plexServer = scope.currentOrigin.server; scope.origins.push( { "type": "dizquetv", "name" : "dizqueTV - Custom Shows", + "loaded" : false, } ); - updateLibrary(scope.plexServer) + updateLibrary(scope.origins[0]) }) - let updateLibrary = async(server) => { + let updateLibrary = async(origin) => { + scope.currentOrigin = origin; + origin.loaded = false; + if ( origin.type !== 'plex' ) { + scope.plexServer = undefined; + await updateCustomShows(); + origin.loaded = true; + return; + } + let server = scope.currentOrigin.server; let lib = await plex.getLibrary(server); let play = await plex.getPlaylists(server); + scope.currentOrigin.loaded = true; + scope.plexServer = server; play.forEach( p => { p.type = "playlist"; diff --git a/web/directives/plex-settings.js b/web/directives/plex-settings.js index 53a51a2..83994fd 100644 --- a/web/directives/plex-settings.js +++ b/web/directives/plex-settings.js @@ -20,12 +20,9 @@ module.exports = function (plex, dizquetv, $timeout) { scope.servers = servers; if(servers) { for (let i = 0; i < scope.servers.length; i++) { - scope.servers[i].uiStatus = 0; scope.servers[i].backendStatus = 0; let t = (new Date()).getTime(); - scope.servers[i].uiPending = t; scope.servers[i].backendPending = t; - scope.refreshUIStatus(t, i); scope.refreshBackendStatus(t, i); } } @@ -51,22 +48,6 @@ module.exports = function (plex, dizquetv, $timeout) { scope.refreshServerList(); } - scope.isAnyUIBad = () => { - let t = (new Date()).getTime(); - if(scope.servers) { - for (let i = 0; i < scope.servers.length; i++) { - let s = scope.servers[i]; - if ( - (s.uiStatus == -1) - || ( (s.uiStatus == 0) && (s.uiPending + 30000 < t) ) - ) { - return true; - } - } - } - return false; - }; - scope.isAnyBackendBad = () => { let t = (new Date()).getTime(); if(scope.servers) { @@ -84,15 +65,6 @@ module.exports = function (plex, dizquetv, $timeout) { }; - scope.refreshUIStatus = async (t, i) => { - let s = await plex.check(scope.servers[i]); - if (scope.servers[i].uiPending == t) { - // avoid updating for a previous instance of the row - scope.servers[i].uiStatus = s; - } - scope.$apply(); - }; - scope.refreshBackendStatus = async (t, i) => { let s = await dizquetv.checkExistingPlexServer(scope.servers[i].name); if (scope.servers[i].backendPending == t) { diff --git a/web/public/locales/en/main.json b/web/public/locales/en/main.json index 3bf946d..a067645 100644 --- a/web/public/locales/en/main.json +++ b/web/public/locales/en/main.json @@ -19,12 +19,10 @@ "minutes_to_sign_plex": "You have 2 minutes to sign into your Plex Account.", "name": "Name", "uri": "URI", - "ui_route": "UI Route", - "backend_route": "Backend Route", + "routeStatus": "Route Status", "ok": "ok", "error": "error", - "ui_bad": "If a Plex server configuration has problems with the UI route, the channel editor won't be able to access its content.", - "backend_bad": "If a Plex server configuration has problems with the backend route, dizqueTV won't be able to play its content.", + "backend_bad": "A route problem means the dizqueTV server can't establish a connection with the configured Plex server.", "plex_transcoder_settings": "Plex Transcoder Settings", "update": "Update", "reset_options": "Reset Options", diff --git a/web/public/templates/plex-library.html b/web/public/templates/plex-library.html index adc2f58..74d0a78 100644 --- a/web/public/templates/plex-library.html +++ b/web/public/templates/plex-library.html @@ -43,7 +43,13 @@ Content: - -