From 715e03d1548ce185249cc44e202ec4879562bb5a Mon Sep 17 00:00:00 2001 From: vexorian Date: Tue, 23 Mar 2021 22:03:09 -0400 Subject: [PATCH 1/8] Prepare 1.3.3 release --- README.md | 2 +- src/constants.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff86293..6c4769b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# dizqueTV 1.3.2-prerelease +# dizqueTV 1.3.3-prerelease ![Discord](https://img.shields.io/discord/711313431457693727?logo=discord&logoColor=fff&style=flat-square) ![GitHub top language](https://img.shields.io/github/languages/top/vexorian/dizquetv?logo=github&style=flat-square) ![Docker Pulls](https://img.shields.io/docker/pulls/vexorian/dizquetv?logo=docker&logoColor=fff&style=flat-square) Create live TV channel streams from media on your Plex servers. diff --git a/src/constants.js b/src/constants.js index 15e9c2e..760e229 100644 --- a/src/constants.js +++ b/src/constants.js @@ -5,5 +5,5 @@ module.exports = { TVGUIDE_MAXIMUM_FLEX_DURATION : 6 * 60 * 60 * 1000, TOO_FREQUENT: 100, - VERSION_NAME: "1.3.2-prerelease" + VERSION_NAME: "1.3.3-prerelease" } From 0cf9bb314a9a491b988635a3fe4ce28b925be2da Mon Sep 17 00:00:00 2001 From: vexorian Date: Tue, 23 Mar 2021 22:13:12 -0400 Subject: [PATCH 2/8] #293 Fix Sort TV shows deleting movies --- web/services/common-program-tools.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/services/common-program-tools.js b/web/services/common-program-tools.js index e6f5c8e..b851c21 100644 --- a/web/services/common-program-tools.js +++ b/web/services/common-program-tools.js @@ -30,8 +30,7 @@ module.exports = function (getShowData) { }) newProgs = newProgs.concat(shows[keys[i]]) } - newProgs.concat(movies); - return newProgs; + return newProgs.concat(movies); } function shuffle(array, lo, hi ) { From d0f17417b77e70510242f08d73c9f0d2fbb84706 Mon Sep 17 00:00:00 2001 From: vexorian Date: Thu, 25 Mar 2021 10:17:48 -0400 Subject: [PATCH 3/8] Close button for toast notifications --- web/directives/toast-notifications.js | 5 +++++ web/public/templates/toast-notifications.html | 14 +++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/web/directives/toast-notifications.js b/web/directives/toast-notifications.js index bb6f645..cb83870 100644 --- a/web/directives/toast-notifications.js +++ b/web/directives/toast-notifications.js @@ -110,6 +110,11 @@ module.exports = function ($timeout) { eventSource.addEventListener('xmltv', normalEvent("TV Guide") ); eventSource.addEventListener('lifecycle', normalEvent("Server") ); }; + + scope.destroy = (index) => { + scope.toasts.splice(index,1); + } + scope.setup(); } }; diff --git a/web/public/templates/toast-notifications.html b/web/public/templates/toast-notifications.html index 825a520..9bd38f6 100644 --- a/web/public/templates/toast-notifications.html +++ b/web/public/templates/toast-notifications.html @@ -4,8 +4,20 @@ ng-repeat="toast in toasts track by $index" class="dizque-toast" ng-class="toast.clazz" + ng-click="destroy($index)" > - {{ toast.title }} +
+
+ {{ toast.title }} +
+
+ +
+
{{ toast.text }}
From a742da3ae0a6e3d6c5a92090803d2c000421eb24 Mon Sep 17 00:00:00 2001 From: vexorian Date: Thu, 25 Mar 2021 17:13:21 -0400 Subject: [PATCH 4/8] #286 : Update guide images when the Plex server configuration is changed. Also make sure that programs inside of filler lists and custom shows are fixed up when modifying the server or deleting it. --- src/api.js | 14 +- src/dao/custom-show-db.js | 4 +- src/dao/filler-db.js | 4 +- src/dao/plex-server-db.js | 141 ++++++++++++++++++--- src/plex-player.js | 2 +- web/directives/plex-server-edit.js | 4 + web/public/templates/plex-server-edit.html | 5 +- 7 files changed, 146 insertions(+), 28 deletions(-) diff --git a/src/api.js b/src/api.js index ee59ad9..ef2dd40 100644 --- a/src/api.js +++ b/src/api.js @@ -27,7 +27,7 @@ module.exports = { router: api } function api(db, channelDB, fillerDB, customShowDB, xmltvInterval, guideService, _m3uService, eventService ) { let m3uService = _m3uService; const router = express.Router() - const plexServerDB = new PlexServerDB(channelDB, channelCache, db); + const plexServerDB = new PlexServerDB(channelDB, channelCache, fillerDB, customShowDB, db); router.get('/api/version', async (req, res) => { try { @@ -141,18 +141,24 @@ function api(db, channelDB, fillerDB, customShowDB, xmltvInterval, guideService }) router.post('/api/plex-servers', async (req, res) => { try { - await plexServerDB.updateServer(req.body); + let report = await plexServerDB.updateServer(req.body); + let modifiedPrograms = 0; + let destroyedPrograms = 0; + report.forEach( (r) => { + modifiedPrograms += r.modifiedPrograms; + destroyedPrograms += r.destroyedPrograms; + } ); res.status(204).send("Plex server updated.");; eventService.push( "settings-update", { - "message": `Plex server ${req.body.name} updated.`, + "message": `Plex server ${req.body.name} updated. ${modifiedPrograms} programs modified, ${destroyedPrograms} programs deleted`, "module" : "plex-server", "detail" : { "serverName" : req.body.name, "action" : "update" }, - "level" : "info" + "level" : "warning" } ); diff --git a/src/dao/custom-show-db.js b/src/dao/custom-show-db.js index f174f3b..2f581d5 100644 --- a/src/dao/custom-show-db.js +++ b/src/dao/custom-show-db.js @@ -110,8 +110,8 @@ class CustomShowDB { async getAllShowsInfo() { //returns just name and id - let fillers = await this.getAllShows(); - return fillers.map( (f) => { + let shows = await this.getAllShows(); + return shows.map( (f) => { return { 'id' : f.id, 'name': f.name, diff --git a/src/dao/filler-db.js b/src/dao/filler-db.js index b9d7f9b..fcd2d3e 100644 --- a/src/dao/filler-db.js +++ b/src/dao/filler-db.js @@ -192,8 +192,8 @@ class FillerDB { } function fixup(json) { - if (typeof(json.fillerContent) === 'undefined') { - json.fillerContent = []; + if (typeof(json.content) === 'undefined') { + json.content = []; } if (typeof(json.name) === 'undefined') { json.name = "Unnamed Filler"; diff --git a/src/dao/plex-server-db.js b/src/dao/plex-server-db.js index ebbf09e..5b349c5 100644 --- a/src/dao/plex-server-db.js +++ b/src/dao/plex-server-db.js @@ -1,14 +1,20 @@ //hmnn this is more of a "PlexServerService"... +const ICON_REGEX = /https?:\/\/.*(\/library\/metadata\/\d+\/thumb\/\d+).X-Plex-Token=.*/; + +const ICON_FIELDS = ["icon", "showIcon", "seasonIcon", "episodeIcon"]; + class PlexServerDB { - constructor(channelDB, channelCache, db) { + constructor(channelDB, channelCache, fillerDB, showDB, db) { this.channelDB = channelDB; this.db = db; this.channelCache = channelCache; + this.fillerDB = fillerDB; + this.showDB = showDB; } - async deleteServer(name) { + async fixupAllChannels(name, newServer) { let channelNumbers = await this.channelDB.getAllChannelNumbers(); let report = await Promise.all( channelNumbers.map( async (i) => { let channel = await this.channelDB.getChannel(i); @@ -16,17 +22,10 @@ class PlexServerDB channelNumber : channel.number, channelName : channel.name, destroyedPrograms: 0, + modifiedPrograms: 0, }; - this.fixupProgramArray(channel.programs, name, channelReport); - this.fixupProgramArray(channel.fillerContent, name, channelReport); - this.fixupProgramArray(channel.fallback, name, channelReport); - if (typeof(channel.fillerContent) !== 'undefined') { - channel.fillerContent = channel.fillerContent.filter( - (p) => { - return (true !== p.isOffline); - } - ); - } + this.fixupProgramArray(channel.programs, name,newServer, channelReport); + //if fallback became offline, remove it if ( (typeof(channel.fallback) !=='undefined') && (channel.fallback.length > 0) @@ -38,15 +37,87 @@ class PlexServerDB channel.offlinePicture = `http://localhost:${process.env.PORT}/images/generic-offline-screen.png`; } } - this.fixupProgramArray(channel.fallback, name, channelReport); + this.fixupProgramArray(channel.fallback, name,newServer, channelReport); await this.channelDB.saveChannel(i, channel); - this.db['plex-servers'].remove( { name: name } ); return channelReport; }) ); this.channelCache.clear(); return report; } + async fixupAllFillers(name, newServer) { + let fillers = await this.fillerDB.getAllFillers(); + let report = await Promise.all( fillers.map( async (filler) => { + let fillerReport = { + channelNumber : "--", + channelName : filler.name + " (filler)", + destroyedPrograms: 0, + modifiedPrograms: 0, + }; + this.fixupProgramArray( filler.content, name,newServer, fillerReport ); + filler.content = this.removeOffline(filler.content); + + await this.fillerDB.saveFiller( filler.id, filler ); + + return fillerReport; + } ) ); + return report; + + } + + async fixupAllShows(name, newServer) { + let shows = await this.showDB.getAllShows(); + let report = await Promise.all( shows.map( async (show) => { + let showReport = { + channelNumber : "--", + channelName : show.name + " (custom show)", + destroyedPrograms: 0, + modifiedPrograms: 0, + }; + this.fixupProgramArray( show.content, name,newServer, showReport ); + show.content = this.removeOffline(show.content); + + await this.showDB.saveShow( show.id, show ); + + return showReport; + } ) ); + return report; + + } + + + removeOffline( progs ) { + if (typeof(progs) === 'undefined') { + return progs; + } + return progs.filter( + (p) => { + return (true !== p.isOffline); + } + ); + } + + async fixupEveryProgramHolders(serverName, newServer) { + let reports = await Promise.all( [ + this.fixupAllChannels( serverName, newServer ), + this.fixupAllFillers(serverName, newServer), + this.fixupAllShows(serverName, newServer), + ] ); + let report = []; + reports.forEach( + (r) => r.forEach( (r2) => { + report.push(r2) + } ) + ); + return report; + } + + async deleteServer(name) { + let report = await this.fixupEveryProgramHolders(name, null); + this.db['plex-servers'].remove( { name: name } ); + return report; + } + doesNameExist(name) { return this.db['plex-servers'].find( { name: name} ).length > 0; } @@ -77,11 +148,15 @@ class PlexServerDB arChannels: arChannels, index: s.index, } + this.normalizeServer(newServer); + + let report = await this.fixupEveryProgramHolders(name, newServer); this.db['plex-servers'].update( { _id: s._id }, newServer ); + return report; } @@ -117,26 +192,56 @@ class PlexServerDB arChannels: arChannels, index: index, }; + this.normalizeServer(newServer); this.db['plex-servers'].save(newServer); } - fixupProgramArray(arr, serverName, channelReport) { + fixupProgramArray(arr, serverName,newServer, channelReport) { if (typeof(arr) !== 'undefined') { for(let i = 0; i < arr.length; i++) { - arr[i] = this.fixupProgram( arr[i], serverName, channelReport ); + arr[i] = this.fixupProgram( arr[i], serverName,newServer, channelReport ); } } } - fixupProgram(program, serverName, channelReport) { - if (program.serverKey === serverName) { + fixupProgram(program, serverName,newServer, channelReport) { + if ( (program.serverKey === serverName) && (newServer == null) ) { channelReport.destroyedPrograms += 1; return { isOffline: true, duration: program.duration, } + } else if (program.serverKey === serverName) { + let modified = false; + ICON_FIELDS.forEach( (field) => { + if ( + (typeof(program[field] ) === 'string') + && + program[field].includes("/library/metadata") + && + program[field].includes("X-Plex-Token") + ) { + let m = program[field].match(ICON_REGEX); + if (m.length == 2) { + let lib = m[1]; + let newUri = `${newServer.uri}${lib}?X-Plex-Token=${newServer.accessToken}` + program[field] = newUri; + modified = true; + } + } + + } ); + if (modified) { + channelReport.modifiedPrograms += 1; + } } return program; } + + normalizeServer(server) { + while (server.uri.endsWith("/")) { + server.uri = server.uri.slice(0,-1); + } + } } module.exports = PlexServerDB \ No newline at end of file diff --git a/src/plex-player.js b/src/plex-player.js index d21bcdc..9a75f84 100644 --- a/src/plex-player.js +++ b/src/plex-player.js @@ -49,7 +49,7 @@ class PlexPlayer { let channel = this.context.channel; let server = db['plex-servers'].find( { 'name': lineupItem.serverKey } ); if (server.length == 0) { - throw Error(`Unable to find server "${lineupItem.serverKey}" specied by program.`); + throw Error(`Unable to find server "${lineupItem.serverKey}" specified by program.`); } server = server[0]; if (server.uri.endsWith("/")) { diff --git a/web/directives/plex-server-edit.js b/web/directives/plex-server-edit.js index c608d19..7772381 100644 --- a/web/directives/plex-server-edit.js +++ b/web/directives/plex-server-edit.js @@ -9,11 +9,13 @@ module.exports = function (dizquetv, $timeout) { }, link: function (scope, element, attrs) { scope.state.modified = false; + scope.loading = { show: false }; scope.setModified = () => { scope.state.modified = true; } scope.onSave = async () => { try { + scope.loading = { show: true }; await dizquetv.updatePlexServer(scope.state.server); scope.state.modified = false; scope.state.success = "The server was updated."; @@ -23,6 +25,8 @@ module.exports = function (dizquetv, $timeout) { scope.state.error = "There was an error updating the server"; scope.state.success = ""; console.error(scope.state.error, err); + } finally { + scope.loading = { show: false }; } $timeout( () => { scope.$apply() } , 0 ); } diff --git a/web/public/templates/plex-server-edit.html b/web/public/templates/plex-server-edit.html index 6a3f63f..444034d 100644 --- a/web/public/templates/plex-server-edit.html +++ b/web/public/templates/plex-server-edit.html @@ -84,12 +84,15 @@ - From 91a5f6337e339e83e03534bec0b912ed60014c29 Mon Sep 17 00:00:00 2001 From: vexorian Date: Thu, 25 Mar 2021 22:41:31 -0400 Subject: [PATCH 5/8] #297 include year in plex library. --- web/directives/plex-library.js | 25 +++++++++++++++++++++++++ web/public/templates/plex-library.html | 9 ++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/web/directives/plex-library.js b/web/directives/plex-library.js index 4e21a52..ce1018a 100644 --- a/web/directives/plex-library.js +++ b/web/directives/plex-library.js @@ -219,6 +219,31 @@ module.exports = function (plex, dizquetv, $timeout, commonProgramTools) { scope.customShows = await dizquetv.getAllShowsInfo(); scope.$apply(); } + + scope.displayTitle = (show) => { + let r = ""; + if (show.type === 'episode') { + r += show.showTitle + " - "; + if ( typeof(show.season) !== 'undefined' ) { + r += "S" + show.season.toString().padStart(2,'0'); + } + if ( typeof(show.episode) !== 'undefined' ) { + r += "E" + show.episode.toString().padStart(2,'0'); + } + } + if (r != "") { + r = r + " - "; + } + r += show.title; + if ( + (show.type !== 'episode') + && + (typeof(show.year) !== 'undefined') + ) { + r += " (" + JSON.stringify(show.year) + ")"; + } + return r; + } } }; } \ No newline at end of file diff --git a/web/public/templates/plex-library.html b/web/public/templates/plex-library.html index 7a08241..7c678e1 100644 --- a/web/public/templates/plex-library.html +++ b/web/public/templates/plex-library.html @@ -36,7 +36,7 @@
- {{a.title}} + {{ displayTitle(a) }} @@ -50,7 +50,7 @@ - {{b.title}} + {{ displayTitle(b) }} {{b.durationStr}} @@ -75,8 +75,7 @@ - {{ c.type === 'episode' ? c.showTitle + ' - S' + c.season.toString().padStart(2,'0') + 'E' + c.episode.toString().padStart(2,'0') + ' - ' : '' }} - {{c.title}} + {{ displayTitle(c) }} {{c.durationStr}} @@ -91,7 +90,7 @@
- E{{ d.episode.toString().padStart(2,'0')}} - {{d.title}} + {{ displayTitle(d) }} {{d.durationStr}}
From 8d844f0ae39d40f3d4a422a72ab6d3cbaa0a43e2 Mon Sep 17 00:00:00 2001 From: vexorian Date: Fri, 26 Mar 2021 09:59:00 -0400 Subject: [PATCH 6/8] Slots improvements. Fix rare bug in which some times the starting times would get completely messed up. Consecutive flex times are now guaranteed to be merged into a bigger one. --- src/services/random-slots-service.js | 36 +++++++++++++++------------- src/services/time-slots-service.js | 34 +++++++++++++------------- web/directives/channel-config.js | 10 +++++++- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/services/random-slots-service.js b/src/services/random-slots-service.js index dc3ef70..2cc6064 100644 --- a/src/services/random-slots-service.js +++ b/src/services/random-slots-service.js @@ -276,11 +276,11 @@ module.exports = async( programs, schedule ) => { let s = schedule.slots; let ts = (new Date() ).getTime(); - let curr = ts - ts % DAY; + let t0 = ts; let p = []; let t = t0; - let wantedFinish = 0; + let hardLimit = t0 + schedule.maxDays * DAY; let pushFlex = (d) => { @@ -297,6 +297,15 @@ module.exports = async( programs, schedule ) => { } } + let pushProgram = (item) => { + if ( item.isOffline && (item.type !== 'redirect') ) { + pushFlex(item.duration); + } else { + p.push(item); + t += item.duration; + } + }; + let slotLastPlayed = {}; while ( (t < hardLimit) && (p.length < LIMIT) ) { @@ -338,15 +347,14 @@ module.exports = async( programs, schedule ) => { if (item.isOffline) { //flex or redirect. We can just use the whole duration - p.push(item); - t += remaining; + item.duration = remaining; + pushProgram(item); slotLastPlayed[ slotIndex ] = t; continue; } if (item.duration > remaining) { // Slide - p.push(item); - t += item.duration; + pushProgram(item); slotLastPlayed[ slotIndex ] = t; advanceSlot(slot); continue; @@ -412,8 +420,7 @@ module.exports = async( programs, schedule ) => { } // now unroll them all for (let i = 0; i < pads.length; i++) { - p.push( pads[i].item ); - t += pads[i].item.duration; + pushProgram( pads[i].item ); slotLastPlayed[ slotIndex ] = t; pushFlex( pads[i].pad ); } @@ -421,15 +428,10 @@ module.exports = async( programs, schedule ) => { while ( (t > hardLimit) || (p.length >= LIMIT) ) { t -= p.pop().duration; } - let m = t % schedule.period; - let rem = 0; - if (m > wantedFinish) { - rem = schedule.period + wantedFinish - m; - } else if (m < wantedFinish) { - rem = wantedFinish - m; - } - if (rem > constants.SLACK) { - pushFlex(rem); + let m = (t - t0) % schedule.period; + if (m != 0) { + //ensure the schedule is a multiple of period + pushFlex( schedule.period - m); } diff --git a/src/services/time-slots-service.js b/src/services/time-slots-service.js index 5fd3159..64b6115 100644 --- a/src/services/time-slots-service.js +++ b/src/services/time-slots-service.js @@ -302,6 +302,15 @@ module.exports = async( programs, schedule ) => { } } + let pushProgram = (item) => { + if ( item.isOffline && (item.type !== 'redirect') ) { + pushFlex(item.duration); + } else { + p.push(item); + t += item.duration; + } + }; + if (ts > t0) { pushFlex( ts - t0 ); } @@ -355,14 +364,13 @@ module.exports = async( programs, schedule ) => { if (item.isOffline) { //flex or redirect. We can just use the whole duration - p.push(item); - t += remaining; + item.duration = remaining; + pushProgram(item); continue; } if (item.duration > remaining) { // Slide - p.push(item); - t += item.duration; + pushProgram(item); advanceSlot(slot); continue; } @@ -373,7 +381,7 @@ module.exports = async( programs, schedule ) => { let pads = [ padded ]; while(true) { - let item2 = getNextForSlot(slot); + let item2 = getNextForSlot(slot, remaining); if (total + item2.duration > remaining) { break; } @@ -413,23 +421,17 @@ module.exports = async( programs, schedule ) => { } // now unroll them all for (let i = 0; i < pads.length; i++) { - p.push( pads[i].item ); - t += pads[i].item.duration; + pushProgram( pads[i].item ); pushFlex( pads[i].pad ); } } while ( (t > hardLimit) || (p.length >= LIMIT) ) { t -= p.pop().duration; } - let m = t % schedule.period; - let rem = 0; - if (m > wantedFinish) { - rem = schedule.period + wantedFinish - m; - } else if (m < wantedFinish) { - rem = wantedFinish - m; - } - if (rem > constants.SLACK) { - pushFlex(rem); + let m = (t - t0) % schedule.period; + if (m > 0) { + //ensure the schedule is a multiple of period + pushFlex( schedule.period - m); } diff --git a/web/directives/channel-config.js b/web/directives/channel-config.js index 685bce2..9885f29 100644 --- a/web/directives/channel-config.js +++ b/web/directives/channel-config.js @@ -163,7 +163,15 @@ module.exports = function ($timeout, $location, dizquetv, resolutionOptions, get let t = Date.now(); let originalStart = scope.channel.startTime.getTime(); let n = scope.channel.programs.length; - let totalDuration = scope.channel.duration; + //scope.channel.totalDuration might not have been initialized + let totalDuration = 0; + for (let i = 0; i < n; i++) { + totalDuration += scope.channel.programs[i].duration; + } + if (totalDuration == 0) { + return; + } + let m = (t - originalStart) % totalDuration; let x = 0; let runningProgram = -1; From c2731f0a3478a178e031f26935b57349e52ce1c6 Mon Sep 17 00:00:00 2001 From: vexorian Date: Fri, 26 Mar 2021 10:04:31 -0400 Subject: [PATCH 7/8] Maybe this helps? --- src/video.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/video.js b/src/video.js index 6c1d483..1010476 100644 --- a/src/video.js +++ b/src/video.js @@ -123,10 +123,14 @@ 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) => { // Check if channel queried is valid + res.on("error", (e) => { + console.err("There was an unexpected error in stream.", e); + } ); if (typeof req.query.channel === 'undefined') { res.status(400).send("No Channel Specified") return } + let audioOnly = ("true" == req.query.audioOnly); console.log(`/stream audioOnly=${audioOnly}`); let session = parseInt(req.query.session); @@ -323,6 +327,7 @@ function video( channelDB , fillerDB, db) { res.writeHead(200, { 'Content-Type': 'video/mp2t' }); + try { playerObj = await player.play(res); } catch (err) { From c75c9bc8e1cea73dbb7ede83b6d466eb66996ed3 Mon Sep 17 00:00:00 2001 From: vexorian Date: Fri, 26 Mar 2021 10:05:39 -0400 Subject: [PATCH 8/8] Rename 1.3.3 to 1.4.1 --- README.md | 2 +- src/constants.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6c4769b..3581c59 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# dizqueTV 1.3.3-prerelease +# dizqueTV 1.4.1-prerelease ![Discord](https://img.shields.io/discord/711313431457693727?logo=discord&logoColor=fff&style=flat-square) ![GitHub top language](https://img.shields.io/github/languages/top/vexorian/dizquetv?logo=github&style=flat-square) ![Docker Pulls](https://img.shields.io/docker/pulls/vexorian/dizquetv?logo=docker&logoColor=fff&style=flat-square) Create live TV channel streams from media on your Plex servers. diff --git a/src/constants.js b/src/constants.js index 760e229..aa15f72 100644 --- a/src/constants.js +++ b/src/constants.js @@ -5,5 +5,5 @@ module.exports = { TVGUIDE_MAXIMUM_FLEX_DURATION : 6 * 60 * 60 * 1000, TOO_FREQUENT: 100, - VERSION_NAME: "1.3.3-prerelease" + VERSION_NAME: "1.4.1-prerelease" }