TV-Center/public/calendar.js

245 lines
5.7 KiB
JavaScript

const raws = {};
let hideConfirmed = true;
const icsUrls = [
{
url: '/sonarr-hs-ics',
name: 'hidden-sea',
},
// {
// url: '/sonarr-cb-ics',
// name: 'cold-badlands',
// },
// {
// url: '/sonarr-fv-ics',
// name: 'fancy-valley',
// },
{
url: '/sonarr-ag-ics',
name: 'ancient-grove',
},
{
url: '/sonarr-bs-ics',
name: 'bold-silence',
},
{
url: '/sonarr-fd-ics',
name: 'frosty-darkness',
},
{
url: '/sonarr-rs-ics',
name: 'royal-stream [4K]',
},
];
async function fetchIcs(url, name, shouldForce)
{
let icalRaw = raws[name] || '';
if (!raws[name] || shouldForce) {
const response = await fetch(url);
icalRaw = await response.text();
raws[name] = icalRaw;
}
const parse = ICAL.parse(icalRaw.trim());
const component = new ICAL.Component(parse);
// console.log(component);
const eventComps = component.getAllSubcomponents('vevent');
const events = eventComps.map((item) => {
if (item.getFirstPropertyValue('class') === 'PRIVATE') {
return null;
}
let title = item.getFirstPropertyValue('summary');
const status = item.getFirstPropertyValue('status');
const start = item.getFirstPropertyValue('dtstart').toJSDate();
const end = item.getFirstPropertyValue('dtend').toJSDate();
const publisher = item.getFirstPropertyValue('categories');
let isAdded = false;
if (status.toLowerCase() === 'confirmed') {
// Status toggled to only show upcoming/missing.
if (hideConfirmed) {
return null;
}
isAdded = true;
title = `${title}`;
}
const now = Date.now();
if (!isAdded)
{
/**
* Start date in the past
*/
if (now > start.getTime()) {
title = `🟠 ${title}`;
}
else {
title = `${title}`;
}
}
// if (status.toLowerCase() !== 'confirmed' && status !== 'tentative') {
// console.log(status);
// }
title = `${title} [${publisher}]`;
return {
title: title,
start,
end,
display: 'list-item',
classNames: [name],
extendedProps: {
hostname: name,
}
};
});
return events;
}
let keyHandlersAdded = false;
function keyHandlers(calendar)
{
if (keyHandlersAdded) {
return;
}
window.addEventListener('keydown', function(ev) {
const key = ev.key;
if (!key) {
return;
}
switch (key) {
case 'ArrowLeft':
calendar.prev();
break;
case 'ArrowRight':
calendar.next();
break;
}
});
keyHandlersAdded = true;
}
function scrollToCalendarDay()
{
const date = new Date();
const today = date.toISOString().split('T')[0];
const dateRow = document.querySelector(`[data-date="${today}"]`);
if (!dateRow) {
console.log('Could not find date row', today);
return;
}
dateRow.scrollIntoView({
behavior: 'smooth',
block: 'start',
});
}
const showAllText = 'Show all tracked episodes';
const showTrackedText = 'Show only missing/upcoming episodes';
const toggleButton = {
text: (hideConfirmed ? showAllText : showTrackedText),
click: async function() {
if (!hideConfirmed) {
toggleButton.text = showAllText;
}
else {
toggleButton.text = showTrackedText;
}
hideConfirmed = !hideConfirmed;
await loadSonarrCalendar();
},
};
const refreshButton = {
text: 'Refresh calendar',
click: function() {
loadSonarrCalendar(true);
},
};
async function loadSonarrCalendar(shouldForce = false)
{
const calendarElement = document.querySelector('#sonarr-calendar');
let events = [];
let promises = [];
for (const list of icsUrls)
{
const { url, name } = list;
promises.push(fetchIcs(url, name, shouldForce));
}
events = await Promise.all(promises);
events = events.flat();
events = events.filter(x => x !== null);
const calendar = new FullCalendar.Calendar(calendarElement, {
// initialView: 'dayGridMonth',
customButtons: {
toggleButton,
refreshButton,
},
themeSystem: 'bootstrap5',
initialView: 'listWeek',
initialDate: new Date(),
headerToolbar: {
left: 'prev,next today',
center: 'title',
// right: 'dayGridMonth,dayGridWeek,dayGridDay,listWeek',
right: 'toggleButton refreshButton',
},
events: events,
eventDidMount: function(info) {
const hostname = info.event.extendedProps.hostname;
info.el.querySelector('.fc-list-event-title').innerHTML += `<span class="float-end">${hostname}</span>`;
}
});
const message = document.querySelector('#status-message');
try {
calendar.render();
if (message) {
message.textContent = '';
}
keyHandlers(calendar);
}
catch (err) {
console.error(err);
if (message) {
message.textContent = 'An error occurred loading schedule...';
}
}
}
window.addEventListener('DOMContentLoaded', function() {
loadSonarrCalendar();
this.setInterval(
function() {
loadSonarrCalendar(true);
},
60 * 1000
);
});