360 lines
11 KiB
JavaScript
360 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.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);
|
|
}
|
|
};
|
|
|
|
} |