mirror of
https://github.com/danbulant/Mangades
synced 2026-06-19 06:11:38 +00:00
basic anilist login
This commit is contained in:
parent
8e253443d1
commit
8010384624
3 changed files with 187 additions and 114 deletions
12
src/pages/callback.svelte
Normal file
12
src/pages/callback.svelte
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<script>
|
||||
import { goto } from '@roxi/routify'
|
||||
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("/");
|
||||
</script>
|
||||
|
||||
{data}
|
||||
|
|
@ -1,73 +1,9 @@
|
|||
<script>
|
||||
import { params } from '@roxi/routify'
|
||||
import request from "../util/request";
|
||||
import ratelimit from "../util/ratelimit";
|
||||
import { goto, url } from '@roxi/routify/runtime/helpers';
|
||||
import MultiSelect from '../components/multiSelect.svelte';
|
||||
import { goto } from '@roxi/routify/runtime/helpers';
|
||||
import { getUserDetails, getUserManga, isLogedIn } from "../util/anilist";
|
||||
|
||||
var name = "";
|
||||
// var name = $params.search;
|
||||
// $: {
|
||||
// const url = new URL(window.location.toString());
|
||||
// url.searchParams.set("search", name || "");
|
||||
// history.replaceState(history.state, "", url.toString());
|
||||
// }
|
||||
/**
|
||||
* Searches for results
|
||||
* @param {string} title
|
||||
* @returns {Promise<object>}
|
||||
*/
|
||||
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);
|
||||
for(const rating of filters.contentRating) {
|
||||
query.append("contentRating[]", rating);
|
||||
}
|
||||
for(const demographic of filters.demographic) {
|
||||
query.append("demographic[]", demographic);
|
||||
}
|
||||
for(const status of filters.status) {
|
||||
query.append("status[]", status);
|
||||
}
|
||||
query.set("order[" + filters.sort + "]", filters.sortValue);
|
||||
const res = await request("manga", query);
|
||||
for(const manga of res.results) {
|
||||
for(const relation of manga.relationships) {
|
||||
if(relation.type === "cover") {
|
||||
console.log(manga, relation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function update(name, filters) {
|
||||
result = ratelimit(search, name, filters);
|
||||
}
|
||||
|
||||
var result;
|
||||
// $: update(name, filters);
|
||||
|
||||
var scrollSearch = null;
|
||||
/**
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
async function scroll(e) {
|
||||
if(scrollSearch !== null) return;
|
||||
if(document.body.scrollHeight - window.scrollY - window.innerHeight < 300 && (await result).results.length < (await result).total) {
|
||||
scrollSearch = name;
|
||||
const res = await search(name, filters, (await result).results.length);
|
||||
if(scrollSearch === name && res.results.length) {
|
||||
(await result).results.push(...res.results);
|
||||
result = result; // trigger reload
|
||||
}
|
||||
setTimeout(() => {
|
||||
scrollSearch = null;
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
var randomMangaLoading = false;
|
||||
async function randomManga() {
|
||||
|
|
@ -76,27 +12,22 @@
|
|||
$goto("./" + res.data.id);
|
||||
}
|
||||
|
||||
const filters = {
|
||||
contentRating: ["safe", "suggestive"],
|
||||
demographic: [],
|
||||
status: [],
|
||||
sort: "updatedAt",
|
||||
sortValue: "desc"
|
||||
};
|
||||
|
||||
function open() {
|
||||
var id = name;
|
||||
if(name.startsWith("https://mangadex.org/title/")) {
|
||||
id = name.substr("https://mangadex.org/title/".length);
|
||||
id = name.substring("https://mangadex.org/title/".length);
|
||||
id = id.split("/")[0];
|
||||
} else 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(name)) {
|
||||
return alert("You provided invalid ID or link. Make sure you copy the full URL from mangadex.org title page");
|
||||
}
|
||||
$goto("./" + id);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:scroll={scroll} />
|
||||
const anilistID = "8375";
|
||||
|
||||
let userDetails = getUserDetails();
|
||||
let userManga = getUserManga();
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Mangadex search & downloader</title>
|
||||
|
|
@ -106,26 +37,49 @@
|
|||
<main>
|
||||
|
||||
<h1>miniMANGADEX</h1>
|
||||
<div class="flex">
|
||||
|
||||
<div class="flex search">
|
||||
<input type="text" placeholder="Enter UUID or URL of mangadex.org manga" bind:value={name}>
|
||||
<button on:click={open}>Go</button>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<button on:click={randomManga} disabled={randomMangaLoading}>Random</button>
|
||||
{#if isLogedIn()}
|
||||
{#await userDetails then userDetails}
|
||||
<a href="https://anilist.co/user/{userDetails.data.User.name}" target="_blank">
|
||||
<img class="avatar" width=100 height=100 src={userDetails.data.User.avatar.medium} alt="Your ({userDetails.data.User.name}) avatar">
|
||||
</a>
|
||||
{/await}
|
||||
{:else}
|
||||
<a class="button" href='https://anilist.co/api/v2/oauth/authorize?client_id={anilistID}&response_type=token'>Login with AniList</a>
|
||||
{/if}
|
||||
<a href="https://mangadex.org">Mangadex.org</a>
|
||||
</div>
|
||||
|
||||
{#if isLogedIn()}
|
||||
{#await userManga then userManga}
|
||||
{#each userManga.data.MediaListCollection.lists as list}
|
||||
<h2>{list.name}</h2>
|
||||
|
||||
<div class="items">
|
||||
{#each list.entries as entry}
|
||||
<div class="item">
|
||||
<img src={entry.media.coverImage.large} width=100 height=142 alt="{entry.media.title}">
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
{/await}
|
||||
{/if}
|
||||
|
||||
<p>Wondering why this downgrade? My main site was taken down 3 times for copyright infringement because of this site, even though I wasn't hosting anything. I removed any link they reported, yet they still removed my site multiple times (I should always have 48 hour window to remove the link, but they removed my site right after sending email to me). Comeso (the company that was sending copyright infringement emails) didn't reply to my attempts to contact them using the email they provided or the website they sent. They also sent few invalid copyright infringement emails, yet my webhosting still took my site down for them.</p>
|
||||
<p>I disabled search engine indexing, so google shouldn't show results of manga directly but just link to this page. Search functionality got removed and instead you need to send the URL itself, which should prevent automatic scanners.</p>
|
||||
<hr>
|
||||
|
||||
<p>This site works by using Mangadex API <i>from your browser</i>, and loading or downloading the manga directly from MD@H, without using my servers (so I don't host any content seen here, nor can I delete it). The whole site is client side only (it runs in your browser). I cannot delete any content (images or text), only hide it from this specific site - but there are tons of other sites, and anybody with decent coding skills can clone this page and remove the rule hiding the content (this page is open source).</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>DISCLAIMER: This site isn't distributing any content and is using mangadex.org API. All of the site's requests are done client side, my servers aren't sharing any manga data. Website is open source, and I don't claim any copyright on the publications.</p>
|
||||
<p>DISCLAIMER: This site isn't distributing any content and is using mangadex.org API. All of the site's requests are done client side, my servers aren't sharing any manga data. Website is open source, and I don't claim any copyright on the publications. <i>If you believe in good faith you're downloading copyrighted content, file a DMCA at yourself, your operating system (as it took a part in the download), your ISP, your browser and all the free libraries that are used in any of the previous (made by volunteers), and then here. /s</i></p>
|
||||
|
||||
<hr>
|
||||
|
||||
|
|
@ -138,15 +92,40 @@
|
|||
<hr>
|
||||
|
||||
<p>
|
||||
Website's source code available on <b><a href="https://github.com/danbulant/mangades">GitHub</a></b> under GPLv3. Hosted using CloudFlare Pages.
|
||||
Website's source code available on <b><a href="https://github.com/danbulant/mangades">GitHub</a></b> under GPLv3. Hosted on Cloudflare Pages, a static site hosting, where none of the images are stored.
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<style lang="postcss">
|
||||
.filters {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
.items {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
||||
}
|
||||
.item img {
|
||||
border-radius: 5px;
|
||||
height: 15rem;
|
||||
width: auto;
|
||||
}
|
||||
.item h4 {
|
||||
margin: 0;
|
||||
}
|
||||
.avatar {
|
||||
border-radius: 999px;
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
}
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
.search button {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.search input {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
|
|
@ -154,19 +133,6 @@
|
|||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
.flex select {
|
||||
margin: 0;
|
||||
}
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.flex select.flex-grow {
|
||||
flex-grow: 1;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
margin-bottom: 5px;
|
||||
|
|
@ -175,22 +141,11 @@
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.value {
|
||||
text-align: right;
|
||||
a:not(.button) {
|
||||
color: rgb(33, 50, 87);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: black;
|
||||
}
|
||||
a:hover {
|
||||
a:hover:not(.button) {
|
||||
color: rgb(0,100,200);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
106
src/util/anilist.js
Normal file
106
src/util/anilist.js
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
export function isLogedIn() {
|
||||
const token = localStorage.getItem("token");
|
||||
const expiration = new Date(localStorage.getItem("expiration"));
|
||||
|
||||
if(!token) return false;
|
||||
if(expiration.getTime() < Date.now()) {
|
||||
localStorage.removeItem("token");
|
||||
localStorage.removeItem("expiration");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getUserID() {
|
||||
const token = localStorage.getItem("token");
|
||||
let data = JSON.parse(atob(token.substring(token.indexOf(".") + 1, token.lastIndexOf("."))));
|
||||
return data.sub;
|
||||
}
|
||||
|
||||
export function makeRequest(query, variables) {
|
||||
let auth = {};
|
||||
if(isLogedIn()) {
|
||||
auth.Authorization = "Bearer " + localStorage.getItem("token");
|
||||
}
|
||||
return fetch("https://graphql.anilist.co", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
...auth
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query,
|
||||
variables
|
||||
})
|
||||
}).then(data => data.json());
|
||||
}
|
||||
|
||||
export function getUserDetails() {
|
||||
const id = getUserID();
|
||||
return makeRequest(`
|
||||
query ($id: Int) {
|
||||
User(id: $id) {
|
||||
name
|
||||
avatar {
|
||||
medium
|
||||
}
|
||||
options {
|
||||
titleLanguage
|
||||
displayAdultContent
|
||||
}
|
||||
statistics {
|
||||
manga {
|
||||
count
|
||||
chaptersRead
|
||||
volumesRead
|
||||
}
|
||||
}
|
||||
}
|
||||
}`, { id });
|
||||
}
|
||||
|
||||
export function getUserManga() {
|
||||
const id = getUserID();
|
||||
return makeRequest(`
|
||||
query($id: Int) {
|
||||
MediaListCollection(userId: $id, type: MANGA) {
|
||||
lists {
|
||||
name
|
||||
isCustomList
|
||||
status
|
||||
isSplitCompletedList
|
||||
entries {
|
||||
status
|
||||
progress
|
||||
progressVolumes
|
||||
repeat
|
||||
priority
|
||||
private
|
||||
notes
|
||||
score(format: POINT_10_DECIMAL)
|
||||
media {
|
||||
id
|
||||
title {
|
||||
romaji
|
||||
english
|
||||
native
|
||||
userPreferred
|
||||
}
|
||||
status
|
||||
chapters
|
||||
volumes
|
||||
coverImage {
|
||||
large
|
||||
medium
|
||||
color
|
||||
}
|
||||
isAdult
|
||||
isFavourite
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`, { id });
|
||||
}
|
||||
Loading…
Reference in a new issue