aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFuwn <[email protected]>2023-10-24 19:11:21 -0700
committerFuwn <[email protected]>2023-10-24 19:11:21 -0700
commit7051fd67e98be0166d4f093f111dfa5dfa28bc0a (patch)
tree61395da21f35395a88950428990f21ca9c12d261 /src
parentfeat: badge wall (diff)
parentchore(git): ignore data folder (diff)
downloaddue.moe-7051fd67e98be0166d4f093f111dfa5dfa28bc0a.tar.xz
due.moe-7051fd67e98be0166d4f093f111dfa5dfa28bc0a.zip
merge: main into badges
Diffstat (limited to 'src')
-rw-r--r--src/lib/AniList/forum.ts58
-rw-r--r--src/lib/AniList/user.ts5
-rw-r--r--src/lib/List/Anime/CleanAnimeList.svelte10
-rw-r--r--src/lib/List/CleanMangaList.svelte2
-rw-r--r--src/lib/List/Template/MangaListTemplate.svelte4
-rw-r--r--src/lib/Media/manga.ts13
-rw-r--r--src/lib/Settings/SettingCheckboxToggle.svelte54
-rw-r--r--src/lib/Tools/EpisodeDiscussionCollector.svelte44
-rw-r--r--src/lib/userBadgesDatabase.ts8
-rw-r--r--src/routes/+layout.svelte10
-rw-r--r--src/routes/@[user]/+page.server.ts5
-rw-r--r--src/routes/@[user]/+page.svelte45
-rw-r--r--src/routes/feeds/activity-notifications/+server.ts6
-rw-r--r--src/routes/settings/+page.svelte99
-rw-r--r--src/routes/tools/+page.svelte23
-rw-r--r--src/routes/user/[user]/+page.svelte44
-rw-r--r--src/routes/user/[user]/badges/+page.svelte207
-rw-r--r--src/stores/settings.ts8
18 files changed, 305 insertions, 340 deletions
diff --git a/src/lib/AniList/forum.ts b/src/lib/AniList/forum.ts
new file mode 100644
index 00000000..6b95fa07
--- /dev/null
+++ b/src/lib/AniList/forum.ts
@@ -0,0 +1,58 @@
+import { user } from './user';
+
+export interface Thread {
+ id: number;
+ title: string;
+ createdAt: number;
+}
+
+export interface ThreadPage {
+ data: {
+ Page: {
+ threads: Thread[];
+ pageInfo: {
+ hasNextPage: boolean;
+ currentPage: number;
+ };
+ };
+ };
+}
+
+const threadPage = async (page: number, userId: number): Promise<ThreadPage> =>
+ await (
+ await fetch('https://graphql.anilist.co', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Accept: 'application/json'
+ },
+ body: JSON.stringify({
+ query: `{ Page(perPage: 50, page: ${page}) {
+ threads(userId: ${userId}) { id title createdAt }
+ pageInfo { hasNextPage }
+} }`
+ })
+ })
+ ).json();
+
+export const threads = async (username: string): Promise<Thread[]> => {
+ const allThreads = [];
+ const userId = (await user(username)).id;
+ let page = 1;
+ let currentPage = await threadPage(page, userId);
+
+ for (const thread of currentPage.data.Page.threads) {
+ allThreads.push(thread);
+ }
+
+ while (currentPage.data.Page.pageInfo.hasNextPage) {
+ page += 1;
+ currentPage = await threadPage(page, userId);
+
+ for (const thread of currentPage.data.Page.threads) {
+ allThreads.push(thread);
+ }
+ }
+
+ return allThreads;
+};
diff --git a/src/lib/AniList/user.ts b/src/lib/AniList/user.ts
index dd9995fd..fdc98a58 100644
--- a/src/lib/AniList/user.ts
+++ b/src/lib/AniList/user.ts
@@ -15,6 +15,9 @@ export interface User {
volumesRead: number;
};
};
+ avatar: {
+ large: string;
+ };
}
export const user = async (username: string): Promise<User> => {
@@ -28,7 +31,7 @@ export const user = async (username: string): Promise<User> => {
},
body: JSON.stringify({
query: `{ User(name: "${username}") {
- name id statistics {
+ name id avatar { large } statistics {
anime {
count meanScore minutesWatched episodesWatched
}
diff --git a/src/lib/List/Anime/CleanAnimeList.svelte b/src/lib/List/Anime/CleanAnimeList.svelte
index ffd34788..30443e83 100644
--- a/src/lib/List/Anime/CleanAnimeList.svelte
+++ b/src/lib/List/Anime/CleanAnimeList.svelte
@@ -37,14 +37,14 @@
{@const progress = (anime.mediaListEntry || { progress: 0 }).progress}
<li>
<a
- href={$settings.linkToAniList
- ? `https://anilist.co/anime/${anime.id}`
- : `https://www.livechart.me/search?q=${
+ href={$settings.linkToLiveChart
+ ? `https://www.livechart.me/search?q=${
anime.title.native || anime.title.english || anime.title.romaji
- }`}
+ }`
+ : `https://anilist.co/anime/${anime.id}`}
target="_blank"
>
- {#if lastUpdatedMedia === anime.id}
+ {#if lastUpdatedMedia === anime.id && anime.episodes !== progress}
<span style="color: lightcoral">
{anime.title.english || anime.title.romaji || anime.title.native}
</span>
diff --git a/src/lib/List/CleanMangaList.svelte b/src/lib/List/CleanMangaList.svelte
index a56a1c81..180c12f2 100644
--- a/src/lib/List/CleanMangaList.svelte
+++ b/src/lib/List/CleanMangaList.svelte
@@ -33,7 +33,7 @@
<li>
<a href={`https://anilist.co/manga/${manga.id}`} target="_blank">
- {#if lastUpdatedMedia === manga.id}
+ {#if lastUpdatedMedia === manga.id && manga.chapters !== progress}
<span style="color: lightcoral">
{manga.title.english || manga.title.romaji || manga.title.native}
</span>
diff --git a/src/lib/List/Template/MangaListTemplate.svelte b/src/lib/List/Template/MangaListTemplate.svelte
index 9823f97f..a0b48bdf 100644
--- a/src/lib/List/Template/MangaListTemplate.svelte
+++ b/src/lib/List/Template/MangaListTemplate.svelte
@@ -69,7 +69,9 @@
($settings.displayNotStarted === true ? 0 : 1)
);
let finalMedia = releasingMedia;
- const chapterPromises = finalMedia.map((m: Media) => chapterCount(identity, m));
+ const chapterPromises = finalMedia.map((m: Media) =>
+ chapterCount(identity, m, $settings.disableGuessing)
+ );
const chapterCounts = await Promise.all(chapterPromises);
finalMedia.forEach((m: Media, i) => {
diff --git a/src/lib/Media/manga.ts b/src/lib/Media/manga.ts
index 9d0e08a6..3c0cf837 100644
--- a/src/lib/Media/manga.ts
+++ b/src/lib/Media/manga.ts
@@ -14,7 +14,8 @@ export const pruneAllManga = async () => {
export const chapterCount = async (
identity: UserIdentity,
manga: Media,
- preferActivity = false
+ disableGuessing: boolean
+ // preferActivity = false
): Promise<number | null> => {
const chapters = await chapterDatabase.chapters.get(manga.id);
@@ -22,11 +23,15 @@ export const chapterCount = async (
return chapters.chapters === -1 ? null : chapters.chapters;
}
- if (preferActivity) {
- return await recentMediaActivities(identity, manga);
- }
+ // if (preferActivity) {
+ // return await recentMediaActivities(identity, manga);
+ // }
const tryRecentMediaActivities = async () => {
+ if (disableGuessing) {
+ return null;
+ }
+
const anilistData = await recentMediaActivities(identity, manga);
await chapterDatabase.chapters.put({
diff --git a/src/lib/Settings/SettingCheckboxToggle.svelte b/src/lib/Settings/SettingCheckboxToggle.svelte
new file mode 100644
index 00000000..ab603278
--- /dev/null
+++ b/src/lib/Settings/SettingCheckboxToggle.svelte
@@ -0,0 +1,54 @@
+<script lang="ts">
+ import settings, { type Settings } from '../../stores/settings';
+
+ type BooleanSettingsKeys<T> = {
+ [K in keyof T]: T[K] extends boolean ? K : never;
+ };
+ type SettingsBooleanKeys = BooleanSettingsKeys<Settings>;
+
+ export let sectionBreak = false;
+ export let disabled = false;
+ export let text: string;
+ export let setting: SettingsBooleanKeys[keyof SettingsBooleanKeys];
+
+ // const toggler = (key: keyof Settings) => [
+ // () =>
+ // settings.update((s) => {
+ // (s[key] as boolean) = true;
+
+ // $settings = s;
+
+ // return s;
+ // }),
+ // () =>
+ // settings.update((s) => {
+ // (s[key] as boolean) = false;
+
+ // $settings = s;
+
+ // return s;
+ // })
+ // ];
+
+ const check = (e: Event & { currentTarget: EventTarget & HTMLInputElement }): void => {
+ settings.setKey(setting, (e.target as HTMLInputElement).checked);
+ };
+</script>
+
+<input type="checkbox" on:change={check} bind:checked={$settings[setting]} />
+
+{#if disabled}
+ <strike>
+ {text}
+ </strike>
+ <slot />
+{:else}
+ {text}
+ <slot />
+{/if}
+
+<br />
+
+{#if sectionBreak}
+ <p />
+{/if}
diff --git a/src/lib/Tools/EpisodeDiscussionCollector.svelte b/src/lib/Tools/EpisodeDiscussionCollector.svelte
new file mode 100644
index 00000000..a9acd8ae
--- /dev/null
+++ b/src/lib/Tools/EpisodeDiscussionCollector.svelte
@@ -0,0 +1,44 @@
+<script lang="ts">
+ import { threads } from '$lib/AniList/forum';
+
+ let searchInput = '';
+ let searchInputFinal = '';
+</script>
+
+<p>
+ <input type="text" placeholder="Username" bind:value={searchInput} />
+ <a href={`#`} on:click={() => (searchInputFinal = searchInput)}>Search</a>
+</p>
+
+{#if searchInputFinal !== ''}
+ {#await threads(searchInputFinal)}
+ Loading ...
+ {:then threads}
+ <ul>
+ {#each threads
+ .filter((thread) => thread.title.includes('[Spoilers]') && thread.title.includes('Episode'))
+ .sort((a, b) => b.createdAt - a.createdAt) as thread}
+ <li>
+ <a href={`https://anilist.co/forum/thread/${thread.id}`} target="_blank">
+ {thread.title.replace('[Spoilers]', '')}
+ </a>
+ </li>
+ {/each}
+ </ul>
+ {:catch}
+ <p>
+ Threads could not be loaded. You might have been <a
+ href="https://en.wikipedia.org/wiki/Rate_limiting"
+ target="_blank">rate limited</a
+ >.
+ </p>
+ <p>
+ Try again in a few minutes. If the problem persists, please contact <a
+ href="https://anilist.co/user/fuwn"
+ target="_blank">@fuwn</a
+ > on AniList.
+ </p>
+ {/await}
+{:else}
+ <p>Enter a username to search for to continue.</p>
+{/if}
diff --git a/src/lib/userBadgesDatabase.ts b/src/lib/userBadgesDatabase.ts
index c129770e..78655cd3 100644
--- a/src/lib/userBadgesDatabase.ts
+++ b/src/lib/userBadgesDatabase.ts
@@ -8,16 +8,16 @@ export interface Badge {
id?: number;
}
-const database = new Database('./due_moe.sqlite3', {
+const database = new Database('./data/due_moe.sqlite3', {
verbose: dev ? console.log : undefined
});
database.exec(`create table if not exists user_badges (
id integer primary key,
user_id integer not null,
- post text not null,
- image text not null,
- description text default null,
+ post text(1000) not null,
+ image text(1000) not null,
+ description text(1000) default null,
time timestamp default current_timestamp
)`);
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 19df3f1c..20ae9ef4 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -52,11 +52,17 @@
<p id="desktop-navigation-bar">
「 <a href="/">Home</a> • <a href="/completed">Completed</a> •
<a href="/updates">Manga & LN Updates</a> •
- <a href="/tools">Tools</a> • <a href="/settings">Settings</a> 」
+ <a href="/tools">Tools</a> • {#if data.user}
+ <a href={`/user/${currentUserIdentity.name}`}>Profile</a> •
+ {/if} <a href="/settings">Settings</a> 」
</p>
<div id="mobile-navigation-bar">
- <a href="/">Home</a> • <a href="/completed">Completed</a> • <a href="/tools">Tools</a><br />
+ <a href="/">Home</a> • <a href="/completed">Completed</a> • <a href="/tools">Tools</a>
+ {#if data.user}
+ • <a href={`/user/${currentUserIdentity.name}`}>Profile</a>
+ {/if}
+ <br />
<a href="/settings">Settings</a>
<a href="/updates">Manga & LN Updates</a>
diff --git a/src/routes/@[user]/+page.server.ts b/src/routes/@[user]/+page.server.ts
deleted file mode 100644
index 76d2d889..00000000
--- a/src/routes/@[user]/+page.server.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const load = ({ params }) => {
- return {
- username: params.user
- };
-};
diff --git a/src/routes/@[user]/+page.svelte b/src/routes/@[user]/+page.svelte
deleted file mode 100644
index 1763193a..00000000
--- a/src/routes/@[user]/+page.svelte
+++ /dev/null
@@ -1,45 +0,0 @@
-<script lang="ts">
- import { user, type User } from '$lib/AniList/user';
- import { onMount } from 'svelte';
-
- export let data;
-
- let userData: User | undefined = undefined;
-
- onMount(() => {
- user(data.username).then((profile) => {
- userData = profile;
- });
- });
-
- // 8.5827814569536423841e0
-</script>
-
-{#if userData === null}
- Could not load user profile for <a
- href={`https://anilist.co/user/${data.username}`}
- target="_blank">@{data.username}</a
- >.
-
- <p />
-
- Does this user exist?
-{:else if userData === undefined}
- Loading ...
-{:else}
- <a href={`https://anilist.co/user/${userData.name}`} target="_blank" title={String(userData.id)}
- >@{userData.name}</a
- >
-
- <p />
-
- This user has watched {(userData.statistics.anime.minutesWatched / 60 / 24).toFixed(1)} days of anime
- and read
- {((userData.statistics.manga.chaptersRead * 8.58) / 60 / 24).toFixed(1)} days of manga.
-{/if}
-
-<p />
-
-<hr />
-
-This page is under construction!
diff --git a/src/routes/feeds/activity-notifications/+server.ts b/src/routes/feeds/activity-notifications/+server.ts
index 06c55ace..dd4ee0b4 100644
--- a/src/routes/feeds/activity-notifications/+server.ts
+++ b/src/routes/feeds/activity-notifications/+server.ts
@@ -1,5 +1,9 @@
import { notifications, type Notification } from '$lib/AniList/notifications';
+const htmlEncode = (input: string) => {
+ return input.replace(/[\u00A0-\u9999<>&]/g, (i) => '&#' + i.charCodeAt(0) + ';');
+};
+
const render = (posts: Notification[] = []) => `<?xml version="1.0" encoding="UTF-8" ?>
<rss
version="2.0"
@@ -41,7 +45,7 @@ const render = (posts: Notification[] = []) => `<?xml version="1.0" encoding="UT
return `<item>
<guid isPermaLink="false">${notification.id}</guid>
-<title>${title}</title>
+<title>${htmlEncode(title)}</title>
<link>${link}</link>
<author>${notification.user.name}</author>
<media:thumbnail url="${notification.user.avatar.large}" />
diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte
index b0885436..b8d368cc 100644
--- a/src/routes/settings/+page.svelte
+++ b/src/routes/settings/+page.svelte
@@ -5,7 +5,7 @@
import manga from '../../stores/manga';
import anime from '../../stores/anime';
import settings from '../../stores/settings';
- import SettingToggle from '$lib/Settings/SettingToggle.svelte';
+ import SettingCheckboxToggle from '$lib/Settings/SettingCheckboxToggle.svelte';
import SettingHint from '$lib/Settings/SettingHint.svelte';
import { pruneAllManga } from '$lib/Media/manga';
@@ -44,55 +44,32 @@
<details open>
<summary>Display</summary>
- <SettingToggle setting={'forceLightTheme'} on={'Use preferred'} off={'Force light'}>
- theme
- </SettingToggle>
- <SettingToggle
- setting={'linkToAniList'}
- on={'Link anime to LiveChart.me'}
- off={'Link anime to AniList'}
- />
- <SettingToggle setting={'displayPausedMedia'} on={'Hide'} off={'Show'}>
- paused media
- </SettingToggle>
- <SettingToggle
- setting={'limitListHeight'}
- on={'Display full list area'}
- off={'Limit list area to screen'}
- />
- <SettingToggle setting={'displaySocialButton'} on={'Hide'} off={'Show'} sectionBreak>
- social button
- </SettingToggle>
-
- <p />
-
- <SettingToggle setting={'displayUnresolved'} on={'Hide'} off={'Show'}>unresolved</SettingToggle>
- <SettingHint>Displays unresolved chapter counts as "?"</SettingHint>
-
- <p />
-
- <SettingToggle setting={'displayNotStarted'} on={'Hide'} off={'Show'}>
- media with zero progress
- </SettingToggle>
- <SettingHint>
- May cause <a href="https://en.wikipedia.org/wiki/Rate_limiting" target="_blank">
- rate-limiting
- </a> depending on how much releasing manga are on your lists
- </SettingHint>
-
- <p />
-
- <SettingToggle setting={'closeAnimeByDefault'} on={'Expand'} off={'Close'}>
- anime panel by default
- </SettingToggle>
- <SettingToggle setting={'closeMangaByDefault'} on={'Expand'} off={'Close'}>
- manga panel by default
- </SettingToggle>
- <SettingToggle setting={'sortByDifference'}>
- Sort anime by {@html !$settings.sortByDifference
- ? 'difference between last watched and next episode'
- : 'days left until next episode'}
- </SettingToggle>
+ <SettingCheckboxToggle setting="forceLightTheme" text="Force light theme" />
+ <SettingCheckboxToggle setting="linkToLiveChart" text="Link anime to LiveChart.me" />
+ <SettingCheckboxToggle setting="displayPausedMedia" text="Show paused media" />
+ <SettingCheckboxToggle setting="limitListHeight" text="Limit list area to screen" />
+ <SettingCheckboxToggle setting="displaySocialButton" text="Show social button" />
+ <SettingCheckboxToggle setting="displayUnresolved" text="Display unresolved media" />
+ <SettingCheckboxToggle setting="displayNotStarted" text="Show media with zero progress">
+ <SettingHint lineBreak>
+ May cause <a href="https://en.wikipedia.org/wiki/Rate_limiting" target="_blank">
+ rate-limiting
+ </a> depending on how much releasing manga are on your lists
+ </SettingHint>
+ </SettingCheckboxToggle>
+
+ <br />
+
+ <SettingCheckboxToggle setting="closeAnimeByDefault" text="Close anime panel by default" />
+ <SettingCheckboxToggle setting="closeMangaByDefault" text="Close manga panel by default" />
+ <SettingCheckboxToggle
+ setting="sortByDifference"
+ text="Sort anime by difference between last watched and next episode"
+ >
+ <SettingHint lineBreak>
+ By default, anime will be sorted by the number of days left until the next episode airs.
+ </SettingHint>
+ </SettingCheckboxToggle>
</details>
<p />
@@ -100,12 +77,20 @@
<details open>
<summary>Calculation</summary>
- <SettingToggle setting={'roundDownChapters'} on={'Maintain'} off={'Round down'}>
- chapters
- </SettingToggle>
- <SettingHint>
- 50/50.6 would {@html $settings.roundDownChapters ? '' : '<b>not</b>'} be due
- </SettingHint>
+ <SettingCheckboxToggle setting="roundDownChapters" text="Round down chapters">
+ <SettingHint lineBreak>
+ Round down to the nearest whole number. (e.g., 50/50.6 would <b>not</b> be due)
+ </SettingHint>
+ </SettingCheckboxToggle>
+
+ <br />
+
+ <SettingCheckboxToggle setting="disableGuessing" text="Disable informed chapter estimation">
+ <SettingHint lineBreak>
+ Enabling this setting will disable light novel chapter counts and may cause inaccuracy in
+ unresolved manga chapter counts
+ </SettingHint>
+ </SettingCheckboxToggle>
</details>
<p />
@@ -115,7 +100,7 @@
<a href={'#'} on:click={pruneUnresolved}>Re-cache <b>ALL</b> unresolved manga</a>
- <p />
+ <br />
<a href={'#'} on:click={pruneAllManga}>Re-cache <b>ALL</b> manga</a>
<SettingHint lineBreak>Force a re-cache of all cached manga chapter counts</SettingHint>
diff --git a/src/routes/tools/+page.svelte b/src/routes/tools/+page.svelte
index 3976aeba..5a12fb0f 100644
--- a/src/routes/tools/+page.svelte
+++ b/src/routes/tools/+page.svelte
@@ -3,28 +3,33 @@
import { todaysCharacterBirthdays } from '$lib/AniList/character';
import Wrapped from '$lib/Tools/Wrapped.svelte';
import { browser } from '$app/environment';
+ import EpisodeDiscussionCollector from '$lib/Tools/EpisodeDiscussionCollector.svelte';
export let data;
- let tool = browser ? Number(new URLSearchParams(window.location.search).get('tool')) || 0 : 0;
+ const urlParameters = browser ? new URLSearchParams(window.location.search) : null;
+ let tool = browser && urlParameters?.size !== 0 ? urlParameters?.get('tool') : 'default';
</script>
<p>
<select bind:value={tool}>
- <option value={0}>Tools</option>
- <option value={1}>Today's Character Birthdays</option>
- <option value={2}>Activity History Hole Risks</option>
- <option value={3}>Wrapped (Beta)</option>
+ <option value="default" selected disabled hidden>Tool</option>
+ <option value="todays_character_birthdays">Today's Character Birthdays</option>
+ <option value="activity_history_hole_risks">Activity History Hole Risks</option>
+ <option value="wrapped">Wrapped (Beta)</option>
+ <option value="episode_discussion_collector">Episode Discussion Collector (Beta)</option>
</select>
</p>
-{#if tool === 0}
+{#if tool === 'default'}
Select a tool to continue.
-{:else if tool === 2}
+{:else if tool === 'activity_history_hole_risks'}
<ActivityHistory user={data.user} />
-{:else if tool === 3}
+{:else if tool === 'wrapped'}
<div id="wrapped"><Wrapped user={data.user} /></div>
-{:else if tool === 1}
+{:else if tool === 'episode_discussion_collector'}
+ <EpisodeDiscussionCollector />
+{:else if tool === 'todays_character_birthdays'}
<ul>
{#await todaysCharacterBirthdays()}
<li>Loading ...</li>
diff --git a/src/routes/user/[user]/+page.svelte b/src/routes/user/[user]/+page.svelte
index 227ba252..858e6aec 100644
--- a/src/routes/user/[user]/+page.svelte
+++ b/src/routes/user/[user]/+page.svelte
@@ -27,14 +27,38 @@
{:else if userData === undefined}
Loading ...
{:else}
- <p>
- <a href={`https://anilist.co/user/${userData.name}`} target="_blank" title={String(userData.id)}
- >@{userData.name}</a
- >
- • <a href={`/user/${userData.name}/badges`}>Badge Wall</a>
- </p>
-
- This user has watched {(userData.statistics.anime.minutesWatched / 60 / 24).toFixed(1)} days of anime
- and read
- {((userData.statistics.manga.chaptersRead * 8.58) / 60 / 24).toFixed(1)} days of manga.
+ <div class="user-grid">
+ <p>
+ <a
+ href={`https://anilist.co/user/${userData.name}`}
+ target="_blank"
+ title={String(userData.id)}
+ >
+ <img src={userData.avatar.large} alt="" width="100vw" />
+ </a>
+ </p>
+
+ <div>
+ <p>
+ <a
+ href={`https://anilist.co/user/${userData.name}`}
+ target="_blank"
+ title={String(userData.id)}>@{userData.name}</a
+ >
+ • <a href={`/user/${userData.name}/badges`}>Badge Wall</a>
+ </p>
+
+ This user has watched {(userData.statistics.anime.minutesWatched / 60 / 24).toFixed(1)} days of
+ anime and read
+ {((userData.statistics.manga.chaptersRead * 8.58) / 60 / 24).toFixed(1)} days of manga.
+ </div>
+ </div>
{/if}
+
+<style>
+ .user-grid {
+ display: flex;
+ flex-wrap: wrap;
+ column-gap: 1.5em;
+ }
+</style>
diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte
index 276bf1ca..293a7ba5 100644
--- a/src/routes/user/[user]/badges/+page.svelte
+++ b/src/routes/user/[user]/badges/+page.svelte
@@ -8,195 +8,6 @@
let editMode = false;
let currentUserIdentity: ReturnType<typeof userIdentity>;
- // const badges: Badge[] = [
- // {
- // post: 'https://anilist.co/activity/611973592',
- // image: 'https://files.catbox.moe/6tvw17.png'
- // },
- // { post: 'https://anilist.co/activity/611972285', image: 'https://files.catbox.moe/rn5qr5.png' },
- // { post: 'https://anilist.co/activity/611977824', image: 'https://i.imgur.com/DFkT4zB.png' },
- // {
- // post: 'https://anilist.co/activity/612036793',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1144851101414326333/Badge2_26-08-23.png'
- // },
- // {
- // post: 'https://anilist.co/activity/612273794',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1144773312468234351/DOGDAY_5_v2.png'
- // },
- // { post: 'https://anilist.co/activity/613961295', image: 'https://files.catbox.moe/6rebg8.png' },
- // { post: 'https://anilist.co/activity/614793182', image: 'https://imgur.com/QhJbw4l.png' },
- // { post: 'https://anilist.co/activity/615002857', image: 'https://files.catbox.moe/oc8g02.png' },
- // { post: 'https://anilist.co/activity/615426233', image: 'https://files.catbox.moe/4z226e.png' },
- // { post: 'https://anilist.co/activity/615427328', image: 'https://files.catbox.moe/tqcltp.png' },
- // { post: 'https://anilist.co/activity/615920191', image: 'https://files.catbox.moe/frw5p5.png' },
- // { post: 'https://anilist.co/activity/616629257', image: 'https://files.catbox.moe/15st7d.png' },
- // { post: 'https://anilist.co/activity/617442391', image: 'https://i.imgur.com/aHkSRCz.gif' },
- // {
- // post: 'https://anilist.co/activity/617445099',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1148663790452346961/chondyunbday.gif'
- // },
- // {
- // post: 'https://anilist.co/activity/617616590',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1148678438551568444/Badge_3.png'
- // },
- // { post: 'https://anilist.co/activity/617842237', image: 'https://i.imgur.com/Zx4uiAz.gif' },
- // { post: 'https://anilist.co/activity/618296369', image: 'https://i.imgur.com/V6UsqYI.gif' },
- // { post: 'https://anilist.co/activity/618664650', image: 'https://imgur.com/x98vT7p.png' },
- // { post: 'https://anilist.co/activity/619306471', image: 'https://i.imgur.com/GppbpqE.png' },
- // { post: 'https://anilist.co/activity/619657632', image: 'https://files.catbox.moe/barla6.png' },
- // { post: 'https://anilist.co/activity/619659847', image: 'https://i.imgur.com/e81dgSB.gif' },
- // { post: 'https://anilist.co/activity/619661657', image: 'https://i.imgur.com/S0fSeD4.gif' },
- // { post: 'https://anilist.co/activity/619664832', image: 'https://i.imgur.com/EXNQE3n.gif' },
- // {
- // post: 'https://anilist.co/activity/619764622',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1151314632942817290/persona_5_3.png'
- // },
- // { post: 'https://anilist.co/activity/620025361', image: 'https://i.imgur.com/DmEl13g.gif' },
- // { post: 'https://anilist.co/activity/620125206', image: 'https://i.imgur.com/SmzhGyu.gif' },
- // { post: 'https://anilist.co/activity/620125762', image: 'https://i.imgur.com/38I5gUM.gif' },
- // { post: 'https://anilist.co/activity/620126356', image: 'https://i.imgur.com/9I7Xggm.gif' },
- // { post: 'https://anilist.co/activity/620600819', image: 'https://i.imgur.com/nHREaUc.png' },
- // { post: 'https://anilist.co/activity/620989269', image: 'https://imgur.com/XjhyOHU.png' },
- // {
- // post: 'https://anilist.co/activity/621253410',
- // image:
- // 'https://cdn.discordapp.com/attachments/1139717993845239849/1147701375707381760/0028HLA.png'
- // },
- // { post: 'https://anilist.co/activity/621787546', image: 'https://i.imgur.com/tn5yVsk.gif' },
- // {
- // post: 'https://anilist.co/activity/621789551',
- // image: 'https://i.postimg.cc/Z5325GDx/ota-day-otaku-academia-ittle-witch-academia.png'
- // },
- // { post: 'https://anilist.co/activity/622236894', image: 'https://i.imgur.com/vicrIfS.png' },
- // { post: 'https://anilist.co/activity/622237728', image: 'https://i.imgur.com/TLSC65A.jpg' },
- // { post: 'https://anilist.co/activity/623156563', image: 'https://files.catbox.moe/ujf0ym.png' },
- // { post: 'https://anilist.co/activity/623990926', image: 'https://files.catbox.moe/gkalwm.png' },
- // {
- // post: 'https://anilist.co/activity/623995806',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1154888665638649916/monikabday.png'
- // },
- // { post: 'https://anilist.co/activity/624542383', image: 'https://files.catbox.moe/9tzs66.png' },
- // {
- // post: 'https://anilist.co/activity/624542383',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1154540564671377459/EMILIA_BADGE_2.png'
- // },
- // { post: 'https://anilist.co/activity/624543474', image: 'https://imgur.com/WQuXh6g.png' },
- // {
- // post: 'https://anilist.co/activity/624544489',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1154736156093726870/fsdfwefewfwf.png'
- // },
- // {
- // post: 'https://anilist.co/activity/624545233',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1153606849464111134/katoubadge1.png'
- // },
- // { post: 'https://anilist.co/activity/624548754', image: 'https://imgur.com/j5aqX5w.png' },
- // {
- // post: 'https://anilist.co/activity/624549956',
- // image:
- // 'https://cdn.discordapp.com/attachments/1152962059126972417/1154745849465811015/Day_of_Mid_2.png'
- // },
- // { post: 'https://anilist.co/activity/626483669', image: 'https://files.catbox.moe/lz0r48.png' },
- // {
- // post: 'https://anilist.co/activity/626483669',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1156396779332456538/jojobdayb.png'
- // },
- // {
- // post: 'https://anilist.co/activity/626770819',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1156582649779994664/kikurihiroi.png'
- // },
- // { post: 'https://anilist.co/activity/626772329', image: 'https://i.imgur.com/P09v438.gif' },
- // {
- // post: 'https://anilist.co/activity/627283326',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1157124224197083226/coffeeday2.png'
- // },
- // {
- // post: 'https://anilist.co/activity/628202238',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1156472801457340506/rinshima1.png'
- // },
- // {
- // post: 'https://anilist.co/activity/628202913',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1157574135069806592/Badge-1_-_01_10_23.png'
- // },
- // {
- // post: 'https://anilist.co/activity/628305048',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1157650582094479370/SakeDay2.png'
- // },
- // { post: 'https://anilist.co/activity/629168789', image: 'https://files.catbox.moe/0mwudd.png' },
- // { post: 'https://anilist.co/activity/629592629', image: 'https://files.catbox.moe/pyjy0z.png' },
- // { post: 'https://anilist.co/activity/629593251', image: 'https://files.catbox.moe/e9xx50.png' },
- // { post: 'https://anilist.co/activity/630084060', image: 'https://i.imgur.com/zVU0gie.gif' },
- // { post: 'https://anilist.co/activity/630462423', image: 'https://files.catbox.moe/b63wxi.png' },
- // {
- // post: 'https://anilist.co/activity/630464366',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1158527481486266490/codegeass1.png'
- // },
- // { post: 'https://anilist.co/activity/630996180', image: 'https://files.catbox.moe/ap15dx.png' },
- // { post: 'https://anilist.co/activity/631494022', image: 'https://files.catbox.moe/fw4rqx.png' },
- // {
- // post: 'https://anilist.co/activity/631503062',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1158787682231660684/rize1.png'
- // },
- // {
- // post: 'https://anilist.co/activity/632259051',
- // image:
- // 'https://cdn.discordapp.com/attachments/1154438205731524638/1158943217459412992/Luna_Bday2023_Axel5.png'
- // },
- // { post: 'https://anilist.co/activity/632260829', image: 'https://files.catbox.moe/ighico.png' },
- // { post: 'https://anilist.co/activity/632311940', image: 'https://files.catbox.moe/ukv6tv.png' },
- // {
- // post: 'https://anilist.co/activity/632311940',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1160915207711895593/Gintoki_2.png'
- // },
- // {
- // post: 'https://anilist.co/activity/632407688',
- // image:
- // 'https://cdn.discordapp.com/attachments/1136989514653519924/1159856849735127110/Nishinoya_1.png'
- // },
- // { post: 'https://anilist.co/activity/632832412', image: 'https://files.catbox.moe/9lk6s1.png' },
- // { post: 'https://anilist.co/activity/633710355', image: 'https://i.imgur.com/JmpriDr.gif' },
- // { post: 'https://anilist.co/activity/633710743', image: 'https://files.catbox.moe/it9d7q.png' },
- // {
- // post: 'https://anilist.co/activity/633711260',
- // image:
- // 'https://cdn.discordapp.com/attachments/1118627570074800264/1160674827670134804/Sonia1.png'
- // },
- // { post: 'https://anilist.co/activity/634118108', image: 'https://files.catbox.moe/tzudpj.png' },
- // {
- // post: 'https://anilist.co/activity/634119722',
- // image:
- // 'https://cdn.discordapp.com/attachments/1085425937933418578/1162583650840354846/Mystery_Day_badge_4.png'
- // }
- // ];
-
- // onMount(async () => {
- // const id = (await user(data.username)).id;
-
- // for (const badge of badges) {
- // await fetch(`/api/badges-add?id=${id}`, {
- // method: 'POST',
- // body: JSON.stringify(badge)
- // });
- // }
- // });
-
onMount(async () => {
if (data.user) {
currentUserIdentity = userIdentity(data.user);
@@ -258,9 +69,21 @@
</p>
<p>
- <input type="text" placeholder="Image URL" name="image_url" />
- <input type="text" placeholder="Activity URL" name="activity_url" />
- <input type="text" placeholder="Description (Optional)" name="description" />
+ <input type="text" placeholder="Image URL" name="image_url" minlength="1" maxlength="1000" />
+ <input
+ type="text"
+ placeholder="Activity URL"
+ name="activity_url"
+ minlength="1"
+ maxlength="1000"
+ />
+ <input
+ type="text"
+ placeholder="Description (Optional)"
+ name="description"
+ minlength="1"
+ maxlength="1000"
+ />
<a href={`#`} on:click={submitBadge}>Add Badge</a>
</p>
{/if}
diff --git a/src/stores/settings.ts b/src/stores/settings.ts
index 0c9742ee..5ffae4f5 100644
--- a/src/stores/settings.ts
+++ b/src/stores/settings.ts
@@ -11,10 +11,11 @@ export interface Settings {
roundDownChapters: boolean;
sortByDifference: boolean;
forceLightTheme: boolean;
- linkToAniList: boolean;
+ linkToLiveChart: boolean;
displayPausedMedia: boolean;
limitListHeight: boolean;
displaySocialButton: boolean;
+ disableGuessing: boolean;
}
const defaultSettings: Settings = {
@@ -27,10 +28,11 @@ const defaultSettings: Settings = {
roundDownChapters: true,
sortByDifference: false,
forceLightTheme: false,
- linkToAniList: true,
+ linkToLiveChart: true,
displayPausedMedia: true,
limitListHeight: false,
- displaySocialButton: false
+ displaySocialButton: false,
+ disableGuessing: false
};
const createStore = () => {