361 lines
11 KiB
JavaScript

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.title = "TV Guide";
$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 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;
} 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,
subTitle: subTitle,
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);
}
};
}