Compare commits

..

12 Commits

Author SHA1 Message Date
75772754cd Update apiRequestFunctions to new API endpoints 2024-08-10 21:56:52 +02:00
6d55a13e49 merge 2024-08-10 17:50:32 +02:00
2bc789d589 premerge 2024-08-10 17:42:04 +02:00
db-2001
23ecbd1b20 Addresses https://github.com/C9Glax/tranga-website/issues/87 2024-06-10 22:19:46 -04:00
db-2001
59bfb0e0c4 Update Manga viewer popup to use popup-window elements 2024-05-18 18:38:55 -04:00
db-2001
b3b7b31f7d Tweak behavior for mobile devices 2024-05-18 15:08:38 -04:00
db-2001
2a76b7ee5d Fix for overwriting unchanged settings on front-end 2024-04-26 21:50:43 -04:00
db-2001
c3b4d4b39b Syntax error in previous commit 2024-04-26 21:47:02 -04:00
db-2001
426fd87304 C9Glax/tranga-website #85 2024-04-26 10:18:42 -04:00
db-2001
1aa230bce2 Custom Progress Bar with Half Working Animation 2024-04-25 02:49:34 -04:00
8eda0dcb1d
Merge pull request #78 from C9Glax/dependabot/github_actions/docker/setup-buildx-action-3.3.0
Bump docker/setup-buildx-action from 3.1.0 to 3.3.0
2024-04-22 21:56:08 +02:00
dependabot[bot]
b36cbe1d90
Bump docker/setup-buildx-action from 3.1.0 to 3.3.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.1.0 to 3.3.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.1.0...v3.3.0)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 15:49:51 +00:00
21 changed files with 4264 additions and 4236 deletions

View File

@ -3,8 +3,6 @@ name: Docker Image CI
on: on:
push: push:
branches: [ "cuttingedge" ] branches: [ "cuttingedge" ]
pull_request:
branches: [ "cuttingedge" ]
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@ -24,7 +22,7 @@ jobs:
# https://github.com/marketplace/actions/docker-setup-buildx # https://github.com/marketplace/actions/docker-setup-buildx
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v3.1.0 uses: docker/setup-buildx-action@v3.3.0
# https://github.com/docker/login-action#docker-hub # https://github.com/docker/login-action#docker-hub
- name: Login to Docker Hub - name: Login to Docker Hub
@ -37,7 +35,7 @@ jobs:
- name: Build and push Website - name: Build and push Website
uses: docker/build-push-action@v4.1.1 uses: docker/build-push-action@v4.1.1
with: with:
context: ./ context: ./Website
file: ./Dockerfile file: ./Dockerfile
#platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6 #platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
platforms: linux/amd64 platforms: linux/amd64

View File

@ -2,9 +2,7 @@ name: Docker Image CI
on: on:
push: push:
branches: [ "dev" ] branches: [ "cuttingedge" ]
pull_request:
branches: [ "dev" ]
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@ -24,7 +22,7 @@ jobs:
# https://github.com/marketplace/actions/docker-setup-buildx # https://github.com/marketplace/actions/docker-setup-buildx
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v3.1.0 uses: docker/setup-buildx-action@v3.3.0
# https://github.com/docker/login-action#docker-hub # https://github.com/docker/login-action#docker-hub
- name: Login to Docker Hub - name: Login to Docker Hub
@ -37,11 +35,9 @@ jobs:
- name: Build and push Website - name: Build and push Website
uses: docker/build-push-action@v4.1.1 uses: docker/build-push-action@v4.1.1
with: with:
context: ./ context: ./Website
file: ./Dockerfile file: ./Dockerfile
#platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6 #platforms: linux/amd63,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
platforms: linux/amd64 platforms: linux/amd64
pull: true pull: true
push: true push: true
tags: |
glax/tranga-website:dev

View File

@ -41,9 +41,13 @@ async function GetData(uri){
return json; return json;
} }
async function PostData(uri){ async function PostData(uri, body){
let request = await fetch(uri, { let request = await fetch(uri, {
method: 'POST' method: 'POST',
headers: {
'Accept': 'application/json'
},
body: body
}); });
//console.log(request); //console.log(request);
} }
@ -55,131 +59,132 @@ function DeleteData(uri){
} }
async function Ping(){ async function Ping(){
let ret = await GetData(`${apiUri}/Ping`); let ret = await GetData(`${apiUri}/v2/Ping`);
return ret; return ret;
} }
async function GetAvailableControllers(){ async function GetAvailableControllers(){
var uri = apiUri + "/Connectors"; var uri = `${apiUri}/v2/Connector/Types`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetPublicationFromConnector(connector, title){ async function GetPublicationFromConnector(connector, title){
var uri; var uri = `${apiUri}/v2/Connector/${connector}/GetManga`;
if(title.includes("http")){ if(title.startsWith("http")){
uri = `${apiUri}/Manga/FromConnector?connector=${connector}&url=${title}`; uri += `?url=${title}`
}else{ }else{
uri = `${apiUri}/Manga/FromConnector?connector=${connector}&title=${title}`; uri += `?title=${title}`
} }
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetChapters(connector, internalId, language){ async function GetCoverUrl(internalId){
var uri = `${apiUri}/Manga/Chapters?connector=${connector}&internalId=${internalId}&translatedLanguage=${language}`; return `${apiUri}/v2/Manga/${internalId}/Cover`;
let json = await GetData(uri);
return json;
}
function GetCoverUrl(internalId){
return `${apiUri}/Manga/Cover?internalId=${internalId}`;
} }
async function GetAllJobs(){ async function GetAllJobs(){
var uri = `${apiUri}/Jobs`; var uri = `${apiUri}/v2/Jobs`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetRunningJobs(){ async function GetRunningJobs(){
var uri = `${apiUri}/Jobs/Running`; var uri = `${apiUri}/v2/Jobs/Running`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetWaitingJobs(){ async function GetWaitingJobs(){
var uri = `${apiUri}/Jobs/Waiting`; var uri = `${apiUri}/v2/Jobs/Waiting`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetMonitorJobs(){ async function GetMonitorJobs(){
var uri = `${apiUri}/Jobs/MonitorJobs`; var uri = `${apiUri}/v2/Jobs/Monitoring`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetProgress(jobId){ async function GetJob(jobId){
var uri = `${apiUri}/Jobs/Progress?jobId=${jobId}`; var uri = `${apiUri}/v2/Job/${jobId}`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetSettings(){ async function GetSettings(){
var uri = `${apiUri}/Settings`; var uri = `${apiUri}/v2/Settings`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetAvailableNotificationConnectors(){ async function GetAvailableNotificationConnectors(){
var uri = `${apiUri}/NotificationConnectors/Types`; var uri = `${apiUri}/v2/NotificationConnector/Types`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetNotificationConnectors(){ async function GetNotificationConnectors(){
var uri = `${apiUri}/NotificationConnectors`; var uri = `${apiUri}/v2/NotificationConnector`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetAvailableLibraryConnectors(){ async function GetAvailableLibraryConnectors(){
var uri = `${apiUri}/LibraryConnectors/Types`; var uri = `${apiUri}/v2/LibraryConnector/Types`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetLibraryConnectors(){ async function GetLibraryConnectors(){
var uri = `${apiUri}/LibraryConnectors`; var uri = `${apiUri}/v2/LibraryConnector`;
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
async function GetRateLimits() { async function GetRateLimits() {
var uri = `${apiUri}/Settings/customRequestLimit` var uri = `${apiUri}/v2/Settings/RateLimit`
let json = await GetData(uri); let json = await GetData(uri);
return json; return json;
} }
function CreateMonitorJob(connector, internalId, language, interval, folder, chapterNo){ async function GetMangaChapters(connector, internalId) {
var uri = `${apiUri}/Jobs/MonitorManga?connector=${connector}&internalId=${internalId}&interval=${interval}&translatedLanguage=${language}&ignoreBelowChapterNum=${chapterNo}&customFolderName=${folder}`; var uri = `${apiUri}/v2/Manga/${internalId}`
//console.log(uri); let json = await GetData(uri);
PostData(uri); return json;
} }
function CreateDownloadNewChaptersJob(connector, internalId, language){ function CreateMonitorJob(internalId, language, interval, folder = null, chapterNo){
var uri = `${apiUri}/Jobs/DownloadNewChapters?connector=${connector}&internalId=${internalId}&translatedLanguage=${language}`; var uri = `${apiUri}/v2/Job/Create/MonitorManga`;
PostData(uri); let data = `{ "internalId": ${internalId}, "language": ${language}, "interval": ${interval}, "startChapter": ${chapterNo}, "customFolder": ${folder} }`
PostData(uri, data);
}
function CreateDownloadNewChaptersJob(internalId, language){
var uri = `${apiUri}/v2/Job/Create/DownloadNewChaptersJob`;
let data = `{ "internalId": ${internalId}, "language": ${language} }`
PostData(uri, data);
} }
function StartJob(jobId){ function StartJob(jobId){
var uri = `${apiUri}/Jobs/StartNow?jobId=${jobId}`; var uri = `${apiUri}/v2/Job/${jobId}/StartNow`;
PostData(uri); PostData(uri);
} }
function UpdateDownloadLocation(downloadLocation){ function UpdateDownloadLocation(downloadLocation){
var uri = `${apiUri}/Settings/UpdateDownloadLocation?downloadLocation=${downloadLocation}`; var uri = `${apiUri}/v2/Settings/DownloadLocation`;
PostData(uri); PostData(uri, `{ "location": ${location} }`);
} }
function RefreshLibraryMetadata() { function RefreshMangaMetadata(internalId) {
var uri = `${apiUri}/Jobs/UpdateMetadata`; var uri = `${apiUri}/v2/Job/Create/UpdateMetaDataJob`;
PostData(uri); PostData(uri, `{ "internalId": ${internalId} }`);
} }
async function DownloadLogs() { async function DownloadLogs() {
var uri = `${apiUri}/LogFile`; var uri = `${apiUri}/v2/LogFile`;
//Below taken from https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream //Below taken from https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
fetch(uri) fetch(uri)
@ -242,126 +247,119 @@ Date.prototype.timeNow = function () {
function UpdateAprilFoolsMode() { function UpdateAprilFoolsMode() {
checkBox = document.getElementById("aprilFoolsMode"); checkBox = document.getElementById("aprilFoolsMode");
var uri = `${apiUri}/Settings/AprilFoolsMode?enabled=${checkBox.checked}`; var uri = `${apiUri}/v2/Settings/AprilFoolsMode`;
PostData(uri); PostData(uri, `{ "value": ${checkBox.checked} }` );
} }
function ResetRateLimits() { function ResetRateLimits() {
var uri = `${apiUri}/Settings/customRequestLimit/Reset`; var uri = `${apiUri}/v2/Settings/RateLimit`;
PostData(uri); PostData(uri);
OpenSettings(); OpenSettings();
} }
function ResetUserAgent() { function ResetUserAgent() {
var uri = `${apiUri}/Settings/userAgent/Reset`; var uri = `${apiUri}/v2/Settings/UserAgent`;
PostData(uri); PostData(uri);
OpenSettings(); OpenSettings();
} }
//Komga //Komga
function UpdateKomga(komgaUrl, komgaAuth){ function UpdateKomga(komgaUrl, komgaAuth){
var uri = `${apiUri}/LibraryConnectors/Update?libraryConnector=Komga&komgaUrl=${komgaUrl}&komgaAuth=${komgaAuth}`; var uri = `${apiUri}/v2/LibraryConnector/Komga`;
PostData(uri); PostData(uri, `{ "url": ${komgaUrl}, "auth": ${komgaAuth} }`);
} }
function ResetKomga(){ function ResetKomga(){
var uri = `${apiUri}/LibraryConnectors/Reset?libraryConnector=Komga`; var uri = `${apiUri}/v2/LibraryConnector/Komga`;
PostData(uri); DeleteData(uri);
} }
function TestKomga(komgaUrl, komgaAuth){ function TestKomga(komgaUrl, komgaAuth){
var uri = `${apiUri}/LibraryConnectors/Test?libraryConnector=Komga&komgaUrl=${komgaUrl}&komgaAuth=${komgaAuth}`; var uri = `${apiUri}/v2/LibraryConnector/Komga/Test`;
PostData(uri); PostData(uri, `{ "url": ${komgaUrl}, "auth": ${komgaAuth} }`);
} }
//Kavita //Kavita
function UpdateKavita(kavitaUrl, kavitaUsername, kavitaPassword){ function UpdateKavita(kavitaUrl, kavitaUsername, kavitaPassword){
var uri = `${apiUri}/LibraryConnectors/Update?libraryConnector=Kavita&kavitaUrl=${kavitaUrl}&kavitaUsername=${kavitaUsername}&kavitaPassword=${kavitaPassword}`; var uri = `${apiUri}/v2/LibraryConnector/Kavita`;
PostData(uri); PostData(uri, `{ "url": ${kavitaUrl}, "uasername": ${kavitaUsername}, "password": ${kavitaPassword} }`);
} }
function ResetKavita(){ function ResetKavita(){
var uri = `${apiUri}/LibraryConnectors/Reset?libraryConnector=Kavita`; var uri = `${apiUri}/v2/LibraryConnector/Kavita`;
PostData(uri); DeleteData(uri);
} }
function TestKavita(kavitaUrl, kavitaUsername, kavitaPassword){ function TestKavita(kavitaUrl, kavitaUsername, kavitaPassword){
var uri = `${apiUri}/LibraryConnectors/Test?libraryConnector=Kavita&kavitaUrl=${kavitaUrl}&kavitaUsername=${kavitaUsername}&kavitaPassword=${kavitaPassword}`; var uri = `${apiUri}/v2/LibraryConnector/Kavita/Test`;
PostData(uri); PostData(uri, `{ "url": ${kavitaUrl}, "uasername": ${kavitaUsername}, "password": ${kavitaPassword} }`);
} }
//Gotify //Gotify
function UpdateGotify(gotifyUrl, gotifyAppToken){ function UpdateGotify(gotifyUrl, gotifyAppToken){
var uri = `${apiUri}/NotificationConnectors/Update?notificationConnector=Gotify&gotifyUrl=${gotifyUrl}&gotifyAppToken=${gotifyAppToken}`; var uri = `${apiUri}/v2/NotificationConnector/Gotify`;
PostData(uri); PostData(uri, `{ "url": ${gotifyUrl}, "appToken": ${gotifyAppToken} }`);
} }
function ResetGotify(){ function ResetGotify(){
var uri = `${apiUri}/NotificationConnectors/Reset?notificationConnector=Gotify`; var uri = `${apiUri}/v2/NotificationConnector/Gotify`;
PostData(uri); DeleteData(uri);
} }
function TestGotify(gotifyUrl, gotifyAppToken){ function TestGotify(gotifyUrl, gotifyAppToken){
var uri = `${apiUri}/NotificationConnectors/Test?notificationConnector=Gotify&gotifyUrl=${gotifyUrl}&gotifyAppToken=${gotifyAppToken}`; var uri = `${apiUri}/v2/NotificationConnector/Gotify/Test`;
PostData(uri); PostData(uri, `{ "url": ${gotifyUrl}, "appToken": ${gotifyAppToken} }`);
} }
//LunaSea //LunaSea
function UpdateLunaSea(lunaseaWebhook){ function UpdateLunaSea(lunaseaWebhook){
var uri = `${apiUri}/NotificationConnectors/Update?notificationConnector=LunaSea&lunaseaWebhook=${lunaseaWebhook}`; var uri = `${apiUri}/v2/NotificationConnector/LunaSea`;
PostData(uri); PostData(uri, `{ "webhook": ${lunaseaWebhook} }`);
} }
function ResetLunaSea(){ function ResetLunaSea(){
var uri = `${apiUri}/NotificationConnectors/Reset?notificationConnector=LunaSea`; var uri = `${apiUri}/v2/NotificationConnector/LunaSea`;
PostData(uri); DeleteData(uri);
} }
function TestLunaSea(lunaseaWebhook){ function TestLunaSea(lunaseaWebhook){
var uri = `${apiUri}/NotificationConnectors/Test?notificationConnector=LunaSea&lunaseaWebhook=${lunaseaWebhook}`; var uri = `${apiUri}/v2/NotificationConnector/LunaSea/Test`;
PostData(uri); PostData(uri, `{ "webhook": ${lunaseaWebhook} }`);
} }
//Ntfy //Ntfy
function UpdateNtfy(ntfyEndpoint, ntfyAuth){ function UpdateNtfy(ntfyEndpoint, ntfyUser, ntfyPass){
var uri = `${apiUri}/NotificationConnectors/Update?notificationConnector=Ntfy&ntfyUrl=${ntfyEndpoint}&ntfyAuth=${ntfyAuth}`; var uri = `${apiUri}/v2/NotificationConnector/Ntfy`;
PostData(uri); PostData(uri, `{ "url": ${ntfyEndpoint}, "username": ${ntfyUser}, "password": ${ntfyPass} }`);
} }
function ResetNtfy(){ function ResetNtfy(){
var uri = `${apiUri}/NotificationConnectors/Reset?notificationConnector=Ntfy`; var uri = `${apiUri}/v2/NotificationConnector/Ntfy`;
PostData(uri); DeleteData(uri);
} }
function TestNtfy(ntfyEndpoint, ntfyAuth){ function TestNtfy(ntfyEndpoint, ntfyUser, ntfyPass){
var uri = `${apiUri}/NotificationConnectors/Test?notificationConnector=Ntfy&ntfyUrl=${ntfyEndpoint}&ntfyAuth=${ntfyAuth}`; var uri = `${apiUri}/v2/NotificationConnector/Ntfy/Test`;
PostData(uri); PostData(uri, `{ "url": ${ntfyEndpoint}, "username": ${ntfyUser}, "password": ${ntfyPass} }`);
} }
function UpdateUserAgent(userAgent){ function UpdateUserAgent(userAgent){
var uri = `${apiUri}/Settings/userAgent?userAgent=${userAgent}`; var uri = `${apiUri}/v2/Settings/UserAgent`;
PostData(uri); PostData(uri, `{ "value": ${userAgent} }`);
} }
function UpdateRateLimit(byteValue, rateLimit) { function UpdateRateLimit(rateLimitType, rateLimitValue) {
var uri = `${apiUri}/Settings/customRequestLimit?requestType=${byteValue}&requestsPerMinute=${rateLimit}`; var uri = `${apiUri}/v2/Settings/RateLimit/${rateLimitType}`;
PostData(uri); PostData(uri, `{ "value": ${rateLimitValue} }`);
} }
function RemoveJob(jobId){ function RemoveJob(jobId){
var uri = `${apiUri}/Jobs?jobId=${jobId}`; var uri = `${apiUri}/v2/Job/${jobId}`;
DeleteData(uri); DeleteData(uri);
} }
function CancelJob(jobId){ function CancelJob(jobId){
var uri = `${apiUri}/Jobs/Cancel?jobId=${jobId}`; var uri = `${apiUri}/v2/Job/${jobId}/Cancel`;
PostData(uri); PostData(uri);
} }
async function GetLogmessages(count){
var uri = `${apiUri}/LogMessages?count=${count}`;
let json = await GetData(uri);
console.log(json);
return json;
}

View File

@ -1,4 +1,4 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -6,6 +6,10 @@
<link id='basestyle' rel="stylesheet" href="styles/base.css"> <link id='basestyle' rel="stylesheet" href="styles/base.css">
<link id='librarystyle' rel="stylesheet" href="styles/style_default.css"> <link id='librarystyle' rel="stylesheet" href="styles/style_default.css">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400..900&display=swap" rel="stylesheet">
</head> </head>
<body> <body>
<wrapper> <wrapper>
@ -231,11 +235,12 @@
<div class="section-item"> <div class="section-item">
<span class="title"><img src='connector-icons/ntfy.svg'>Ntfy<connector-configured id="ntfyConfigured"></connector-configured></span> <span class="title"><img src='connector-icons/ntfy.svg'>Ntfy<connector-configured id="ntfyConfigured"></connector-configured></span>
<label for="ntfyEndpoint"></label><input placeholder="URL" id="ntfyEndpoint" type="text"> <label for="ntfyEndpoint"></label><input placeholder="URL" id="ntfyEndpoint" type="text">
<label for="ntfyAuth"></label><input placeholder="Auth" id="ntfyAuth" type="text"> <label for="ntfyUser"></label><input placeholder="Username" id="ntfyUser" type="text">
<label for="ntfyPass"></label><input placeholder="Password" id="ntfyPass" type="password">
<div class="section-buttons-container"> <div class="section-buttons-container">
<span onclick="TestNtfy(ntfyEndpoint.value, ntfyAuth.value);" class='section-button' id="test-connector">Test</span> <span onclick="TestNtfy(ntfyEndpoint.value, ntfyUser.value, ntfyPass.value);" class='section-button' id="test-connector">Test</span>
<span onclick="ClearNtfy()" class='section-button' id="reset">Reset</span> <span onclick="ClearNtfy()" class='section-button' id="reset">Reset</span>
<span onclick="UpdateNtfy(ntfyEndpoint.value, ntfyAuth.value);" class='section-button'>Apply</span> <span onclick="UpdateNtfy(ntfyEndpoint.value, ntfyUser.value, ntfyPass.value);" class='section-button'>Apply</span>
</div> </div>
</div> </div>
</div> </div>
@ -253,24 +258,32 @@
<popup id="publicationViewerPopup"> <popup id="publicationViewerPopup">
<blur-background id="blurBackgroundPublicationPopup" onclick="publicationViewerPopup.style.display= 'none';"></blur-background> <blur-background id="blurBackgroundPublicationPopup" onclick="publicationViewerPopup.style.display= 'none';"></blur-background>
<publication-viewer> <popup-window>
<img id="pubviewcover" src="media/cover.jpg" alt="cover"> <border-bar>
<publication-details> <popup-title><a class="mangaTitle" id="publicationViewerName"></a></popup-title><status-filter id="publicationViewerStatus"></status-filter>
<publication-name id="publicationViewerName">Best Manga there is</publication-name> <popup-close onclick="publicationViewerPopup.style.display = 'none'">&times</popup-close>
<publication-tags id="publicationViewerTags">A Manga</publication-tags> </border-bar>
<publication-author id="publicationViewerAuthor">Glax</publication-author> <manga-details>
<publication-description id="publicationViewerDescription">
An interesting description. The description is very intriguing, yet wholesome. <img-container>
</publication-description> <img id="pubviewcover">
<publication-interactions> <manga-connector id="publicationViewerConnector"></manga-connector>
<publication-starttask id="startJobButton">Start Job ▶️</publication-starttask> <span class="latest-chapter-no" id="publicationViewerChapterNo"></span>
<publication-canceltask id="cancelJobButton">Cancel Job ❌</publication-canceltask> </img-container>
<publication-delete id="deleteJobButton">Delete Job 🗑️</publication-delete> <div style="height: 100%;">
<publication-add id="createMonitorJobButton">Monitor </publication-add> <tag-cloud id="publicationViewerTags"></tag-cloud>
<publication-add id="createDownloadChapterJobButton">Download Chapter 📥</publication-add> <div class="mangaDescription" id="publicationViewerDescription"></div>
</publication-interactions> </div>
</publication-details> </manga-details>
</publication-viewer> <!-- <manga-chapter id="publicationViewerChapters"></manga-chapter> -->
<border-bar>
<div class="button-container">
<border-bar-button onclick="RefreshMangaMetadata(selectedManga.internalId)">Refresh Metadata</border-bar-button>
<border-bar-button id="reset" onclick="RemoveJob(selectedJob.id); UpdateJobs(); mangaViewerPopup.style.display = 'none'">Remove Manga</border-bar-button>
<border-bar-button class="primary" onclick="StartJob(selectedJob.id); mangaViewerPopup.style.display = 'none'">Start Job</border-bar-button>
</div>
</border-bar>
</popup-window>
</popup> </popup>
<popup id="jobStatusView"> <popup id="jobStatusView">

View File

@ -1,4 +1,4 @@
let monitoringJobsCount = 0; let monitoringJobsCount = 0;
let runningJobs = []; let runningJobs = [];
let waitingJobs = []; let waitingJobs = [];
let notificationConnectorTypes = []; let notificationConnectorTypes = [];
@ -19,11 +19,6 @@ const filterContent = document.querySelector("#filterContent");
const settingsCog = document.querySelector("#settingscog"); const settingsCog = document.querySelector("#settingscog");
const filterFunnel = document.querySelector("#filterFunnel"); const filterFunnel = document.querySelector("#filterFunnel");
const tasksContent = document.querySelector("content"); 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 //Manga viewer popup
const mangaViewerPopup = document.querySelector("#publicationViewerPopup"); const mangaViewerPopup = document.querySelector("#publicationViewerPopup");
@ -31,8 +26,10 @@ const mangaViewerWindow = document.querySelector("publication-viewer");
const mangaViewerDescription = document.querySelector("#publicationViewerDescription"); const mangaViewerDescription = document.querySelector("#publicationViewerDescription");
const mangaViewerName = document.querySelector("#publicationViewerName"); const mangaViewerName = document.querySelector("#publicationViewerName");
const mangaViewerTags = document.querySelector("#publicationViewerTags"); const mangaViewerTags = document.querySelector("#publicationViewerTags");
const mangaViewerAuthor = document.querySelector("#publicationViewerAuthor");
const mangaViewCover = document.querySelector("#pubviewcover"); const mangaViewCover = document.querySelector("#pubviewcover");
const mangaViewConn = document.querySelector('#publicationViewerConnector');
const mangaViewStatus = document.querySelector('#publicationViewerStatus');
const mangaViewChapterNo = document.querySelector('#publicationViewerChapterNo');
//General Rate Limits //General Rate Limits
const defaultRL = document.querySelector("#defaultRL"); const defaultRL = document.querySelector("#defaultRL");
@ -63,7 +60,8 @@ const settingLunaseaWebhook = document.querySelector("#lunaseaWebhook");
//Ntfy //Ntfy
const settingNtfyEndpoint = document.querySelector("#ntfyEndpoint"); const settingNtfyEndpoint = document.querySelector("#ntfyEndpoint");
const settingNtfyAuth = document.querySelector("#ntfyAuth"); const settingNtfyUser = document.querySelector("#ntfyUser");
const settingNtfyPass = document.querySelector("#ntfyPass");
//Connector Configured //Connector Configured
const settingKomgaConfigured = document.querySelector("#komgaConfigured"); const settingKomgaConfigured = document.querySelector("#komgaConfigured");
@ -157,8 +155,8 @@ function Setup(){
GetSettings().then((json) => { GetSettings().then((json) => {
//console.log(json); //console.log(json);
settingApiUri.placeholder = apiUri; settingApiUri.placeholder = apiUri;
settingDownloadLocation.value = json.downloadLocation; settingDownloadLocation.placeholder = json.downloadLocation;
settingUserAgent.value = json.userAgent; settingUserAgent.placeholder = json.userAgent;
settingAprilFoolsMode.checked = json.aprilFoolsMode; settingAprilFoolsMode.checked = json.aprilFoolsMode;
}); });
GetRateLimits().then((json) => { GetRateLimits().then((json) => {
@ -475,7 +473,7 @@ function CreateSearchResult(manga, connector) {
//Description //Description
var description = document.createElement('div'); var description = document.createElement('div');
description.className = 'mangaDescription'; description.className = 'mangaDescription abbreviated';
description.innerText = manga.description; description.innerText = manga.description;
mangaDetails.appendChild(description); mangaDetails.appendChild(description);
@ -487,7 +485,7 @@ function CreateSearchResult(manga, connector) {
folderRow = document.createElement('row'); folderRow = document.createElement('row');
folderLabel = document.createElement('label'); folderLabel = document.createElement('label');
folderLabel.innerText = 'Download Folder:'; folderLabel.innerText = 'Download Folder';
folderRow.appendChild(folderLabel); folderRow.appendChild(folderLabel);
folderInput = document.createElement('input'); folderInput = document.createElement('input');
downloadFolder = manga.folderName; downloadFolder = manga.folderName;
@ -499,7 +497,7 @@ function CreateSearchResult(manga, connector) {
intervalRow = document.createElement('row'); intervalRow = document.createElement('row');
intervalLabel = document.createElement('label'); intervalLabel = document.createElement('label');
intervalLabel.innerText = 'Job Interval:'; intervalLabel.innerText = 'Job Interval';
intervalRow.appendChild(intervalLabel); intervalRow.appendChild(intervalLabel);
intervalInput = document.createElement('input'); intervalInput = document.createElement('input');
intervalInput.placeholder = '03:00:00 (HH:MM:SS)'; intervalInput.placeholder = '03:00:00 (HH:MM:SS)';
@ -510,7 +508,7 @@ function CreateSearchResult(manga, connector) {
chapterRow = document.createElement('row'); chapterRow = document.createElement('row');
chapterLabel = document.createElement('label'); chapterLabel = document.createElement('label');
chapterLabel.innerText = 'Download from Chapter:'; chapterLabel.innerText = 'Download from Chapter';
chapterRow.appendChild(chapterLabel); chapterRow.appendChild(chapterLabel);
chapterInput = document.createElement('input'); chapterInput = document.createElement('input');
chapterInput.placeholder = (manga.ignoreChaptersBelow + 1).toString(); chapterInput.placeholder = (manga.ignoreChaptersBelow + 1).toString();
@ -551,15 +549,13 @@ function IsInLibrary(id) {
} }
function AddManga(id, connector) { function AddManga(id, connector) {
//console.log('Adding Manga'); console.log('Adding Manga');
mangaID = id; mangaID = id;
mangaConnector = connector; mangaConnector = connector;
mangaLanguage = document.getElementById('newMangaTranslatedLanguage').value.toLowerCase(); mangaLanguage = document.getElementById('newMangaTranslatedLanguage').value.toLowerCase();
folderInput = document.getElementById(id.concat('-downloadfolder')).value; folderInput = document.getElementById(id.concat('-downloadfolder')).value;
if (folderInput == null || folderInput == '') { if (folderInput != null || folderInput != '') {
mangaFolder = document.getElementById(id.concat('-downloadfolder')).placeholder;
} else {
mangaFolder = folderInput; mangaFolder = folderInput;
} }
@ -580,65 +576,93 @@ function AddManga(id, connector) {
CreateMonitorJob(mangaConnector, mangaID, mangaLanguage, mangaInterval, mangaFolder, mangaChapter); CreateMonitorJob(mangaConnector, mangaID, mangaLanguage, mangaInterval, mangaFolder, mangaChapter);
} }
createMonitorJobButton.addEventListener("click", () => {
CreateMonitorJob(newMangaConnector.value, selectedManga.internalId, newMangaTranslatedLanguage.value);
UpdateJobs();
mangaViewerPopup.style.display = "none";
});
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";
});
function ShowMangaWindow(job, manga, event, add){ function ShowMangaWindow(job, manga, event, add){
selectedManga = manga; selectedManga = manga;
selectedJob = job; selectedJob = job;
//Show popup
mangaViewerPopup.style.display = "block";
//Set position to mouse-position //Title
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; mangaViewerName.innerText = manga.sortName;
mangaViewerTags.innerText = manga.tags.join(", "); mangaViewerName.href = manga.websiteUrl;
mangaViewerDescription.innerText = manga.description;
mangaViewerAuthor.innerText = manga.authors.join(',');
mangaViewCover.src = GetCoverUrl(manga.internalId);
toEditId = manga.internalId;
//Check what action should be listed //Author and Genre Tag Cloud
if(add){ mangaViewerTags.replaceChildren();
createMonitorJobButton.style.display = "initial"; manga.authors.forEach(author => {
createDownloadChapterJobButton.style.display = "none"; var authorCard = document.createElement('author-tag');
cancelJobButton.style.display = "none";
startJobButton.style.display = "none"; var personImg = document.createElement('img');
deleteJobButton.style.display = "none"; personImg.src = 'media/person.svg';
} authorCard.appendChild(personImg);
else{
createMonitorJobButton.style.display = "none"; var authorName = document.createElement('span');
createDownloadChapterJobButton.style.display = "none"; authorName.innerText = author;
cancelJobButton.style.display = "initial"; authorCard.appendChild(authorName);
startJobButton.style.display = "initial";
deleteJobButton.style.display = "initial"; mangaViewerTags.appendChild(authorCard);
});
manga.tags.forEach(tag => {
var tagElement = document.createElement('manga-tag');
tagElement.innerText = tag;
mangaViewerTags.appendChild(tagElement);
});
//Description
mangaViewerDescription.innerText = manga.description;
//Image and Connector
mangaViewCover.src = GetCoverUrl(manga.internalId);
mangaViewConn.innerText = job.mangaConnector.name.toUpperCase();
mangaViewConn.style.backgroundColor = stringToColour(job.mangaConnector.name);
mangaViewChapterNo.innerText = manga.latestChapterAvailable.toString();
//Release Status
switch(manga.releaseStatus){
case 0:
mangaViewStatus.setAttribute("release-status", "Ongoing");
mangaViewStatus.innerText = "Ongoing";
break;
case 1:
mangaViewStatus.setAttribute("release-status", "Completed");
mangaViewStatus.innerText = "Completed";
break;
case 2:
mangaViewStatus.setAttribute("release-status", "On Hiatus");
mangaViewStatus.innerText = "On Hiatus";
break;
case 3:
mangaViewStatus.setAttribute("release-status", "Cancelled");
mangaViewStatus.innerText = "Cancelled";
break;
case 4:
mangaViewStatus.setAttribute("release-status", "Upcoming");
mangaViewStatus.innerText = "Upcoming";
break;
default:
mangaViewStatus.setAttribute("release-status", "Status Unavailable");
mangaViewStatus.innerText = "Status Unavailable";
break;
} }
// //Individual Manga Chapters
// chapters = document.querySelector('#publicationViewerChapters');
// chapters.replaceChildren();
// var mangaChapters = GetMangaChapters(job.mangaConnector.name, manga.internalId);
// mangaChapters.then(value => {
// sortedChapters = value.sort((a, b) => b.chapterNumber - a.chapterNumber);
// sortedChapters.forEach(chapter => {
// chapterNo = chapter.chapterNumber;
// var chapterElement = document.createElement('chapter-row');
// chapterElement.innerText = chapter.fileName;
// chapters.appendChild(chapterElement);
// })
// }).then(() => {
// //Show popup
// mangaViewerPopup.style.display = "block";
// });
mangaViewerPopup.style.display = "block"
} }
function HidePublicationPopup(){ function HidePublicationPopup(){
@ -735,7 +759,7 @@ settingGotifyUrl.addEventListener("keypress", (event) => { if(event.key === "Ent
settingGotifyAppToken.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(); }); settingLunaseaWebhook.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingNtfyEndpoint.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(); }); settingNtfyPass.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
settingUserAgent.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(); }); settingApiUri.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
@ -762,7 +786,8 @@ function OpenSettings(){
settingGotifyUrl.value = ""; settingGotifyUrl.value = "";
settingGotifyAppToken.value = ""; settingGotifyAppToken.value = "";
settingLunaseaWebhook.value = ""; settingLunaseaWebhook.value = "";
settingNtfyAuth.value = ""; settingNtfyUser.value = "";
settingNtfyPass.value = "";
settingNtfyEndpoint.value = ""; settingNtfyEndpoint.value = "";
settingUserAgent.value = ""; settingUserAgent.value = "";
settingApiUri.value = ""; settingApiUri.value = "";
@ -775,10 +800,10 @@ function OpenSettings(){
GetSettings().then((json) => { GetSettings().then((json) => {
//console.log(json); //console.log(json);
settingApiUri.value = apiUri; settingApiUri.placeholder = apiUri;
settingUserAgent.value = json.userAgent; settingUserAgent.placeholder = json.userAgent;
settingAprilFoolsMode.checked = json.aprilFoolsMode; settingAprilFoolsMode.checked = json.aprilFoolsMode;
settingDownloadLocation.value = json.downloadLocation; settingDownloadLocation.placeholder = json.downloadLocation;
//console.log(json.styleSheet); //console.log(json.styleSheet);
}); });
GetRateLimits().then((json) => { GetRateLimits().then((json) => {
@ -795,15 +820,15 @@ function OpenSettings(){
switch(libraryConnectorTypes[connector.libraryType]){ switch(libraryConnectorTypes[connector.libraryType]){
case "Kavita": case "Kavita":
settingKavitaConfigured.setAttribute("configuration", "Active"); settingKavitaConfigured.setAttribute("configuration", "Active");
settingKavitaUrl.value = connector.baseUrl; settingKavitaUrl.placeholder = connector.baseUrl;
settingKavitaUser.value = "***"; settingKavitaUser.placeholder = "***";
settingKavitaPass.value = "***"; settingKavitaPass.placeholder = "***";
break; break;
case "Komga": case "Komga":
settingKomgaConfigured.setAttribute("configuration", "Active"); settingKomgaConfigured.setAttribute("configuration", "Active");
settingKomgaUrl.value = connector.baseUrl; settingKomgaUrl.placeholder = connector.baseUrl;
settingKomgaUser.value = "***"; settingKomgaUser.placeholder = "***";
settingKomgaPass.value = "***"; settingKomgaPass.placeholder = "***";
break; break;
default: default:
console.log("Unknown type"); console.log("Unknown type");
@ -816,18 +841,19 @@ function OpenSettings(){
json.forEach(connector => { json.forEach(connector => {
switch(notificationConnectorTypes[connector.notificationConnectorType]){ switch(notificationConnectorTypes[connector.notificationConnectorType]){
case "Gotify": case "Gotify":
settingGotifyUrl.value = connector.endpoint; settingGotifyUrl.placeholder = connector.endpoint;
settingGotifyAppToken.value = "***"; settingGotifyAppToken.placeholder = "***";
settingGotifyConfigured.setAttribute("configuration", "Active"); settingGotifyConfigured.setAttribute("configuration", "Active");
break; break;
case "LunaSea": case "LunaSea":
settingLunaseaConfigured.setAttribute("configuration", "Active"); settingLunaseaConfigured.setAttribute("configuration", "Active");
settingLunaseaWebhook.value = connector.id; settingLunaseaWebhook.placeholder = connector.id;
break; break;
case "Ntfy": case "Ntfy":
settingNtfyConfigured.setAttribute("configuration", "Active"); settingNtfyConfigured.setAttribute("configuration", "Active");
settingNtfyEndpoint.value = connector.endpoint; settingNtfyEndpoint.placeholder = connector.endpoint;
settingNtfyAuth.value = "***"; settingNtfyUser.placeholder = "***"
settingNtfyPass.placeholder = "***";
break; break;
default: default:
console.log("Unknown type"); console.log("Unknown type");
@ -870,7 +896,8 @@ function ClearLunasea(){
function ClearNtfy(){ function ClearNtfy(){
settingNtfyEndpoint.value = ""; settingNtfyEndpoint.value = "";
settingNtfyAuth.value = ""; settingNtfyUser.value = "";
settingNtfyPass.value = "";
settingNtfyConfigured.setAttribute("configuration", "Not Configured"); settingNtfyConfigured.setAttribute("configuration", "Not Configured");
ResetNtfy(); ResetNtfy();
} }
@ -904,8 +931,8 @@ function UpdateSettings(){
} }
if(settingNtfyEndpoint.value != "" && if(settingNtfyEndpoint.value != "" &&
settingNtfyAuth.value != ""){ settingNtfyUser.value != ""){
UpdateNtfy(settingNtfyEndpoint.value, settingNtfyAuth.value); UpdateNtfy(settingNtfyEndpoint.value, settingNtfyUser.value, settingNtfyPass.value);
} }
if(settingUserAgent.value != ""){ if(settingUserAgent.value != ""){
@ -1029,16 +1056,14 @@ function createJob(jobjson){
title.innerText = manga.sortName; title.innerText = manga.sortName;
details.appendChild(title); details.appendChild(title);
var progressBar = document.createElement("progress"); var progressBarContainer = document.createElement('div');
progressBar.className = "jobProgressBar"; progressBarContainer.className = 'progress-container';
progressBar.id = `jobProgressBar${GetValidSelector(jobjson.id)}`;
details.appendChild(progressBar);
var progressSpan = document.createElement("span"); var progressBar = document.createElement("div");
progressSpan.className = "jobProgressSpan"; progressBar.className = "pending";
progressSpan.id = `jobProgressSpan${GetValidSelector(jobjson.id)}`; progressBar.id = `jobProgressBar${GetValidSelector(jobjson.id)}`;
progressSpan.innerText = "Pending..."; progressBarContainer.appendChild(progressBar);
details.appendChild(progressSpan); details.appendChild(progressBarContainer);
var cancelSpan = document.createElement("span"); var cancelSpan = document.createElement("span");
cancelSpan.className = "jobCancel"; cancelSpan.className = "jobCancel";
@ -1058,18 +1083,12 @@ function ShowJobQueue(){
function UpdateJobProgress(jobId){ function UpdateJobProgress(jobId){
GetProgress(jobId).then((json) => { GetProgress(jobId).then((json) => {
var progressBar = document.querySelector(`#jobProgressBar${GetValidSelector(jobId)}`); var progressBar = document.querySelector(`#jobProgressBar${GetValidSelector(jobId)}`);
var progressSpan = document.querySelector(`#jobProgressSpan${GetValidSelector(jobId)}`);
if(progressBar != null && json.progress != 0){ if(progressBar != null && json.progress != 0){
progressBar.value = json.progress; progressBar.className = 'jobProgressBar';
} percentageStr = Intl.NumberFormat("en-US", { style: "percent"}).format(json.progress);
if(progressSpan != null){ console.log(percentageStr);
var percentageStr = "0%"; progressBar.style.width = percentageStr;
var timeleftStr = "00:00:00"; progressBar.innerText = percentageStr;
if(json.progress != 0){
percentageStr = Intl.NumberFormat("en-US", { style: "percent"}).format(json.progress);
timeleftStr = json.timeRemaining.split('.')[0];
}
progressSpan.innerText = `${percentageStr} ${timeleftStr}`;
} }
}); });
} }
@ -1079,7 +1098,7 @@ function GetValidSelector(str){
return clean.join(''); return clean.join('');
} }
const stringToColour = (str) => { function stringToColour(str) {
let hash = 0; let hash = 0;
str.split('').forEach(char => { str.split('').forEach(char => {
hash = char.charCodeAt(0) + ((hash << 5) - hash) hash = char.charCodeAt(0) + ((hash << 5) - hash)

View File

@ -1,4 +1,4 @@
:root{ :root{
--background-color: #030304; --background-color: #030304;
--second-background-color: white; --second-background-color: white;
--primary-color: #f5a9b8; --primary-color: #f5a9b8;
@ -20,6 +20,7 @@ body{
background-color: var(--background-color); background-color: var(--background-color);
font-family: "Inter", sans-serif; font-family: "Inter", sans-serif;
overflow-x: hidden; overflow-x: hidden;
font-weight: 400;
} }
wrapper { wrapper {
@ -420,11 +421,14 @@ popup popup-window {
overflow: hidden; overflow: hidden;
} }
popup#jobStatusView popup-window { /*Remove below when individual chapter download is implemented*/
left: 10%; #publicationViewerPopup > popup-window {
top: 10%; height: fit-content;
height: 80%; width: auto;
width: 80%; max-width: 80%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
} }
popup-content{ popup-content{
@ -642,9 +646,9 @@ a:active {
user-select: none; /* Standard syntax */ user-select: none; /* Standard syntax */
} }
.section-button#reset:hover { #reset:hover {
color: red; color: rgb(255, 44, 29);
border-color: red; border-color: rgb(255, 44, 29);
} }
.section-buttons-container > .section-button:hover { .section-buttons-container > .section-button:hover {
border-color: var(--secondary-color); border-color: var(--secondary-color);
@ -711,111 +715,6 @@ blur-background {
z-index: 5; z-index: 5;
} }
publication-viewer{
display: block;
width: 460px;
position: absolute;
top: 200px;
left: 400px;
background-color: var(--accent-color);
border-radius: 5px;
overflow: hidden;
padding: 15px;
}
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;
height: 100%;
width: 100%;
object-fit: cover;
border-radius: 5px;
z-index: 0;
}
publication-viewer publication-details > * {
margin: 5px 0;
}
publication-viewer publication-details publication-name {
width: initial;
overflow-x: scroll;
white-space: nowrap;
scrollbar-width: none;
}
publication-viewer publication-details publication-tags::before {
content: "Tags";
display: block;
font-weight: bolder;
}
publication-viewer publication-details publication-tags {
overflow-x: scroll;
white-space: nowrap;
scrollbar-width: none;
}
publication-viewer publication-details publication-author::before {
content: "Author: ";
font-weight: bolder;
}
publication-viewer publication-details publication-description::before {
content: "Description";
display: block;
font-weight: bolder;
}
publication-viewer publication-details publication-description {
font-size: 12pt;
margin: 5px 0;
height: 145px;
overflow-x: scroll;
}
publication-viewer publication-details publication-interactions {
display: flex;
flex-direction: row;
justify-content: end;
align-items: start;
width: 100%;
}
publication-viewer publication-details publication-interactions > * {
margin: 0 10px;
font-size: 16pt;
cursor: pointer;
}
publication-viewer publication-details publication-interactions publication-starttask {
color: var(--secondary-color);
}
publication-viewer publication-details publication-interactions publication-delete {
color: red;
}
publication-view publication-details publication-interactions publication-canceltask {
color: yellow;
}
publication-viewer publication-details publication-interactions publication-add {
color: limegreen;
}
footer-tag-popup { footer-tag-popup {
display: none; display: none;
padding: 2px 4px; padding: 2px 4px;
@ -913,22 +812,21 @@ popup-content #loaderdiv {
#newMangaResult > .section-item { #newMangaResult > .section-item {
flex-direction: row; flex-direction: row;
min-height: 300px;
flex-grow: 0;
width: auto; width: auto;
height: auto;
padding: 0; padding: 0;
overflow-x: hidden;
overflow-y: auto;
} }
img-container { img-container {
height: 100%; height: 300px;
width: 200px; width: 180px;
position: relative; position: relative;
left: 0; left: 0;
top: 0; top: 0;
border-radius: 10px; border-radius: 10px;
overflow: hidden; overflow: hidden;
flex-shrink: 0;
flex-grow: 0;
} }
img-container > img { img-container > img {
@ -957,6 +855,43 @@ manga-connector {
text-align: center; text-align: center;
} }
manga-details {
display: flex;
flex-direction: row;
width: 100%;
margin: 2px;
}
manga-details > .mangaDescription {
width: 100%;
}
manga-chapter {
display: flex;
height: 100%;
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
border-style: solid;
border-width: 2px;
margin: 5px;
border-radius: 10px;
border-color: #bbb;
scrollbar-width: thin;
scrollbar-color: var(--secondary-color) var(--second-background-color);
}
chapter-row {
font-size: 12pt;
width: 100%;
border-style: solid;
border-color: #ccc;
border-width: 1px;
padding-left: 50px;
padding-top: 7px;
padding-bottom: 7px;
}
span.latest-chapter-no { span.latest-chapter-no {
position: absolute; position: absolute;
right: 5px; right: 5px;
@ -971,28 +906,26 @@ span.latest-chapter-no {
} }
div.new-manga-download-settings { div.new-manga-download-settings {
position: absolute; position: relative;
overflow: hidden; overflow: hidden;
bottom: 0; width: calc(100%-20px);
right: 0;
width: 100%;
height: auto; height: auto;
padding: 10px; padding: 10px;
} }
.new-manga-download-settings > row { .new-manga-download-settings > row {
width: 50%; width: 80%;
display: flex; display: flex;
flex-direction: row; flex-direction: column;
align-items: center; margin-top: 20px;
margin-left: 5px; margin-left: 5px;
margin-bottom: 5px;
} }
.new-manga-download-settings > row > label { .new-manga-download-settings > row > label {
margin-left: 15px;
text-wrap: nowrap; text-wrap: nowrap;
font-size: 11pt; font-size: 10pt;
font-weight: bold;
color: #474646;
} }
.new-manga-download-settings > row > input { .new-manga-download-settings > row > input {
@ -1004,14 +937,42 @@ div.new-manga-download-settings {
border-style: solid; border-style: solid;
border-color: lightgray; border-color: lightgray;
outline: none; outline: none;
text-align: end;
float: right; float: right;
width: 300px; width: 100%;
} }
.new-manga-download-settings > row > input:focus { .new-manga-download-settings > row > input:focus {
border-color: var(--secondary-color); border-color: var(--secondary-color);
} }
@media only screen and (max-width: 768px) {
/* For mobile phones: */
img-container {
display: none;
}
.section-item > tag-cloud {
display: none !important;
}
.new-manga-download-settings > row, .downloadManga, border-bar-button.in-library {
width: calc(100% - 25px) !important;
align-self: center;
position: relative;
}
popup popup-window {
width: 100%;
height: calc(100% - var(--topbar-height));
top: var(--topbar-height);
left: 0;
border-radius: 0;
}
.section-item {
width: 100% !important;
}
}
.section-item > .jobImage { .section-item > .jobImage {
height: 100%; height: 100%;
width: auto; width: auto;
@ -1130,17 +1091,26 @@ author-tag > img {
.mangaDescription { .mangaDescription {
font-size: 10pt; font-size: 10pt;
max-height: 120px;
overflow-y: auto;
padding: 4px; padding: 4px;
height: auto; height: auto;
margin: 2px; margin: 2px;
} }
.abbreviated {
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 10;
line-clamp: 10;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
word-wrap: break-word;
}
.downloadManga { .downloadManga {
position: absolute; position: relative;
right: 10px; float: right;
bottom: 10px; width: fit-content;
margin: 5px 5px 0 auto;
border-radius: 5px; border-radius: 5px;
padding: 5px 10px; padding: 5px 10px;
@ -1148,9 +1118,10 @@ author-tag > img {
} }
border-bar-button.in-library { border-bar-button.in-library {
position: absolute; position: relative;
right: 10px; float: right;
bottom: 10px; margin: 5px 5px 0 auto;
width: fit-content;
border-radius: 5px; border-radius: 5px;
padding: 5px 10px; padding: 5px 10px;
@ -1159,6 +1130,7 @@ border-bar-button.in-library {
background-color: #08962e; background-color: #08962e;
color: #fff; color: #fff;
border: none; border: none;
cursor: default;
} }
border-bar-button.in-library:hover { border-bar-button.in-library:hover {
@ -1166,16 +1138,48 @@ border-bar-button.in-library:hover {
color: #fff; color: #fff;
} }
.section-item > .jobDetails > .jobProgressBar { .section-item > .jobDetails > .progress-container {
margin: 5px; margin: 5px;
height: 10px; height: 15px;
border-radius: 7px; border-radius: 12px;
overflow: hidden;
background-color: #999999;
position: relative;
} }
.section-item > .jobDetails > .jobProgressSpan { .progress-container > .jobProgressBar {
margin: 5px; margin: 0px;
margin-left: auto; display: block;
margin-right: 5px; height: 15px;
padding-left: 5px;
border-radius: 12px;
position: absolute;
left: 0;
top: 0;
background-color: #0075fa;
color: white;
justify-content: left;
font-size: 8pt;
line-height: 15px;
}
.progress-container > .pending {
width: 50%;
display: block;
height: 15px;
top: 0%;
position: absolute;
border-radius: 12px;
background-color: #0075fa;
animation: bounce;
animation-duration: 2s;
animation-iteration-count: infinite;
}
@keyframes bounce {
0% {width: 10%; transform: translateX(0);};
50% {width: 50%; transform: translateX(100%);};
100% {width: 10%; transform: translateX(0);};
} }
.section-item > .jobDetails > .jobCancel { .section-item > .jobDetails > .jobCancel {