diff --git a/Website/apiConnector.js b/Website/apiConnector.js new file mode 100644 index 0000000..0a94b9e --- /dev/null +++ b/Website/apiConnector.js @@ -0,0 +1,95 @@ +const apiUri = "http://localhost:5177"; + +async function GetData(uri){ + let request = await fetch(uri, { + method: 'GET', + headers: { + 'Accept': 'application/json' + } + }); + let json = await request.json(); + return json; +} + +function PostData(uri){ + fetch(uri, { + method: 'POST' + }); +} + +function DeleteData(uri){ + fetch(uri, { + method: 'DELETE' + }); +} + +async function GetAvailableControllers(){ + var uri = apiUri + "/Tranga/GetAvailableControllers"; + let json = await GetData(uri); + return json; +} + +async function GetPublication(connectorName, title){ + var uri = apiUri + `/Tranga/GetPublicationsFromConnector?connectorName=${connectorName}&title=${title}`; + let json = await GetData(uri); + return json; +} + +async function GetKnownPublications(){ + var uri = apiUri + "/Tranga/GetKnownPublications"; + let json = await GetData(uri); + return json; +} + +async function GetTaskTypes(){ + var uri = apiUri + "/Tasks/GetTaskTypes"; + let json = await GetData(uri); + return json; +} +async function GetRunningTasks(){ + var uri = apiUri + "/Tranga/GetRunningTasks"; + let json = await GetData(uri); + return json; +} + +async function GetTasks(){ + var uri = apiUri + "/Tasks/GetList"; + let json = await GetData(uri); + return json; +} + +async function GetSettings(){ + var uri = apiUri + "/Settings/Get"; + let json = await GetData(uri); + return json; +} + +function CreateTask(taskType, reoccurrence, connectorName, publicationId, language){ + var uri = apiUri + `/Tasks/Create?taskType=${taskType}&connectorName=${connectorName}&publicationId=${publicationId}&reoccurrenceTime=${reoccurrence}&language=${language}`; + PostData(uri); +} + +function StartTask(taskType, connectorName, publicationId){ + var uri = apiUri + `/Tasks/Start?taskType=${taskType}&connectorName=${connectorName}&publicationId=${publicationId}`; + PostData(uri); +} + +function EnqueueTask(taskType, connectorName, publicationId){ + var uri = apiUri + `/Queue/Enqueue?taskType=${taskType}&connectorName=${connectorName}&publicationId=${publicationId}`; + PostData(uri); +} + +function UpdateSettings(downloadLocation, komgaUrl, komgaAuth){ + var uri = apiUri + `/Settings/Update?downloadLocation=${downloadLocation}&komgaUrl=${komgaAuth}&komgaAuth=${komgaAuth}`; + PostData(uri); +} + +function DeleteTask(taskType, connectorName, publicationId){ + var uri = apiUri + `/Tasks/Delete?taskType=${taskType}&connectorName=${connectorName}&publicationId=${publicationId}`; + DeleteData(uri); +} + +function DequeueTask(taskType, connectorName, publicationId){ + var uri = apiUri + `/Queue/Dequeue?taskType=${taskType}&connectorName=${connectorName}&publicationId=${publicationId}`; + DeleteData(uri); +} \ No newline at end of file diff --git a/Website/index.html b/Website/index.html new file mode 100644 index 0000000..44b8c62 --- /dev/null +++ b/Website/index.html @@ -0,0 +1,88 @@ + + + + + Tranga + + + + + + + Tranga + + + + + + settingscog + + + + + + +

Made with Blåhaj 🦈

+
+ +
+

+

+
+ + + + MangaDex + Tensei Pandemic + + +
+ + + + + +

Add Task

+ Close +
+ + + + + + + + +
+
+
+
+ + + + cover + + Tensei Pandemic + Imamura Hinata + Imamura Hinata is a high school boy with a cute appearance. + Since his trauma with the first love, he wanted to be more manly than anybody else. But one day he woke up to something different… + The total opposite of his ideal male body! + Pandemic love comedy! + + Delete Task ❌ + Add Task ➕ + + + + +
+ + + + + + + + + \ No newline at end of file diff --git a/Website/interaction.js b/Website/interaction.js new file mode 100644 index 0000000..3d93d40 --- /dev/null +++ b/Website/interaction.js @@ -0,0 +1,230 @@ +const slideInRight = [ + { right: "-20rem" }, + { right: "0" } +]; + +const slideInRightTiming = { + duration: 200, + iterations: 1, + fill: "forwards", + easing: "ease-out" +} + +const slideOutRightTiming = { + direction: "reverse", + duration: 200, + iterations: 1, + fill: "forwards", + easing: "ease-in" +} + +let publications = []; +let tasks = []; +let toEditId; + +const taskTypesSelect = document.querySelector("#taskTypes") +const searchPublicationQuery = document.querySelector("#searchPublicationQuery"); +const selectPublication = document.querySelector("#taskSelectOutput"); +const connectorSelect = document.querySelector("#connectors"); +const settingsTab = document.querySelector("#settingstab"); +const settingsCog = document.querySelector("#settingscog"); +const selectRecurrence = document.querySelector("#selectReccurrence"); +const tasksContent = document.querySelector("content"); +const addTaskPopup = document.querySelector("#addTaskPopup"); +const publicationViewerPopup = document.querySelector("#publicationViewerPopup"); +const publicationViewerWindow = document.querySelector("publication-viewer"); +const publicationViewerDescription = document.querySelector("#publicationViewerDescription"); +const publicationViewerName = document.querySelector("#publicationViewerName"); +const publicationViewerAuthor = document.querySelector("#publicationViewerAuthor"); +const pubviewcover = document.querySelector("#pubviewcover"); +const publicationDelete = document.querySelector("publication-delete"); +const publicationAdd = document.querySelector("publication-add"); +const closetaskpopup = document.querySelector("#closePopupImg"); + +settingsCog.addEventListener("click", () => slide()); +closetaskpopup.addEventListener("click", () => HideAddTaskPopup()); +document.querySelector("#blurBackgroundTaskPopup").addEventListener("click", () => HideAddTaskPopup()); +document.querySelector("#blurBackgroundPublicationPopup").addEventListener("click", () => HidePublicationPopup()); +publicationDelete.addEventListener("click", () => DeleteTaskClick()); +publicationAdd.addEventListener("click", () => AddTaskClick()); + +/* +let availableTaskTypes; +GetTaskTypes() + .then(json => availableTaskTypes = json) + .then(json => + json.forEach(taskType => { + var option = document.createElement('option'); + option.value = taskType; + option.innerText = taskType; + taskTypesSelect.appendChild(option); + }));*/ + +let availableConnectors; +GetAvailableControllers() + .then(json => availableConnectors = json) + //.then(json => console.log(json)) + .then(json => + json.forEach(connector => { + var option = document.createElement('option'); + option.value = connector; + option.innerText = connector; + connectorSelect.appendChild(option); + }) + ); + +searchPublicationQuery.addEventListener("keypress", (event) => { + if(event.key === "Enter"){ + selectRecurrence.disabled = true; + connectorSelect.disabled = true; + searchPublicationQuery.disabled = true; + + selectPublication.replaceChildren(); + GetPublication(connectorSelect.value, searchPublicationQuery.value) + //.then(json => console.log(json)); + .then(json => + json.forEach(publication => { + var option = CreatePublication(publication, connectorSelect.value); + option.addEventListener("click", (mouseEvent) => { + ShowPublicationViewerWindow(publication.internalId, mouseEvent, true); + }); + selectPublication.appendChild(option); + } + )) + .then(() => { + selectRecurrence.disabled = false; + connectorSelect.disabled = false; + searchPublicationQuery.disabled = false; + }); + } +}); + +function CreatePublication(publication, connector){ + var publicationElement = document.createElement('publication'); + publicationElement.setAttribute("id", publication.internalId); + var img = document.createElement('img'); + img.src = publication.posterUrl; + publicationElement.appendChild(img); + var info = document.createElement('publication-information'); + var connectorName = document.createElement('connector-name'); + connectorName.innerText = connector; + connectorName.className = "pill"; + info.appendChild(connectorName); + var publicationName = document.createElement('publication-name'); + publicationName.innerText = publication.sortName; + info.appendChild(publicationName); + publicationElement.appendChild(info); + if(publications.filter(pub => pub.internalId === publication.internalId) < 1) + publications.push(publication); + return publicationElement; +} + +function DeleteTaskClick(){ + taskToDelete = tasks.filter(tTask => tTask.publication.internalId === toEditId)[0]; + DeleteTask("DownloadNewChapters", taskToDelete.connectorName, toEditId); + HidePublicationPopup(); +} + +function AddTaskClick(){ + CreateTask("DownloadNewChapters", selectRecurrence.value, connectorSelect.value, toEditId, "en") + HideAddTaskPopup(); + HidePublicationPopup(); +} + +var slideIn = true; +function slide() { + if (slideIn) + settingsTab.animate(slideInRight, slideInRightTiming); + else + settingsTab.animate(slideInRight, slideOutRightTiming); + slideIn = !slideIn; +} + +function ResetContent(){ + tasksContent.replaceChildren(); + var add = document.createElement("div"); + add.setAttribute("id", "addPublication") + var plus = document.createElement("p"); + plus.innerText = "+"; + add.appendChild(plus); + add.addEventListener("click", () => ShowNewTaskWindow()); + tasksContent.appendChild(add); +} +function ShowPublicationViewerWindow(publicationId, event, add){ + publicationViewerWindow.style.top = `${event.clientY - 60}px`; + publicationViewerWindow.style.left = `${event.clientX}px`; + var publication = publications.filter(pub => pub.internalId === publicationId)[0]; + + publicationViewerName.innerText = publication.sortName; + publicationViewerDescription.innerText = publication.description; + publicationViewerAuthor.innerText = publication.author; + pubviewcover.src = publication.posterUrl; + toEditId = publicationId; + + if(add){ + publicationAdd.style.display = "block"; + publicationDelete.style.display = "none"; + } + else{ + publicationAdd.style.display = "none"; + publicationDelete.style.display = "block"; + } + + toEditId = publicationId; + publicationViewerPopup.style.display = "block"; +} + +function ShowNewTaskWindow(){ + selectPublication.replaceChildren(); + addTaskPopup.style.display = "block"; +} +function HideAddTaskPopup(){ + addTaskPopup.style.display = "none"; +} + +function HidePublicationPopup(){ + publicationViewerPopup.style.display = "none"; +} + +const fadeIn = [ + { opacity: "0" }, + { opacity: "1" } +]; + +const fadeInTiming = { + duration: 50, + iterations: 1, + fill: "forwards" +} + +ResetContent(); +GetTasks() + //.then(json => console.log(json)) + .then(json => json.forEach(task => { + var publication = CreatePublication(task.publication, task.connectorName); + publication.addEventListener("click", (event) => ShowPublicationViewerWindow(task.publication.internalId, event, false)); + tasksContent.appendChild(publication); + tasks.push(task); + })); + +setInterval(() => { + var cTasks = []; + GetTasks() + //.then(json => console.log(json)) + .then(json => json.forEach(task => cTasks.push(task))) + .then(() => { + if(tasks.length != cTasks.length) { + ResetContent(); + cTasks.forEach(task => { + var publication = CreatePublication(task.publication, task.connectorName); + publication.addEventListener("click", (event) => ShowPublicationViewerWindow(task.publication.internalId, event, false)); + tasksContent.appendChild(publication); + }) + + tasks = cTasks; + } + } + ); + + +}, 1000); \ No newline at end of file diff --git a/Website/media/blahaj.png b/Website/media/blahaj.png new file mode 100644 index 0000000..dbbff93 Binary files /dev/null and b/Website/media/blahaj.png differ diff --git a/Website/media/close-x.svg b/Website/media/close-x.svg new file mode 100644 index 0000000..fc8cc4d --- /dev/null +++ b/Website/media/close-x.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Website/media/settings-cogwheel.svg b/Website/media/settings-cogwheel.svg new file mode 100644 index 0000000..7e61388 --- /dev/null +++ b/Website/media/settings-cogwheel.svg @@ -0,0 +1,21 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Website/style.css b/Website/style.css new file mode 100644 index 0000000..e9220bf --- /dev/null +++ b/Website/style.css @@ -0,0 +1,391 @@ +:root{ + --background-color: #eee; + --second-background-color: #fff; + --primary-color: #f5a9b8; + --secondary-color: #5bcefa; + --accent-color: #fff; + --topbar-height: 60px; + box-sizing: border-box; +} + +body{ + padding: 0; + margin: 0; + display: flex; + flex-flow: column; + flex-wrap: nowrap; + height: 100vh; + background-color: var(--background-color); + font-family: "Inter", sans-serif; + overflow-x: hidden; +} + +background-placeholder{ + background-color: var(--second-background-color); + opacity: 1; + position: absolute; + width: 100%; + height: 100%; + border-radius: 0 0 5px 0; + z-index: -1; +} + +topbar { + display: flex; + align-items: center; + height: var(--topbar-height); + background-color: var(--secondary-color); +} + +titlebox { + position: relative; + display: flex; + margin: 0 0 0 40px; + height: 100%; + align-items:center; + justify-content:center; +} + +titlebox span{ + font-size: 24pt; + font-weight: bold; + background: linear-gradient(150deg, var(--primary-color), var(--accent-color)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + margin-left: 20px; +} + +titlebox img { + height: 100%; + margin-right: 10px; +} + +spacer{ + flex-grow: 1; +} + +searchdiv{ + display: block; + margin: 0 10px 0 0; +} + +#searchbox { + padding: 6px 8px; + border: 0; + border-radius: 3px; + font-size: 14pt; + width: 250px; +} + +#settingscog { + cursor: pointer; + margin: 0px 30px; + height: calc(100% - 40px); + filter: invert(100%) sepia(0%) saturate(7465%) hue-rotate(115deg) brightness(116%) contrast(101%); +} + +viewport { + position: relative; + display: flex; + flex-flow: row; + flex-wrap: nowrap; + flex-grow: 1; +} + +sidebar{ + position: relative; + width: 20rem; + margin-bottom: 20px; + border-radius: 0 0 5px 0; + display: flex; + flex-direction: column; + +} + +content { + position: relative; + flex-grow: 1; + margin: 0 10px 10px 10px; + border-radius: 5px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: start; + align-content: start; +} + +settingstab{ + position: absolute; + right: -20rem; + bottom: 0; + background-color: rgba(0,0,0,0.5); + width: 20rem; + height: calc(100% - var(--topbar-height) - 40px); + margin-bottom: 10px; + border-radius: 5px 0 0 5px; +} + +#addPublication { + cursor: pointer; + background-color: var(--secondary-color); + width: 180px; + height: 300px; + border-radius: 5px; + margin: 10px 10px; + padding: 15px 20px; + position: relative; +} + +#addPublication p{ + width: 100%; + text-align: center; + font-size: 150pt; + vertical-align: middle; + line-height: 300px; + margin: 0; + color: var(--accent-color); +} + +.pill { + flex-grow: 0; + height: 14pt; + font-size: 12pt; + border-radius: 9pt; + background-color: var(--primary-color); + padding: 2pt 20px; +} + +publication{ + cursor: pointer; + background-color: var(--secondary-color); + width: 180px; + height: 300px; + border-radius: 5px; + margin: 10px 10px; + padding: 15px 20px; + position: relative; +} + +publication::after{ + content: ''; + position: absolute; + left: 0; top: 0; + border-radius: 5px; + width: 100%; height: 100%; + background: linear-gradient(rgba(0, 0, 0, 0.5),rgba(0, 0, 0, 0.1)); +} + +publication-information { + display: flex; + flex-direction: column; + justify-content: start; +} + +publication-information * { + z-index: 1; + color: var(--accent-color); +} + +connector-name{ + width: fit-content; + margin: 10px 0; +} + +publication-name{ + width: fit-content; + font-size: 16pt; + font-weight: bold; +} + +publication img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 0; +} + +popup{ + display: none; + width: 100%; + min-height: 100%; + top: 0; + left: 0; + position: absolute; + z-index: 2; +} + +blur-background { + width: 100%; + height: 100%; + position: absolute; + left: 0; + background-color: black; + opacity: 0.5; +} + +addtask-window { + display: flex; + flex-direction: column; + flex-wrap: nowrap; + position: absolute; + left: 12.5%; + top: 15%; + width: 75%; + min-height: 70%; + max-height: 80%; + padding: 0; + background-color: var(--accent-color); + z-index: 5; + border-radius: 5px; +} + +window-titlebar { + width: 100%; + height: 60px; + background-color: var(--primary-color); + border-radius: 5px 5px 0 0; + color: var(--accent-color); + display: flex block; + flex-direction: row; + justify-content: space-between; + align-items: center; +} + +window-titlebar p { + margin: 0 30px; + font-size: 14pt; + font-weight: bolder; + letter-spacing: 1px; +} + +window-titlebar #closePopupImg { + height: 70%; + cursor: pointer; + margin-right: 20px; + filter: invert(100%) sepia(0%) saturate(100%) hue-rotate(115deg) brightness(116%) contrast(101%); +} + +window-content { + display: flex; + flex-direction: column; + padding: 20px 5%; + overflow-x: scroll; +} + +addtask-settings{ + display: flex; + justify-content: center; + align-items: center; +} + +addtask-settings select, addtask-settings input{ + padding: 5px; + font-size: 10pt; + border: 1px solid rgba(0,0,0,0.2); + border-radius: 3px; + background-color: transparent; + margin: 10px 0; + width: 150px; +} + +addtask-settings label { + font-weight: bolder; + margin: 0 5px; +} + +addtask-settings addtask-setting{ + margin: 0 15px; +} + +#taskSelectOutput{ + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: start; + align-content: start; +} + +#publicationViewerPopup{ + z-index: 6; +} + +publication-viewer{ + display: block; + width: 500px; + height: 300px; + position: absolute; + top: 200px; + left: 400px; + background-color: var(--accent-color); + border-radius: 5px; + overflow: hidden; +} + +publication-viewer{ + padding: 30px; +} + +publication-viewer::after{ + content: ''; + position: absolute; + left: 0; top: 0; + border-radius: 5px; + width: 100%; height: 100%; + background: rgba(0,0,0,0.8); + backdrop-filter: blur(3px); +} + +publication-viewer img { + position: absolute; + left: 0; + top: 0; + min-height: 100%; + max-width: 100%; + border-radius: 5px; + z-index: 0; +} + +publication-viewer publication-information publication-name{ + margin: 5px 0; +} + +publication-viewer publication-information publication-author { + margin: 5px 0; +} + +publication-viewer publication-information publication-author::before { + content: "Author: "; +} + +publication-viewer publication-information publication-description::before { + content: "Description"; + display: block; + font-weight: bolder; +} + +publication-viewer publication-information publication-description { + font-size: 12pt; + margin: 5px 0; + max-height: 200px; + overflow-x: scroll; +} + +publication-viewer publication-information publication-delete { + position: absolute; + bottom: 0px; + right: 0px; + color: red; + margin: 20px; + font-size: 16pt; +} + +publication-viewer publication-information publication-add { + position: absolute; + bottom: 0px; + right: 0px; + color: limegreen; + margin: 20px; + font-size: 16pt; +} \ No newline at end of file