initial sveltekit port

This commit is contained in:
Daniel Bulant 2022-12-07 22:57:58 +01:00
parent be20130716
commit dd99b774ef
62 changed files with 304 additions and 12418 deletions

12
.editorconfig Normal file
View file

@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false

8
.gitignore vendored
View file

@ -7,4 +7,10 @@ pnpm-lock.yaml
/.routify/
.env
dist
dist
.svelte-kit
/package
/build
.env
.env.*
!.env.example

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
17

4
.prettierrc Normal file
View file

@ -0,0 +1,4 @@
{
"tabWidth": 4,
"useTabs": false
}

4
_headers Normal file
View file

@ -0,0 +1,4 @@
/*
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
cache-control: public, max-age=3600, must-revalidate

12138
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,67 +1,37 @@
{
"name": "svelte-app",
"version": "1.0.0",
"@comments scripts": {
"dev": "develop with blazing fast rebuilds",
"dev:features": "develop with features like SSR and serviceworker enabled",
"build": "run build scripts below",
"build:app": "build single page application (SPA)",
"build:static": "Generate static pages",
"serve": "serve content in 'dist' folder",
"rollup": "run the rollup bundler",
"nollup": "run the nollup no-bundler",
"routify": "run routify"
},
"name": "mangades",
"version": "1.1.0",
"type": "module",
"scripts": {
"dev": "run-p routify nollup",
"dev:ssr": "run-p routify rollup",
"build": "run-s build:*",
"build:app": "routify -b && rollup -c",
"build:static": "spank",
"serve": "spassr --ssr",
"rollup": "rollup -cw",
"nollup": "nollup -c --verbose --host 0.0.0.0",
"routify": "routify"
"dev": "vite dev",
"build": "vite build",
"package": "svelte-kit package",
"preview": "svelte-kit preview"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^19.0.2",
"@rollup/plugin-node-resolve": "13.0.0",
"@roxi/routify": "^2.18.8",
"@sveltejs/adapter-auto": "1.0.0-next.90",
"@sveltejs/kit": "1.0.0-next.572",
"@types/streamsaver": "^2.0.1",
"cross-env": "^7.0.3",
"fs-extra": "^10.1.0",
"nollup": "^0.16.5",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.16",
"postcss-import": "^14.1.0",
"rollup": "^2.79.0",
"rollup-plugin-hot": "^0.1.1",
"rollup-plugin-livereload": "^2.0.5",
"rollup-plugin-svelte": "^7.1.0",
"rollup-plugin-svelte-hot": "^1.0.0-8",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-workbox": "^5.2.1",
"spank": "^1.9.0",
"spassr": "^2.6.0",
"svelte": "^3.50.0",
"svelte-check": "^2.10.1",
"svelte-preprocess": "^4.10.7",
"tossr": "^1.4.2"
},
"routify": {
"extensions": "svelte,html,svx,md"
},
"spassr": {},
"spank": {
"blacklist": [
"/example/modal/basic/4"
]
"tossr": "^1.4.2",
"typescript": "^4.9.3",
"vite-plugin-windicss": "^1.8.8"
},
"dependencies": {
"@formkit/auto-animate": "1.0.0-beta.3",
"fflate": "^0.6.10",
"streamsaver": "^2.0.6",
"svelte-local-storage-store": "^0.3.1",
"svelte-markdown": "^0.2.3",
"swiper": "^8.3.2"
"swiper": "^8.3.2",
"vite": "^3.0.9"
}
}

View file

@ -1,91 +0,0 @@
import svelte from 'rollup-plugin-svelte-hot';
import Hmr from 'rollup-plugin-hot';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import { copySync, removeSync } from 'fs-extra';
import { spassr } from 'spassr';
import getConfig from '@roxi/routify/lib/utils/config';
import autoPreprocess from 'svelte-preprocess';
import postcssImport from 'postcss-import';
import { injectManifest } from 'rollup-plugin-workbox';
const { distDir } = getConfig() // use Routify's distDir for SSOT
const assetsDir = 'assets'
const buildDir = `${distDir}/build`
const isNollup = !!process.env.NOLLUP
const production = !process.env.ROLLUP_WATCH;
// clear previous builds
removeSync(distDir)
removeSync(buildDir)
const serve = () => ({
writeBundle: async () => {
const options = {
assetsDir: [assetsDir, distDir],
entrypoint: `${assetsDir}/__app.html`,
script: `${buildDir}/main.js`
}
spassr({ ...options, port: 5000 })
spassr({ ...options, ssr: true, port: 5005, ssrOptions: { inlineDynamicImports: true, dev: true } })
}
})
const copyToDist = () => ({ writeBundle() { copySync(assetsDir, distDir) } })
export default {
preserveEntrySignatures: false,
input: [`src/main.js`],
output: {
sourcemap: true,
format: 'esm',
dir: buildDir,
// for performance, disabling filename hashing in development
chunkFileNames:`[name]${production && '-[hash]' || ''}.js`
},
plugins: [
svelte({
emitCss: false,
hot: isNollup,
preprocess: [
autoPreprocess({
postcss: { plugins: [postcssImport()] }
})
]
}),
// resolve matching modules from current working directory
resolve({
browser: true,
dedupe: importee => !!importee.match(/svelte(\/|$)/)
}),
commonjs(),
production && terser(),
!production && !isNollup && serve(),
!production && !isNollup && livereload(distDir), // refresh entire window when code is updated
!production && isNollup && Hmr({ inMemory: true, public: assetsDir, }), // refresh only updated code
{
// provide node environment on the client
transform: code => ({
code: code.replace(/process\.env\.NODE_ENV/g, `"${process.env.NODE_ENV}"`),
map: { mappings: '' }
})
},
injectManifest({
globDirectory: assetsDir,
globPatterns: ['**/*.{js,css,svg}', '__app.html'],
swSrc: `src/sw.js`,
swDest: `${distDir}/serviceworker.js`,
maximumFileSizeToCacheInBytes: 10000000, // 10 MB,
mode: 'production'
}),
production && copyToDist(),
],
watch: {
clearScreen: false,
buildDelay: 100,
}
}

View file

@ -1,10 +0,0 @@
<script>
import { Router } from "@roxi/routify";
import { routes } from "../.routify/routes";
</script>
<style global>
@import "../assets/global.css";
</style>
<Router {routes} />

15
src/app.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script data-goatcounter="https://mangades.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="%sveltekit.assets%/global.css" />
<link rel="stylesheet" href="%sveltekit.assets%/swiper.min.css" />
%sveltekit.head%
</head>
<body>
<div id="svelte">%sveltekit.body%</div>
</body>
</html>

1
src/global.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="@sveltejs/kit" />

View file

@ -1,6 +1,5 @@
<script>
import { goto } from '@roxi/routify/runtime/helpers';
import autoAnimate from "@formkit/auto-animate";
import { goto } from "$app/navigation";
import request from "../util/request";
export var entries;
@ -33,7 +32,7 @@
isLoading = false;
return
}
$goto("./" + item.id);
goto("./" + item.id);
}
</script>
@ -43,7 +42,7 @@
</dialog>
{/if}
<div class="items" class:items-list={itemsList} use:autoAnimate>
<div class="items" class:items-list={itemsList}>
{#each entries.sort((a, b) => a.priority - b.priority) as entry}
<div class="item" class:r18={entry.media.isAdult} on:click={() => find(entry)}>
<div class="flex">

View file

@ -1,5 +1,5 @@
<script>
import request, { imageproxy } from "../util/request";
import request, { imageproxy } from "$lib/util/request";
export var mangaId;

View file

@ -1,5 +1,4 @@
<script>
import { url } from "@roxi/routify/runtime/helpers";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
@ -24,6 +23,7 @@
dispatch("select", e);
}
}
console.log("ch", chapter);
</script>
<tr class="chapter item" on:mouseenter={mouseenter} on:click={click} class:selected={selected} style="background-image: linear-gradient(to right, rgba(0, 255, 0, 0.247) {progress * 100}%, transparent {progress * 100}%)">
@ -33,7 +33,7 @@
<div class="title">{chapter.attributes.title || " "}</div>
<div class="scanlation">{scanlationGroup || "Unknown group"}</div>
</td>
<td class="action no-wrap"><a href={$url("./" + chapter.id + "/1")} on:click|stopPropagation={() => !disabledDownload && dispatch("view")}>View</a></td>
<td class="action no-wrap"><a href="./{chapter.id}/1" on:click|stopPropagation={() => !disabledDownload && dispatch("view")}>View</a></td>
</tr>
<style lang="postcss">

View file

@ -1,7 +1,6 @@
<script>
import SvelteMarkdown from "svelte-markdown";
import autoAnimate from "@formkit/auto-animate";
import { imageproxy } from "../util/request";
import { imageproxy } from "$lib/util/request";
export var entries;
export var itemsList;
@ -12,7 +11,7 @@
</script>
<div class="items" class:items-list={itemsList} use:autoAnimate>
<div class="items" class:items-list={itemsList}>
{#each entries as entry}
{@const title = entry.attributes.title.en || entry.attributes.title.ja || Object.values(entry.attributes.title)[0]}
<a href="/{entry.id}" class="item" class:r18={!["safe", "suggestive"].includes(entry.attributes.contentRating)} on:click={() => open(entry)}>

View file

@ -1,5 +1,6 @@
export function isLogedIn() {
if(typeof window === "undefined") return;
const token = localStorage.getItem("token");
const expiration = new Date(localStorage.getItem("expiration"));

18
src/lib/util/request.js Normal file
View file

@ -0,0 +1,18 @@
export const proxy = "/cors-anywhere/?url="; //"https://cors-anywhere.danbulant.cloud/";
export const imageproxy = proxy; // "https://cors-anywhere.danbulant.workers.dev/?";
export const base = proxy + encodeURIComponent("https://api.mangadex.org/");
export const baseServer = "https://api.mangadex.org/";
export function getURL(endpoint, query) {
if(typeof window === "undefined") return baseServer + endpoint + ((query ? "?" + query.toString() : ""));
return base + encodeURIComponent(endpoint + ((query ? "?" + query.toString() : "")));
}
function request(endpoint, query, type = "GET", body) {
return fetch(getURL(endpoint, query), {
method: type,
body: body ? JSON.stringify(body) : undefined
}).then(resp => resp.json());
}
export default request;

View file

@ -1,5 +0,0 @@
<script>
import { redirect } from "@roxi/routify/runtime/helpers";
$redirect("./1");
</script>

View file

@ -1,7 +1,3 @@
<script>
import { url } from '@roxi/routify'
</script>
<style lang="postcss">
.huge {
font-size: 12rem;
@ -17,8 +13,9 @@
<div class="e404">
<div class="huge">404</div>
<div class="big">Page not found.
<!-- link to the parent folder of _fallback.svelte -->
<a href={$url('../')}>Go back</a>
<div class="big">
Page not found.
<!-- link to the parent folder of _fallback.svelte -->
<a href="/">Go back</a>
</div>
</div>

View file

@ -1,32 +1,31 @@
<script>
import { logs } from "../util/logs";
import { afterPageLoad } from "@roxi/routify";
import { logs } from "$lib/util/logs";
let skipFirst = true;
let last = window.location.pathname;
$afterPageLoad(page => {
if(skipFirst) return skipFirst = false;
if(window.goatcounter) window.goatcounter.count({
path: window.location.pathname,
title: page.title,
referrer: last
});
else console.warn("Page change; GoatCounter not loaded (yet?)", window.location.pathname);
last = window.location.pathname;
});
// let skipFirst = true;
// let last = window.location.pathname;
// $afterPageLoad(page => {
// if(skipFirst) return skipFirst = false;
// if(window.goatcounter) window.goatcounter.count({
// path: window.location.pathname,
// title: page.title,
// referrer: last
// });
// else console.warn("Page change; GoatCounter not loaded (yet?)", window.location.pathname);
// last = window.location.pathname;
// });
let defaultDarkmode = window && window.matchMedia('(prefers-color-scheme: dark)').matches;
window && window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
let defaultDarkmode = typeof window !== "undefined" && window.matchMedia('(prefers-color-scheme: dark)').matches;
typeof window !== "undefined" && window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
if(defaultDarkmode == darkmode) {
darkmode = event.matches;
defaultDarkmode = event.matches;
}
});
let darkmode = localStorage && localStorage.getItem("darkmode") || defaultDarkmode;
let darkmode = typeof localStorage !== "undefined" && localStorage.getItem("darkmode") || defaultDarkmode;
$: if(localStorage && darkmode !== defaultDarkmode) localStorage.setItem("darkmode", darkmode);
$: if(typeof localStorage !== "undefined" && darkmode !== defaultDarkmode) localStorage.setItem("darkmode", darkmode);
$: if(darkmode) {
$: if(typeof window !== "undefined") if(darkmode) {
document.body.classList.add("dark");
} else {
document.body.classList.remove("dark");

View file

@ -1,16 +1,17 @@
<script>
import { params } from '@roxi/routify';
import request from "../util/request";
import { goto } from '@roxi/routify/runtime/helpers';
import { getUserDetails, getUserManga, isLogedIn } from "../util/anilist";
import AnilistItems from "../components/anilistItems.svelte";
import ListOrGrid from "../components/listOrGrid.svelte";
import ratelimit from '../util/ratelimit';
import MangadexItems from '../components/mangadexItems.svelte';
<script lang="ts">
import request from "$lib/util/request";
import { getUserDetails, getUserManga, isLogedIn } from "$lib/util/anilist";
import AnilistItems from "$lib/components/anilistItems.svelte";
import ListOrGrid from "$lib/components/listOrGrid.svelte";
import ratelimit from '$lib/util/ratelimit';
import MangadexItems from '$lib/components/mangadexItems.svelte';
import { goto } from "$app/navigation";
/** @type {string} */
var name = $params.search;
$: {
import type { load } from "./+page";
export var data: Awaited<ReturnType<typeof load>>;
var name: string = data.url.searchParams.get("search") || "";
$: if(typeof window !== "undefined") {
const url = new URL(window.location.toString());
url.searchParams.set("search", name || "");
history.replaceState(history.state, "", url.toString());
@ -36,8 +37,8 @@
async function search(title, filters, offset=0) {
var query = new URLSearchParams();
if(title) query.set("title", title);
query.set("limit", 100);
query.set("offset", offset);
query.set("limit", "100");
query.set("offset", offset.toString());
query.append("includes[]", "author");
query.append("includes[]", "cover_art");
query.append("includes[]", "artist");
@ -93,7 +94,7 @@
async function randomManga() {
randomMangaLoading = true;
const res = await request("manga/random");
$goto("./" + res.data.id);
goto("./" + res.data.id);
}
function open() {
@ -105,10 +106,10 @@
if(!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(id)) {
return alert("You provided invalid ID or link. Make sure you copy the full URL from mangadex.org title page");
}
$goto("./" + id);
goto("./" + id);
}
const anilistID = window.location.hostname === "manga.danbulant.eu" ? "8374" : "8375";
const anilistID = data.url.hostname === "manga.danbulant.eu" ? "8374" : "8375";
let userDetails = isLogedIn() && getUserDetails();
let userManga = isLogedIn() && getUserManga();

8
src/routes/+page.ts Normal file
View file

@ -0,0 +1,8 @@
export const prerender = true;
/** @type {import('./$types').PageLoad} */
export function load({ url }) {
return {
url
}
}

View file

@ -0,0 +1,17 @@
import { error } from '@sveltejs/kit';
import request from '$lib/util/request';
/** @type {import('./$types').PageLoad} */
export async function load({ params }) {
const blocked = ["227e3f72-863f-46f9-bafe-c43104ca29ee", "b0b721ff-c388-4486-aa0f-c2b0bb321512"];
if (blocked.includes(params.manga)) {
throw error(404, 'blocked because of copyright');
}
const manga = await request("manga/" + params.manga + "?includes[]=author&includes[]=cover_art&includes[]=artist");
console.log(manga);
return {
manga: manga.data.attributes,
mangaRelationships: manga.data.relationships,
id: manga.data.id
}
}

View file

@ -1,27 +1,26 @@
<script>
import { url } from "@roxi/routify/runtime/helpers";
import Chapter from "../../components/chapter.svelte";
import { EpubGenerator } from "../../util/generateEpub";
import { CBZGenerator } from "../../util/generateCbz";
import request, { imageproxy } from "../../util/request";
import { BaseGenerator } from "../../util/baseGenerator";
import { arraysEqual } from "../../util/arrays";
import { makeRequest } from "../../util/anilist";
import Tabs from "../../components/tabs/tabs.svelte";
import Chapter from "$lib/components/chapter.svelte";
import { EpubGenerator } from "$lib/util/generateEpub";
import { CBZGenerator } from "$lib/util/generateCbz";
import request, { imageproxy } from "$lib/util/request";
import { BaseGenerator } from "$lib/util/baseGenerator";
import { arraysEqual } from "$lib/util/arrays";
import { makeRequest } from "$lib/util/anilist";
import Tabs from "$lib/components/tabs/tabs.svelte";
import { slide } from "svelte/transition";
import { Swiper, SwiperSlide } from 'swiper/svelte';
import ArtList from "../../components/artList.svelte";
import ArtList from "$lib/components/artList.svelte";
import SvelteMarkdown from 'svelte-markdown';
import ArtDialog from "../../components/artDialog.svelte";
import ArtDialog from "$lib/components/artDialog.svelte";
export var scoped;
export var data;
var mangaId = scoped.id;
$: mangaId = scoped.id;
var manga = scoped.manga;
$: manga = scoped.manga;
var relationships = scoped.mangaRelationships;
$: relationships = scoped.mangaRelationships;
var mangaId = data.id;
$: mangaId = data.id;
var manga = data.manga;
$: manga = data.manga;
var relationships = data.mangaRelationships;
$: relationships = data.mangaRelationships;
var title = manga.title.en || manga.title.jp || Object.values(manga.title)[0];
$: title = manga.title.en || manga.title.jp || Object.values(manga.title)[0];
@ -261,7 +260,7 @@
if(swiper && tabs.indexOf(selectedTab) !== swiper.realIndex) swiper.slideTo(tabs.indexOf(selectedTab));
}
$: chapters && chapters.then(() => swiper.slideToClosest())
$: typeof window !== "undefined" && chapters && chapters.then(() => swiper.slideToClosest())
let swiper;
function swiperInit(e) {
@ -326,7 +325,7 @@
<div class="flex">
<div class="linklist">
<a href={$url("..")}>Go back to search page</a> <br>
<a href="..">Go back to search page</a> <br>
<a href="https://mangadex.org/title/{mangaId}">Mangadex.org</a>
</div>
<div class="copyright-header" class:copyright-header-active={copyrightOpen} on:click={() => copyrightOpen = !copyrightOpen}>Copyright infringement? (click)</div>
@ -435,7 +434,7 @@
monochrome: "Monochrome version",
adapted_from: "Adapted from",
based_on: "Based on",
shared_universe: "Shared universe"
shared_universe: "Shared universe"
}[relatedManga.related] || relatedManga.related}</a> <br>
{/each}
</div>

View file

@ -0,0 +1,2 @@
export const trailingSlash = 'always';
export const ssr = false;

View file

@ -0,0 +1,21 @@
import request from "$lib/util/request";
/** @type {import('./$types').LayoutServerLoad} */
export async function load({ parent, params }) {
const data = await parent();
const id = params.chapter;
const chapterData = (await request("chapter/" + id)).data;
console.log("cd", chapterData);
const atHome = await request("at-home/server/" + id);
console.log("@h", data);
return {
manga: data.manga,
mangaId: data.id,
id,
chapter: chapterData,
atHome
};
}

View file

@ -0,0 +1,8 @@
import { redirect } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function load() {
// throw redirect(301, "./1");
}
export const trailingSlash = "always";

View file

@ -1,19 +1,34 @@
<script>
import { goto, url } from "@roxi/routify/runtime/helpers";
import { imageproxy, proxy } from "../../../util/request";
<script lang="ts">
import { goto, preloadData } from "$app/navigation";
import { imageproxy, proxy } from "$lib/util/request";
import { onMount } from "svelte";
export var page;
export var scoped;
export var data;
var chapter = scoped.chapter;
$: chapter = scoped.chapter;
var manga = scoped.manga;
$: manga = scoped.manga;
var atHome = scoped.atHome;
$: atHome = scoped.atHome;
var chapter = data.chapter;
$: chapter = data.chapter;
var page = data.page;
$: page = data.page;
var manga = data.manga;
$: manga = data.manga;
var atHome = data.atHome;
$: atHome = data.atHome;
var title = manga.title.en || manga.title.jp || Object.values(manga.title)[0];
$: title = manga.title.en || manga.title.jp || Object.values(manga.title)[0];
// $: if(last !== -1) preloadPage(page + 1);
// onMount(() => preloadPage(page + 1));
// let last = -1;
// function preloadPage(num: number) {
// if(last === num) return;
// if(typeof window === "undefined") return;
// preloadData("./" + num);
// (new Image()).src = `${imageproxy}${atHome.baseUrl}/${quality}/${atHome.chapter.hash}/${atHome.chapter[quality][num - 1]}`;
// last = num;
// }
var quality = "data";
var wasArrowUpUp = true;
@ -62,7 +77,7 @@
function next() {
if(!image.complete) return;
if(page > (atHome.chapter[quality].length - 2)) return;
$goto("./" + (parseInt(page) + 1));
goto("./" + (parseInt(page) + 1));
document.scrollingElement.scrollTo({
top: 0
});
@ -71,7 +86,7 @@
function prev() {
if(!image.complete) return;
if(page < 2) return;
$goto("./" + (page - 1));
goto("./" + (page - 1));
document.scrollingElement.scrollTo({
top: 0
});
@ -152,7 +167,7 @@
};
//for zoom detection
var px_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
var px_ratio = typeof window === "undefined" ? 1 : window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
function isZooming(){
var newPx_ratio = window.devicePixelRatio || window.screen.availWidth / document.documentElement.clientWidth;
@ -169,7 +184,7 @@
/** @type {HTMLImageElement} */
var image;
var ratio = 0;
$: actualHeight = ratio > 1 ? document.body.clientHeight * ratio : document.body.clientHeight - 17;
$: actualHeight = typeof window === "undefined" ? -1 : ratio > 1 ? document.body.clientHeight * ratio : document.body.clientHeight - 17;
/**
* @param {Event} e
@ -193,17 +208,17 @@
</svelte:head>
<div class="top">
<a class="back" href={$url("../..")}>Back to chapter list</a>
<a class="back" href="../.." data-sveltekit-preload-code="viewport">Back to chapter list</a>
</div>
<img draggable={false} bind:this={image} style="height: {actualHeight}px" on:load={loaded} on:touchstart={handleTouchStart} on:touchmove={handleTouchMove} on:mousedown={mouseclick} on:mouseup={preventDefault} src={`${imageproxy}${atHome.baseUrl}/${quality}/${atHome.chapter.hash}/${atHome.chapter[quality][page - 1]}`} alt="Page {page} in chapter {chapter.attributes.chapter} of {manga.title.en}">
<div class="bottom">
{#if page > 1}
<a href={$url("./" + (page - 1))} class="prev">Previous</a>
<a href="./{page - 1}" class="prev">Previous</a>
{/if}
{#if page < atHome.chapter[quality].length - 1}
<a href={$url("./" + (parseInt(page) + 1))} class="next">Next</a>
<a href="./{parseInt(page) + 1}" class="next">Next</a>
{/if}
</div>

View file

@ -0,0 +1,6 @@
export function load({ params }) {
return {
page: params.page
}
}

View file

@ -1,5 +1,5 @@
<script>
import request from "../../../util/request";
import request from "$lib/util/request";
export var scoped;
export var chapter;

View file

@ -1,7 +1,5 @@
<script>
import { url } from "@roxi/routify";
import request from "../../util/request";
import request from "$lib/util/request";
export var manga;
@ -23,7 +21,7 @@
{#if blocked.includes(manga)}
<main>
<a href={$url("..")}>Search</a>
<a href="..">Search</a>
<h1>
Content blocked.
</h1>

View file

@ -1,12 +1,13 @@
<script>
import { goto } from '@roxi/routify'
import { goto } from "$app/navigation";
let data = new URLSearchParams(window.location.hash.substring(1));
console.log(Object.fromEntries([...data.entries()]));
localStorage.setItem("token", data.get("access_token"));
localStorage.setItem("expiration", new Date(Date.now() + Number(data.get("expires_in"))).toISOString());
$goto("/");
goto("/");
</script>
{data}

View file

@ -0,0 +1,2 @@
export const ssr = false;
export const csr = true;

View file

@ -0,0 +1,19 @@
/** @type {import('./$types').RequestHandler} */
export async function GET({ url }) {
console.log("[CORS] " + url.searchParams.get('url'));
const ret = await fetch(url.searchParams.get('url'));
return new Response(await ret.arrayBuffer(), {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, HEAD, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Accept, X-Requested-With',
'Access-Control-Max-Age': '86400',
'Content-Type': ret.headers.get('Content-Type')!,
'Cache-Control': 'public, max-age=172800', // 2 days
'Expires': new Date(Date.now() + 172800000).toUTCString()
},
});
}

View file

@ -1,12 +0,0 @@
export const proxy = "https://cors-anywhere.danbulant.cloud/";
export const imageproxy = "https://cors-anywhere.danbulant.workers.dev/?";
export const base = proxy + "https://api.mangadex.org/";
function request(endpoint, query, type = "GET", body) {
return fetch(base + endpoint + ((query ? "?" + query.toString() : "")), {
method: type,
body: body ? JSON.stringify(body) : undefined
}).then(resp => resp.json());
}
export default request;

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View file

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

15
svelte.config.js Normal file
View file

@ -0,0 +1,15 @@
import adapter from '@sveltejs/adapter-auto';
import preprocess from 'svelte-preprocess';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter({
precompress: true
})
},
preprocess: preprocess()
};
export default config;

11
tsconfig.json Normal file
View file

@ -0,0 +1,11 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
}
},
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"],
"extends": "./.svelte-kit/tsconfig.json"
}

View file

@ -1,17 +0,0 @@
{
"version": 2,
"functions": {
"api/vercel-ssr/index.js": {
"includeFiles": "dist/**"
}
},
"routes": [
{
"handle": "filesystem"
},
{
"src": "/.*",
"dest": "/api/vercel-ssr/index.js"
}
]
}

10
vite.config.js Normal file
View file

@ -0,0 +1,10 @@
import { sveltekit } from '@sveltejs/kit/vite';
import WindiCSS from 'vite-plugin-windicss';
export default {
clearScreen: false,
plugins: [
WindiCSS(),
sveltekit()
]
}