From 388bf11e1689f9f038f175ad71c3f8bcc22e8f17 Mon Sep 17 00:00:00 2001 From: vexorian Date: Sat, 18 Sep 2021 18:20:46 -0400 Subject: [PATCH 1/6] Remove some unnecessary logs --- src/helperFuncs.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/helperFuncs.js b/src/helperFuncs.js index dbbf273..98e7552 100644 --- a/src/helperFuncs.js +++ b/src/helperFuncs.js @@ -243,10 +243,7 @@ function pickRandomWithMaxDuration(channel, fillers, maxDuration) { let w = s + d; n += w; if (weighedPick(w,n)) { - console.log(`${s} ${d} ${clip.title} picked `); pick1 = clip; - } else { - console.log(`${s} ${d} ${clip.title} not picked `); } } } From 84abfac78b27a08fa2f29d7b5d37bcc21a98f88d Mon Sep 17 00:00:00 2001 From: vexorian Date: Sun, 19 Sep 2021 00:53:17 -0400 Subject: [PATCH 2/6] Fix #369 : A case where flex can cut abruptly, redirect-related --- src/channel-cache.js | 5 +++++ src/video.js | 21 ++++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/channel-cache.js b/src/channel-cache.js index 3588c96..bc2dc6b 100644 --- a/src/channel-cache.js +++ b/src/channel-cache.js @@ -140,6 +140,10 @@ function recordPlayback(channelId, t0, lineupItem) { } } +function clearPlayback(channelId) { + delete cache[channelId]; +} + function clear() { //it's not necessary to clear the playback cache and it may be undesirable configCache = {}; @@ -156,4 +160,5 @@ module.exports = { getChannelConfig: getChannelConfig, saveChannelConfig: saveChannelConfig, getFillerLastPlayTime: getFillerLastPlayTime, + clearPlayback: clearPlayback, } diff --git a/src/video.js b/src/video.js index 9ed736d..5f7e347 100644 --- a/src/video.js +++ b/src/video.js @@ -2,7 +2,7 @@ const express = require('express') const helperFuncs = require('./helperFuncs') const FFMPEG = require('./ffmpeg') const FFMPEG_TEXT = require('./ffmpegText') -const PlexTranscoder = require('./plexTranscoder') +const constants = require('./constants') const fs = require('fs') const ProgramPlayer = require('./program-player'); const channelCache = require('./channel-cache') @@ -121,7 +121,7 @@ function video( channelDB , fillerDB, db) { } ); // Stream individual video to ffmpeg concat above. This is used by the server, NOT the client - router.get('/stream', async (req, res) => { + let streamFunction = async (req, res, t0, allowSkip) => { // Check if channel queried is valid res.on("error", (e) => { console.error("There was an unexpected error in stream.", e); @@ -166,7 +166,6 @@ function video( channelDB , fillerDB, db) { // Get video lineup (array of video urls with calculated start times and durations.) - let t0 = (new Date()).getTime(); let lineupItem = channelCache.getCurrentLineupItem( channel.number, t0); let prog = null; let brandChannel = channel; @@ -242,12 +241,15 @@ function video( channelDB , fillerDB, db) { duration: t, isOffline : true, }; - } else if (prog.program.isOffline && prog.program.duration - prog.timeElapsed <= 10000) { + } else if ( allowSkip && (prog.program.isOffline && prog.program.duration - prog.timeElapsed <= constants.SLACK + 1) ) { //it's pointless to show the offline screen for such a short time, might as well //skip to the next program - prog.programIndex = (prog.programIndex + 1) % channel.programs.length; - prog.program = channel.programs[prog.programIndex ]; - prog.timeElapsed = 0; + let dt = prog.program.duration - prog.timeElapsed; + for (let i = 0; i < redirectChannels.length; i++) { + channelCache.clearPlayback(redirectChannels[i].number ); + } + console.log("Too litlle time before the filler ends, skip to next slot"); + return await streamFunction(req, res, t0 + dt + 1, false); } if ( (prog == null) || (typeof(prog) === 'undefined') || (prog.program == null) || (typeof(prog.program) == "undefined") ) { throw "No video to play, this means there's a serious unexpected bug or the channel db is corrupted." @@ -360,6 +362,11 @@ function video( channelDB , fillerDB, db) { console.log("Client Closed"); stop(); }); + }; + + router.get('/stream', async (req, res) => { + let t0 = (new Date).getTime(); + return await streamFunction(req, res, t0, true); }); From 460b552d3766cbd1862baaddd5cfa29c059e919e Mon Sep 17 00:00:00 2001 From: vexorian Date: Sun, 19 Sep 2021 00:53:46 -0400 Subject: [PATCH 3/6] New Collections browser now supports Smart Collections too! --- web/services/plex.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/services/plex.js b/web/services/plex.js index fc71ad8..35575ff 100644 --- a/web/services/plex.js +++ b/web/services/plex.js @@ -286,9 +286,12 @@ module.exports = function ($http, $window, $interval) { if ( (includeCollections === true) && (res.viewGroup !== "artist" ) ) { let k = res.librarySectionID; - k = `/library/sections/${k}/collection`; + k = `/library/sections/${k}/collections`; let collections = await client.Get(k); - let directories = collections.Directory; + if ( typeof(collections.Metadata) === 'undefined') { + collections.Metadata = []; + } + let directories = collections.Metadata; let nestedCollections = []; for (let i = 0; i < directories.length; i++) { let title; @@ -299,7 +302,7 @@ module.exports = function ($http, $window, $interval) { } nestedCollections.push( { - key : directories[i].fastKey, + key : directories[i].key, title : title, type: "collection", collectionType : res.viewGroup, From a56924463e2fcca9552e5d8e72609a24a0b56b4d Mon Sep 17 00:00:00 2001 From: vexorian Date: Sun, 19 Sep 2021 13:27:28 -0400 Subject: [PATCH 4/6] #356 Improve channel number validations, server and client-side. --- src/dao/channel-db.js | 28 ++++++++++++++++++++++------ web/directives/channel-config.js | 14 +++++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/dao/channel-db.js b/src/dao/channel-db.js index ac81bf4..a09eeff 100644 --- a/src/dao/channel-db.js +++ b/src/dao/channel-db.js @@ -29,10 +29,8 @@ class ChannelDB { } async saveChannel(number, json) { - if (typeof(number) === 'undefined') { - throw Error("Mising channel number"); - } - let f = path.join(this.folder, `${number}.json` ); + await this.validateChannelJson(number, json); + let f = path.join(this.folder, `${json.number}.json` ); return await new Promise( (resolve, reject) => { let data = undefined; try { @@ -50,12 +48,30 @@ class ChannelDB { } saveChannelSync(number, json) { - json.number = number; + this.validateChannelJson(number, json); + let data = JSON.stringify(json); - let f = path.join(this.folder, `${number}.json` ); + let f = path.join(this.folder, `${json.number}.json` ); fs.writeFileSync( f, data ); } + validateChannelJson(number, json) { + json.number = number; + if (typeof(json.number) === 'undefined') { + throw Error("Expected a channel.number"); + } + if (typeof(json.number) === 'string') { + try { + json.number = parseInt(json.number); + } catch (err) { + console.error("Error parsing channel number.", err); + } + } + if ( isNaN(json.number)) { + throw Error("channel.number must be a integer"); + } + } + async deleteChannel(number) { let f = path.join(this.folder, `${number}.json` ); await new Promise( (resolve, reject) => { diff --git a/web/directives/channel-config.js b/web/directives/channel-config.js index 9885f29..b9008db 100644 --- a/web/directives/channel-config.js +++ b/web/directives/channel-config.js @@ -953,7 +953,7 @@ module.exports = function ($timeout, $location, dizquetv, resolutionOptions, get scope.error.any = true; - if (typeof channel.number === "undefined" || channel.number === null || channel.number === "") { + if (typeof channel.number === "undefined" || channel.number === null || channel.number === "" ) { scope.error.number = "Select a channel number" scope.error.tab = "basic"; } else if (channelNumbers.indexOf(parseInt(channel.number, 10)) !== -1 && scope.isNewChannel) { // we need the parseInt for indexOf to work properly @@ -962,6 +962,9 @@ module.exports = function ($timeout, $location, dizquetv, resolutionOptions, get } else if (!scope.isNewChannel && channel.number !== scope.beforeEditChannelNumber && channelNumbers.indexOf(parseInt(channel.number, 10)) !== -1) { scope.error.number = "Channel number already in use." scope.error.tab = "basic"; + } else if ( ! checkChannelNumber(channel.number) ) { + scope.error.number = "Invalid channel number."; + scope.error.tab = "basic"; } else if (channel.number < 0 || channel.number > 9999) { scope.error.name = "Enter a valid number (0-9999)" scope.error.tab = "basic"; @@ -1670,3 +1673,12 @@ module.exports = function ($timeout, $location, dizquetv, resolutionOptions, get function validURL(url) { return /^(ftp|http|https):\/\/[^ "]+$/.test(url); } + +function checkChannelNumber(number) { + if ( /^[1-9][0-9]+$/.test(number) ) { + let x = parseInt(number); + return (0 <= x && x < 10000); + } else { + return false; + } +} From 395bc48c01673742f04b1906775abd3643683503 Mon Sep 17 00:00:00 2001 From: vexorian Date: Sun, 19 Sep 2021 13:28:14 -0400 Subject: [PATCH 5/6] TV Guide error retries with backoff so that they don't generate a tremendous amount of logs. Detect issues with channels provided to TV guide early-on. --- src/services/tv-guide-service.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/services/tv-guide-service.js b/src/services/tv-guide-service.js index cd3160d..6768b2f 100644 --- a/src/services/tv-guide-service.js +++ b/src/services/tv-guide-service.js @@ -11,6 +11,7 @@ class TVGuideService constructor(xmltv, db, cacheImageService, eventService) { this.cached = null; this.lastUpdate = 0; + this.lastBackoff = 100; this.updateTime = 0; this.currentUpdate = -1; this.currentLimit = -1; @@ -34,7 +35,15 @@ class TVGuideService let t = (new Date()).getTime(); this.updateTime = t; this.updateLimit = t + limit; - let channels = inputChannels; + + let channels = []; + for (let i = 0; i < inputChannels.length; i++) { + if (typeof(inputChannels[i]) !== 'undefined') { + channels.push(inputChannels[i]); + } else { + console.error(`There is an issue with one of the channels provided to TV-guide service, it will be ignored: ${i}` ); + } + } this.updateChannels = channels; return t; } @@ -345,10 +354,13 @@ class TVGuideService this.cached = await this.buildItManaged(); console.log("Internal TV Guide data refreshed at " + (new Date()).toLocaleString() ); await this.refreshXML(); + this.lastBackoff = 100; } catch(err) { console.error("Unable to update internal guide data", err); - await _wait(100); - console.error("Retrying TV guide..."); + let w = Math.min(this.lastBackoff * 2, 300000); + await _wait(w); + this.lastBackoff = w; + console.error(`Retrying TV guide after ${w} milliseconds wait...`); await this.buildIt(); } finally { From dcceb19a95a7043915cb33b45ce4b9b31717f204 Mon Sep 17 00:00:00 2001 From: vexorian Date: Sun, 19 Sep 2021 14:02:09 -0400 Subject: [PATCH 6/6] #336 make 'send guide updates' false by default. --- src/dao/plex-server-db.js | 4 ++-- src/database-migration.js | 2 +- web/directives/plex-settings.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dao/plex-server-db.js b/src/dao/plex-server-db.js index 02d19ed..7d83af4 100644 --- a/src/dao/plex-server-db.js +++ b/src/dao/plex-server-db.js @@ -134,7 +134,7 @@ class PlexServerDB s = s[0]; let arGuide = server.arGuide; if (typeof(arGuide) === 'undefined') { - arGuide = true; + arGuide = false; } let arChannels = server.arChannels; if (typeof(arChannels) === 'undefined') { @@ -176,7 +176,7 @@ class PlexServerDB name = resultName; let arGuide = server.arGuide; if (typeof(arGuide) === 'undefined') { - arGuide = true; + arGuide = false; } let arChannels = server.arGuide; if (typeof(arChannels) === 'undefined') { diff --git a/src/database-migration.js b/src/database-migration.js index 9ce4a9d..3eada1f 100644 --- a/src/database-migration.js +++ b/src/database-migration.js @@ -485,7 +485,7 @@ function splitServersSingleChannels(db, channelDB ) { let saveServer = (name, uri, accessToken, arGuide, arChannels) => { if (typeof(arGuide) === 'undefined') { - arGuide = true; + arGuide = false; } if (typeof(arChannels) === 'undefined') { arChannels = false; diff --git a/web/directives/plex-settings.js b/web/directives/plex-settings.js index f9714b1..53a51a2 100644 --- a/web/directives/plex-settings.js +++ b/web/directives/plex-settings.js @@ -192,7 +192,7 @@ module.exports = function (plex, dizquetv, $timeout) { accessToken: server.accessToken, } } - connection.arGuide = true + connection.arGuide = false connection.arChannels = false // should not be enabled unless dizqueTV tuner already added to plex await dizquetv.addPlexServer(connection); } catch (err) {