Files
jellyfin-plugin-mediacleaner/Jellyfin.Plugin.MediaCleaner/Pages/home.js

254 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
document.addEventListener('pageshow', async () => {
await refreshFrontEnd();
});
const refreshFrontEnd = async () => {
await updateMediaCleanerState();
var moviesTitle = document.getElementById("moviesTitle");
var seriesTitle = document.getElementById("seriesTitle");
moviesTitle.innerHTML = await getMediaCleanerMoviesTitle();
seriesTitle.innerHTML = await getMediaCleanerSeriesTitle();
await populateTables();
addClickHandlersToLinks();
addClickHandlersToDeleteButtons();
finishLoading();
}
const getMediaCleanerSeriesInfo = async () => {
const response = await fetch("/mediacleaner/state/getSeriesInfo");
if(!response.ok){
throw new Error(`Response status: ${response.status}`)
}
return response.json();
};
const getMediaCleanerMovieInfo = async () => {
const response = await fetch("/mediacleaner/state/getMovieInfo");
if(!response.ok){
throw new Error(`Response status: ${response.status}`)
}
return response.json();
};
const updateMediaCleanerState = async () => {
const response = await fetch("/mediacleaner/state/updateState");
if(!response.ok){
throw new Error(`Response status: ${response.status}`)
}
return response.json();
};
const getMediaCleanerSeriesTitle = async () => {
const response = await fetch("/mediacleaner/state/getSeriesTitle");
if(!response.ok){
throw new Error(`Response status: ${response.status}`);
}
return response.json();
};
const getMediaCleanerMoviesTitle = async () => {
const response = await fetch("/mediacleaner/state/getMoviesTitle");
if(!response.ok){
throw new Error(`Response status: ${response.status}`);
}
return response.json();
};
const populateTables = async () => {
var moviesInfo = await getMediaCleanerMovieInfo();
var seriesInfo = await getMediaCleanerSeriesInfo();
var seriesTableBody = seriesTable.getElementsByTagName('tbody')[0];
seriesTableBody.replaceChildren();
var seriesDeleteButton = document.getElementById('seriesDeleteButton');
var moviesTableBody = moviesTable.getElementsByTagName('tbody')[0];
moviesTableBody.replaceChildren();
var moviesDeleteButton = document.getElementById('moviesDeleteButton');
if (moviesInfo.length > 0){
for(let i = 0; i < moviesInfo.length; i++){
var row = moviesTableBody.insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
cell1.innerHTML = moviesInfo[i].Name;
cell1.className = "table-text";
cell2.appendChild(createCheckbox(moviesInfo[i], moviesTable, moviesDeleteButton));
cell2.className = "table-checkbox"
}
}
else{
var columnCount = moviesTable.tHead.rows[0].cells.length;
var row = moviesTableBody.insertRow(-1);
var cell1 = row.insertCell(0);
cell1.colSpan = columnCount;
cell1.innerHTML = "No stale movies found.";
cell1.className = "table-text";
}
if(seriesInfo.length > 0){
for(let i = 0; i < seriesInfo.length; i++){
var row = seriesTableBody.insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
cell1.innerHTML = seriesInfo[i].Name;
cell1.className = "table-text";
cell2.innerHTML = seriesInfo[i].Seasons.map(season => season).join(", ");
cell2.className = "table-text";
cell3.appendChild(createCheckbox(seriesInfo[i], seriesTable, seriesDeleteButton));
cell3.className = "table-checkbox"
}
}
else{
var columnCount = seriesTable.tHead.rows[0].cells.length;
var row = seriesTableBody.insertRow(-1);
var cell1 = row.insertCell(0);
cell1.colSpan = columnCount;
cell1.innerHTML = "No stale series found.";
cell1.className = "table-text";
}
};
const createCheckbox = (mediaInfo = {}, table, deleteButton) => {
const container = document.createElement('div');
container.className = 'checkboxContainer';
container.style.marginBottom = 0;
const label = document.createElement('label');
label.className = 'emby-checkbox-label';
label.style.textAlign = 'center';
label.style.paddingLeft = '1.8em';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.setAttribute('is', 'emby-checkbox');
checkbox.dataset.mediaInfo = JSON.stringify(mediaInfo) || '';
const span = document.createElement('span');
span.textContent = '';
label.appendChild(checkbox);
label.appendChild(span);
container.appendChild(label);
checkbox.addEventListener('change', (e) => {
if(isDeleteButtonVisible(table)){
deleteButton.style.visibility = 'visible';
}
else {
deleteButton.style.visibility = 'hidden';
}
});
return container;
};
const isDeleteButtonVisible = (table) => {
const checkboxes = table.getElementsByClassName('emby-checkbox');
const hasChecked = Array.from(checkboxes).some(checkbox => checkbox.checked);
return hasChecked;
}
const addClickHandlersToLinks = () => {
const linkBtns = document.querySelectorAll("button.links");
linkBtns.forEach(btn => {
btn.addEventListener("click", () => {
const target = btn.dataset.target;
if (!target) return;
window.location.hash = target;
})
})
}
const addClickHandlersToDeleteButtons = () => {
const deleteMoviesButtonElement = document.getElementById("moviesDeleteButton");
const deleteSeriesButtonElement = document.getElementById("seriesDeleteButton");
deleteMoviesButtonElement.addEventListener("click", deleteFromRadarr);
deleteSeriesButtonElement.addEventListener("click", deleteFromSonarr);
}
const getCheckedMedia = (table) => {
const checkboxes = table.getElementsByClassName('emby-checkbox');
const selectedMediaCheckboxes = Array.from(checkboxes).filter(checkbox => checkbox.checked);
const selectedMedia = selectedMediaCheckboxes.map(selectedMediaCheckbox => JSON.parse(selectedMediaCheckbox.dataset.mediaInfo));
console.log("Selected media: ", selectedMedia);
return selectedMedia;
}
const deleteMovieFromRadarrApi = async (movie) => {
const response = await fetch("/radarr/deleteMovieFromRadarr", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(movie)
});
if(!response.ok){
throw new Error(`Response status: ${response.status}`)
}
}
const deleteSeriesFromSonarrApi = async (series) => {
const response = await fetch("/sonarr/deleteSeriesFromSonarr", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(series)
});
if(!response.ok){
throw new Error(`Response status: ${response.status}`)
}
}
const deleteFromRadarr = async () => {
// Get all movies with checked checkboxes
const selectedMovies = getCheckedMedia(moviesTable);
selectedMovies.forEach(async movie => await deleteMovieFromRadarrApi(movie));
refreshFrontEnd();
}
const deleteFromSonarr = () => {
// Need to GET first for seriesIds?
const selectedSeries = getCheckedMedia(seriesTable);
selectedSeries.forEach(async series => await deleteSeriesFromSonarrApi(series));
// Use tvdbId included in filenames.
// /api/v5/series?tvdbId=383275
// Possibly use statistics from GET to show on front end?
// Likely need to use EpisodeFile bulk DELETE endpoint
// /api/v5/episodefile/bulk
console.log("Delete from Sonarr!")
}
const finishLoading = () => {
const loadingElement = document.getElementById("loading");
const homepage = document.getElementById("homepage");
loadingElement.style.visibility = "hidden";
homepage.style.visibility = "visible";
}
const startLoading = () => {
const loadingElement = document.getElementById("loading");
const homepage = document.getElementById("homepage");
loadingElement.style.visibility = "visible";
homepage.style.visibility = "hidden";
}