dizquetv/src/helperFuncs.js

227 lines
8.1 KiB
JavaScript

module.exports = {
getCurrentProgramAndTimeElapsed: getCurrentProgramAndTimeElapsed,
createLineup: createLineup,
isChannelIconEnabled: isChannelIconEnabled,
}
let channelCache = require('./channel-cache');
const SLACK = require('./constants').SLACK;
function getCurrentProgramAndTimeElapsed(date, channel) {
let channelStartTime = (new Date(channel.startTime)).getTime();
if (channelStartTime > date) {
let t0 = date;
let t1 = channelStartTime;
console.log(t0, t1);
console.log("Channel start time is above the given date. Flex time is picked till that.");
return {
program: {
isOffline: true,
duration : t1 - t0,
},
timeElapsed: 0,
programIndex: -1,
}
}
let timeElapsed = (date - channelStartTime) % channel.duration
let currentProgramIndex = -1
for (let y = 0, l2 = channel.programs.length; y < l2; y++) {
let program = channel.programs[y]
if (timeElapsed - program.duration < 0) {
currentProgramIndex = y
if ( (program.duration > 2*SLACK) && (timeElapsed > program.duration - SLACK) ) {
timeElapsed = 0;
currentProgramIndex = (y + 1) % channel.programs.length;
}
break;
} else {
timeElapsed -= program.duration
}
}
if (currentProgramIndex === -1)
throw new Error("No program found; find algorithm fucked up")
return { program: channel.programs[currentProgramIndex], timeElapsed: timeElapsed, programIndex: currentProgramIndex }
}
function createLineup(obj, channel, isFirst) {
let timeElapsed = obj.timeElapsed
// Start time of a file is never consistent unless 0. Run time of an episode can vary.
// When within 30 seconds of start time, just make the time 0 to smooth things out
// Helps prevents loosing first few seconds of an episode upon lineup change
let activeProgram = obj.program
let lineup = []
if ( typeof(activeProgram.err) !== 'undefined') {
let remaining = activeProgram.duration - timeElapsed;
lineup.push( {
type: 'offline',
title: 'Error',
err: activeProgram.err,
streamDuration: remaining,
duration: remaining,
start: 0
})
return lineup;
}
if (activeProgram.isOffline === true) {
//offline case
let remaining = activeProgram.duration - timeElapsed;
//look for a random filler to play
let filler = null;
let special = null;
if (typeof(channel.fillerContent) !== 'undefined') {
if ( (channel.offlineMode === 'clip') && (channel.fallback.length != 0) ) {
special = JSON.parse(JSON.stringify(channel.fallback[0]));
}
let randomResult = pickRandomWithMaxDuration(channel, channel.fillerContent, remaining + (isFirst? (24*60*60*1000) : 0) );
filler = randomResult.filler;
if (filler == null && (typeof(randomResult.minimumWait) !== undefined) && (remaining > randomResult.minimumWait) ) {
remaining = randomResult.minimumWait;
}
}
let isSpecial = false;
if (filler == null) {
filler = special;
isSpecial = true;
}
if (filler != null) {
let fillerstart = 0;
if (isSpecial) {
if (filler.duration > remaining) {
fillerstart = filler.duration - remaining;
} else {
ffillerstart = 0;
}
} else if(isFirst) {
fillerstart = Math.max(0, filler.duration - remaining);
//it's boring and odd to tune into a channel and it's always
//the start of a commercial.
let more = Math.max(0, filler.duration - fillerstart - 15000 - SLACK);
fillerstart += Math.floor(more * Math.random() );
}
lineup.push({ // just add the video, starting at 0, playing the entire duration
type: 'commercial',
title: filler.title,
key: filler.key,
plexFile: filler.plexFile,
file: filler.file,
ratingKey: filler.ratingKey,
start: fillerstart,
streamDuration: Math.max(1, Math.min(filler.duration - fillerstart, remaining) ),
duration: filler.duration,
serverKey: filler.serverKey
});
return lineup;
}
// pick the offline screen
remaining = Math.min(remaining, 10*60*1000);
//don't display the offline screen for longer than 10 minutes. Maybe the
//channel's admin might change the schedule during that time and then
//it would be better to start playing the content.
lineup.push( {
type: 'offline',
title: 'Channel Offline',
streamDuration: remaining,
duration: remaining,
start: 0
})
return lineup;
}
if (timeElapsed < 30000) {
timeElapsed = 0
}
return [ {
type: 'program',
title: activeProgram.title,
key: activeProgram.key,
plexFile: activeProgram.plexFile,
file: activeProgram.file,
ratingKey: activeProgram.ratingKey,
start: timeElapsed,
streamDuration: activeProgram.duration - timeElapsed,
duration: activeProgram.duration,
serverKey: activeProgram.serverKey
} ];
}
function pickRandomWithMaxDuration(channel, list, maxDuration) {
let pick1 = null;
let pick2 = null;
let n = 0;
let m = 0;
let t0 = (new Date()).getTime();
let minimumWait = 1000000000;
const D = 24*60*60*1000;
if (typeof(channel.fillerRepeatCooldown) === 'undefined') {
channel.fillerRepeatCooldown = 30*60*1000;
}
for (let i = 0; i < list.length; i++) {
let clip = list[i];
// a few extra milliseconds won't hurt anyone, would it? dun dun dun
if (clip.duration <= maxDuration + SLACK ) {
let t1 = channelCache.getProgramLastPlayTime( channel.number, clip );
let timeSince = ( (t1 == 0) ? D : (t0 - t1) );
if (timeSince < channel.fillerRepeatCooldown - SLACK) {
let w = channel.fillerRepeatCooldown - timeSince;
if (clip.duration + w <= maxDuration + SLACK) {
minimumWait = Math.min(minimumWait, w);
}
timeSince = 0;
//30 minutes is too little, don't repeat it at all
}
if (timeSince >= D) {
let w = Math.pow(clip.duration, 1.0 / 4.0);
n += w;
if ( n*Math.random() < w) {
pick1 = clip;
}
} else {
let adjust = Math.floor(timeSince / (60*1000));
if (adjust > 0) {
adjust = adjust * adjust;
//weighted
m += adjust;
if ( Math.floor(m*Math.random()) < adjust) {
pick2 = clip;
}
}
}
}
}
let pick = (pick1 == null) ? pick2: pick1;
let pickTitle = "null";
if (pick != null) {
pickTitle = pick.title;
}
return {
filler: pick,
minimumWait : minimumWait,
}
}
function isChannelIconEnabled( ffmpegSettings, channel, type) {
if (! ffmpegSettings.enableFFMPEGTranscoding || ffmpegSettings.disableChannelOverlay ) {
return false;
}
let d = channel.disableFillerOverlay;
if (typeof(d) === 'undefined') {
d = true;
}
if ( (typeof type !== `undefined`) && (type == 'commercial') && d ) {
return false;
}
if (channel.icon === '' || !channel.overlayIcon) {
return false;
}
return true;
}