diff --git a/site/img/icons/site.webmanifest b/site/img/icons/site.webmanifest index e1fcc6e..d53c213 100644 --- a/site/img/icons/site.webmanifest +++ b/site/img/icons/site.webmanifest @@ -19,7 +19,8 @@ "type": "image/png" } ], - "theme_color": "#333333", + "theme_color": "#444444", "background_color": "#1d1d1d", - "display": "standalone" + "display": "standalone", + "start_url": "/" } diff --git a/site/index.html b/site/index.html index 520833b..d5cfe78 100644 --- a/site/index.html +++ b/site/index.html @@ -6,6 +6,7 @@ + @@ -50,24 +51,43 @@ + - - + + + @@ -128,7 +148,7 @@

Load your .tachibk, .proto.gz or extracted .json file

-

+

    @@ -142,7 +162,7 @@

    -

    +

      diff --git a/site/scripts/library.js b/site/scripts/library.js index a5fd762..3f4ba3e 100644 --- a/site/scripts/library.js +++ b/site/scripts/library.js @@ -7,9 +7,11 @@ import { loadSettings } from './settings.js'; const url = new URL(window.location); export var activeTabId = null; const httpRegex = RegExp('^https?://'); +var repoData = null; // Function to Initialise the Tab Contents and Library from the JSON found in the data variable. export function initializeLibrary() { + if (!repoData) repoData = getRepoIndex(); const categories = window.data.backupCategories || []; let mangaItems = window.data.backupManga; const editCategoryOptions = document.getElementById('edit-category-options'); @@ -235,7 +237,9 @@ export function initializeLibrary() { showMangaDetails( manga, window.data.backupCategories, - window.data.backupSources.find(source => source.sourceId === manga.source).name + repoData?.find(entry => entry.id == manga.source) + ? repoData?.find(entry => entry.id == manga.source) + : window.data.backupSources.find(source => source.sourceId === manga.source) ); }); mangaItem.addEventListener('mouseenter', event => { @@ -325,11 +329,30 @@ export function showTab(tabId) { //Adds info to Manga Details Modal function showMangaDetails(manga, categories, source) { - consts.modalTitle.forEach(element => (element.textContent = manga.customTitle || manga.title)); + const repoMatch = repoData?.find(entry => entry.id == manga.source); + const newWindowIcon = addMaterialSymbol(null, 'open_in_new'); + newWindowIcon.classList.add('link-icon'); + consts.modalTitle.forEach(element => { + element.textContent = manga.customTitle || manga.title; + element.parentNode.removeAttribute('href'); + if (manga.url.match(httpRegex)) { + element.parentNode.href = manga.url; + element.appendChild(newWindowIcon.cloneNode(true)); + } else if (repoMatch) { + element.parentNode.href = repoMatch.baseUrl + manga.url; + element.appendChild(newWindowIcon.cloneNode(true)); + } + }); consts.modalSource.forEach(element => { element.innerHTML = ''; addMaterialSymbol(element, 'language'); - element.append(source); + if (source.baseUrl) { + const link = document.createElement('a'); + link.setAttribute('href', source.baseUrl); + link.append(`${source.name} (${source.lang.toUpperCase()})`); + link.appendChild(newWindowIcon.cloneNode(true)); + element.append(link); + } else element.append(source.name); }); consts.modalThumb.forEach(element => (element.src = mangaCover(manga))); document.documentElement.style.setProperty( @@ -459,22 +482,26 @@ function showMangaDetails(manga, categories, source) { const chapterBox = document.createElement('div'); chapterBox.className = 'chapter-box'; - const chapterLink = document.createElement(chapter.url.match(httpRegex) ? 'a' : 'div'); - if (chapter.url.match(httpRegex)) { - chapterLink.href = chapter.url; + const chapterName = document.createElement('div'); + if (chapter.url.match(httpRegex) || repoMatch) { + const chapterLink = document.createElement('a'); chapterLink.target = '_blank'; - } - chapterLink.textContent = chapter.name; + if (repoMatch) chapterLink.href = repoMatch.baseUrl + chapter.url; + else chapterLink.href = chapter.url; + chapterLink.textContent = chapter.name; + chapterLink.appendChild(newWindowIcon.cloneNode(true)); + chapterName.appendChild(chapterLink); + } else chapterName.textContent = chapter.name; if (chapter.read) { - chapterLink.classList.add('read'); + chapterName.classList.add('read'); } if (chapter.scanlator) { const chapterScanlator = document.createElement('div'); chapterScanlator.classList.add('scanlator'); chapterScanlator.textContent = chapter.scanlator; - chapterLink.appendChild(chapterScanlator); + chapterName.appendChild(chapterScanlator); } - chapterBox.appendChild(chapterLink); + chapterBox.appendChild(chapterName); if (Array.isArray(manga.history)) { const historyItem = manga.history.find(history => history.url === chapter.url); @@ -704,3 +731,54 @@ document.addEventListener('click', event => { hideEditMenu(); } }); + +// Fetch repo from saved settings +function getRepoFromSettings() { + const repoSetting = window.data.backupPreferences?.find(s => s.key == 'extension_repos'); + if (!repoSetting) return false; + const newList = []; + const encoder = new TextEncoder(); + const decoder = new TextDecoder(); + try { + const byteArray = encoder.encode(atob(repoSetting.value.truevalue)); + byteArray.forEach(byte => { + if (byte == byteArray[0]) newList.push([]); + else newList[newList.length - 1].push(byte); + }); + newList.forEach((item, index) => { + newList[index] = decoder.decode(new Uint8Array(item.slice(1))); + }); + } catch { + console.log('Malformed repo field'); + return false; + } + return newList; +} + +function getRepoIndex() { + const repoUrls = getRepoFromSettings(); + if (!repoUrls) return []; + const usedSources = window.data.backupSources?.map(source => source.sourceId); + const sources = + consts.fork == 'sy' + ? [ + { id: '6901', baseUrl: 'https://e-hentai.org', language: 'all' }, + { id: '6902', baseUrl: 'https://exhentai.org', language: 'all' }, + ] + : []; + repoUrls.forEach(repoUrl => { + // fetch(`../index.min.json`) + fetch(`${repoUrl}/index.min.json`) + .then(response => response.json()) + .then(response => + response.forEach(pkg => { + pkg.sources.forEach(source => { + if (usedSources && usedSources.length && !usedSources.includes(source.id)) return; + sources.push(source); + }); + }) + ) + .catch(e => alert(`Error fetching the repo list. ${e}`)); + }); + return sources; +} diff --git a/site/scripts/loadBackup.js b/site/scripts/loadBackup.js index 5c8b6d4..630672f 100644 --- a/site/scripts/loadBackup.js +++ b/site/scripts/loadBackup.js @@ -1,6 +1,6 @@ import { closeModal, showModal } from './modals.js'; import { initializeLibrary } from './library.js'; -import { saveSetting } from './settings.js'; +import { loadSettings, saveSetting } from './settings.js'; export function handleFileLoad(event, fork = 'mihon') { const file = event.target.files[0]; diff --git a/site/scripts/materialSymbol.js b/site/scripts/materialSymbol.js index 9088cf1..c4eeb46 100644 --- a/site/scripts/materialSymbol.js +++ b/site/scripts/materialSymbol.js @@ -1,8 +1,8 @@ export function addMaterialSymbol(element, symbol) { const symbolSpan = document.createElement('span'); - symbolSpan.className = 'material-symbols-outlined'; + symbolSpan.classList.add('material-symbols-outlined'); symbolSpan.textContent = symbol; if (element instanceof NodeList) element.forEach(e => e.appendChild(symbolSpan.cloneNode(true))); - else element.appendChild(symbolSpan.cloneNode(true)); + else if (element) element.appendChild(symbolSpan.cloneNode(true)); return symbolSpan; } diff --git a/site/styles/manga-details.css b/site/styles/manga-details.css index ebfe653..de0bb5b 100644 --- a/site/styles/manga-details.css +++ b/site/styles/manga-details.css @@ -26,6 +26,12 @@ z-index: 0; } +#manga-modal span.link-icon { + font-size: 0.5em; + margin: 0 0 0 0.25rem; + vertical-align: super; +} + .manga-meta { position: relative; text-align: justify; @@ -64,6 +70,13 @@ text-align: right; } +#manga-title-link, +#manga-source > a, +#manga-chapters a { + color: white; + text-decoration: none; +} + #manga-title { margin-bottom: 8px; text-align: start; diff --git a/site/styles/root.css b/site/styles/root.css index 355f383..cbea9f6 100644 --- a/site/styles/root.css +++ b/site/styles/root.css @@ -10,7 +10,7 @@ --color-scanlator: #888; --color-unread-badge-bg: #b0c6ffdd; --color-unread-badge-text: #002d6edd; - --missing-cover: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDhweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSI0OHB4IiBmaWxsPSIjMzMzIj48cGF0aCBkPSJNMTgwLTEyMHEtMjQgMC00Mi0xOHQtMTgtNDJ2LTI3MmwxMDMgMTAzIDE3Mi0xNzIgMTcwIDE3MCAxNzEtMTcxIDEwNCAxMDR2MjM4cTAgMjQtMTggNDJ0LTQyIDE4SDE4MFptMC03MjBoNjAwcTI0IDAgNDIgMTh0MTggNDJ2Mjc3TDczNi02MDcgNTY1LTQzNiAzOTUtNjA2IDIyMy00MzQgMTIwLTUzN3YtMjQzcTAtMjQgMTgtNDJ0NDItMThaIi8+PC9zdmc+'); + --missing-cover: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNDhweCIgdmlld0JveD0iMCAtOTYwIDk2MCA5NjAiIHdpZHRoPSI0OHB4IiBmaWxsPSIjNDQ0Ij48cGF0aCBkPSJNMTgwLTEyMHEtMjQgMC00Mi0xOHQtMTgtNDJ2LTI3MmwxMDMgMTAzIDE3Mi0xNzIgMTcwIDE3MCAxNzEtMTcxIDEwNCAxMDR2MjM4cTAgMjQtMTggNDJ0LTQyIDE4SDE4MFptMC03MjBoNjAwcTI0IDAgNDIgMTh0MTggNDJ2Mjc3TDczNi02MDcgNTY1LTQzNiAzOTUtNjA2IDIyMy00MzQgMTIwLTUzN3YtMjQzcTAtMjQgMTgtNDJ0NDItMThaIi8+PC9zdmc+'); } /* Dark theme */