diff --git a/index.js b/index.js index b97c8c7..da5ee00 100644 --- a/index.js +++ b/index.js @@ -309,6 +309,10 @@ function initDB(db, channelDB) { let data = fs.readFileSync(path.resolve(path.join(__dirname, 'resources/loading-screen.png'))) fs.writeFileSync(process.env.DATABASE + '/images/loading-screen.png', data) } + if (!fs.existsSync(process.env.DATABASE + '/images/black.png')) { + let data = fs.readFileSync(path.resolve(path.join(__dirname, 'resources/black.png'))) + fs.writeFileSync(process.env.DATABASE + '/images/black.png', data) + } if (!fs.existsSync( path.join(process.env.DATABASE, 'custom.css') )) { let data = fs.readFileSync(path.resolve(path.join(__dirname, 'resources', 'default-custom.css'))) fs.writeFileSync( path.join(process.env.DATABASE, 'custom.css'), data) diff --git a/resources/black.png b/resources/black.png new file mode 100644 index 0000000..72bdc8d Binary files /dev/null and b/resources/black.png differ diff --git a/src/ffmpeg.js b/src/ffmpeg.js index 00ace6c..30a6895 100644 --- a/src/ffmpeg.js +++ b/src/ffmpeg.js @@ -471,7 +471,8 @@ class FFMPEG extends events.EventEmitter { `-c:v`, (transcodeVideo ? this.opts.videoEncoder : 'copy'), `-sc_threshold`, `1000000000`, ); - if (stillImage) { + // do not use -tune stillimage for nv + if (stillImage && ! this.opts.videoEncoder.toLowerCase().includes("nv") ) { ffmpegArgs.push('-tune', 'stillimage'); } } @@ -482,7 +483,6 @@ class FFMPEG extends events.EventEmitter { if ( transcodeVideo && (this.audioOnly !== true) ) { // add the video encoder flags ffmpegArgs.push( - `-b:v`, `${this.opts.videoBitrate}k`, `-maxrate:v`, `${this.opts.videoBitrate}k`, `-bufsize:v`, `${this.opts.videoBufSize}k` ); diff --git a/src/offline-player.js b/src/offline-player.js index 38d846e..9140041 100644 --- a/src/offline-player.js +++ b/src/offline-player.js @@ -18,6 +18,11 @@ class OfflinePlayer { context.channel.offlinePicture = `http://localhost:${process.env.PORT}/images/loading-screen.png`; context.channel.offlineSoundtrack = undefined; } + if (context.isInterlude === true) { + context.channel = JSON.parse( JSON.stringify(context.channel) ); + context.channel.offlinePicture = `http://localhost:${process.env.PORT}/images/black.png`; + context.channel.offlineSoundtrack = undefined; + } this.ffmpeg = new FFMPEG(context.ffmpegSettings, context.channel); this.ffmpeg.setAudioOnly(this.context.audioOnly); } diff --git a/src/program-player.js b/src/program-player.js index 260ff10..3d9fd1c 100644 --- a/src/program-player.js +++ b/src/program-player.js @@ -42,6 +42,11 @@ class ProgramPlayer { /* loading */ context.isLoading = true; this.delegate = new OfflinePlayer(false, context); + } else if (program.type === 'interlude') { + console.log("About to play interlude stream"); + /* interlude */ + context.isInterlude = true; + this.delegate = new OfflinePlayer(false, context); } else if (program.type === 'offline') { console.log("About to play offline stream"); /* offline */ diff --git a/src/throttler.js b/src/throttler.js index ac42a11..10e4c67 100644 --- a/src/throttler.js +++ b/src/throttler.js @@ -7,7 +7,9 @@ function equalItems(a, b) { if ( (typeof(a) === 'undefined') || a.isOffline || b.isOffline ) { return false; } - return ( a.type === b.type); + console.log("no idea how to compare this: " + JSON.stringify(a) ); + console.log(" with this: " + JSON.stringify(b) ); + return a.title === b.title; } @@ -17,15 +19,14 @@ function wereThereTooManyAttempts(sessionId, lineupItem) { let t1 = (new Date()).getTime(); let previous = cache[sessionId]; + let result = false; + if (typeof(previous) === 'undefined') { previous = cache[sessionId] = { t0: t1 - constants.TOO_FREQUENT * 5, lineupItem: null, }; - } - - let result = false; - if (t1 - previous.t0 < constants.TOO_FREQUENT) { + } else if (t1 - previous.t0 < constants.TOO_FREQUENT) { //certainly too frequent result = equalItems( previous.lineupItem, lineupItem ); } @@ -49,4 +50,4 @@ function wereThereTooManyAttempts(sessionId, lineupItem) { } -module.exports = wereThereTooManyAttempts; \ No newline at end of file +module.exports = wereThereTooManyAttempts; diff --git a/src/video.js b/src/video.js index fb6fefa..e4f6f96 100644 --- a/src/video.js +++ b/src/video.js @@ -167,6 +167,8 @@ function video( channelService, fillerDB, db, programmingService, activeChannelS isFirst = true; } + let isBetween = ( (typeof req.query.between !== 'undefined') && (req.query.between=='1') ); + let ffmpegSettings = db['ffmpeg-settings'].find()[0] // Check if ffmpeg path is valid @@ -180,20 +182,35 @@ function video( channelService, fillerDB, db, programmingService, activeChannelS // Get video lineup (array of video urls with calculated start times and durations.) - let lineupItem = channelCache.getCurrentLineupItem( channel.number, t0); + let prog = null; let brandChannel = channel; let redirectChannels = []; let upperBounds = []; + const GAP_DURATION = 750; if (isLoading) { lineupItem = { type: 'loading', - streamDuration: 40, - duration: 40, + title: "Loading Screen", + streamDuration: GAP_DURATION, + duration: GAP_DURATION, + redirectChannels: [channel], start: 0, }; - } else if (lineupItem != null) { + } else if (isBetween) { + lineupItem = { + type: 'interlude', + title: "Interlude Screen", + streamDuration: GAP_DURATION, + duration: GAP_DURATION, + redirectChannels: [channel], + start: 0, + }; + } else { + lineupItem = channelCache.getCurrentLineupItem( channel.number, t0); + } + if (lineupItem != null) { redirectChannels = lineupItem.redirectChannels; upperBounds = lineupItem.upperBounds; brandChannel = redirectChannels[ redirectChannels.length -1]; @@ -278,7 +295,7 @@ function video( channelService, fillerDB, db, programmingService, activeChannelS lineupItem = lineup.shift(); } - if ( !isLoading && (lineupItem != null) ) { + if ( !isBetween && !isLoading && (lineupItem != null) ) { let upperBound = 1000000000; let beginningOffset = 0; if (typeof(lineupItem.beginningOffset) !== 'undefined') { @@ -317,7 +334,7 @@ function video( channelService, fillerDB, db, programmingService, activeChannelS } console.log("========================================================="); - if (! isLoading) { + if (! isLoading && ! isBetween) { channelCache.recordPlayback(channel.number, t0, lineupItem); } if (wereThereTooManyAttempts(session, lineupItem)) { @@ -553,8 +570,12 @@ function video( channelService, fillerDB, db, programmingService, activeChannelS data += `file 'http://localhost:${process.env.PORT}/stream?channel=${channelNum}&first=0&session=${sessionId}&audioOnly=${audioOnly}'\n`; } data += `file 'http://localhost:${process.env.PORT}/stream?channel=${channelNum}&first=1&session=${sessionId}&audioOnly=${audioOnly}'\n` + + data += `file 'http://localhost:${process.env.PORT}/stream?channel=${channelNum}&between=1&session=${sessionId}&audioOnly=${audioOnly}'\n`; + for (var i = 0; i < maxStreamsToPlayInARow - 1; i++) { data += `file 'http://localhost:${process.env.PORT}/stream?channel=${channelNum}&session=${sessionId}&audioOnly=${audioOnly}'\n` + data += `file 'http://localhost:${process.env.PORT}/stream?channel=${channelNum}&between=1&session=${sessionId}&audioOnly=${audioOnly}'\n` } res.send(data)