dizquetv/web/directives/channel-config.js
2020-08-10 22:53:40 -04:00

879 lines
39 KiB
JavaScript

module.exports = function ($timeout, $location) {
return {
restrict: 'E',
templateUrl: 'templates/channel-config.html',
replace: true,
scope: {
channels: "=channels",
channel: "=channel",
onDone: "=onDone"
},
link: function (scope, element, attrs) {
scope.hasFlex = false;
scope.showHelp = false;
scope._frequencyModified = false;
scope._frequencyMessage = "";
scope.millisecondsOffset = 0;
scope.minProgramIndex = 0;
if (typeof scope.channel === 'undefined' || scope.channel == null) {
scope.channel = {}
scope.channel.programs = []
scope.channel.fillerContent = []
scope.channel.fillerRepeatCooldown = 30 * 60 * 1000;
scope.channel.fallback = [];
scope.isNewChannel = true
scope.channel.icon = `${$location.protocol()}://${location.host}/images/dizquetv.png`
scope.channel.disableFillerOverlay = true;
scope.channel.iconWidth = 120
scope.channel.iconDuration = 60
scope.channel.iconPosition = "2"
scope.channel.startTime = new Date()
scope.channel.startTime.setMilliseconds(0)
scope.channel.startTime.setSeconds(0)
scope.channel.offlinePicture = `${$location.protocol()}://${location.host}/images/generic-offline-screen.png`
scope.channel.offlineSoundtrack = ''
scope.channel.offlineMode = "pic";
if (scope.channel.startTime.getMinutes() < 30)
scope.channel.startTime.setMinutes(0)
else
scope.channel.startTime.setMinutes(30)
if (scope.channels.length > 0) {
scope.channel.number = scope.channels[scope.channels.length - 1].number + 1
scope.channel.name = "Channel " + scope.channel.number
} else {
scope.channel.number = 1
scope.channel.name = "Channel 1"
}
scope.showRotatedNote = false;
} else {
scope.beforeEditChannelNumber = scope.channel.number
let t = Date.now();
let originalStart = scope.channel.startTime.getTime();
let n = scope.channel.programs.length;
let totalDuration = scope.channel.duration;
let m = (t - originalStart) % totalDuration;
let x = 0;
let runningProgram = -1;
let offset = 0;
for (let i = 0; i < n; i++) {
let d = scope.channel.programs[i].duration;
if (x + d > m) {
runningProgram = i
offset = m - x;
break;
} else {
x += d;
}
}
if (typeof(scope.channel.fillerRepeatCooldown) === 'undefined') {
scope.channel.fillerRepeatCooldown = 30 * 60 * 1000;
}
if (typeof(scope.channel.offlinePicture)==='undefined') {
scope.channel.offlinePicture = `${$location.protocol()}://${location.host}/images/generic-offline-screen.png`
scope.channel.offlineSoundtrack = '';
}
if (typeof(scope.channel.fillerContent)==='undefined') {
scope.channel.fillerContent = [];
}
if (typeof(scope.channel.fallback)==='undefined') {
scope.channel.fallback = [];
scope.channel.offlineMode = "pic";
}
if (typeof(scope.channel.offlineMode)==='undefined') {
scope.channel.offlineMode = 'pic';
}
if (typeof(scope.channel.disableFillerOverlay) === 'undefined') {
scope.channel.disableFillerOverlay = true;
}
scope.millisecondsOffset = (t - offset) % 1000;
scope.channel.startTime = new Date(t - offset - scope.millisecondsOffset);
// move runningProgram to index 0
scope.channel.programs = scope.channel.programs.slice(runningProgram, this.length)
.concat(scope.channel.programs.slice(0, runningProgram) );
updateChannelDuration();
setTimeout( () => { scope.showRotatedNote = true }, 1, 'funky');
}
scope.finshedProgramEdit = (program) => {
scope.channel.programs[scope.selectedProgram] = program
scope._selectedProgram = null
updateChannelDuration()
}
scope.dropFunction = (dropIndex, index, program) => {
if (scope.channel.programs[index].start == program.start) {
return false;
}
setTimeout( () => {
scope.channel.programs.splice(dropIndex + index, 0, program);
updateChannelDuration()
}, 1);
return true;
}
scope.updateChannelFromOfflineResult = (program) => {
scope.channel.offlineMode = program.channelOfflineMode;
scope.channel.offlinePicture = program.channelPicture;
scope.channel.offlineSoundtrack = program.channelSound;
scope.channel.fillerRepeatCooldown = program.repeatCooldown * 60000;
scope.channel.fillerContent = JSON.parse( angular.toJson(program.filler) );
scope.channel.fallback = JSON.parse( angular.toJson(program.fallback) );
scope.channel.disableFillerOverlay = program.disableOverlay;
}
scope.finishedOfflineEdit = (program) => {
let editedProgram = scope.channel.programs[scope.selectedProgram];
let duration = program.durationSeconds * 1000;
scope.updateChannelFromOfflineResult(program);
editedProgram.duration = duration;
editedProgram.actualDuration = duration;
editedProgram.isOffline = true;
scope._selectedOffline = null
updateChannelDuration()
}
scope.finishedAddingOffline = (result) => {
let duration = result.durationSeconds * 1000;
let program = {
duration: duration,
actualDuration: duration,
isOffline: true
}
scope.updateChannelFromOfflineResult(result);
scope.channel.programs.push( program );
scope._selectedOffline = null
scope._addingOffline = null;
updateChannelDuration()
}
scope.$watch('channel.startTime', () => {
updateChannelDuration()
})
scope.sortShows = () => {
scope.removeOffline();
let shows = {}
let movies = []
let newProgs = []
let progs = scope.channel.programs
for (let i = 0, l = progs.length; i < l; i++) {
if (progs[i].type === 'movie') {
movies.push(progs[i])
} else {
if (typeof shows[progs[i].showTitle] === 'undefined')
shows[progs[i].showTitle] = []
shows[progs[i].showTitle].push(progs[i])
}
}
let keys = Object.keys(shows)
for (let i = 0, l = keys.length; i < l; i++) {
shows[keys[i]].sort((a, b) => {
if (a.season === b.season) {
if (a.episode > b.episode) {
return 1
} else {
return -1
}
} else if (a.season > b.season) {
return 1;
} else if (b.season > a.season) {
return -1;
} else {
return 0
}
})
newProgs = newProgs.concat(shows[keys[i]])
}
scope.channel.programs = newProgs.concat(movies)
updateChannelDuration()
}
scope.dateForGuide = (date) => {
let t = date.toLocaleTimeString(undefined, {
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
if (t.charCodeAt(1) == 58) {
t = "0" + t;
}
return date.toLocaleDateString(undefined,{
year: "numeric",
month: "2-digit",
day: "2-digit"
}) + " " + t;
}
scope.sortByDate = () => {
scope.removeOffline();
scope.channel.programs.sort( (a,b) => {
let aHas = ( typeof(a.date) !== 'undefined' );
let bHas = ( typeof(b.date) !== 'undefined' );
if (!aHas && !bHas) {
return 0;
} else if (! aHas) {
return 1;
} else if (! bHas) {
return -1;
}
if (a.date < b.date ) {
return -1;
} else if (a.date > b.date) {
return 1;
} else {
let aHasSeason = ( typeof(a.season) !== 'undefined' );
let bHasSeason = ( typeof(b.season) !== 'undefined' );
if (! aHasSeason && ! bHasSeason) {
return 0;
} else if (! aHasSeason) {
return 1;
} else if (! bHasSeason) {
return -1;
}
if (a.season < b.season) {
return -1;
} else if (a.season > b.season) {
return 1;
} else if (a.episode < b.episode) {
return -1;
} else if (a.episode > b.episode) {
return 1;
} else {
return 0;
}
}
});
updateChannelDuration()
}
scope.removeDuplicates = () => {
let tmpProgs = {}
let progs = scope.channel.programs
for (let i = 0, l = progs.length; i < l; i++) {
if (progs[i].type === 'movie') {
tmpProgs[progs[i].title + progs[i].durationStr] = progs[i]
} else {
tmpProgs[progs[i].showTitle + '-' + progs[i].season + '-' + progs[i].episode] = progs[i]
}
}
let newProgs = []
let keys = Object.keys(tmpProgs)
for (let i = 0, l = keys.length; i < l; i++) {
newProgs.push(tmpProgs[keys[i]])
}
scope.channel.programs = newProgs
}
scope.removeOffline = () => {
let tmpProgs = []
let progs = scope.channel.programs
for (let i = 0, l = progs.length; i < l; i++) {
if (progs[i].isOffline !== true) {
tmpProgs.push(progs[i]);
}
}
scope.channel.programs = tmpProgs
updateChannelDuration()
}
scope.describeFallback = () => {
if (scope.channel.offlineMode === 'pic') {
if (
(typeof(scope.channel.offlineSoundtrack) !== 'undefined')
&& (scope.channel.offlineSoundtrack.length > 0)
) {
return "pic+sound";
} else {
return "pic";
}
} else {
return "clip";
}
}
scope.programSquareStyle = (program) => {
let background ="";
if (program.isOffline) {
background = "rgb(255, 255, 255)";
} else {
let r = 0, g = 0, b = 0, r2=0, g2=0,b2=0;
let i = 0;
let angle = 45;
let w = 3;
if (program.type === 'episode') {
let h = Math.abs(scope.getHashCode(program.showTitle, false));
let h2 = Math.abs(scope.getHashCode(program.showTitle, true));
r = h % 256;
g = (h / 256) % 256;
b = (h / (256*256) ) % 256;
i = h % 360;
r2 = (h2 / (256*256) ) % 256;
g2 = (h2 / (256*256) ) % 256;
b2 = (h2 / (256*256) ) % 256;
angle = -90 + h % 180
} else {
r = 10, g = 10, b = 10;
r2 = 245, g2 = 245, b2 = 245;
angle = 45;
w = 6;
}
let rgb1 = "rgb("+ r + "," + g + "," + b +")";
let rgb2 = "rgb("+ r2 + "," + g2 + "," + b2 +")"
background = "repeating-linear-gradient( " + angle + "deg, " + rgb1 + ", " + rgb1 + " " + w + "px, " + rgb2 + " " + w + "px, " + rgb2 + " " + (w*2) + "px)";
}
let ems = Math.pow( Math.min(24*60*60*1000, program.actualDuration), 0.7 );
ems = ems / Math.pow(5*60*1000., 0.7);
ems = Math.max( 0.25 , ems);
let top = Math.max(0.0, (1.75 - ems) / 2.0) ;
if (top == 0.0) {
top = "1px";
} else {
top = top + "em";
}
return {
'width': '0.5em',
'height': ems + 'em',
'margin-right': '0.50em',
'background': background,
'border': '1px solid black',
'margin-top': top,
'margin-bottom': '1px',
};
}
scope.getHashCode = (s, rev) => {
var hash = 0;
if (s.length == 0) return hash;
let inc = 1, st = 0, e = s.length;
if (rev) {
inc = -1, st = e - 1, e = -1;
}
for (var i = st; i != e; i+= inc) {
hash = s.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
scope.nightChannel = (a, b) => {
let o =(new Date()).getTimezoneOffset() * 60 * 1000;
let m = 24*60*60*1000;
a = (m + a * 60 * 60 * 1000 + o) % m;
b = (m + b * 60 * 60 * 1000 + o) % m;
if (b < a) {
b += m;
}
b -= a;
let progs = [];
let t = scope.channel.startTime.getTime();
function pos(x) {
if (x % m < a) {
return m + x % m - a;
} else {
return x % m - a;
}
}
t -= pos(t);
scope.channel.startTime = new Date(t);
for (let i = 0, l = scope.channel.programs.length; i < l; i++) {
let p = pos(t);
if ( (p != 0) && (p + scope.channel.programs[i].duration > b) ) {
//time to pad
let d = m - p;
progs.push(
{
duration: d,
actualDuration: d,
isOffline: true,
}
)
t += d;
p = 0;
}
progs.push( scope.channel.programs[i] );
t += scope.channel.programs[i].duration;
}
if (pos(t) != 0) {
let d = m - pos(t);
progs.push(
{
duration: d,
actualDuration: d,
isOffline: true,
}
)
}
scope.channel.programs = progs;
updateChannelDuration();
}
scope.addBreaks = (afterMinutes, minDurationSeconds, maxDurationSeconds) => {
let after = afterMinutes * 60 * 1000 + 5000; //allow some seconds of excess
let minDur = minDurationSeconds;
let maxDur = maxDurationSeconds;
let progs = [];
let tired = 0;
for (let i = 0, l = scope.channel.programs.length; i <= l; i++) {
let prog = scope.channel.programs[i % l];
if (prog.isOffline) {
tired = 0;
} else {
if (tired + prog.actualDuration >= after) {
tired = 0;
let dur = 1000 * (minDur + Math.floor( (maxDur - minDur) * Math.random() ) );
progs.push( {
isOffline : true,
duration: dur,
actualDuration: dur,
});
}
tired += prog.actualDuration;
}
if (i < l) {
progs.push(prog);
}
}
scope.channel.programs = progs;
updateChannelDuration();
}
scope.padTimes = (paddingMod, allow5) => {
let mod = paddingMod * 60 * 1000;
if (mod == 0) {
mod = 60*60*1000;
}
scope.removeOffline();
let progs = [];
let t = scope.channel.startTime.getTime();
t = t - t % mod;
scope.millisecondsOffset = 0;
scope.channel.startTime = new Date(t);
function addPad(force) {
let m = t % mod;
let r = (mod - t % mod) % mod;
if ( (force && (m != 0)) || ((m >= 15*1000) && (r >= 15*1000)) ) {
if (allow5 && (m <= 5*60*1000) ) {
r = 5*60*1000 - m;
}
// (If the difference is less than 30 seconds, it's
// not worth padding it
progs.push( {
duration : r,
actualDuration : r,
isOffline : true,
});
t += r;
}
}
for (let i = 0, l = scope.channel.programs.length; i < l; i++) {
let prog = scope.channel.programs[i];
progs.push(prog);
t += prog.actualDuration;
addPad(i == l - 1);
}
scope.channel.programs = progs;
updateChannelDuration();
}
scope.blockShuffle = (blockCount, randomize) => {
if (typeof blockCount === 'undefined' || blockCount == null)
return
let shows = {}
let movies = []
let newProgs = []
let progs = scope.channel.programs
for (let i = 0, l = progs.length; i < l; i++) {
if (progs[i].type === 'movie') {
movies.push(progs[i])
} else {
if (typeof shows[progs[i].showTitle] === 'undefined')
shows[progs[i].showTitle] = []
shows[progs[i].showTitle].push(progs[i])
}
}
let keys = Object.keys(shows)
let index = 0
if (randomize)
index = getRandomInt(0, keys.length - 1)
while (keys.length > 0) {
if (shows[keys[index]].length === 0) {
keys.splice(index, 1)
if (randomize) {
let tmp = index
index = getRandomInt(0, keys.length - 1)
while (keys.length > 1 && tmp == index)
index = getRandomInt(0, keys.length - 1)
} else {
if (index >= keys.length)
index = 0
}
continue
}
for (let i = 0, l = blockCount; i < l; i++) {
if (shows[keys[index]].length > 0)
newProgs.push(shows[keys[index]].shift())
}
if (randomize) {
let tmp = index
index = getRandomInt(0, keys.length - 1)
while (keys.length > 1 && tmp == index)
index = getRandomInt(0, keys.length - 1)
} else {
index++
if (index >= keys.length)
index = 0
}
}
scope.channel.programs = newProgs.concat(movies)
updateChannelDuration()
}
scope.randomShuffle = () => {
shuffle(scope.channel.programs)
updateChannelDuration()
}
scope.cyclicShuffle = () => {
cyclicShuffle(scope.channel.programs);
updateChannelDuration();
}
scope.equalizeShows = () => {
scope.removeDuplicates();
scope.channel.programs = equalizeShows(scope.channel.programs, {} );
updateChannelDuration();
}
scope.startFrequencyTweak = () => {
let programs = {};
for (let i = 0; i < scope.channel.programs.length; i++) {
if (! scope.channel.programs[i].isOffline) {
let c = getShowCode(scope.channel.programs[i]);
if ( typeof(programs[c]) === 'undefined') {
programs[c] = 0;
}
programs[c] += scope.channel.programs[i].actualDuration;
}
}
let mx = 0;
Object.keys(programs).forEach(function(key,index) {
mx = Math.max(mx, programs[key]);
});
let arr = [];
Object.keys(programs).forEach( (key,index) => {
let w = Math.ceil( (24.00*programs[key]) / mx );
let obj = {
name : key,
weight: w,
specialCategory: false,
displayName: key,
}
if (key.startsWith("_internal.")) {
obj.specialCategory = true;
obj.displayName = key.slice("_internal.".length);
}
arr.push(obj);
});
if (arr.length <= 1) {
scope._frequencyMessage = "Add more TV shows to the programming before using this option.";
} else {
scope._frequencyMessage = "";
}
scope._frequencyModified = false;
scope._programFrequencies = arr;
}
scope.tweakFrequencies = (freqs) => {
var f = {};
for (let i = 0; i < freqs.length; i++) {
f[freqs[i].name] = freqs[i].weight;
}
scope.removeDuplicates();
scope.channel.programs = equalizeShows(scope.channel.programs, f );
updateChannelDuration();
scope.startFrequencyTweak();
scope._frequencyMessage = "TV Show weights have been applied.";
}
scope.wipeSchedule = () => {
scope.channel.programs = [];
updateChannelDuration();
}
scope.makeOfflineFromChannel = (duration) => {
return {
channelOfflineMode: scope.channel.offlineMode,
channelPicture: scope.channel.offlinePicture,
channelSound: scope.channel.offlineSoundtrack,
repeatCooldown : Math.floor(scope.channel.fillerRepeatCooldown / 60000),
filler: JSON.parse( angular.toJson(scope.channel.fillerContent) ),
fallback: JSON.parse( angular.toJson(scope.channel.fallback) ),
durationSeconds: duration,
disableOverlay : scope.channel.disableFillerOverlay,
}
}
scope.addOffline = () => {
scope._addingOffline = scope.makeOfflineFromChannel(10*60);
}
function getShowCode(program) {
//used for equalize and frequency tweak
let showName = "_internal.Unknown";
if ( (program.type == 'episode') && ( typeof(program.showTitle) !== 'undefined' ) ) {
showName = program.showTitle;
} else {
showName = "_internal.Movies";
}
return showName;
}
function getRandomInt(min, max) {
min = Math.ceil(min)
max = Math.floor(max)
return Math.floor(Math.random() * (max - min + 1)) + min
}
function shuffle(array) {
let currentIndex = array.length, temporaryValue, randomIndex
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex)
currentIndex -= 1
temporaryValue = array[currentIndex]
array[currentIndex] = array[randomIndex]
array[randomIndex] = temporaryValue
}
return array
}
function equalizeShows(array, freqObject) {
let shows = {};
let progs = [];
for (let i = 0; i < array.length; i++) {
if (array[i].isOffline) {
continue;
}
vid = array[i];
let code = getShowCode(array[i]);
if ( typeof(shows[code]) === 'undefined') {
shows[code] = {
total: 0,
episodes: []
}
}
shows[code].total += vid.actualDuration;
shows[code].episodes.push(vid);
}
let maxDuration = 0;
Object.keys(shows).forEach(function(key,index) {
let w = 3;
if ( typeof(freqObject[key]) !== 'undefined') {
w = freqObject[key];
}
shows[key].total = Math.ceil(shows[key].total / w );
maxDuration = Math.max( maxDuration, shows[key].total );
});
let F = 2;
let good = true;
Object.keys(shows).forEach(function(key,index) {
let amount = Math.floor( (maxDuration*F) / shows[key].total);
good = (good && (amount % F == 0) );
});
if (good) {
F = 1;
}
Object.keys(shows).forEach(function(key,index) {
let amount = Math.floor( (maxDuration*F) / shows[key].total);
let episodes = shows[key].episodes;
if (amount % F != 0) {
}
for (let i = 0; i < amount; i++) {
for (let j = 0; j < episodes.length; j++) {
progs.push( JSON.parse( angular.toJson(episodes[j]) ) );
}
}
});
return progs;
}
function cyclicShuffle(array) {
let shows = {};
let next = {};
let counts = {};
// some precalculation, useful to stop the shuffle from being quadratic...
for (let i = 0; i < array.length; i++) {
var vid = array[i];
if (vid.type === 'episode' && vid.season != 0) {
let countKey = {
title: vid.showTitle,
s: vid.season,
e: vid.episode,
}
let key = JSON.stringify(countKey);
let c = ( (typeof(counts[key]) === 'undefined') ? 0 : counts[key] );
counts[key] = c + 1;
let showEntry = {
c: c,
it: array[i],
}
if ( typeof(shows[vid.showTitle]) === 'undefined') {
shows[vid.showTitle] = [];
}
shows[vid.showTitle].push(showEntry);
}
}
//this is O(|N| log|M|) where |N| is the total number of TV
// episodes and |M| is the maximum number of episodes
// in a single show. I am pretty sure this is a lower bound
// on the time complexity that's possible here.
Object.keys(shows).forEach(function(key,index) {
shows[key].sort( (a,b) => {
if (a.c == b.c) {
if (a.it.season == b.it.season) {
if (a.it.episode == b.it.episode) {
return 0;
} else {
return (a.it.episode < b.it.episode)?-1: 1;
}
} else {
return (a.it.season < b.it.season)?-1: 1;
}
} else {
return (a.c < b.c)? -1: 1;
}
});
next[key] = Math.floor( Math.random() * shows[key].length );
});
shuffle(array);
for (let i = 0; i < array.length; i++) {
if (array[i].type !== 'movie' && array[i].season != 0) {
let title = array[i].showTitle;
var sequence = shows[title];
var j = next[title];
array[i] = sequence[j].it;
next[title] = (j + 1) % sequence.length;
}
}
return array
}
scope.updateChannelDuration = updateChannelDuration
function updateChannelDuration() {
scope.showRotatedNote = false;
scope.channel.duration = 0
scope.hasFlex = false;
for (let i = 0, l = scope.channel.programs.length; i < l; i++) {
scope.channel.programs[i].start = new Date(scope.channel.startTime.valueOf() + scope.channel.duration)
scope.channel.duration += scope.channel.programs[i].duration
scope.channel.programs[i].stop = new Date(scope.channel.startTime.valueOf() + scope.channel.duration)
if (scope.channel.programs[i].isOffline) {
scope.hasFlex = true;
}
}
}
scope.error = {}
scope._onDone = (channel) => {
if (typeof channel === 'undefined')
scope.onDone()
else {
channelNumbers = []
for (let i = 0, l = scope.channels.length; i < l; i++)
channelNumbers.push(scope.channels[i].number)
// validate
var now = new Date()
if (typeof channel.number === "undefined" || channel.number === null || channel.number === "")
scope.error.number = "Select a channel number"
else if (channelNumbers.indexOf(parseInt(channel.number, 10)) !== -1 && scope.isNewChannel) // we need the parseInt for indexOf to work properly
scope.error.number = "Channel number already in use."
else if (!scope.isNewChannel && channel.number !== scope.beforeEditChannelNumber && channelNumbers.indexOf(parseInt(channel.number, 10)) !== -1)
scope.error.number = "Channel number already in use."
else if (channel.number <= 0 || channel.number >= 2000)
scope.error.name = "Enter a valid number (1-2000)"
else if (typeof channel.name === "undefined" || channel.name === null || channel.name === "")
scope.error.name = "Enter a channel name."
else if (channel.icon !== "" && !validURL(channel.icon))
scope.error.icon = "Please enter a valid image URL. Or leave blank."
else if (channel.overlayIcon && !validURL(channel.icon))
scope.error.icon = "Please enter a valid image URL. Cant overlay an invalid image."
else if (now < channel.startTime)
scope.error.startTime = "Start time must not be set in the future."
else if (channel.programs.length === 0)
scope.error.programs = "No programs have been selected. Select at least one program."
else {
channel.startTime.setMilliseconds( scope.millisecondsOffset);
scope.onDone(JSON.parse(angular.toJson(channel)))
}
$timeout(() => { scope.error = {} }, 3500)
}
}
scope.importPrograms = (selectedPrograms) => {
for (let i = 0, l = selectedPrograms.length; i < l; i++)
selectedPrograms[i].commercials = []
scope.channel.programs = scope.channel.programs.concat(selectedPrograms)
updateChannelDuration()
}
scope.selectProgram = (index) => {
scope.selectedProgram = index;
let program = scope.channel.programs[index];
if(program.isOffline) {
scope._selectedOffline = scope.makeOfflineFromChannel( Math.round( (program.duration + 500) / 1000 ) );
} else {
scope._selectedProgram = JSON.parse(angular.toJson(program));
}
}
scope.removeItem = (x) => {
scope.channel.programs.splice(x, 1)
updateChannelDuration()
}
scope.paddingOptions = [
{ id: -1, description: "Allowed start times", allow5: false },
{ id: 30, description: ":00, :30", allow5: false },
{ id: 15, description: ":00, :15, :30, :45", allow5: false },
{ id: 60, description: ":00", allow5: false },
{ id: 20, description: ":00, :20, :40", allow5: false },
{ id: 10, description: ":00, :10, :20, ..., :50", allow5: false },
{ id: 5, description: ":00, :05, :10, ..., :55", allow5: false },
{ id: 60, description: ":00, :05", allow5: true },
{ id: 30, description: ":00, :05, :30, :35", allow5: true },
]
scope.paddingOption = scope.paddingOptions[0];
scope.breakAfterOptions = [
{ id: -1, description: "After" },
{ id: 5, description: "5 minutes" },
{ id: 10, description: "10 minutes" },
{ id: 15, description: "15 minutes" },
{ id: 20, description: "20 minutes" },
{ id: 25, description: "25 minutes" },
{ id: 30, description: "30 minutes" },
{ id: 60, description: "1 hour" },
{ id: 90, description: "90 minutes" },
{ id: 120, description: "2 hours" },
]
scope.breakAfter = -1;
scope.minBreakSize = -1;
scope.maxBreakSize = -1;
let breakSizeOptions = [
{ id: 30, description: "30 seconds" },
{ id: 45, description: "45 seconds" },
{ id: 60, description: "60 seconds" },
{ id: 90, description: "90 seconds" },
{ id: 120, description: "2 minutes" },
{ id: 180, description: "3 minutes" },
{ id: 300, description: "5 minutes" },
{ id: 450, description: "7.5 minutes" },
{ id: 600, description: "10 minutes" },
{ id: 1200, description: "20 minutes" },
]
scope.minBreakSizeOptions = [
{ id: -1, description: "Min Duration" },
]
scope.minBreakSizeOptions = scope.minBreakSizeOptions.concat(breakSizeOptions);
scope.maxBreakSizeOptions = [
{ id: -1, description: "Max Duration" },
]
scope.maxBreakSizeOptions = scope.maxBreakSizeOptions.concat(breakSizeOptions);
scope.nightStartHours = [ { id: -1, description: "Start" } ];
scope.nightEndHours = [ { id: -1, description: "End" } ];
scope.nightStart = -1;
scope.nightEnd = -1;
for (let i=0; i < 24; i++) {
let v = { id: i, description: ( (i<10) ? "0" : "") + i + ":00" };
scope.nightStartHours.push(v);
scope.nightEndHours.push(v);
}
scope.paddingMod = 30;
}
}
}
function validURL(url) {
return /^(ftp|http|https):\/\/[^ "]+$/.test(url);
}