const MINUTE = 60 * 1000; module.exports = function ($scope, $timeout, dizquetv) { $scope.offset = 0; $scope.M = 60 * MINUTE; $scope.zoomLevel = 3 $scope.T = 190 * MINUTE; $scope.before = 15 * MINUTE; $scope.enableNext = false; $scope.enableBack = false; $scope.showNow = false; $scope.nowPosition = 0; $scope.refreshHandle = null; const intl = new Intl.DateTimeFormat('default', { hour12: true, hour: 'numeric', minute: 'numeric' }); let hourMinute = (d) => { return intl.format(d); }; $scope.updateBasics = () => { $scope.channelNumberWidth = 5; $scope.channelIconWidth = 8; $scope.channelWidth = $scope.channelNumberWidth + $scope.channelIconWidth; //we want 1 minute = 1 colspan $scope.colspanPercent = (100 - $scope.channelWidth) / ($scope.T / MINUTE); $scope.channelColspan = Math.floor($scope.channelWidth / $scope.colspanPercent); $scope.channelNumberColspan = Math.floor($scope.channelNumberWidth / $scope.colspanPercent); $scope.channelIconColspan = $scope.channelColspan - $scope.channelNumberColspan; $scope.totalSpan = Math.floor($scope.T / MINUTE); $scope.colspanPercent = (100 - $scope.channelWidth) / ($scope.T / MINUTE); $scope.channelColspan = Math.floor($scope.channelWidth / $scope.colspanPercent); $scope.channelNumberColspan = Math.floor($scope.channelNumberWidth / $scope.colspanPercent); $scope.channelIconColspan = $scope.channelColspan - $scope.channelNumberColspan; } $scope.updateBasics(); $scope.channelNumberWidth = 5; $scope.channelIconWidth = 8; $scope.channelWidth = $scope.channelNumberWidth + $scope.channelIconWidth; //we want 1 minute = 1 colspan $scope.applyLater = () => { $timeout( () => $scope.$apply(), 0 ); }; $scope.channelNumbers = []; $scope.channels = {}; $scope.lastUpdate = -1; $scope.updateJustNow = () => { $scope.t1 = (new Date()).getTime(); if ($scope.t0 <= $scope.t1 && $scope.t1 < $scope.t0 + $scope.T) { let n = ($scope.t1 - $scope.t0) / MINUTE; $scope.nowPosition = ($scope.channelColspan + n) * $scope.colspanPercent if ($scope.nowPosition >= 50 && $scope.offset >= 0) { $scope.offset = 0; $scope.adjustZoom(); } $scope.showNow = true; } else { $scope.showNow = false; } } $scope.nowTimer = () => { $scope.updateJustNow(); $timeout( () => $scope.nowTimer() , 10000); } $timeout( () => $scope.nowTimer() , 10000); $scope.refreshManaged = async (skipStatus) => { $scope.t1 = (new Date()).getTime(); $scope.t1 = ($scope.t1 - $scope.t1 % MINUTE ); $scope.t0 = $scope.t1 - $scope.before + $scope.offset; $scope.times = []; $scope.updateJustNow(); let pending = 0; let addDuration = (d) => { let m = (pending + d) % MINUTE; let r = (pending + d) - m; pending = m; return Math.floor( r / MINUTE ); } let deleteIfZero = () => { if ( $scope.times.length > 0 && $scope.times[$scope.times.length - 1].duration < 1) { $scope.times = $scope.times.slice(0, $scope.times.length - 1); } } let rem = $scope.T; let t = $scope.t0; if (t % $scope.M != 0) { let dif = $scope.M - t % $scope.M; $scope.times.push( { duration : addDuration(dif), } ); deleteIfZero(); t += dif; rem -= dif; } while (rem > 0) { let d = Math.min(rem, $scope.M ); $scope.times.push( { duration : addDuration(d), label: hourMinute( new Date(t) ), } ); t += d; rem -= d; } if (skipStatus !== true) { $scope.channelNumbers = [0]; $scope.channels = {} ; $scope.channels[0] = { loading: true, } $scope.applyLater(); console.log("getting status..."); let status = await dizquetv.getGuideStatus(); $scope.lastUpdate = new Date(status.lastUpdate).getTime(); console.log("got status: " + JSON.stringify(status) ); $scope.channelNumbers = status.channelNumbers; $scope.channels = {} ; } for (let i = 0; i < $scope.channelNumbers.length; i++) { if ( typeof($scope.channels[$scope.channelNumbers[i]]) === 'undefined') { $scope.channels[$scope.channelNumbers[i]] = {}; } $scope.channels[$scope.channelNumbers[i]].loading = true; } $scope.applyLater(); $scope.enableBack = false; $scope.enableNext = false; await Promise.all($scope.channelNumbers.map( $scope.loadChannel) ); setupTimer(); }; let cancelTimerIfExists = () => { if ($scope.refreshHandle != null) { $timeout.cancel($scope.refreshHandle); } } $scope.$on('$locationChangeStart', () => { console.log("$locationChangeStart" ); cancelTimerIfExists(); } ); let setupTimer = () => { cancelTimerIfExists(); $scope.refreshHandle = $timeout( () => $scope.checkUpdates(), 60000 ); } $scope.adjustZoom = async() => { switch ($scope.zoomLevel) { case 1: $scope.T = 50 * MINUTE; $scope.M = 10 * MINUTE; $scope.before = 5 * MINUTE; break; case 2: $scope.T = 100 * MINUTE; $scope.M = 15 * MINUTE; $scope.before = 10 * MINUTE; break; case 3: $scope.T = 190 * MINUTE; $scope.M = 30 * MINUTE; $scope.before = 15 * MINUTE; break; case 4: $scope.T = 270 * MINUTE; $scope.M = 60 * MINUTE; $scope.before = 15 * MINUTE; break; case 5: $scope.T = 380 * MINUTE; $scope.M = 90 * MINUTE; $scope.before = 15 * MINUTE; break; } $scope.updateBasics(); await $scope.refresh(true); } $scope.zoomOut = async() => { $scope.zoomLevel = Math.min( 5, $scope.zoomLevel + 1 ); await $scope.adjustZoom(); } $scope.zoomIn = async() => { $scope.zoomLevel = Math.max( 1, $scope.zoomLevel - 1 ); await $scope.adjustZoom(); } $scope.zoomOutEnabled = () => { return $scope.zoomLevel < 5; } $scope.zoomInEnabled = () => { return $scope.zoomLevel > 1; } $scope.next = async() => { $scope.offset += $scope.M * 7 / 8 await $scope.adjustZoom(); } $scope.back = async() => { $scope.offset -= $scope.M * 7 / 8 await $scope.adjustZoom(); } $scope.backEnabled = () => { return $scope.enableBack; } $scope.nextEnabled = () => { return $scope.enableNext; } $scope.loadChannel = async (number) => { console.log(`number=${number}` ); let d0 = new Date($scope.t0); let d1 = new Date($scope.t0 + $scope.T); let lineup = await dizquetv.getChannelLineup(number, d0, d1); let ch = { icon : lineup.icon, number : lineup.number, name: lineup.name, altTitle: `${lineup.number} - ${lineup.name}`, programs: [], }; let pending = 0; let totalAdded = 0; let addDuration = (d) => { totalAdded += d; let m = (pending + d) % MINUTE; let r = (pending + d) - m; pending = m; return Math.floor( r / MINUTE ); } let deleteIfZero = () => { if ( ch.programs.length > 0 && ch.programs[ ch.programs.length - 1].duration < 1) { ch.programs = ch.programs.slice(0, ch.programs.length - 1); } } for (let i = 0; i < lineup.programs.length; i++) { let program = lineup.programs[i]; let ad = new Date(program.start); let bd = new Date(program.stop); let a = ad.getTime(); let b = bd.getTime(); let hasStart = true; let hasStop = true; if (a < $scope.t0) { //cut-off a = $scope.t0; hasStart = false; $scope.enableBack = true; } else if ( (a > $scope.t0) && (i == 0) ) { ch.programs.push( { duration: addDuration( (a - $scope.t0) ), showTitle: "", start: false, end: true, } ); deleteIfZero(); } if (b > $scope.t0 + $scope.T) { b = $scope.t0 + $scope.T; hasStop = false; $scope.enableNext = true; } let subTitle = undefined; let episodeTitle = undefined; let altTitle = hourMinute(ad) + "-" + hourMinute(bd); if (typeof(program.title) !== 'undefined') { altTitle = altTitle + " · " + program.title; } if (typeof(program.sub) !== 'undefined') { ps = "" + program.sub.season; if (ps.length < 2) { ps = "0" + ps; } pe = "" + program.sub.episode; if (pe.length < 2) { pe = "0" + pe; } subTitle = `S${ps} · E${pe}`; altTitle = altTitle + " " + subTitle; episodeTitle = program.sub.title; } else if ( typeof(program.date) === 'undefined' ) { subTitle = '.'; } else { subTitle = program.date.slice(0,4); } ch.programs.push( { duration: addDuration(b - a), altTitle: altTitle, showTitle: program.title, // movie title, episode title or track title subTitle: subTitle, episodeTitle : episodeTitle, start: hasStart, end: hasStop, } ); deleteIfZero(); } if (totalAdded < $scope.T) { ch.programs.push( { duration: addDuration( $scope.T - totalAdded ), showTitle: "", start: false, end: true, } ); deleteIfZero(); } $scope.channels[number] = ch; $scope.applyLater(); } $scope.refresh = async (skipStatus) => { try { await $scope.refreshManaged(skipStatus); } catch (err) { console.error("Refresh failed?", err); } } $scope.adjustZoom(); $scope.refresh(); $scope.checkUpdates = async () => { try { console.log("get status " + new Date() ); let status = await dizquetv.getGuideStatus(); let t = new Date(status.lastUpdate).getTime(); if ( t > $scope.lastUpdate) { $scope.refreshManaged(); } else { setupTimer(); } } catch(err) { console.error(err); } }; }