Tranga-Website/Website/interaction.js
db-2001 c7e49fb6bc Added in remaining Tranga settings functionality
Changed CSS style to be stored in local storage since we might want it to be browser specific (mobile vs desktop vs tablet)
2024-02-09 11:17:33 -05:00

907 lines
31 KiB
JavaScript

let monitoringJobsCount = 0;
let runningJobs = [];
let waitingJobs = [];
let notificationConnectorTypes = [];
let libraryConnectorTypes = [];
let selectedManga;
let selectedJob;
let searchMatch;
let connectorMatch = [];
let connectorNameMatch;
let statusMatch = [];
let statusNameMatch = [];
const searchBox = document.querySelector("#searchbox");
const settingsPopup = document.querySelector("#settingsPopup");
const filterBox = document.querySelector("#filterBox");
const settingsCog = document.querySelector("#settingscog");
const filterFunnel = document.querySelector("#filterFunnel");
const tasksContent = document.querySelector("content");
const createMonitorTaskButton = document.querySelector("#createMonitoJobButton");
const createDownloadChapterTaskButton = document.querySelector("#createDownloadChapterJobButton");
const startJobButton = document.querySelector("#startJobButton");
const cancelJobButton = document.querySelector("#cancelJobButton");
const deleteJobButton = document.querySelector("#deleteJobButton");
//Manga viewer popup
const mangaViewerPopup = document.querySelector("#publicationViewerPopup");
const mangaViewerWindow = document.querySelector("publication-viewer");
const mangaViewerDescription = document.querySelector("#publicationViewerDescription");
const mangaViewerName = document.querySelector("#publicationViewerName");
const mangaViewerTags = document.querySelector("#publicationViewerTags");
const mangaViewerAuthor = document.querySelector("#publicationViewerAuthor");
const mangaViewCover = document.querySelector("#pubviewcover");
//Rate Limits
const manganatoRateLimit = document.querySelector('#manganatoRL');
const mangaseeRateLimit = document.querySelector('#mangaseeRL');
const mangadexRateLimit = document.querySelector('#mDexRL');
const mangakatanaRateLimit = document.querySelector('#mKatanaRL');
const mangaworldRateLimit = document.querySelector('#mWorldRL');
const batoRateLimit = document.querySelector('#batoRL');
const mangalifeRateLimit = document.querySelector('#mLifeRL');
//Komga
const settingKomgaUrl = document.querySelector("#komgaUrl");
const settingKomgaUser = document.querySelector("#komgaUsername");
const settingKomgaPass = document.querySelector("#komgaPassword");
//Kavita
const settingKavitaUrl = document.querySelector("#kavitaUrl");
const settingKavitaUser = document.querySelector("#kavitaUsername");
const settingKavitaPass = document.querySelector("#kavitaPassword");
//Gotify
const settingGotifyUrl = document.querySelector("#gotifyUrl");
const settingGotifyAppToken = document.querySelector("#gotifyAppToken");
//Lunasea
const settingLunaseaWebhook = document.querySelector("#lunaseaWebhook");
//Ntfy
const settingNtfyEndpoint = document.querySelector("#ntfyEndpoint");
const settingNtfyAuth = document.querySelector("#ntfyAuth");
//Connector Configured
const settingKomgaConfigured = document.querySelector("#komgaConfigured");
const settingKavitaConfigured = document.querySelector("#kavitaConfigured");
const settingGotifyConfigured = document.querySelector("#gotifyConfigured");
const settingLunaseaConfigured = document.querySelector("#lunaseaConfigured");
const settingNtfyConfigured = document.querySelector("#ntfyConfigured");
const settingUserAgent = document.querySelector("#userAgent");
const settingApiUri = document.querySelector("#settingApiUri");
const settingCSSStyle = document.querySelector('#cssStyle');
const newMangaPopup = document.querySelector("#newMangaPopup");
const newMangaConnector = document.querySelector("#newMangaConnector");
const newMangaTitle = document.querySelector("#newMangaTitle");
const newMangaResult = document.querySelector("#newMangaResult");
const newMangaTranslatedLanguage = document.querySelector("#newMangaTranslatedLanguage");
//Jobs
const jobsRunningTag = document.querySelector("#jobsRunningTag");
const jobsQueuedTag = document.querySelector("#jobsQueuedTag");
const loaderdiv = document.querySelector('#loaderdiv');
const jobStatusView = document.querySelector("#jobStatusView");
const jobStatusRunning = document.querySelector("#jobStatusRunning");
const jobStatusWaiting = document.querySelector("#jobStatusWaiting");
function Setup(){
Ping().then((ret) => {
loaderdiv.style.display = 'none';
GetAvailableNotificationConnectors().then((json) => {
//console.log(json);
json.forEach(connector => {
notificationConnectorTypes[connector.Key] = connector.Value;
});
});
GetAvailableLibraryConnectors().then((json) => {
//console.log(json);
json.forEach(connector => {
libraryConnectorTypes[connector.Key] = connector.Value;
});
});
GetAvailableControllers().then((json) => {
//console.log(json);
newMangaConnector.replaceChildren();
connectorFilterBox = document.querySelector("#connectorFilterBox");
json.forEach(connector => {
//Add the connector to the New Manga dropdown
var option = document.createElement('option');
option.value = connector;
option.innerText = connector;
newMangaConnector.appendChild(option);
//Add the connector to the filter box
connectorFilter = document.createElement('connector-name');
connectorFilter.innerText = connector;
connectorFilter.className = "pill";
connectorFilter.style.backgroundColor = stringToColour(connector);
connectorFilter.addEventListener("click", (event) => {
ToggleFilterConnector(connector, event);
});
connectorFilterBox.appendChild(connectorFilter);
});
});
//Add the publication status options to the filter bar
publicationStatusOptions = ["Ongoing", "Completed", "On Hiatus", "Cancelled", "Upcoming", "Status Unavailable"];
statusFilterBox = document.querySelector("#statusFilterBox");
publicationStatusOptions.forEach(publicationStatus => {
var releaseStatus = document.createElement('status-filter');
releaseStatus.innerText = publicationStatus;
releaseStatus.setAttribute("release-status", publicationStatus);
releaseStatus.addEventListener("click", (event) => {
ToggleFilterStatus(publicationStatus, event);
});
statusFilterBox.appendChild(releaseStatus);
});
ResetContent();
UpdateJobs();
GetSettings().then((json) => {
//console.log(json);
settingApiUri.placeholder = apiUri;
});
//If the cssStyle key isn't in the local storage of the browser, then set the css style to the default and load the page
//Otherwise get the style key from storage and set it.
if (!localStorage.getItem('cssStyle')) {
localStorage.setItem('cssStyle', 'card_compact');
document.getElementById('librarystyle').setAttribute('href', 'styles/' + localStorage.getItem('cssStyle') + '.css');
document.getElementById('card_compact').selected = true;
} else {
css_style = localStorage.getItem('cssStyle');
document.getElementById('librarystyle').setAttribute('href', 'styles/' + css_style + '.css');
document.getElementById(css_style).selected = true;
}
setInterval(() => {
UpdateJobs();
}, 1000);
});
//Clear the previous values if any exist.
searchBox.value = "";
connectorMatch.length = 0;
statusMatch.length = 0;
}
Setup();
function ToggleFilterConnector(connector, event) {
//console.log("Initial Array:");
//console.log(connectorMatch);
if (connectorMatch.includes(connector)) {
idx = connectorMatch.indexOf(connector);
connectorMatch.splice(idx, 1);
event.target.style.outline = 'none';
event.target.style.outlineOffset = "0px";
} else {
connectorMatch.push(connector);
event.target.style.outline = '4px solid var(--secondary-color)';
event.target.style.outlineOffset = '3px';
}
//console.log("Final Array");
//console.log(connectorMatch);
FilterResults();
}
function ToggleFilterStatus(status, event) {
//console.log("Initial Array:");
//console.log(statusMatch);
if (statusMatch.includes(status)) {
idx = statusMatch.indexOf(status);
statusMatch.splice(idx, 1);
event.target.style.outline = 'none';
event.target.style.outlineOffset = "0px";
} else {
statusMatch.push(status);
event.target.style.outline = '4px solid var(--secondary-color)';
event.target.style.outlineOffset = '3px';
}
//console.log("Final Array");
//console.log(statusMatch);
FilterResults();
}
function ClearFilter() {
searchBox.value = "";
statusMatch.length = 0;
connectorMatch.length = 0;
FilterResults();
//Get rid of the outlines
connectorFilterBox = document.querySelector("#connectorFilterBox");
connectorFilterBox.childNodes.forEach(connector => {
if (connector.nodeName.toLowerCase() == 'connector-name') {
connector.style.outline = 'none';
connector.style.outlineOffset = "0px";
}
});
statusFilterBox = document.querySelector("#statusFilterBox");
statusFilterBox.childNodes.forEach(publicationStatus => {
if (publicationStatus.nodeName.toLowerCase() == 'status-filter') {
publicationStatus.style.outline = 'none';
publicationStatus.style.outlineOffset = "0px";
}
});
}
settingCSSStyle.addEventListener("change", (event) => {
localStorage.setItem('cssStyle', settingCSSStyle.value);
document.getElementById('librarystyle').setAttribute('href', 'styles/' + localStorage.getItem('cssStyle') + '.css');
});
function ResetContent(){
//Delete everything
tasksContent.replaceChildren();
//Add "Add new Task" Button
var add = document.createElement("div");
add.setAttribute("id", "addPublication")
var plus = document.createElement("p");
plus.innerText = "+";
add.appendChild(plus);
add.addEventListener("click", () => ShowNewMangaSearch());
tasksContent.appendChild(add);
//Populate with the monitored mangas
GetMonitorJobs().then((json) => {
//console.log(json);
json.forEach(job => {
var mangaView = CreateManga(job.manga, job.mangaConnector.name);
mangaView.addEventListener("click", (event) => {
ShowMangaWindow(job, job.manga, event, false);
});
tasksContent.appendChild(mangaView);
});
monitoringJobsCount = json.length;
});
}
function ShowNewMangaSearch(){
newMangaTitle.value = "";
newMangaPopup.style.display = "block";
newMangaResult.replaceChildren();
}
newMangaTitle.addEventListener("keypress", (event) => { if(event.key === "Enter") GetNewMangaItems();});
function GetNewMangaItems(){
if(newMangaTitle.value.length < 4)
return;
newMangaResult.replaceChildren();
newMangaConnector.disabled = true;
newMangaTitle.disabled = true;
newMangaTranslatedLanguage.disabled = true;
GetPublicationFromConnector(newMangaConnector.value, newMangaTitle.value).then((json) => {
//console.log(json);
if(json.length > 0)
newMangaResult.style.display = "flex";
json.forEach(result => {
var mangaElement = CreateManga(result, newMangaConnector.value)
newMangaResult.appendChild(mangaElement);
mangaElement.addEventListener("click", (event) => {
ShowMangaWindow(null, result, event, true);
});
});
newMangaConnector.disabled = false;
newMangaTitle.disabled = false;
newMangaTranslatedLanguage.disabled = false;
});
}
//Returns a new "Publication" Item to display in the jobs section
function CreateManga(manga, connector){
//Create a new publication and set an internal ID
var mangaElement = document.createElement('publication');
mangaElement.id = GetValidSelector(manga.internalId);
//Append the cover image to the publication
var mangaImage = document.createElement('img');
mangaImage.src = GetCoverUrl(manga.internalId);
mangaElement.appendChild(mangaImage);
//Append the publication information to the publication
//console.log(manga);
var info = document.createElement('publication-information');
var connectorName = document.createElement('connector-name');
connectorName.innerText = connector;
connectorName.className = "pill";
connectorName.style.backgroundColor = stringToColour(connector);
info.appendChild(connectorName);
var mangaName = document.createElement('publication-name');
mangaName.innerText = manga.sortName;
//Create the publication status indicator
var releaseStatus = document.createElement('publication-status');
releaseStatus.setAttribute("release-status", manga.releaseStatus);
switch(manga.releaseStatus){
case 0:
releaseStatus.setAttribute("release-status", "Ongoing");
break;
case 1:
releaseStatus.setAttribute("release-status", "Completed");
break;
case 2:
releaseStatus.setAttribute("release-status", "On Hiatus");
break;
case 3:
releaseStatus.setAttribute("release-status", "Cancelled");
break;
case 4:
releaseStatus.setAttribute("release-status", "Upcoming");
break;
default:
releaseStatus.setAttribute("release-status", "Status Unavailable");
break;
}
info.appendChild(mangaName);
mangaElement.appendChild(info);
mangaElement.appendChild(releaseStatus); //Append the release status indicator to the publication element
return mangaElement;
}
createMonitorJobButton.addEventListener("click", () => {
CreateMonitorJob(newMangaConnector.value, selectedManga.internalId, newMangaTranslatedLanguage.value);
UpdateJobs();
mangaViewerPopup.style.display = "none";
ResetContent();
});
startJobButton.addEventListener("click", () => {
StartJob(selectedJob.id);
mangaViewerPopup.style.display = "none";
});
cancelJobButton.addEventListener("click", () => {
CancelJob(selectedJob.id);
mangaViewerPopup.style.display = "none";
});
deleteJobButton.addEventListener("click", () => {
RemoveJob(selectedJob.id);
UpdateJobs();
mangaViewerPopup.style.display = "none";
ResetContent();
});
function ShowMangaWindow(job, manga, event, add){
selectedManga = manga;
selectedJob = job;
//Show popup
mangaViewerPopup.style.display = "block";
//Set position to mouse-position
if(event.clientY < window.innerHeight - mangaViewerWindow.offsetHeight)
mangaViewerWindow.style.top = `${event.clientY}px`;
else
mangaViewerWindow.style.top = `${event.clientY - mangaViewerWindow.offsetHeight}px`;
if(event.clientX < window.innerWidth - mangaViewerWindow.offsetWidth)
mangaViewerWindow.style.left = `${event.clientX}px`;
else
mangaViewerWindow.style.left = `${event.clientX - mangaViewerWindow.offsetWidth}px`;
//Edit information inside the window
mangaViewerName.innerText = manga.sortName;
mangaViewerTags.innerText = manga.tags.join(", ");
mangaViewerDescription.innerText = manga.description;
mangaViewerAuthor.innerText = manga.authors.join(',');
mangaViewCover.src = GetCoverUrl(manga.internalId);
toEditId = manga.internalId;
//Check what action should be listed
if(add){
createMonitorJobButton.style.display = "initial";
createDownloadChapterJobButton.style.display = "none";
cancelJobButton.style.display = "none";
startJobButton.style.display = "none";
deleteJobButton.style.display = "none";
}
else{
createMonitorJobButton.style.display = "none";
createDownloadChapterJobButton.style.display = "none";
cancelJobButton.style.display = "initial";
startJobButton.style.display = "initial";
deleteJobButton.style.display = "initial";
}
}
function HidePublicationPopup(){
publicationViewerPopup.style.display = "none";
}
searchBox.addEventListener("keyup", () => FilterResults());
//Filter shown jobs
function FilterResults(){
//For each publication
tasksContent.childNodes.forEach(publication => {
//If the search box isn't empty check that the title contains the searchbox content. If it does then
//'searchMatch' is true and the manga is shown. If the search box is empty, then consider this field
//to be true anyways.
if (searchBox.value.length > 0) {
publication.childNodes.forEach(item => {
if (item.nodeName.toLowerCase() == "publication-information"){
item.childNodes.forEach(information => {
if (information.nodeName.toLowerCase() == "publication-name") {
if (information.textContent.toLowerCase().includes(searchBox.value.toLowerCase())){
searchMatch = 1;
} else {
searchMatch = 0;
}
}
});
}
});
} else {
searchMatch = 1;
}
//If the array connectorMatch isn't empty then check that the connector matches one of the ones
//in the array
if (connectorMatch.length > 0) {
publication.childNodes.forEach(item => {
if (item.nodeName.toLowerCase() == "publication-information"){
item.childNodes.forEach(information => {
if (information.nodeName.toLowerCase() == "connector-name") {
if (connectorMatch.includes(information.textContent)){
connectorNameMatch = 1;
} else {
connectorNameMatch = 0;
}
}
});
}
});
} else {
connectorNameMatch = 1;
}
//If the array statusMatch isn't empty then check that the status matches one of the ones
//in the array
if (statusMatch.length > 0) {
publication.childNodes.forEach(item => {
if (item.nodeName.toLowerCase() == "publication-status"){
if (statusMatch.includes(item.getAttribute('release-status'))) {
statusNameMatch = 1;
} else {
statusNameMatch = 0;
}
}
});
} else {
statusNameMatch = 1;
}
//If all of the filtering conditions are met then show the manga, otherwise hide it.
if (searchMatch && connectorNameMatch && statusNameMatch) {
publication.style.display = 'initial';
} else {
publication.style.display = 'none';
}
});
}
settingsCog.addEventListener("click", () => {
OpenSettings();
settingsPopup.style.display = "flex";
});
filterFunnel.addEventListener("click", () => {
filterBox.classList.toggle("animate");
});
settingKomgaUrl.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingKomgaUser.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingKomgaPass.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingKavitaUrl.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingKavitaUser.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingKavitaPass.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingGotifyUrl.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingGotifyAppToken.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingLunaseaWebhook.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingNtfyEndpoint.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingNtfyAuth.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingUserAgent.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingApiUri.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
manganatoRateLimit.addEventListener("keypress", (event) => { if(event.key === "Enter") NewRateLimit(event);});
mangaseeRateLimit.addEventListener("keypress", (event) => { if(event.key === "Enter") NewRateLimit(event);});
mangadexRateLimit.addEventListener("keypress", (event) => { if(event.key === "Enter") NewRateLimit(event);});
mangakatanaRateLimit.addEventListener("keypress", (event) => { if(event.key === "Enter") NewRateLimit(event);});
mangaworldRateLimit.addEventListener("keypress", (event) => { if(event.key === "Enter") NewRateLimit(event);});
batoRateLimit.addEventListener("keypress", (event) => { if(event.key === "Enter") NewRateLimit(event);});
mangalifeRateLimit.addEventListener("keypress", (event) => { if(event.key === "Enter") NewRateLimit(event);});
function NewRateLimit(event) {
if (event.target.value.length > 0 && event.target.value != 0) {
console.log(event.target.id);
switch (event.target.id) {
case "manganatoRL":
connector = 'Manganato';
byteValue = 1;
UpdateRateLimit(connector, byteValue, event.target.value);
break;
case "mangaseeRL":
connector = 'Mangasee';
byteValue = 1;
UpdateRateLimit(connector, byteValue, event.target.value);
break;
case "mDexRL":
connector = 'MangaDex'
byteValue = 250;
UpdateRateLimit(connector, byteValue, event.target.value);
break;
case "mKatanaRL":
connector = 'MangaKatana';
byteValue = 1;
UpdateRateLimit(connector, byteValue, event.target.value);
break;
case "mWorldRL":
connector = 'Mangaworld';
byteValue = 1;
UpdateRateLimit(connector, byteValue, event.target.value);
break;
case "batoRL":
connector = 'Bato';
byteValue = 1;
UpdateRateLimit(connector, byteValue, event.target.value);
break;
case "mLifeRL":
connector = 'Manga4Life';
byteValue = 1;
UpdateRateLimit(connector, byteValue, event.target.value);
break;
default:
console.log("Unknown connector:");
console.log(event.target.id);
}
}
}
function OpenSettings(){
settingGotifyConfigured.setAttribute("configuration", "Not Configured");
settingLunaseaConfigured.setAttribute("configuration", "Not Configured");
settingNtfyConfigured.setAttribute("configuration", "Not Configured");
settingKavitaConfigured.setAttribute("configuration", "Not Configured");
settingKomgaConfigured.setAttribute("configuration", "Not Configured");
settingKomgaUrl.value = "";
settingKomgaUser.value = "";
settingKomgaPass.value = "";
settingKavitaUrl.value = "";
settingKavitaUser.value = "";
settingKavitaPass.value = "";
settingGotifyUrl.value = "";
settingGotifyAppToken.value = "";
settingLunaseaWebhook.value = "";
settingNtfyAuth.value = "";
settingNtfyEndpoint.value = "";
settingUserAgent.value = "";
settingApiUri.value = "";
GetSettings().then((json) => {
//console.log(json);
settingApiUri.placeholder = apiUri;
settingUserAgent.placeholder = json.userAgent;
//console.log(json.styleSheet);
});
GetLibraryConnectors().then((json) => {
//console.log(json);
json.forEach(connector => {
switch(libraryConnectorTypes[connector.libraryType]){
case "Kavita":
settingKavitaConfigured.setAttribute("configuration", "Active");
settingKavitaUrl.value = connector.baseUrl;
settingKavitaUser.value = "***";
settingKavitaPass.value = "***";
break;
case "Komga":
settingKomgaConfigured.setAttribute("configuration", "Active");
settingKomgaUrl.value = connector.baseUrl;
settingKomgaUser.value = "***";
settingKomgaPass.value = "***";
break;
default:
console.log("Unknown type");
console.log(connector);
break;
}
});
});
GetNotificationConnectors().then((json) => {
console.log(json);
json.forEach(connector => {
switch(notificationConnectorTypes[connector.notificationConnectorType]){
case "Gotify":
settingGotifyUrl.value = connector.endpoint;
settingGotifyAppToken.value = "***";
settingGotifyConfigured.setAttribute("configuration", "Active");
break;
case "LunaSea":
settingLunaseaConfigured.setAttribute("configuration", "Active");
settingLunaseaWebhook.value = connector.id;
break;
case "Ntfy":
settingNtfyConfigured.setAttribute("configuration", "Active");
settingNtfyEndpoint.value = connector.endpoint;
settingNtfyAuth.value = "***";
break;
default:
console.log("Unknown type");
console.log(connector);
break;
}
});
});
}
//Functions for clearing/resetting connectors in the settings pop-up
function ClearKomga(){
settingKomgaUrl.value = "";
settingKomgaUser.value = "";
settingKomgaPass.value = "";
settingKomgaConfigured.setAttribute("configuration", "Not Configured");
ResetKomga();
}
function ClearKavita(){
settingKavitaUrl.value = "";
settingKavitaUser.value = "";
settingKavitaPass.value = "";
settingKavitaConfigured.setAttribute("configuration", "Not Configured");
ResetKavita();
}
function ClearGotify(){
settingGotifyUrl.value = "";
settingGotifyAppToken.value = ""
settingGotifyConfigured.setAttribute("configuration", "Not Configured");
ResetGotify();
}
function ClearLunasea(){
settingLunaseaWebhook.value = "";
settingLunaseaConfigured.setAttribute("configuration", "Not Configured");
ResetLunaSea();
}
function ClearNtfy(){
settingNtfyEndpoint.value = "";
settingNtfyAuth.value = "";
settingNtfyConfigured.setAttribute("configuration", "Not Configured");
ResetNtfy();
}
function UpdateSettings(){
if(settingApiUri.value != ""){
apiUri = settingApiUri.value;
setCookie("apiUri", apiUri);
Setup();
}
if(settingKomgaUrl.value != "" &&
settingKomgaUser.value != "" &&
settingKomgaPass.value != ""){
UpdateKomga(settingKomgaUrl.value, utf8_to_b64(`${settingKomgaUser.value}:${settingKomgaPass.value}`));
}
if(settingKavitaUrl.value != "" &&
settingKavitaUser.value != "" &&
settingKavitaPass.value != ""){
UpdateKavita(settingKavitaUrl.value, settingKavitaUser.value, settingKavitaPass.value);
}
if(settingGotifyUrl.value != "" &&
settingGotifyAppToken.value != ""){
UpdateGotify(settingGotifyUrl.value, settingGotifyAppToken.value);
}
if(settingLunaseaWebhook.value != ""){
UpdateLunaSea(settingLunaseaWebhook.value);
}
if(settingNtfyEndpoint.value != "" &&
settingNtfyAuth.value != ""){
UpdateNtfy(settingNtfyEndpoint.value, settingNtfyAuth.value);
}
if(settingUserAgent.value != ""){
UpdateUserAgent(settingUserAgent.value);
}
if (manganatoRateLimit.value.length > 0) {
UpdateRateLimit('Manganato', 1, manganatoRateLimit.value);
}
if (mangaseeRateLimit.value.length > 0) {
UpdateRateLimit('Mangasee', 1, mangaseeRateLimit.value);
}
if (mangadexRateLimit.value.length > 0) {
UpdateRateLimit('MangaDex', 250, mangadexRateLimit.value);
}
if (mangakatanaRateLimit.value.length > 0) {
UpdateRateLimit('MangaKatana', 1, mangakatanaRateLimit.value);
}
if (mangaworldRateLimit.value.length > 0) {
UpdateRateLimit('Mangaworld', 1, mangaworldRateLimit.value);
}
if (batoRateLimit.value.length > 0) {
UpdateRateLimit('Bato', 1, batoRateLimit.value);
}
if (mangalifeRateLimit.value.length > 0) {
UpdateRateLimit('Manga4Life', 1, mangalifeRateLimit.value);
}
setTimeout(() => {
OpenSettings();
Setup();
}, 100)
}
function utf8_to_b64(str) {
return window.btoa(unescape(encodeURIComponent( str )));
}
function UpdateJobs(){
GetMonitorJobs().then((json) => {
if(monitoringJobsCount != json.length){
ResetContent();
//console.log(json);
json.forEach(job => {
var mangaView = CreateManga(job.manga, job.mangaConnector.name);
mangaView.addEventListener("click", (event) => {
ShowMangaWindow(job, job.manga, event, false);
});
tasksContent.appendChild(mangaView);
});
monitoringJobsCount = json.length;
}
});
//Get the jobs that are waiting in the queue
GetWaitingJobs().then((json) => {
jobsQueuedTag.innerText = json.length;
var nowWaitingJobs = [];
json.forEach(job => {
if(!waitingJobs.includes(GetValidSelector(job.id))){
var jobDom = createJob(job);
jobStatusWaiting.appendChild(jobDom);
}
nowWaitingJobs.push(GetValidSelector(job.id));
});
waitingJobs = nowWaitingJobs;
});
jobStatusWaiting.childNodes.forEach(child => {
if(!waitingJobs.includes(child.id))
jobStatusWaiting.removeChild(child);
});
//Get currently running jobs
GetRunningJobs().then((json) => {
jobsRunningTag.innerText = json.length;
var nowRunningJobs = [];
json.forEach(job => {
if(!runningJobs.includes(GetValidSelector(job.id))){
var jobDom = createJob(job);
jobStatusRunning.appendChild(jobDom);
}
nowRunningJobs.push(GetValidSelector(job.id));
UpdateJobProgress(job.id);
});
runningJobs = nowRunningJobs;
});
jobStatusRunning.childNodes.forEach(child => {
if(!runningJobs.includes(child.id))
jobStatusRunning.removeChild(child);
});
}
function createJob(jobjson){
var manga;
if(jobjson.chapter != null)
manga = jobjson.chapter.parentManga;
else if(jobjson.manga != null)
manga = jobjson.manga;
else return null;
var wrapper = document.createElement("div");
wrapper.className = "jobWrapper";
wrapper.id = GetValidSelector(jobjson.id);
var image = document.createElement("img");
image.className = "jobImage";
image.src = GetCoverUrl(manga.internalId);
wrapper.appendChild(image);
var title = document.createElement("span");
title.className = "jobTitle";
if(jobjson.chapter != null)
title.innerText = `${manga.sortName} - ${jobjson.chapter.fileName}`;
else if(jobjson.manga != null)
title.innerText = manga.sortName;
wrapper.appendChild(title);
var progressBar = document.createElement("progress");
progressBar.className = "jobProgressBar";
progressBar.id = `jobProgressBar${GetValidSelector(jobjson.id)}`;
wrapper.appendChild(progressBar);
var progressSpan = document.createElement("span");
progressSpan.className = "jobProgressSpan";
progressSpan.id = `jobProgressSpan${GetValidSelector(jobjson.id)}`;
progressSpan.innerText = "0% 00:00:00";
wrapper.appendChild(progressSpan);
var cancelSpan = document.createElement("span");
cancelSpan.className = "jobCancel";
cancelSpan.innerText = "Cancel";
cancelSpan.addEventListener("click", () => CancelJob(jobjson.id));
wrapper.appendChild(cancelSpan);
return wrapper;
}
function ShowJobQueue(){
jobStatusView.style.display = "initial";
}
function UpdateJobProgress(jobId){
GetProgress(jobId).then((json) => {
var progressBar = document.querySelector(`#jobProgressBar${GetValidSelector(jobId)}`);
var progressSpan = document.querySelector(`#jobProgressSpan${GetValidSelector(jobId)}`);
if(progressBar != null && json.progress != 0){
progressBar.value = json.progress;
}
if(progressSpan != null){
var percentageStr = "0%";
var timeleftStr = "00:00:00";
if(json.progress != 0){
percentageStr = Intl.NumberFormat("en-US", { style: "percent"}).format(json.progress);
timeleftStr = json.timeRemaining.split('.')[0];
}
progressSpan.innerText = `${percentageStr} ${timeleftStr}`;
}
});
}
function GetValidSelector(str){
var clean = [...str.matchAll(/[a-zA-Z0-9]*-*_*/g)];
return clean.join('');
}
const stringToColour = (str) => {
let hash = 0;
str.split('').forEach(char => {
hash = char.charCodeAt(0) + ((hash << 5) - hash)
})
let colour = '#'
for (let i = 0; i < 3; i++) {
const value = (hash >> (i * 8)) & 0xff
colour += value.toString(16).padStart(2, '0')
}
return colour
}