aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Tools
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-03-01 16:20:51 -0800
committerFuwn <[email protected]>2026-03-01 16:21:02 -0800
commiteae5d24d9e79e59a19d4721caaeaa0ca650ecb33 (patch)
tree1b685bb248e051dfa26d2bfdebe6689402dd93c5 /src/lib/Tools
parentchore(tooling): remove legacy eslint and prettier (diff)
downloaddue.moe-eae5d24d9e79e59a19d4721caaeaa0ca650ecb33.tar.xz
due.moe-eae5d24d9e79e59a19d4721caaeaa0ca650ecb33.zip
chore(biome): drop formatter style overrides
Diffstat (limited to 'src/lib/Tools')
-rw-r--r--src/lib/Tools/ActivityHistory/Grid.svelte30
-rw-r--r--src/lib/Tools/ActivityHistory/Tool.svelte81
-rw-r--r--src/lib/Tools/Birthdays.svelte168
-rw-r--r--src/lib/Tools/BirthdaysTemplate.svelte46
-rw-r--r--src/lib/Tools/DumpProfile.svelte42
-rw-r--r--src/lib/Tools/EpisodeDiscussionCollector.svelte16
-rw-r--r--src/lib/Tools/FollowFix.svelte10
-rw-r--r--src/lib/Tools/Hayai.svelte134
-rw-r--r--src/lib/Tools/InputTemplate.svelte14
-rw-r--r--src/lib/Tools/Likes.svelte33
-rw-r--r--src/lib/Tools/Picker.svelte8
-rw-r--r--src/lib/Tools/RandomFollower.svelte14
-rw-r--r--src/lib/Tools/SequelCatcher/List.svelte34
-rw-r--r--src/lib/Tools/SequelCatcher/Tool.svelte47
-rw-r--r--src/lib/Tools/SequelSpy/Prequels.svelte14
-rw-r--r--src/lib/Tools/SequelSpy/Tool.svelte54
-rw-r--r--src/lib/Tools/Tracker/Tool.svelte75
-rw-r--r--src/lib/Tools/UmaMusumeBirthdays.svelte70
-rw-r--r--src/lib/Tools/Wrapped/ActivityHistory.svelte8
-rw-r--r--src/lib/Tools/Wrapped/DataLoader.svelte2
-rw-r--r--src/lib/Tools/Wrapped/Media.svelte8
-rw-r--r--src/lib/Tools/Wrapped/MediaExtras.svelte4
-rw-r--r--src/lib/Tools/Wrapped/Tool.svelte1251
-rw-r--r--src/lib/Tools/Wrapped/Top/Activity.svelte8
-rw-r--r--src/lib/Tools/Wrapped/Top/Anime.svelte2
-rw-r--r--src/lib/Tools/Wrapped/Top/Manga.svelte4
-rw-r--r--src/lib/Tools/Wrapped/wrapped.css132
-rw-r--r--src/lib/Tools/tools.ts223
28 files changed, 1338 insertions, 1194 deletions
diff --git a/src/lib/Tools/ActivityHistory/Grid.svelte b/src/lib/Tools/ActivityHistory/Grid.svelte
index 84c182fa..6a931ab2 100644
--- a/src/lib/Tools/ActivityHistory/Grid.svelte
+++ b/src/lib/Tools/ActivityHistory/Grid.svelte
@@ -1,16 +1,16 @@
<script lang="ts">
import {
- fillMissingDays,
- type ActivityHistoryEntry,
- activityHistory
-} from '$lib/Data/AniList/activity';
-import { onMount } from 'svelte';
-import userIdentity from '$stores/identity';
-import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
-import { clearAllParameters } from '../../Utility/parameters';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import tooltip from '$lib/Tooltip/tooltip';
-import LogInRestricted from '$lib/Error/LogInRestricted.svelte';
+ fillMissingDays,
+ type ActivityHistoryEntry,
+ activityHistory,
+} from "$lib/Data/AniList/activity";
+import { onMount } from "svelte";
+import userIdentity from "$stores/identity";
+import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
+import { clearAllParameters } from "../../Utility/parameters";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import tooltip from "$lib/Tooltip/tooltip";
+import LogInRestricted from "$lib/Error/LogInRestricted.svelte";
export let user: AniListAuthorisation;
export let activityData: ActivityHistoryEntry[] | null = null;
@@ -20,15 +20,15 @@ let activityHistoryData: ActivityHistoryEntry[];
let baseHue = Math.floor(Math.random() * 360);
onMount(async () => {
- clearAllParameters();
+ clearAllParameters();
- activityHistoryData = activityData || (await activityHistory($userIdentity));
+ activityHistoryData = activityData || (await activityHistory($userIdentity));
});
const gradientColour = (amount: number, maxAmount: number, baseHue: number) => {
- const lightness = 100 - Math.round((amount / maxAmount) * 50);
+ const lightness = 100 - Math.round((amount / maxAmount) * 50);
- return `hsl(${baseHue}, 100%, ${lightness}%)`;
+ return `hsl(${baseHue}, 100%, ${lightness}%)`;
};
</script>
diff --git a/src/lib/Tools/ActivityHistory/Tool.svelte b/src/lib/Tools/ActivityHistory/Tool.svelte
index 06924b22..3cf7b09e 100644
--- a/src/lib/Tools/ActivityHistory/Tool.svelte
+++ b/src/lib/Tools/ActivityHistory/Tool.svelte
@@ -1,19 +1,19 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
+import Spacer from "$lib/Layout/Spacer.svelte";
import {
- activityHistory,
- fillMissingDays,
- type ActivityHistoryEntry
-} from '$lib/Data/AniList/activity';
-import { onMount } from 'svelte';
-import userIdentity from '$stores/identity';
-import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
-import { clearAllParameters } from '../../Utility/parameters';
-import { domToBlob } from 'modern-screenshot';
-import ActivityHistoryGrid from './Grid.svelte';
-import SettingHint from '$lib/Settings/SettingHint.svelte';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import LogInRestricted from '$lib/Error/LogInRestricted.svelte';
+ activityHistory,
+ fillMissingDays,
+ type ActivityHistoryEntry,
+} from "$lib/Data/AniList/activity";
+import { onMount } from "svelte";
+import userIdentity from "$stores/identity";
+import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
+import { clearAllParameters } from "../../Utility/parameters";
+import { domToBlob } from "modern-screenshot";
+import ActivityHistoryGrid from "./Grid.svelte";
+import SettingHint from "$lib/Settings/SettingHint.svelte";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import LogInRestricted from "$lib/Error/LogInRestricted.svelte";
export let user: AniListAuthorisation;
@@ -21,9 +21,9 @@ let activityHistoryData: Promise<ActivityHistoryEntry[]>;
let generated = false;
onMount(async () => {
- clearAllParameters();
+ clearAllParameters();
- if (user !== undefined) activityHistoryData = activityHistory($userIdentity);
+ if (user !== undefined) activityHistoryData = activityHistory($userIdentity);
});
// const incrementDate = (date: Date): Date => {
@@ -33,36 +33,41 @@ onMount(async () => {
// };
const screenshot = async () => {
- let element = document.querySelector('.grid') as HTMLElement;
+ let element = document.querySelector(".grid") as HTMLElement;
- if (element !== null) {
- domToBlob(element, {
- quality: 1,
- scale: 2
- }).then((blob) => {
- const downloadWrapper = document.createElement('a');
- const image = document.createElement('img');
- const object = (window.URL || window.webkitURL || window || {}).createObjectURL(blob);
+ if (element !== null) {
+ domToBlob(element, {
+ quality: 1,
+ scale: 2,
+ }).then((blob) => {
+ const downloadWrapper = document.createElement("a");
+ const image = document.createElement("img");
+ const object = (
+ window.URL ||
+ window.webkitURL ||
+ window ||
+ {}
+ ).createObjectURL(blob);
- downloadWrapper.href = object;
- downloadWrapper.target = '_blank';
- image.src = object;
+ downloadWrapper.href = object;
+ downloadWrapper.target = "_blank";
+ image.src = object;
- downloadWrapper.appendChild(image);
+ downloadWrapper.appendChild(image);
- const gridFinal = document.getElementById('grid-final');
+ const gridFinal = document.getElementById("grid-final");
- if (gridFinal !== null) {
- gridFinal.innerHTML = '';
+ if (gridFinal !== null) {
+ gridFinal.innerHTML = "";
- gridFinal.appendChild(downloadWrapper);
+ gridFinal.appendChild(downloadWrapper);
- generated = true;
- }
+ generated = true;
+ }
- downloadWrapper.click();
- });
- }
+ downloadWrapper.click();
+ });
+ }
};
</script>
diff --git a/src/lib/Tools/Birthdays.svelte b/src/lib/Tools/Birthdays.svelte
index 49d72cfa..a41064f9 100644
--- a/src/lib/Tools/Birthdays.svelte
+++ b/src/lib/Tools/Birthdays.svelte
@@ -1,110 +1,118 @@
<script lang="ts">
-import { browser } from '$app/environment';
-import { page } from '$app/stores';
-import { ACDBBirthdays, type ACDBBirthday } from '$lib/Data/Birthday/secondary';
-import { aniSearchBirthdays, type aniSearchBirthday } from '$lib/Data/Birthday/primary';
-import RateLimitedError from '$lib/Error/RateLimited.svelte';
-import { onMount } from 'svelte';
-import { clearAllParameters, parseOrDefault } from '../Utility/parameters';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import Message from '$lib/Loading/Message.svelte';
-import tooltip from '$lib/Tooltip/tooltip';
+import { browser } from "$app/environment";
+import { page } from "$app/stores";
+import { ACDBBirthdays, type ACDBBirthday } from "$lib/Data/Birthday/secondary";
+import {
+ aniSearchBirthdays,
+ type aniSearchBirthday,
+} from "$lib/Data/Birthday/primary";
+import RateLimitedError from "$lib/Error/RateLimited.svelte";
+import { onMount } from "svelte";
+import { clearAllParameters, parseOrDefault } from "../Utility/parameters";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import Message from "$lib/Loading/Message.svelte";
+import tooltip from "$lib/Tooltip/tooltip";
interface Birthday {
- name: string;
- image: string;
- origin?: string;
+ name: string;
+ image: string;
+ origin?: string;
}
-const urlParameters = browser ? new URLSearchParams(window.location.search) : null;
+const urlParameters = browser
+ ? new URLSearchParams(window.location.search)
+ : null;
let date = new Date();
-let month = parseOrDefault(urlParameters, 'month', date.getMonth() + 1);
-let day = parseOrDefault(urlParameters, 'day', date.getDate());
+let month = parseOrDefault(urlParameters, "month", date.getMonth() + 1);
+let day = parseOrDefault(urlParameters, "day", date.getDate());
let birthdays: Promise<{ birthdays: Birthday[]; allSourcesFailed: boolean }>;
$: {
- month = Math.min(month, 12);
- month = Math.max(month, 1);
- day = Math.min(day, new Date(2024, month, 0).getDate());
- day = Math.max(day, 1);
-
- birthdays = resolveBirthdays(month, day);
-
- if (browser) {
- $page.url.searchParams.set('month', month.toString());
- $page.url.searchParams.set('day', day.toString());
- clearAllParameters(['month', 'day']);
- history.replaceState(null, '', `?${$page.url.searchParams.toString()}`);
- }
+ month = Math.min(month, 12);
+ month = Math.max(month, 1);
+ day = Math.min(day, new Date(2024, month, 0).getDate());
+ day = Math.max(day, 1);
+
+ birthdays = resolveBirthdays(month, day);
+
+ if (browser) {
+ $page.url.searchParams.set("month", month.toString());
+ $page.url.searchParams.set("day", day.toString());
+ clearAllParameters(["month", "day"]);
+ history.replaceState(null, "", `?${$page.url.searchParams.toString()}`);
+ }
}
-onMount(() => clearAllParameters(['month', 'day']));
+onMount(() => clearAllParameters(["month", "day"]));
-const normaliseName = (name: string): string => name.toLowerCase().split(' ').sort().join(' ');
+const normaliseName = (name: string): string =>
+ name.toLowerCase().split(" ").sort().join(" ");
const fixName = (name: string): string => {
- const split = name.split(' ');
- const last = split[split.length - 1];
+ const split = name.split(" ");
+ const last = split[split.length - 1];
- if (last === last.toUpperCase()) {
- split[split.length - 1] = last[0] + last.slice(1).toLowerCase();
+ if (last === last.toUpperCase()) {
+ split[split.length - 1] = last[0] + last.slice(1).toLowerCase();
- return split.join(' ');
- }
+ return split.join(" ");
+ }
- const bracketIndex = name.indexOf('[');
+ const bracketIndex = name.indexOf("[");
- if (bracketIndex !== -1) return name.slice(0, bracketIndex).trim();
+ if (bracketIndex !== -1) return name.slice(0, bracketIndex).trim();
- return name;
+ return name;
};
const combineBirthdaySources = (
- acdb: ACDBBirthday[],
- aniSearch: aniSearchBirthday[]
+ acdb: ACDBBirthday[],
+ aniSearch: aniSearchBirthday[],
): Birthday[] => {
- const nameMap = new Map<string, Birthday>();
-
- for (const entry of aniSearch.map((entry) => ({
- ...entry,
- normalisedName: normaliseName(fixName(entry.name))
- }))) {
- if (!nameMap.has(entry.normalisedName))
- nameMap.set(entry.normalisedName, {
- name: fixName(entry.name),
- image: entry.image
- });
- }
-
- for (const entry of acdb) {
- const normalisedName = normaliseName(fixName(entry.name));
-
- if (!nameMap.has(normalisedName))
- nameMap.set(normalisedName, {
- name: entry.name,
- image: entry.character_image,
- origin: entry.origin
- });
- }
-
- return Array.from(nameMap.values());
+ const nameMap = new Map<string, Birthday>();
+
+ for (const entry of aniSearch.map((entry) => ({
+ ...entry,
+ normalisedName: normaliseName(fixName(entry.name)),
+ }))) {
+ if (!nameMap.has(entry.normalisedName))
+ nameMap.set(entry.normalisedName, {
+ name: fixName(entry.name),
+ image: entry.image,
+ });
+ }
+
+ for (const entry of acdb) {
+ const normalisedName = normaliseName(fixName(entry.name));
+
+ if (!nameMap.has(normalisedName))
+ nameMap.set(normalisedName, {
+ name: entry.name,
+ image: entry.character_image,
+ origin: entry.origin,
+ });
+ }
+
+ return Array.from(nameMap.values());
};
async function resolveBirthdays(
- month: number,
- day: number
+ month: number,
+ day: number,
): Promise<{ birthdays: Birthday[]; allSourcesFailed: boolean }> {
- const [acdbResult, aniSearchResult] = await Promise.allSettled([
- ACDBBirthdays(month, day),
- browser ? aniSearchBirthdays(month, day) : Promise.resolve([])
- ]);
- const acdb = acdbResult.status === 'fulfilled' ? acdbResult.value : [];
- const aniSearch = aniSearchResult.status === 'fulfilled' ? aniSearchResult.value : [];
-
- return {
- birthdays: combineBirthdaySources(acdb, aniSearch),
- allSourcesFailed: acdbResult.status === 'rejected' && aniSearchResult.status === 'rejected'
- };
+ const [acdbResult, aniSearchResult] = await Promise.allSettled([
+ ACDBBirthdays(month, day),
+ browser ? aniSearchBirthdays(month, day) : Promise.resolve([]),
+ ]);
+ const acdb = acdbResult.status === "fulfilled" ? acdbResult.value : [];
+ const aniSearch =
+ aniSearchResult.status === "fulfilled" ? aniSearchResult.value : [];
+
+ return {
+ birthdays: combineBirthdaySources(acdb, aniSearch),
+ allSourcesFailed:
+ acdbResult.status === "rejected" && aniSearchResult.status === "rejected",
+ };
}
</script>
diff --git a/src/lib/Tools/BirthdaysTemplate.svelte b/src/lib/Tools/BirthdaysTemplate.svelte
index 17763908..3dc5c4fd 100644
--- a/src/lib/Tools/BirthdaysTemplate.svelte
+++ b/src/lib/Tools/BirthdaysTemplate.svelte
@@ -1,36 +1,38 @@
<script lang="ts">
-import { browser } from '$app/environment';
-import { page } from '$app/stores';
-import { onMount } from 'svelte';
-import { clearAllParameters, parseOrDefault } from '../Utility/parameters';
-import Message from '$lib/Loading/Message.svelte';
-import locale from '$stores/locale';
-import RateLimitedError from '$lib/Error/RateLimited.svelte';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
+import { browser } from "$app/environment";
+import { page } from "$app/stores";
+import { onMount } from "svelte";
+import { clearAllParameters, parseOrDefault } from "../Utility/parameters";
+import Message from "$lib/Loading/Message.svelte";
+import locale from "$stores/locale";
+import RateLimitedError from "$lib/Error/RateLimited.svelte";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
export let remoteURL: string;
-const urlParameters = browser ? new URLSearchParams(window.location.search) : null;
+const urlParameters = browser
+ ? new URLSearchParams(window.location.search)
+ : null;
let date = new Date();
-let month = parseOrDefault(urlParameters, 'month', date.getMonth() + 1);
-let day = parseOrDefault(urlParameters, 'day', date.getDate());
+let month = parseOrDefault(urlParameters, "month", date.getMonth() + 1);
+let day = parseOrDefault(urlParameters, "day", date.getDate());
const remoteBirthdays = fetch(remoteURL);
$: {
- month = Math.min(month, 12);
- month = Math.max(month, 1);
- day = Math.min(day, new Date(2024, month, 0).getDate());
- day = Math.max(day, 1);
+ month = Math.min(month, 12);
+ month = Math.max(month, 1);
+ day = Math.min(day, new Date(2024, month, 0).getDate());
+ day = Math.max(day, 1);
- if (browser) {
- $page.url.searchParams.set('month', month.toString());
- $page.url.searchParams.set('day', day.toString());
- clearAllParameters(['month', 'day']);
- history.replaceState(null, '', `?${$page.url.searchParams.toString()}`);
- }
+ if (browser) {
+ $page.url.searchParams.set("month", month.toString());
+ $page.url.searchParams.set("day", day.toString());
+ clearAllParameters(["month", "day"]);
+ history.replaceState(null, "", `?${$page.url.searchParams.toString()}`);
+ }
}
-onMount(() => clearAllParameters(['month', 'day']));
+onMount(() => clearAllParameters(["month", "day"]));
</script>
{#await remoteBirthdays}
diff --git a/src/lib/Tools/DumpProfile.svelte b/src/lib/Tools/DumpProfile.svelte
index a111028c..a876f587 100644
--- a/src/lib/Tools/DumpProfile.svelte
+++ b/src/lib/Tools/DumpProfile.svelte
@@ -1,29 +1,29 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import { dumpUser } from '$lib/Data/AniList/user';
-import RateLimited from '$lib/Error/RateLimited.svelte';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import InputTemplate from './InputTemplate.svelte';
-import LZString from 'lz-string';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import { dumpUser } from "$lib/Data/AniList/user";
+import RateLimited from "$lib/Error/RateLimited.svelte";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import InputTemplate from "./InputTemplate.svelte";
+import LZString from "lz-string";
-let submission = '';
+let submission = "";
// Credit: @hoh
const decodeJSON = (about: string): JSON | null => {
- const match = (about || '').match(/^\[\]\(json([A-Za-z0-9+/=]+)\)/);
-
- if (match)
- try {
- return JSON.parse(atob(match[1]));
- } catch {
- try {
- return JSON.parse(LZString.decompressFromBase64(match[1]));
- } catch {
- return null;
- }
- }
-
- return null;
+ const match = (about || "").match(/^\[\]\(json([A-Za-z0-9+/=]+)\)/);
+
+ if (match)
+ try {
+ return JSON.parse(atob(match[1]));
+ } catch {
+ try {
+ return JSON.parse(LZString.decompressFromBase64(match[1]));
+ } catch {
+ return null;
+ }
+ }
+
+ return null;
};
</script>
diff --git a/src/lib/Tools/EpisodeDiscussionCollector.svelte b/src/lib/Tools/EpisodeDiscussionCollector.svelte
index 99c53f20..68addbdf 100644
--- a/src/lib/Tools/EpisodeDiscussionCollector.svelte
+++ b/src/lib/Tools/EpisodeDiscussionCollector.svelte
@@ -1,13 +1,13 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import { threads } from '$lib/Data/AniList/forum';
-import { onMount } from 'svelte';
-import { clearAllParameters } from '../Utility/parameters';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import InputTemplate from './InputTemplate.svelte';
-import tooltip from '$lib/Tooltip/tooltip';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import { threads } from "$lib/Data/AniList/forum";
+import { onMount } from "svelte";
+import { clearAllParameters } from "../Utility/parameters";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import InputTemplate from "./InputTemplate.svelte";
+import tooltip from "$lib/Tooltip/tooltip";
-let submission = '';
+let submission = "";
onMount(clearAllParameters);
</script>
diff --git a/src/lib/Tools/FollowFix.svelte b/src/lib/Tools/FollowFix.svelte
index a0e9902a..09a34bd2 100644
--- a/src/lib/Tools/FollowFix.svelte
+++ b/src/lib/Tools/FollowFix.svelte
@@ -1,12 +1,12 @@
<script lang="ts">
-import { toggleFollow } from '$lib/Data/AniList/follow';
-import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
-import LogInRestricted from '$lib/Error/LogInRestricted.svelte';
+import { toggleFollow } from "$lib/Data/AniList/follow";
+import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
+import LogInRestricted from "$lib/Error/LogInRestricted.svelte";
export let user: AniListAuthorisation;
-let input = '';
-let submit = '';
+let input = "";
+let submit = "";
</script>
{#if user === undefined}
diff --git a/src/lib/Tools/Hayai.svelte b/src/lib/Tools/Hayai.svelte
index 4de60a9b..8d9c2c9b 100644
--- a/src/lib/Tools/Hayai.svelte
+++ b/src/lib/Tools/Hayai.svelte
@@ -1,83 +1,95 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import { onMount } from 'svelte';
-import JSZip from 'jszip';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import { onMount } from "svelte";
+import JSZip from "jszip";
let fileInput: HTMLInputElement | null = null;
const handleFileUpload = async () => {
- if (!fileInput || !fileInput.files || fileInput.files.length === 0) return;
-
- const file = fileInput.files[0];
- const reader = new FileReader();
-
- reader.onload = async (event) => {
- const zip = await JSZip.loadAsync((event.target as FileReader).result as ArrayBuffer);
- const newZip = new JSZip();
-
- for (const relativePath in zip.files) {
- const zipEntry = zip.files[relativePath];
-
- if (zipEntry.dir) {
- newZip.folder(relativePath);
- } else if (relativePath.endsWith('.xhtml') || relativePath.endsWith('.html')) {
- newZip.file(relativePath, applyBionicReadingToHTML(await zipEntry.async('text')));
- } else {
- newZip.file(relativePath, await zipEntry.async('arraybuffer'));
- }
- }
-
- downloadEPUB(
- await newZip.generateAsync({ type: 'blob' }),
- `${file.name.split('.epub')[0]}_hayai.epub`
- );
- };
-
- reader.readAsArrayBuffer(file);
+ if (!fileInput || !fileInput.files || fileInput.files.length === 0) return;
+
+ const file = fileInput.files[0];
+ const reader = new FileReader();
+
+ reader.onload = async (event) => {
+ const zip = await JSZip.loadAsync(
+ (event.target as FileReader).result as ArrayBuffer,
+ );
+ const newZip = new JSZip();
+
+ for (const relativePath in zip.files) {
+ const zipEntry = zip.files[relativePath];
+
+ if (zipEntry.dir) {
+ newZip.folder(relativePath);
+ } else if (
+ relativePath.endsWith(".xhtml") ||
+ relativePath.endsWith(".html")
+ ) {
+ newZip.file(
+ relativePath,
+ applyBionicReadingToHTML(await zipEntry.async("text")),
+ );
+ } else {
+ newZip.file(relativePath, await zipEntry.async("arraybuffer"));
+ }
+ }
+
+ downloadEPUB(
+ await newZip.generateAsync({ type: "blob" }),
+ `${file.name.split(".epub")[0]}_hayai.epub`,
+ );
+ };
+
+ reader.readAsArrayBuffer(file);
};
const applyBionicReadingToHTML = (content: string) => {
- const contentParser = new DOMParser().parseFromString(content, 'text/html');
+ const contentParser = new DOMParser().parseFromString(content, "text/html");
- for (const paragraph of contentParser.getElementsByTagName('p'))
- paragraph.innerHTML = applyBionicReadingToString(paragraph.textContent ?? '');
+ for (const paragraph of contentParser.getElementsByTagName("p"))
+ paragraph.innerHTML = applyBionicReadingToString(
+ paragraph.textContent ?? "",
+ );
- return contentParser.documentElement.outerHTML;
+ return contentParser.documentElement.outerHTML;
};
const applyBionicReadingToString = (text: string) =>
- text
- .split(/\s+/)
- .map((word) => {
- if (/^\W+$/.test(word) || word.length <= 2) return word;
-
- let boldLength: number;
-
- if (word.length <= 4) {
- boldLength = 2;
- } else if (word.length <= 7) {
- boldLength = 3;
- } else if (word.length <= 10) {
- boldLength = 4;
- } else {
- boldLength = Math.ceil(word.length * 0.5);
- }
-
- return `<strong>${word.slice(0, boldLength)}</strong>${word.slice(boldLength)}`;
- })
- .join(' ');
+ text
+ .split(/\s+/)
+ .map((word) => {
+ if (/^\W+$/.test(word) || word.length <= 2) return word;
+
+ let boldLength: number;
+
+ if (word.length <= 4) {
+ boldLength = 2;
+ } else if (word.length <= 7) {
+ boldLength = 3;
+ } else if (word.length <= 10) {
+ boldLength = 4;
+ } else {
+ boldLength = Math.ceil(word.length * 0.5);
+ }
+
+ return `<strong>${word.slice(0, boldLength)}</strong>${word.slice(boldLength)}`;
+ })
+ .join(" ");
const downloadEPUB = (blob: Blob | MediaSource, fileName: string) => {
- const link = document.createElement('a');
+ const link = document.createElement("a");
- link.href = URL.createObjectURL(blob);
- link.download = fileName;
+ link.href = URL.createObjectURL(blob);
+ link.download = fileName;
- link.click();
- URL.revokeObjectURL(link.href);
+ link.click();
+ URL.revokeObjectURL(link.href);
};
-onMount(() => (fileInput = document.getElementById('epub-file') as HTMLInputElement));
+onMount(
+ () => (fileInput = document.getElementById("epub-file") as HTMLInputElement),
+);
</script>
<div class="card">
diff --git a/src/lib/Tools/InputTemplate.svelte b/src/lib/Tools/InputTemplate.svelte
index af77b296..e86e5350 100644
--- a/src/lib/Tools/InputTemplate.svelte
+++ b/src/lib/Tools/InputTemplate.svelte
@@ -1,8 +1,8 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import { clearAllParameters } from '$lib/Utility/parameters';
-import { onMount } from 'svelte';
-import SettingHint from '$lib/Settings/SettingHint.svelte';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import { clearAllParameters } from "$lib/Utility/parameters";
+import { onMount } from "svelte";
+import SettingHint from "$lib/Settings/SettingHint.svelte";
export let field: string;
export let submission: string;
@@ -10,15 +10,15 @@ export let event: string | undefined = undefined;
export let submitText: string;
export let saveParameters: string[] = [];
export let onSubmit = () => {
- return;
+ return;
};
export let preserveCase = false;
export let prompt = `Enter a ${
- preserveCase ? field : field.toLowerCase()
+ preserveCase ? field : field.toLowerCase()
} to search for to continue.`;
export let hint: string | undefined = undefined;
-let input = '';
+let input = "";
onMount(() => clearAllParameters(saveParameters));
</script>
diff --git a/src/lib/Tools/Likes.svelte b/src/lib/Tools/Likes.svelte
index d8545c39..dde5c755 100644
--- a/src/lib/Tools/Likes.svelte
+++ b/src/lib/Tools/Likes.svelte
@@ -1,22 +1,25 @@
<script lang="ts">
-import { activityLikes } from '$lib/Data/AniList/activity';
-import { threadLikes } from '$lib/Data/AniList/forum';
-import RateLimited from '$lib/Error/RateLimited.svelte';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import tooltip from '$lib/Tooltip/tooltip';
-import settings from '$stores/settings';
-import InputTemplate from './InputTemplate.svelte';
+import { activityLikes } from "$lib/Data/AniList/activity";
+import { threadLikes } from "$lib/Data/AniList/forum";
+import RateLimited from "$lib/Error/RateLimited.svelte";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import tooltip from "$lib/Tooltip/tooltip";
+import settings from "$stores/settings";
+import InputTemplate from "./InputTemplate.svelte";
-let submission = '';
+let submission = "";
-$: normalisedSubmission = submission.replace(/.*\/(activity|thread)\/(\d+).*/, '$2');
-$: submissionType = submission.replace(/.*\/(activity|thread)\/(\d+).*/, '$1');
+$: normalisedSubmission = submission.replace(
+ /.*\/(activity|thread)\/(\d+).*/,
+ "$2",
+);
+$: submissionType = submission.replace(/.*\/(activity|thread)\/(\d+).*/, "$1");
$: likesPromise =
- submissionType === 'activity'
- ? activityLikes(Number(normalisedSubmission))
- : submissionType === 'thread'
- ? threadLikes(Number(normalisedSubmission))
- : Promise.resolve(null);
+ submissionType === "activity"
+ ? activityLikes(Number(normalisedSubmission))
+ : submissionType === "thread"
+ ? threadLikes(Number(normalisedSubmission))
+ : Promise.resolve(null);
</script>
<InputTemplate
diff --git a/src/lib/Tools/Picker.svelte b/src/lib/Tools/Picker.svelte
index df11eef5..ffece7b6 100644
--- a/src/lib/Tools/Picker.svelte
+++ b/src/lib/Tools/Picker.svelte
@@ -1,8 +1,8 @@
<script lang="ts">
-import { browser } from '$app/environment';
-import { goto } from '$app/navigation';
-import root from '$lib/Utility/root';
-import { tools } from './tools';
+import { browser } from "$app/environment";
+import { goto } from "$app/navigation";
+import root from "$lib/Utility/root";
+import { tools } from "./tools";
export let tool: string;
</script>
diff --git a/src/lib/Tools/RandomFollower.svelte b/src/lib/Tools/RandomFollower.svelte
index 628f1b35..7ef0adb5 100644
--- a/src/lib/Tools/RandomFollower.svelte
+++ b/src/lib/Tools/RandomFollower.svelte
@@ -1,12 +1,12 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import { followers } from '$lib/Data/AniList/following';
-import RateLimited from '$lib/Error/RateLimited.svelte';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import TextSwap from '$lib/Layout/TextTransition.svelte';
-import InputTemplate from './InputTemplate.svelte';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import { followers } from "$lib/Data/AniList/following";
+import RateLimited from "$lib/Error/RateLimited.svelte";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import TextSwap from "$lib/Layout/TextTransition.svelte";
+import InputTemplate from "./InputTemplate.svelte";
-let submission = '';
+let submission = "";
let randomSeed = 0;
</script>
diff --git a/src/lib/Tools/SequelCatcher/List.svelte b/src/lib/Tools/SequelCatcher/List.svelte
index 79e28703..b1512e22 100644
--- a/src/lib/Tools/SequelCatcher/List.svelte
+++ b/src/lib/Tools/SequelCatcher/List.svelte
@@ -1,9 +1,9 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import { filterRelations, type Media } from '$lib/Data/AniList/media';
-import MediaTitleDisplay from '$lib/List/MediaTitleDisplay.svelte';
-import { outboundLink } from '$lib/Media/links';
-import settings from '$stores/settings';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import { filterRelations, type Media } from "$lib/Data/AniList/media";
+import MediaTitleDisplay from "$lib/List/MediaTitleDisplay.svelte";
+import { outboundLink } from "$lib/Media/links";
+import settings from "$stores/settings";
export let mediaListUnchecked: Media[];
@@ -11,18 +11,18 @@ let includeCurrent = false;
let includeSideStories = false;
const matchCheck = (media: Media | undefined, swap = false) =>
- (media &&
- media.mediaListEntry &&
- media.mediaListEntry?.status !== 'CURRENT' &&
- media.mediaListEntry?.status !== 'REPEATING' &&
- media.mediaListEntry?.status !== 'PAUSED') ||
- !media
- ? swap
- ? undefined
- : media
- : swap
- ? media
- : undefined;
+ (media &&
+ media.mediaListEntry &&
+ media.mediaListEntry?.status !== "CURRENT" &&
+ media.mediaListEntry?.status !== "REPEATING" &&
+ media.mediaListEntry?.status !== "PAUSED") ||
+ !media
+ ? swap
+ ? undefined
+ : media
+ : swap
+ ? media
+ : undefined;
</script>
<input type="checkbox" bind:checked={includeCurrent} /> Include current (watching, rewatching,
diff --git a/src/lib/Tools/SequelCatcher/Tool.svelte b/src/lib/Tools/SequelCatcher/Tool.svelte
index 01742d6f..727a3a6c 100644
--- a/src/lib/Tools/SequelCatcher/Tool.svelte
+++ b/src/lib/Tools/SequelCatcher/Tool.svelte
@@ -1,31 +1,38 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import List from './List.svelte';
-import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
-import userIdentity from '$stores/identity';
-import { type Media, mediaListCollection, Type } from '$lib/Data/AniList/media';
-import LogInRestricted from '$lib/Error/LogInRestricted.svelte';
-import anime from '$stores/anime';
-import identity from '$stores/identity';
-import { onMount } from 'svelte';
-import lastPruneTimes from '$stores/lastPruneTimes';
-import Message from '$lib/Loading/Message.svelte';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import Username from '$lib/Layout/Username.svelte';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import List from "./List.svelte";
+import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
+import userIdentity from "$stores/identity";
+import { type Media, mediaListCollection, Type } from "$lib/Data/AniList/media";
+import LogInRestricted from "$lib/Error/LogInRestricted.svelte";
+import anime from "$stores/anime";
+import identity from "$stores/identity";
+import { onMount } from "svelte";
+import lastPruneTimes from "$stores/lastPruneTimes";
+import Message from "$lib/Loading/Message.svelte";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import Username from "$lib/Layout/Username.svelte";
export let user: AniListAuthorisation;
let mediaList: Promise<Media[]>;
onMount(async () => {
- if (user === undefined || $identity.id === -2) return;
+ if (user === undefined || $identity.id === -2) return;
- mediaList = mediaListCollection(user, $userIdentity, Type.Anime, $anime, $lastPruneTimes.anime, {
- forcePrune: true,
- includeCompleted: true,
- all: true,
- includeRelations: true
- });
+ mediaList = mediaListCollection(
+ user,
+ $userIdentity,
+ Type.Anime,
+ $anime,
+ $lastPruneTimes.anime,
+ {
+ forcePrune: true,
+ includeCompleted: true,
+ all: true,
+ includeRelations: true,
+ },
+ );
});
</script>
diff --git a/src/lib/Tools/SequelSpy/Prequels.svelte b/src/lib/Tools/SequelSpy/Prequels.svelte
index 5929821e..98fea353 100644
--- a/src/lib/Tools/SequelSpy/Prequels.svelte
+++ b/src/lib/Tools/SequelSpy/Prequels.svelte
@@ -1,15 +1,15 @@
<script lang="ts">
-import type { MediaPrequel } from '$lib/Data/AniList/prequels';
-import MediaTitleDisplay from '$lib/List/MediaTitleDisplay.svelte';
-import { airingTime } from '$lib/Media/Anime/Airing/time';
-import LinkedTooltip from '$lib/Tooltip/LinkedTooltip.svelte';
-import settings from '$stores/settings';
-import type { Media } from '$lib/Data/AniList/media';
+import type { MediaPrequel } from "$lib/Data/AniList/prequels";
+import MediaTitleDisplay from "$lib/List/MediaTitleDisplay.svelte";
+import { airingTime } from "$lib/Media/Anime/Airing/time";
+import LinkedTooltip from "$lib/Tooltip/LinkedTooltip.svelte";
+import settings from "$stores/settings";
+import type { Media } from "$lib/Data/AniList/media";
export let currentPrequels: MediaPrequel[];
const prequelAiringTime = (prequel: MediaPrequel) =>
- airingTime(prequel as unknown as Media, null, false, true);
+ airingTime(prequel as unknown as Media, null, false, true);
</script>
<ul>
diff --git a/src/lib/Tools/SequelSpy/Tool.svelte b/src/lib/Tools/SequelSpy/Tool.svelte
index 0a862984..71056694 100644
--- a/src/lib/Tools/SequelSpy/Tool.svelte
+++ b/src/lib/Tools/SequelSpy/Tool.svelte
@@ -1,38 +1,42 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
-import { prequels, type MediaPrequel } from '$lib/Data/AniList/prequels';
-import { onMount } from 'svelte';
-import { clearAllParameters, parseOrDefault } from '../../Utility/parameters';
-import { page } from '$app/stores';
-import { browser } from '$app/environment';
-import { season as getSeason } from '$lib/Media/Anime/season';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import identity from '$stores/identity';
-import LogInRestricted from '$lib/Error/LogInRestricted.svelte';
-import Prequels from './Prequels.svelte';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
+import { prequels, type MediaPrequel } from "$lib/Data/AniList/prequels";
+import { onMount } from "svelte";
+import { clearAllParameters, parseOrDefault } from "../../Utility/parameters";
+import { page } from "$app/stores";
+import { browser } from "$app/environment";
+import { season as getSeason } from "$lib/Media/Anime/season";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import identity from "$stores/identity";
+import LogInRestricted from "$lib/Error/LogInRestricted.svelte";
+import Prequels from "./Prequels.svelte";
export let user: AniListAuthorisation;
-let currentPrequels: Promise<MediaPrequel[]> = Promise.resolve([]) as Promise<MediaPrequel[]>;
-const urlParameters = browser ? new URLSearchParams(window.location.search) : null;
-let year = parseOrDefault(urlParameters, 'year', new Date().getFullYear());
-let season = parseOrDefault(urlParameters, 'season', getSeason());
+let currentPrequels: Promise<MediaPrequel[]> = Promise.resolve([]) as Promise<
+ MediaPrequel[]
+>;
+const urlParameters = browser
+ ? new URLSearchParams(window.location.search)
+ : null;
+let year = parseOrDefault(urlParameters, "year", new Date().getFullYear());
+let season = parseOrDefault(urlParameters, "season", getSeason());
$: {
- if (year.toString().length === 4 && $identity.id !== -2 && user)
- currentPrequels = prequels(user, year, season);
+ if (year.toString().length === 4 && $identity.id !== -2 && user)
+ currentPrequels = prequels(user, year, season);
}
$: {
- if (browser) {
- $page.url.searchParams.set('year', year.toString());
- $page.url.searchParams.set('season', season.toString());
- clearAllParameters(['year', 'season']);
- history.replaceState(null, '', `?${$page.url.searchParams.toString()}`);
- }
+ if (browser) {
+ $page.url.searchParams.set("year", year.toString());
+ $page.url.searchParams.set("season", season.toString());
+ clearAllParameters(["year", "season"]);
+ history.replaceState(null, "", `?${$page.url.searchParams.toString()}`);
+ }
}
-onMount(() => clearAllParameters(['year', 'season']));
+onMount(() => clearAllParameters(["year", "season"]));
</script>
{#if user === undefined || $identity.id === -2}
diff --git a/src/lib/Tools/Tracker/Tool.svelte b/src/lib/Tools/Tracker/Tool.svelte
index 1849cbb1..8f7a3197 100644
--- a/src/lib/Tools/Tracker/Tool.svelte
+++ b/src/lib/Tools/Tracker/Tool.svelte
@@ -1,69 +1,70 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import { v6 as uuidv6 } from 'uuid';
-import { database, type TrackerEntry } from '$lib/Database/IDB/tracker';
-import { onMount } from 'svelte';
-import Message from '$lib/Loading/Message.svelte';
-
-let url = '';
-let title = '';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import { v6 as uuidv6 } from "uuid";
+import { database, type TrackerEntry } from "$lib/Database/IDB/tracker";
+import { onMount } from "svelte";
+import Message from "$lib/Loading/Message.svelte";
+
+let url = "";
+let title = "";
let progress = 0;
-let error = '';
+let error = "";
let masterList: TrackerEntry[] | null = null;
let confirmDelete = 0;
$: listAccess = masterList || [];
onMount(async () => {
- masterList = await database.entries.toArray();
+ masterList = await database.entries.toArray();
});
const adjustEntry = (id: string, to: number) => {
- const entry = listAccess.find((entry) => entry.id === id);
+ const entry = listAccess.find((entry) => entry.id === id);
- if (!entry) return;
+ if (!entry) return;
- entry.progress = Math.max(0, to);
+ entry.progress = Math.max(0, to);
- database.entries.update(id, { progress: entry.progress });
+ database.entries.update(id, { progress: entry.progress });
- masterList = listAccess.map((entry) =>
- entry.id === id ? { ...entry, progress: entry.progress } : entry
- );
+ masterList = listAccess.map((entry) =>
+ entry.id === id ? { ...entry, progress: entry.progress } : entry,
+ );
};
const addEntry = async (url: string, title: string, progress: number) => {
- if (!url || !title) {
- error = 'URL and title are required fields';
+ if (!url || !title) {
+ error = "URL and title are required fields";
- return;
- }
+ return;
+ }
- if (listAccess.some((entry) => entry.url === url)) {
- error =
- 'Entry with URL already exists: ' + listAccess.find((entry) => entry.url === url)?.title;
+ if (listAccess.some((entry) => entry.url === url)) {
+ error =
+ "Entry with URL already exists: " +
+ listAccess.find((entry) => entry.url === url)?.title;
- return;
- }
+ return;
+ }
- await database.entries.add({ url, title, progress, id: uuidv6() });
+ await database.entries.add({ url, title, progress, id: uuidv6() });
- masterList = await database.entries.toArray();
+ masterList = await database.entries.toArray();
};
const deleteEntry = async (id: string) => {
- if (confirmDelete !== 1) {
- confirmDelete = 1;
- error = 'Click again to confirm deletion';
+ if (confirmDelete !== 1) {
+ confirmDelete = 1;
+ error = "Click again to confirm deletion";
- return;
- }
+ return;
+ }
- await database.entries.delete(id);
+ await database.entries.delete(id);
- masterList = await database.entries.toArray();
- confirmDelete = 0;
- error = '';
+ masterList = await database.entries.toArray();
+ confirmDelete = 0;
+ error = "";
};
</script>
diff --git a/src/lib/Tools/UmaMusumeBirthdays.svelte b/src/lib/Tools/UmaMusumeBirthdays.svelte
index 7d49cfaa..fc773bcb 100644
--- a/src/lib/Tools/UmaMusumeBirthdays.svelte
+++ b/src/lib/Tools/UmaMusumeBirthdays.svelte
@@ -1,50 +1,54 @@
<script lang="ts">
-import { browser } from '$app/environment';
-import { page } from '$app/stores';
-import RateLimitedError from '$lib/Error/RateLimited.svelte';
-import { onMount } from 'svelte';
-import { clearAllParameters, parseOrDefault } from '../Utility/parameters';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import Message from '$lib/Loading/Message.svelte';
-import tooltip from '$lib/Tooltip/tooltip';
-import settings from '$stores/settings';
-import locale from '$stores/locale';
+import { browser } from "$app/environment";
+import { page } from "$app/stores";
+import RateLimitedError from "$lib/Error/RateLimited.svelte";
+import { onMount } from "svelte";
+import { clearAllParameters, parseOrDefault } from "../Utility/parameters";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import Message from "$lib/Loading/Message.svelte";
+import tooltip from "$lib/Tooltip/tooltip";
+import settings from "$stores/settings";
+import locale from "$stores/locale";
interface Birthday {
- birth_day: number;
- birth_month: number;
- game_id: number;
- id: number;
- name_en: string;
- name_jp: string;
- preferred_url: string;
- sns_icon: string;
+ birth_day: number;
+ birth_month: number;
+ game_id: number;
+ id: number;
+ name_en: string;
+ name_jp: string;
+ preferred_url: string;
+ sns_icon: string;
}
-const urlParameters = browser ? new URLSearchParams(window.location.search) : null;
+const urlParameters = browser
+ ? new URLSearchParams(window.location.search)
+ : null;
let date = new Date();
-let month = parseOrDefault(urlParameters, 'month', date.getMonth() + 1);
-let day = parseOrDefault(urlParameters, 'day', date.getDate());
+let month = parseOrDefault(urlParameters, "month", date.getMonth() + 1);
+let day = parseOrDefault(urlParameters, "day", date.getDate());
let umapyoi: Promise<Birthday[]>;
$: {
- month = Math.min(month, 12);
- month = Math.max(month, 1);
- day = Math.min(day, new Date(new Date().getFullYear(), month, 0).getDate());
- day = Math.max(day, 1);
+ month = Math.min(month, 12);
+ month = Math.max(month, 1);
+ day = Math.min(day, new Date(new Date().getFullYear(), month, 0).getDate());
+ day = Math.max(day, 1);
- if (browser) {
- $page.url.searchParams.set('month', month.toString());
- $page.url.searchParams.set('day', day.toString());
- clearAllParameters(['month', 'day']);
- history.replaceState(null, '', `?${$page.url.searchParams.toString()}`);
- }
+ if (browser) {
+ $page.url.searchParams.set("month", month.toString());
+ $page.url.searchParams.set("day", day.toString());
+ clearAllParameters(["month", "day"]);
+ history.replaceState(null, "", `?${$page.url.searchParams.toString()}`);
+ }
}
onMount(() => {
- clearAllParameters(['month', 'day']);
+ clearAllParameters(["month", "day"]);
- umapyoi = fetch('https://umapyoi.net/api/v1/character/birthday').then((r) => r.json());
+ umapyoi = fetch("https://umapyoi.net/api/v1/character/birthday").then((r) =>
+ r.json(),
+ );
});
</script>
diff --git a/src/lib/Tools/Wrapped/ActivityHistory.svelte b/src/lib/Tools/Wrapped/ActivityHistory.svelte
index f1f1a28a..f47b5f71 100644
--- a/src/lib/Tools/Wrapped/ActivityHistory.svelte
+++ b/src/lib/Tools/Wrapped/ActivityHistory.svelte
@@ -1,12 +1,12 @@
<script lang="ts">
-import type { ActivityHistoryEntry } from '$lib/Data/AniList/activity';
-import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
-import ActivityHistoryGrid from '../ActivityHistory/Grid.svelte';
+import type { ActivityHistoryEntry } from "$lib/Data/AniList/activity";
+import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
+import ActivityHistoryGrid from "../ActivityHistory/Grid.svelte";
export let user: AniListAuthorisation;
export let activities: ActivityHistoryEntry[];
export let year: number;
-export let activityHistoryPosition: 'TOP' | 'BELOW_TOP' | 'ORIGINAL';
+export let activityHistoryPosition: "TOP" | "BELOW_TOP" | "ORIGINAL";
</script>
<div
diff --git a/src/lib/Tools/Wrapped/DataLoader.svelte b/src/lib/Tools/Wrapped/DataLoader.svelte
index 6063f349..99f836b6 100644
--- a/src/lib/Tools/Wrapped/DataLoader.svelte
+++ b/src/lib/Tools/Wrapped/DataLoader.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
-import { onMount } from 'svelte';
+import { onMount } from "svelte";
export let onLoad: () => void;
diff --git a/src/lib/Tools/Wrapped/Media.svelte b/src/lib/Tools/Wrapped/Media.svelte
index bbd7ee5b..f7dd3007 100644
--- a/src/lib/Tools/Wrapped/Media.svelte
+++ b/src/lib/Tools/Wrapped/Media.svelte
@@ -1,8 +1,8 @@
<script lang="ts">
-import type { Media } from '$lib/Data/AniList/media';
-import type { Wrapped } from '$lib/Data/AniList/wrapped';
-import MediaTitleDisplay from '$lib/List/MediaTitleDisplay.svelte';
-import proxy from '$lib/Utility/proxy';
+import type { Media } from "$lib/Data/AniList/media";
+import type { Wrapped } from "$lib/Data/AniList/wrapped";
+import MediaTitleDisplay from "$lib/List/MediaTitleDisplay.svelte";
+import proxy from "$lib/Utility/proxy";
export let animeList: Media[] | undefined;
export let mangaList: Media[] | undefined;
diff --git a/src/lib/Tools/Wrapped/MediaExtras.svelte b/src/lib/Tools/Wrapped/MediaExtras.svelte
index d9dc8efb..6eefcbe9 100644
--- a/src/lib/Tools/Wrapped/MediaExtras.svelte
+++ b/src/lib/Tools/Wrapped/MediaExtras.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
-import type { TopMedia } from '$lib/Data/AniList/wrapped';
-import proxy from '$lib/Utility/proxy';
+import type { TopMedia } from "$lib/Data/AniList/wrapped";
+import proxy from "$lib/Utility/proxy";
export let topMedia: TopMedia;
export let updateWidth: () => void;
diff --git a/src/lib/Tools/Wrapped/Tool.svelte b/src/lib/Tools/Wrapped/Tool.svelte
index 7ce50ac3..680e710e 100644
--- a/src/lib/Tools/Wrapped/Tool.svelte
+++ b/src/lib/Tools/Wrapped/Tool.svelte
@@ -1,38 +1,44 @@
<script lang="ts">
-import Spacer from '$lib/Layout/Spacer.svelte';
-import './wrapped.css';
-import userIdentity from '$stores/identity';
-import type { AniListAuthorisation } from '$lib/Data/AniList/identity';
-import { onMount } from 'svelte';
-import { tops, wrapped, type TopMedia, SortOptions, type Wrapped } from '$lib/Data/AniList/wrapped';
+import Spacer from "$lib/Layout/Spacer.svelte";
+import "./wrapped.css";
+import userIdentity from "$stores/identity";
+import type { AniListAuthorisation } from "$lib/Data/AniList/identity";
+import { onMount } from "svelte";
import {
- fullActivityHistory,
- activityHistory as getActivityHistory,
- type ActivityHistoryEntry
-} from '$lib/Data/AniList/activity';
-import { Type, mediaListCollection, type Media } from '$lib/Data/AniList/media';
-import anime from '$stores/anime';
-import lastPruneTimes from '$stores/lastPruneTimes';
-import manga from '$stores/manga';
-import RateLimitedError from '$lib/Error/RateLimited.svelte';
-import { domToBlob } from 'modern-screenshot';
-import { browser } from '$app/environment';
-import { page } from '$app/stores';
-import { clearAllParameters } from '../../Utility/parameters';
-import SettingHint from '$lib/Settings/SettingHint.svelte';
-import { database } from '$lib/Database/IDB/activities';
-import Activity from './Top/Activity.svelte';
-import Anime from './Top/Anime.svelte';
-import Manga from './Top/Manga.svelte';
-import ActivityHistory from './ActivityHistory.svelte';
-import MediaExtras from './MediaExtras.svelte';
-import MediaPanel from './Media.svelte';
-import Watermark from './Watermark.svelte';
-import DataLoader from './DataLoader.svelte';
-import Skeleton from '$lib/Loading/Skeleton.svelte';
-import Message from '$lib/Loading/Message.svelte';
-import tooltip from '$lib/Tooltip/tooltip';
-import LogInRestricted from '$lib/Error/LogInRestricted.svelte';
+ tops,
+ wrapped,
+ type TopMedia,
+ SortOptions,
+ type Wrapped,
+} from "$lib/Data/AniList/wrapped";
+import {
+ fullActivityHistory,
+ activityHistory as getActivityHistory,
+ type ActivityHistoryEntry,
+} from "$lib/Data/AniList/activity";
+import { Type, mediaListCollection, type Media } from "$lib/Data/AniList/media";
+import anime from "$stores/anime";
+import lastPruneTimes from "$stores/lastPruneTimes";
+import manga from "$stores/manga";
+import RateLimitedError from "$lib/Error/RateLimited.svelte";
+import { domToBlob } from "modern-screenshot";
+import { browser } from "$app/environment";
+import { page } from "$app/stores";
+import { clearAllParameters } from "../../Utility/parameters";
+import SettingHint from "$lib/Settings/SettingHint.svelte";
+import { database } from "$lib/Database/IDB/activities";
+import Activity from "./Top/Activity.svelte";
+import Anime from "./Top/Anime.svelte";
+import Manga from "./Top/Manga.svelte";
+import ActivityHistory from "./ActivityHistory.svelte";
+import MediaExtras from "./MediaExtras.svelte";
+import MediaPanel from "./Media.svelte";
+import Watermark from "./Watermark.svelte";
+import DataLoader from "./DataLoader.svelte";
+import Skeleton from "$lib/Loading/Skeleton.svelte";
+import Message from "$lib/Loading/Message.svelte";
+import tooltip from "$lib/Tooltip/tooltip";
+import LogInRestricted from "$lib/Error/LogInRestricted.svelte";
export let user: AniListAuthorisation;
@@ -60,7 +66,7 @@ let genreTagCount = 5;
let mounted = false;
let generated = false;
let disableActivityHistory = true;
-let excludedKeywordsInput = '';
+let excludedKeywordsInput = "";
let excludedKeywords: string[] = [];
let useFullActivityHistory = false;
let disableLoopingActivityCounter = false;
@@ -72,7 +78,7 @@ let genreTagsSort = SortOptions.SCORE;
let mediaSort = SortOptions.SCORE;
let includeMovies = true;
let includeOVAs = true;
-let activityHistoryPosition: 'TOP' | 'BELOW_TOP' | 'ORIGINAL' = 'ORIGINAL';
+let activityHistoryPosition: "TOP" | "BELOW_TOP" | "ORIGINAL" = "ORIGINAL";
let includeOngoingMediaFromPreviousYears = false;
let excludeUnratedUnwatched = true;
let startDateFilter: Date | null = null;
@@ -90,518 +96,590 @@ let lastEndDateFilter: Date | null = endDateFilter;
const touch = (...values: unknown[]) => values;
$: {
- if (browser && mounted) {
- $page.url.searchParams.set('transparency', transparency.toString());
- $page.url.searchParams.set('lightTheme', lightTheme.toString());
- $page.url.searchParams.set('watermark', watermark.toString());
- $page.url.searchParams.set('includeMusic', includeMusic.toString());
- $page.url.searchParams.set('includeSpecials', includeSpecials.toString());
- $page.url.searchParams.set('includeRepeats', includeRepeats.toString());
- $page.url.searchParams.set('lightMode', lightMode.toString());
- $page.url.searchParams.set('highestRatedCount', highestRatedCount.toString());
- $page.url.searchParams.set('genreTagCount', genreTagCount.toString());
- $page.url.searchParams.set('disableActivityHistory', disableActivityHistory.toString());
- $page.url.searchParams.set(
- 'highestRatedMediaPercentage',
- highestRatedMediaPercentage.toString()
- );
- $page.url.searchParams.set(
- 'highestRatedGenreTagPercentage',
- highestRatedGenreTagPercentage.toString()
- );
- $page.url.searchParams.set('genreTagsSort', genreTagsSort.toString());
- $page.url.searchParams.set('mediaSort', mediaSort.toString());
- $page.url.searchParams.set('includeMovies', includeMovies.toString());
- $page.url.searchParams.set('includeOVAs', includeOVAs.toString());
- $page.url.searchParams.set('excludeUnratedUnwatched', excludeUnratedUnwatched.toString());
- $page.url.searchParams.set(
- 'disableLoopingActivityCounter',
- disableLoopingActivityCounter.toString()
- );
-
- history.replaceState(null, '', `?${$page.url.searchParams.toString()}`);
- }
+ if (browser && mounted) {
+ $page.url.searchParams.set("transparency", transparency.toString());
+ $page.url.searchParams.set("lightTheme", lightTheme.toString());
+ $page.url.searchParams.set("watermark", watermark.toString());
+ $page.url.searchParams.set("includeMusic", includeMusic.toString());
+ $page.url.searchParams.set("includeSpecials", includeSpecials.toString());
+ $page.url.searchParams.set("includeRepeats", includeRepeats.toString());
+ $page.url.searchParams.set("lightMode", lightMode.toString());
+ $page.url.searchParams.set(
+ "highestRatedCount",
+ highestRatedCount.toString(),
+ );
+ $page.url.searchParams.set("genreTagCount", genreTagCount.toString());
+ $page.url.searchParams.set(
+ "disableActivityHistory",
+ disableActivityHistory.toString(),
+ );
+ $page.url.searchParams.set(
+ "highestRatedMediaPercentage",
+ highestRatedMediaPercentage.toString(),
+ );
+ $page.url.searchParams.set(
+ "highestRatedGenreTagPercentage",
+ highestRatedGenreTagPercentage.toString(),
+ );
+ $page.url.searchParams.set("genreTagsSort", genreTagsSort.toString());
+ $page.url.searchParams.set("mediaSort", mediaSort.toString());
+ $page.url.searchParams.set("includeMovies", includeMovies.toString());
+ $page.url.searchParams.set("includeOVAs", includeOVAs.toString());
+ $page.url.searchParams.set(
+ "excludeUnratedUnwatched",
+ excludeUnratedUnwatched.toString(),
+ );
+ $page.url.searchParams.set(
+ "disableLoopingActivityCounter",
+ disableLoopingActivityCounter.toString(),
+ );
+
+ history.replaceState(null, "", `?${$page.url.searchParams.toString()}`);
+ }
}
$: {
- if (dataFetched) {
- const yearChanged = selectedYear !== lastSelectedYear;
- const fullActivityChanged = useFullActivityHistory !== lastUseFullActivityHistory;
- const loopingChanged = disableLoopingActivityCounter !== lastDisableLoopingActivityCounter;
- const startDateChanged = startDateFilter !== lastStartDateFilter;
- const endDateChanged = endDateFilter !== lastEndDateFilter;
-
- if (yearChanged || fullActivityChanged || loopingChanged || startDateChanged || endDateChanged)
- needsRefetch = true;
- }
+ if (dataFetched) {
+ const yearChanged = selectedYear !== lastSelectedYear;
+ const fullActivityChanged =
+ useFullActivityHistory !== lastUseFullActivityHistory;
+ const loopingChanged =
+ disableLoopingActivityCounter !== lastDisableLoopingActivityCounter;
+ const startDateChanged = startDateFilter !== lastStartDateFilter;
+ const endDateChanged = endDateFilter !== lastEndDateFilter;
+
+ if (
+ yearChanged ||
+ fullActivityChanged ||
+ loopingChanged ||
+ startDateChanged ||
+ endDateChanged
+ )
+ needsRefetch = true;
+ }
}
$: {
- touch(
- includeMusic,
- includeSpecials,
- includeRepeats,
- disableActivityHistory,
- highestRatedMediaPercentage,
- highestRatedGenreTagPercentage,
- topGenresTags,
- genreTagsSort,
- mediaSort,
- includeMovies,
- includeOVAs,
- selectedYear,
- includeOngoingMediaFromPreviousYears,
- excludeUnratedUnwatched
- );
-
- if (shouldFetchData) update().then(updateWidth).catch(updateWidth);
+ touch(
+ includeMusic,
+ includeSpecials,
+ includeRepeats,
+ disableActivityHistory,
+ highestRatedMediaPercentage,
+ highestRatedGenreTagPercentage,
+ topGenresTags,
+ genreTagsSort,
+ mediaSort,
+ includeMovies,
+ includeOVAs,
+ selectedYear,
+ includeOngoingMediaFromPreviousYears,
+ excludeUnratedUnwatched,
+ );
+
+ if (shouldFetchData) update().then(updateWidth).catch(updateWidth);
}
$: {
- touch(animeList, mangaList, highestRatedCount);
+ touch(animeList, mangaList, highestRatedCount);
- new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
+ new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
}
$: {
- touch(genreTagCount);
+ touch(genreTagCount);
- if (animeList && mangaList)
- topMedia = tops(
- [...(animeList || []), ...(mangaList || [])],
- genreTagCount,
- genreTagsSort,
- excludedKeywords
- );
+ if (animeList && mangaList)
+ topMedia = tops(
+ [...(animeList || []), ...(mangaList || [])],
+ genreTagCount,
+ genreTagsSort,
+ excludedKeywords,
+ );
- new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
+ new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth);
}
$: {
- touch(excludedKeywords);
-
- if (excludedKeywords.length > 0 && animeList !== undefined && mangaList !== undefined) {
- animeList = originalAnimeList;
- mangaList = originalMangaList;
- animeList = excludeKeywords(animeList as Media[]);
- mangaList = excludeKeywords(mangaList as Media[]);
- }
-
- updateWidth();
+ touch(excludedKeywords);
+
+ if (
+ excludedKeywords.length > 0 &&
+ animeList !== undefined &&
+ mangaList !== undefined
+ ) {
+ animeList = originalAnimeList;
+ mangaList = originalMangaList;
+ animeList = excludeKeywords(animeList as Media[]);
+ mangaList = excludeKeywords(mangaList as Media[]);
+ }
+
+ updateWidth();
}
$: genreTagTitle = (() => {
- switch (genreTagsSort) {
- case SortOptions.SCORE:
- return 'Highest Rated';
- case SortOptions.MINUTES_WATCHED:
- return 'Most Watched';
- case SortOptions.COUNT:
- return 'Most Common';
- }
+ switch (genreTagsSort) {
+ case SortOptions.SCORE:
+ return "Highest Rated";
+ case SortOptions.MINUTES_WATCHED:
+ return "Most Watched";
+ case SortOptions.COUNT:
+ return "Most Common";
+ }
})();
$: animeMostTitle = (() => {
- switch (mediaSort) {
- case SortOptions.SCORE:
- return 'Highest Rated';
- case SortOptions.MINUTES_WATCHED:
- return 'Most Watched';
- case SortOptions.COUNT:
- return 'Most Common';
- }
+ switch (mediaSort) {
+ case SortOptions.SCORE:
+ return "Highest Rated";
+ case SortOptions.MINUTES_WATCHED:
+ return "Most Watched";
+ case SortOptions.COUNT:
+ return "Most Common";
+ }
})();
$: mangaMostTitle = (() => {
- switch (mediaSort) {
- case SortOptions.SCORE:
- return 'Highest Rated';
- case SortOptions.MINUTES_WATCHED:
- return 'Most Read';
- case SortOptions.COUNT:
- return 'Most Common';
- }
+ switch (mediaSort) {
+ case SortOptions.SCORE:
+ return "Highest Rated";
+ case SortOptions.MINUTES_WATCHED:
+ return "Most Read";
+ case SortOptions.COUNT:
+ return "Most Common";
+ }
})();
function updateWidth() {
- if (!browser) return;
-
- const wrappedContainer = document.querySelector('#wrapped') as HTMLElement;
-
- if (!wrappedContainer) return;
-
- wrappedContainer.style.width = `1920px`;
-
- const reset = () => {
- let topWidths = 0;
- let middleWidths = 0;
- let bottomWidths = 0;
-
- wrappedContainer.querySelectorAll('.category').forEach((item) => {
- const category = item as HTMLElement;
- const style = window.getComputedStyle(category);
- const width =
- category.offsetWidth +
- parseFloat(style.marginLeft) +
- parseFloat(style.marginRight) +
- parseFloat(style.paddingLeft) +
- parseFloat(style.paddingRight) +
- parseFloat(style.borderLeftWidth) +
- parseFloat(style.borderRightWidth);
-
- if (category.classList.contains('top-category')) {
- topWidths += width;
- } else if (category.classList.contains('middle-category')) {
- middleWidths += width;
- } else if (category.classList.contains('bottom-category')) {
- bottomWidths += width;
- }
- });
-
- let requiredWidth = topWidths > middleWidths ? topWidths : middleWidths;
-
- if (!disableActivityHistory && bottomWidths > requiredWidth) requiredWidth = bottomWidths;
-
- requiredWidth += wrappedContainer.offsetWidth - wrappedContainer.clientWidth;
-
- wrappedContainer.style.width = `${requiredWidth}px`;
- width = requiredWidth;
- };
-
- reset();
- reset();
+ if (!browser) return;
+
+ const wrappedContainer = document.querySelector("#wrapped") as HTMLElement;
+
+ if (!wrappedContainer) return;
+
+ wrappedContainer.style.width = `1920px`;
+
+ const reset = () => {
+ let topWidths = 0;
+ let middleWidths = 0;
+ let bottomWidths = 0;
+
+ wrappedContainer.querySelectorAll(".category").forEach((item) => {
+ const category = item as HTMLElement;
+ const style = window.getComputedStyle(category);
+ const width =
+ category.offsetWidth +
+ parseFloat(style.marginLeft) +
+ parseFloat(style.marginRight) +
+ parseFloat(style.paddingLeft) +
+ parseFloat(style.paddingRight) +
+ parseFloat(style.borderLeftWidth) +
+ parseFloat(style.borderRightWidth);
+
+ if (category.classList.contains("top-category")) {
+ topWidths += width;
+ } else if (category.classList.contains("middle-category")) {
+ middleWidths += width;
+ } else if (category.classList.contains("bottom-category")) {
+ bottomWidths += width;
+ }
+ });
+
+ let requiredWidth = topWidths > middleWidths ? topWidths : middleWidths;
+
+ if (!disableActivityHistory && bottomWidths > requiredWidth)
+ requiredWidth = bottomWidths;
+
+ requiredWidth +=
+ wrappedContainer.offsetWidth - wrappedContainer.clientWidth;
+
+ wrappedContainer.style.width = `${requiredWidth}px`;
+ width = requiredWidth;
+ };
+
+ reset();
+ reset();
}
onMount(async () => {
- clearAllParameters([
- 'transparency',
- 'lightTheme',
- 'watermark',
- 'includeMusic',
- 'includeSpecials',
- 'includeRepeats',
- 'forceDark',
- 'highestRatedCount',
- 'genreTagCount',
- 'disableActivityHistory',
- 'highestRatedMediaPercentage',
- 'highestRatedGenreTagPercentage',
- 'genreTagsSort',
- 'mediaSort',
- 'includeMovies',
- 'includeOVAs',
- 'disableLoopingActivityCounter'
- ]);
-
- if (browser) {
- transparency = $page.url.searchParams.get('transparency') === 'true';
- lightTheme = $page.url.searchParams.get('lightTheme') === 'true';
- watermark = $page.url.searchParams.get('watermark') === 'true';
- includeMusic = $page.url.searchParams.get('includeMusic') === 'true';
- includeSpecials = $page.url.searchParams.get('includeSpecials') === 'true';
- includeRepeats = $page.url.searchParams.get('includeRepeats') === 'true';
- lightMode = $page.url.searchParams.get('lightMode') === 'true';
- highestRatedCount = parseInt($page.url.searchParams.get('highestRatedCount') || '5', 10);
- genreTagCount = parseInt($page.url.searchParams.get('genreTagCount') || '5', 10);
- disableActivityHistory = $page.url.searchParams.get('disableActivityHistory') === 'true';
- disableLoopingActivityCounter =
- $page.url.searchParams.get('disableLoopingActivityCounter') === 'true';
- highestRatedMediaPercentage =
- $page.url.searchParams.get('highestRatedMediaPercentage') === 'true';
- highestRatedGenreTagPercentage =
- $page.url.searchParams.get('highestRatedGenreTagPercentage') === 'true';
- // genreTagsSort = parseInt($page.url.searchParams.get('genreTagsSort') || '0', 10);
- // mediaSort = parseInt($page.url.searchParams.get('mediaSort') || '0', 10);
- includeMovies = $page.url.searchParams.get('includeMovies') === 'true';
- includeOVAs = $page.url.searchParams.get('includeOVAs') === 'true';
- }
-
- await update().then(() => (mounted = true));
+ clearAllParameters([
+ "transparency",
+ "lightTheme",
+ "watermark",
+ "includeMusic",
+ "includeSpecials",
+ "includeRepeats",
+ "forceDark",
+ "highestRatedCount",
+ "genreTagCount",
+ "disableActivityHistory",
+ "highestRatedMediaPercentage",
+ "highestRatedGenreTagPercentage",
+ "genreTagsSort",
+ "mediaSort",
+ "includeMovies",
+ "includeOVAs",
+ "disableLoopingActivityCounter",
+ ]);
+
+ if (browser) {
+ transparency = $page.url.searchParams.get("transparency") === "true";
+ lightTheme = $page.url.searchParams.get("lightTheme") === "true";
+ watermark = $page.url.searchParams.get("watermark") === "true";
+ includeMusic = $page.url.searchParams.get("includeMusic") === "true";
+ includeSpecials = $page.url.searchParams.get("includeSpecials") === "true";
+ includeRepeats = $page.url.searchParams.get("includeRepeats") === "true";
+ lightMode = $page.url.searchParams.get("lightMode") === "true";
+ highestRatedCount = parseInt(
+ $page.url.searchParams.get("highestRatedCount") || "5",
+ 10,
+ );
+ genreTagCount = parseInt(
+ $page.url.searchParams.get("genreTagCount") || "5",
+ 10,
+ );
+ disableActivityHistory =
+ $page.url.searchParams.get("disableActivityHistory") === "true";
+ disableLoopingActivityCounter =
+ $page.url.searchParams.get("disableLoopingActivityCounter") === "true";
+ highestRatedMediaPercentage =
+ $page.url.searchParams.get("highestRatedMediaPercentage") === "true";
+ highestRatedGenreTagPercentage =
+ $page.url.searchParams.get("highestRatedGenreTagPercentage") === "true";
+ // genreTagsSort = parseInt($page.url.searchParams.get('genreTagsSort') || '0', 10);
+ // mediaSort = parseInt($page.url.searchParams.get('mediaSort') || '0', 10);
+ includeMovies = $page.url.searchParams.get("includeMovies") === "true";
+ includeOVAs = $page.url.searchParams.get("includeOVAs") === "true";
+ }
+
+ await update().then(() => (mounted = true));
});
const triggerFetch = () => {
- shouldFetchData = true;
- needsRefetch = false;
- dataFetched = true;
- fetchKey += 1;
- lastSelectedYear = selectedYear;
- lastUseFullActivityHistory = useFullActivityHistory;
- lastDisableLoopingActivityCounter = disableLoopingActivityCounter;
- lastStartDateFilter = startDateFilter;
- lastEndDateFilter = endDateFilter;
+ shouldFetchData = true;
+ needsRefetch = false;
+ dataFetched = true;
+ fetchKey += 1;
+ lastSelectedYear = selectedYear;
+ lastUseFullActivityHistory = useFullActivityHistory;
+ lastDisableLoopingActivityCounter = disableLoopingActivityCounter;
+ lastStartDateFilter = startDateFilter;
+ lastEndDateFilter = endDateFilter;
};
-const createDummyMedia = (type: 'ANIME' | 'MANGA'): Media => ({
- id: 0,
- idMal: 0,
- status: 'FINISHED',
- type,
- episodes: type === 'ANIME' ? 0 : 0,
- chapters: type === 'MANGA' ? 0 : 0,
- volumes: 0,
- duration: 0,
- format: type === 'ANIME' ? 'TV' : 'MANGA',
- title: {
- romaji: '...',
- english: '...',
- native: '...'
- },
- synonyms: [],
- mediaListEntry: {
- progress: 0,
- progressVolumes: 0,
- status: 'COMPLETED',
- score: 0,
- repeat: 0,
- startedAt: {
- year: 0,
- month: 0,
- day: 0
- },
- completedAt: {
- year: 0,
- month: 0,
- day: 0
- },
- createdAt: 0,
- updatedAt: 0,
- customLists: {}
- },
- startDate: {
- year: 0,
- month: 0
- },
- endDate: {
- year: 0,
- month: 0
- },
- coverImage: {
- extraLarge: 'https://s4.anilist.co/file/anilistcdn/staff/large/default.jpg',
- medium: 'https://s4.anilist.co/file/anilistcdn/staff/large/default.jpg'
- },
- tags: [],
- genres: [],
- season: 'WINTER',
- isAdult: false,
- relations: {
- edges: []
- }
+const createDummyMedia = (type: "ANIME" | "MANGA"): Media => ({
+ id: 0,
+ idMal: 0,
+ status: "FINISHED",
+ type,
+ episodes: type === "ANIME" ? 0 : 0,
+ chapters: type === "MANGA" ? 0 : 0,
+ volumes: 0,
+ duration: 0,
+ format: type === "ANIME" ? "TV" : "MANGA",
+ title: {
+ romaji: "...",
+ english: "...",
+ native: "...",
+ },
+ synonyms: [],
+ mediaListEntry: {
+ progress: 0,
+ progressVolumes: 0,
+ status: "COMPLETED",
+ score: 0,
+ repeat: 0,
+ startedAt: {
+ year: 0,
+ month: 0,
+ day: 0,
+ },
+ completedAt: {
+ year: 0,
+ month: 0,
+ day: 0,
+ },
+ createdAt: 0,
+ updatedAt: 0,
+ customLists: {},
+ },
+ startDate: {
+ year: 0,
+ month: 0,
+ },
+ endDate: {
+ year: 0,
+ month: 0,
+ },
+ coverImage: {
+ extraLarge: "https://s4.anilist.co/file/anilistcdn/staff/large/default.jpg",
+ medium: "https://s4.anilist.co/file/anilistcdn/staff/large/default.jpg",
+ },
+ tags: [],
+ genres: [],
+ season: "WINTER",
+ isAdult: false,
+ relations: {
+ edges: [],
+ },
});
const dummyWrapped: Wrapped = {
- statistics: {
- anime: {
- startYears: [],
- genres: [],
- tags: []
- },
- manga: {
- startYears: [],
- genres: [],
- tags: []
- }
- },
- activities: {
- statusCount: 0,
- messageCount: 0
- },
- avatar: {
- large: 'https://s4.anilist.co/file/anilistcdn/user/avatar/large/3.jpg'
- }
+ statistics: {
+ anime: {
+ startYears: [],
+ genres: [],
+ tags: [],
+ },
+ manga: {
+ startYears: [],
+ genres: [],
+ tags: [],
+ },
+ },
+ activities: {
+ statusCount: 0,
+ messageCount: 0,
+ },
+ avatar: {
+ large: "https://s4.anilist.co/file/anilistcdn/user/avatar/large/3.jpg",
+ },
};
const dummyActivities: ActivityHistoryEntry[] = [];
-const dummyAnimeList: Media[] = [createDummyMedia('ANIME')];
-const dummyMangaList: Media[] = [createDummyMedia('MANGA')];
+const dummyAnimeList: Media[] = [createDummyMedia("ANIME")];
+const dummyMangaList: Media[] = [createDummyMedia("MANGA")];
async function update() {
- if ($userIdentity.id === -1) return;
-
- let rawAnimeList = await mediaListCollection(
- user,
- $userIdentity,
- Type.Anime,
- $anime,
- $lastPruneTimes.anime,
- {
- forcePrune: dateTicked ? false : true,
- includeCompleted: true,
- all: true
- }
- );
- calculatedAnimeList = rawAnimeList
- .filter(
- (item, index, self) =>
- self.findIndex((itemToCompare) => itemToCompare.id === item.id) === index &&
- (includeMusic ? true : item.format !== 'MUSIC') &&
- (includeRepeats
- ? true
- : item.startDate.year === selectedYear || item.endDate.year === selectedYear
- ? true
- : item.mediaListEntry?.repeat === 0) &&
- (item.mediaListEntry?.startedAt.year === selectedYear ||
- item.mediaListEntry?.completedAt.year === selectedYear ||
- ((item.mediaListEntry?.createdAt
- ? new Date(item.mediaListEntry?.createdAt * 1000).getFullYear() === selectedYear
- : false) && item.mediaListEntry
- ? item.mediaListEntry?.progress >= 1
- : false)) &&
- (includeMovies ? true : item.format !== 'MOVIE') &&
- (includeSpecials ? true : item.format !== 'SPECIAL') &&
- (includeOVAs ? true : item.format !== 'OVA') &&
- (excludeUnratedUnwatched ? item.mediaListEntry?.score !== 0 : true) &&
- (excludeUnratedUnwatched ? item.mediaListEntry?.progress !== 0 : true) &&
- (startDateFilter && item.mediaListEntry?.startedAt
- ? new Date(
- item.mediaListEntry.startedAt.year,
- item.mediaListEntry?.startedAt.month - 1,
- item.mediaListEntry.startedAt.day
- ) >= new Date(startDateFilter)
- : true) &&
- (endDateFilter && item.mediaListEntry?.startedAt
- ? new Date(
- item.mediaListEntry.completedAt.year,
- item.mediaListEntry?.completedAt.month - 1,
- item.mediaListEntry.completedAt.day
- ) <= new Date(endDateFilter)
- : true)
- )
- .sort((a, b) => {
- switch (mediaSort) {
- case SortOptions.MINUTES_WATCHED:
- if (a.duration === undefined || a.mediaListEntry?.progress === undefined) return 1;
- else if (b.duration === undefined || b.mediaListEntry?.progress === undefined) return -1;
- else
- return b.duration * b.mediaListEntry.progress - a.duration * a.mediaListEntry.progress;
- case SortOptions.SCORE:
- default:
- if (a.mediaListEntry?.score === undefined) return 1;
- else if (b.mediaListEntry?.score === undefined) return -1;
- else return b.mediaListEntry?.score - a.mediaListEntry?.score;
- }
- });
-
- animeList = rawAnimeList
- .filter(
- (item, index, self) =>
- self.findIndex((itemToCompare) => itemToCompare.id === item.id) === index &&
- (includeMusic ? true : item.format !== 'MUSIC') &&
- (includeRepeats
- ? true
- : item.startDate.year === selectedYear || item.endDate.year === selectedYear
- ? true
- : item.mediaListEntry?.repeat === 0) &&
- (item.mediaListEntry?.startedAt.year === selectedYear ||
- item.mediaListEntry?.completedAt.year === selectedYear ||
- ((item.mediaListEntry?.createdAt
- ? new Date(item.mediaListEntry?.createdAt * 1000).getFullYear() === selectedYear
- : false) && item.mediaListEntry
- ? item.mediaListEntry?.progress >= 1
- : false) ||
- (includeOngoingMediaFromPreviousYears
- ? (item.mediaListEntry?.updatedAt
- ? new Date(item.mediaListEntry?.updatedAt * 1000).getFullYear() === selectedYear
- : false) && item.mediaListEntry
- ? item.mediaListEntry?.status === 'CURRENT'
- : false
- : false)) &&
- (includeMovies ? true : item.format !== 'MOVIE') &&
- (includeSpecials ? true : item.format !== 'SPECIAL') &&
- (includeOVAs ? true : item.format !== 'OVA')
- )
- .sort((a, b) => {
- switch (mediaSort) {
- case SortOptions.MINUTES_WATCHED:
- if (a.duration === undefined || a.mediaListEntry?.progress === undefined) return 1;
- else if (b.duration === undefined || b.mediaListEntry?.progress === undefined) return -1;
- else
- return b.duration * b.mediaListEntry.progress - a.duration * a.mediaListEntry.progress;
- case SortOptions.SCORE:
- default:
- if (a.mediaListEntry?.score === undefined) return 1;
- else if (b.mediaListEntry?.score === undefined) return -1;
- else return b.mediaListEntry?.score - a.mediaListEntry?.score;
- }
- });
-
- let rawMangaList = await mediaListCollection(
- user,
- $userIdentity,
- Type.Manga,
- $manga,
- $lastPruneTimes.manga,
- {
- forcePrune: dateTicked ? false : true,
- includeCompleted: true,
- all: true
- }
- );
- calculatedMangaList = rawMangaList
- .filter(
- (item, index, self) =>
- self.findIndex((itemToCompare) => itemToCompare.id === item.id) === index &&
- (includeRepeats ? true : item.mediaListEntry?.repeat === 0) &&
- (item.mediaListEntry?.startedAt.year === selectedYear ||
- item.mediaListEntry?.completedAt.year === selectedYear ||
- ((item.mediaListEntry?.createdAt
- ? new Date(item.mediaListEntry?.createdAt * 1000).getFullYear() === selectedYear
- : false) && item.mediaListEntry
- ? item.mediaListEntry?.progress >= 1
- : false)) &&
- (excludeUnratedUnwatched ? item.mediaListEntry?.score !== 0 : true) &&
- (excludeUnratedUnwatched ? item.mediaListEntry?.progress !== 0 : true) &&
- (startDateFilter && item.mediaListEntry?.startedAt
- ? new Date(
- item.mediaListEntry.startedAt.year,
- item.mediaListEntry?.startedAt.month - 1,
- item.mediaListEntry.startedAt.day
- ) >= new Date(startDateFilter)
- : true) &&
- (endDateFilter && item.mediaListEntry?.startedAt
- ? new Date(
- item.mediaListEntry.completedAt.year,
- item.mediaListEntry?.completedAt.month - 1,
- item.mediaListEntry.completedAt.day
- ) <= new Date(endDateFilter)
- : true)
- )
- .sort((a, b) => {
- if (a.mediaListEntry?.score === undefined) return 1;
- else if (b.mediaListEntry?.score === undefined) return -1;
- else return b.mediaListEntry?.score - a.mediaListEntry?.score;
- });
-
- mangaList = rawMangaList
- .filter(
- (item, index, self) =>
- self.findIndex((itemToCompare) => itemToCompare.id === item.id) === index &&
- (includeRepeats ? true : item.mediaListEntry?.repeat === 0) &&
- (item.mediaListEntry?.startedAt.year === selectedYear ||
- item.mediaListEntry?.completedAt.year === selectedYear ||
- ((item.mediaListEntry?.createdAt
- ? new Date(item.mediaListEntry?.createdAt * 1000).getFullYear() === selectedYear
- : false) && item.mediaListEntry
- ? item.mediaListEntry?.progress >= 1
- : false) ||
- (includeOngoingMediaFromPreviousYears
- ? (item.mediaListEntry?.updatedAt
- ? new Date(item.mediaListEntry?.updatedAt * 1000).getFullYear() === selectedYear
- : false) && item.mediaListEntry
- ? item.mediaListEntry?.status === 'CURRENT'
- : false
- : false))
- )
- .sort((a, b) => {
- if (a.mediaListEntry?.score === undefined) return 1;
- else if (b.mediaListEntry?.score === undefined) return -1;
- else return b.mediaListEntry?.score - a.mediaListEntry?.score;
- });
-
- episodes = 0;
- minutesWatched = 0;
- chapters = 0;
- dateTicked = false;
-
- for (const media of calculatedAnimeList) {
- episodes += media.mediaListEntry?.progress || 0;
- minutesWatched += (media.mediaListEntry?.progress || 0) * media.duration || 0;
- }
-
- for (const media of calculatedMangaList) chapters += media.mediaListEntry?.progress || 0;
+ if ($userIdentity.id === -1) return;
+
+ let rawAnimeList = await mediaListCollection(
+ user,
+ $userIdentity,
+ Type.Anime,
+ $anime,
+ $lastPruneTimes.anime,
+ {
+ forcePrune: dateTicked ? false : true,
+ includeCompleted: true,
+ all: true,
+ },
+ );
+ calculatedAnimeList = rawAnimeList
+ .filter(
+ (item, index, self) =>
+ self.findIndex((itemToCompare) => itemToCompare.id === item.id) ===
+ index &&
+ (includeMusic ? true : item.format !== "MUSIC") &&
+ (includeRepeats
+ ? true
+ : item.startDate.year === selectedYear ||
+ item.endDate.year === selectedYear
+ ? true
+ : item.mediaListEntry?.repeat === 0) &&
+ (item.mediaListEntry?.startedAt.year === selectedYear ||
+ item.mediaListEntry?.completedAt.year === selectedYear ||
+ ((item.mediaListEntry?.createdAt
+ ? new Date(item.mediaListEntry?.createdAt * 1000).getFullYear() ===
+ selectedYear
+ : false) && item.mediaListEntry
+ ? item.mediaListEntry?.progress >= 1
+ : false)) &&
+ (includeMovies ? true : item.format !== "MOVIE") &&
+ (includeSpecials ? true : item.format !== "SPECIAL") &&
+ (includeOVAs ? true : item.format !== "OVA") &&
+ (excludeUnratedUnwatched ? item.mediaListEntry?.score !== 0 : true) &&
+ (excludeUnratedUnwatched
+ ? item.mediaListEntry?.progress !== 0
+ : true) &&
+ (startDateFilter && item.mediaListEntry?.startedAt
+ ? new Date(
+ item.mediaListEntry.startedAt.year,
+ item.mediaListEntry?.startedAt.month - 1,
+ item.mediaListEntry.startedAt.day,
+ ) >= new Date(startDateFilter)
+ : true) &&
+ (endDateFilter && item.mediaListEntry?.startedAt
+ ? new Date(
+ item.mediaListEntry.completedAt.year,
+ item.mediaListEntry?.completedAt.month - 1,
+ item.mediaListEntry.completedAt.day,
+ ) <= new Date(endDateFilter)
+ : true),
+ )
+ .sort((a, b) => {
+ switch (mediaSort) {
+ case SortOptions.MINUTES_WATCHED:
+ if (
+ a.duration === undefined ||
+ a.mediaListEntry?.progress === undefined
+ )
+ return 1;
+ else if (
+ b.duration === undefined ||
+ b.mediaListEntry?.progress === undefined
+ )
+ return -1;
+ else
+ return (
+ b.duration * b.mediaListEntry.progress -
+ a.duration * a.mediaListEntry.progress
+ );
+ case SortOptions.SCORE:
+ default:
+ if (a.mediaListEntry?.score === undefined) return 1;
+ else if (b.mediaListEntry?.score === undefined) return -1;
+ else return b.mediaListEntry?.score - a.mediaListEntry?.score;
+ }
+ });
+
+ animeList = rawAnimeList
+ .filter(
+ (item, index, self) =>
+ self.findIndex((itemToCompare) => itemToCompare.id === item.id) ===
+ index &&
+ (includeMusic ? true : item.format !== "MUSIC") &&
+ (includeRepeats
+ ? true
+ : item.startDate.year === selectedYear ||
+ item.endDate.year === selectedYear
+ ? true
+ : item.mediaListEntry?.repeat === 0) &&
+ (item.mediaListEntry?.startedAt.year === selectedYear ||
+ item.mediaListEntry?.completedAt.year === selectedYear ||
+ ((item.mediaListEntry?.createdAt
+ ? new Date(item.mediaListEntry?.createdAt * 1000).getFullYear() ===
+ selectedYear
+ : false) && item.mediaListEntry
+ ? item.mediaListEntry?.progress >= 1
+ : false) ||
+ (includeOngoingMediaFromPreviousYears
+ ? (item.mediaListEntry?.updatedAt
+ ? new Date(
+ item.mediaListEntry?.updatedAt * 1000,
+ ).getFullYear() === selectedYear
+ : false) && item.mediaListEntry
+ ? item.mediaListEntry?.status === "CURRENT"
+ : false
+ : false)) &&
+ (includeMovies ? true : item.format !== "MOVIE") &&
+ (includeSpecials ? true : item.format !== "SPECIAL") &&
+ (includeOVAs ? true : item.format !== "OVA"),
+ )
+ .sort((a, b) => {
+ switch (mediaSort) {
+ case SortOptions.MINUTES_WATCHED:
+ if (
+ a.duration === undefined ||
+ a.mediaListEntry?.progress === undefined
+ )
+ return 1;
+ else if (
+ b.duration === undefined ||
+ b.mediaListEntry?.progress === undefined
+ )
+ return -1;
+ else
+ return (
+ b.duration * b.mediaListEntry.progress -
+ a.duration * a.mediaListEntry.progress
+ );
+ case SortOptions.SCORE:
+ default:
+ if (a.mediaListEntry?.score === undefined) return 1;
+ else if (b.mediaListEntry?.score === undefined) return -1;
+ else return b.mediaListEntry?.score - a.mediaListEntry?.score;
+ }
+ });
+
+ let rawMangaList = await mediaListCollection(
+ user,
+ $userIdentity,
+ Type.Manga,
+ $manga,
+ $lastPruneTimes.manga,
+ {
+ forcePrune: dateTicked ? false : true,
+ includeCompleted: true,
+ all: true,
+ },
+ );
+ calculatedMangaList = rawMangaList
+ .filter(
+ (item, index, self) =>
+ self.findIndex((itemToCompare) => itemToCompare.id === item.id) ===
+ index &&
+ (includeRepeats ? true : item.mediaListEntry?.repeat === 0) &&
+ (item.mediaListEntry?.startedAt.year === selectedYear ||
+ item.mediaListEntry?.completedAt.year === selectedYear ||
+ ((item.mediaListEntry?.createdAt
+ ? new Date(item.mediaListEntry?.createdAt * 1000).getFullYear() ===
+ selectedYear
+ : false) && item.mediaListEntry
+ ? item.mediaListEntry?.progress >= 1
+ : false)) &&
+ (excludeUnratedUnwatched ? item.mediaListEntry?.score !== 0 : true) &&
+ (excludeUnratedUnwatched
+ ? item.mediaListEntry?.progress !== 0
+ : true) &&
+ (startDateFilter && item.mediaListEntry?.startedAt
+ ? new Date(
+ item.mediaListEntry.startedAt.year,
+ item.mediaListEntry?.startedAt.month - 1,
+ item.mediaListEntry.startedAt.day,
+ ) >= new Date(startDateFilter)
+ : true) &&
+ (endDateFilter && item.mediaListEntry?.startedAt
+ ? new Date(
+ item.mediaListEntry.completedAt.year,
+ item.mediaListEntry?.completedAt.month - 1,
+ item.mediaListEntry.completedAt.day,
+ ) <= new Date(endDateFilter)
+ : true),
+ )
+ .sort((a, b) => {
+ if (a.mediaListEntry?.score === undefined) return 1;
+ else if (b.mediaListEntry?.score === undefined) return -1;
+ else return b.mediaListEntry?.score - a.mediaListEntry?.score;
+ });
+
+ mangaList = rawMangaList
+ .filter(
+ (item, index, self) =>
+ self.findIndex((itemToCompare) => itemToCompare.id === item.id) ===
+ index &&
+ (includeRepeats ? true : item.mediaListEntry?.repeat === 0) &&
+ (item.mediaListEntry?.startedAt.year === selectedYear ||
+ item.mediaListEntry?.completedAt.year === selectedYear ||
+ ((item.mediaListEntry?.createdAt
+ ? new Date(item.mediaListEntry?.createdAt * 1000).getFullYear() ===
+ selectedYear
+ : false) && item.mediaListEntry
+ ? item.mediaListEntry?.progress >= 1
+ : false) ||
+ (includeOngoingMediaFromPreviousYears
+ ? (item.mediaListEntry?.updatedAt
+ ? new Date(
+ item.mediaListEntry?.updatedAt * 1000,
+ ).getFullYear() === selectedYear
+ : false) && item.mediaListEntry
+ ? item.mediaListEntry?.status === "CURRENT"
+ : false
+ : false)),
+ )
+ .sort((a, b) => {
+ if (a.mediaListEntry?.score === undefined) return 1;
+ else if (b.mediaListEntry?.score === undefined) return -1;
+ else return b.mediaListEntry?.score - a.mediaListEntry?.score;
+ });
+
+ episodes = 0;
+ minutesWatched = 0;
+ chapters = 0;
+ dateTicked = false;
+
+ for (const media of calculatedAnimeList) {
+ episodes += media.mediaListEntry?.progress || 0;
+ minutesWatched +=
+ (media.mediaListEntry?.progress || 0) * media.duration || 0;
+ }
+
+ for (const media of calculatedMangaList)
+ chapters += media.mediaListEntry?.progress || 0;
}
/* eslint-disable @typescript-eslint/no-explicit-any */
@@ -609,51 +687,60 @@ async function update() {
// statistic.startYears.find((y: { startYear: number }) => y.startYear === 2023);
const screenshot = async () => {
- let element = document.querySelector('#wrapped') as HTMLElement;
-
- if (element !== null) {
- domToBlob(element, {
- backgroundColor: transparency ? 'transparent' : lightTheme ? '#edf1f5' : '#0b1622',
- quality: 1,
- scale: 2,
- fetch: {
- requestInit: {
- mode: 'cors'
- },
- bypassingCache: true
- }
- }).then((blob) => {
- const downloadWrapper = document.createElement('a');
- // const wrappedImageButton = document.getElementById(
- // 'wrapped-image-download'
- // ) as HTMLAnchorElement;
- const image = document.createElement('img');
- const object = (window.URL || window.webkitURL || window || {}).createObjectURL(blob);
-
- // downloadWrapper.download = `due_dot_moe_wrapped_${dark ? 'dark' : 'light'}.png`;
- downloadWrapper.href = object;
- downloadWrapper.target = '_blank';
- image.src = object;
-
- downloadWrapper.appendChild(image);
-
- // if (wrappedImageButton !== null) {
- // wrappedImageButton.href = object;
- // }
-
- const wrappedFinal = document.getElementById('wrapped-final');
-
- if (wrappedFinal !== null) {
- wrappedFinal.innerHTML = '';
-
- wrappedFinal.appendChild(downloadWrapper);
-
- generated = true;
- }
-
- downloadWrapper.click();
- });
- }
+ let element = document.querySelector("#wrapped") as HTMLElement;
+
+ if (element !== null) {
+ domToBlob(element, {
+ backgroundColor: transparency
+ ? "transparent"
+ : lightTheme
+ ? "#edf1f5"
+ : "#0b1622",
+ quality: 1,
+ scale: 2,
+ fetch: {
+ requestInit: {
+ mode: "cors",
+ },
+ bypassingCache: true,
+ },
+ }).then((blob) => {
+ const downloadWrapper = document.createElement("a");
+ // const wrappedImageButton = document.getElementById(
+ // 'wrapped-image-download'
+ // ) as HTMLAnchorElement;
+ const image = document.createElement("img");
+ const object = (
+ window.URL ||
+ window.webkitURL ||
+ window ||
+ {}
+ ).createObjectURL(blob);
+
+ // downloadWrapper.download = `due_dot_moe_wrapped_${dark ? 'dark' : 'light'}.png`;
+ downloadWrapper.href = object;
+ downloadWrapper.target = "_blank";
+ image.src = object;
+
+ downloadWrapper.appendChild(image);
+
+ // if (wrappedImageButton !== null) {
+ // wrappedImageButton.href = object;
+ // }
+
+ const wrappedFinal = document.getElementById("wrapped-final");
+
+ if (wrappedFinal !== null) {
+ wrappedFinal.innerHTML = "";
+
+ wrappedFinal.appendChild(downloadWrapper);
+
+ generated = true;
+ }
+
+ downloadWrapper.click();
+ });
+ }
};
// const abbreviate = (string: string, maxLength = 40, enabled = true) => {
@@ -669,38 +756,46 @@ const screenshot = async () => {
// };
const submitExcludedKeywords = () => {
- if (excludedKeywordsInput.length <= 0 && excludedKeywords.length > 0) {
- animeList = originalAnimeList;
- mangaList = originalMangaList;
- excludedKeywords = [];
- } else if (excludedKeywordsInput.length >= 0 && excludedKeywords.length <= 0) {
- originalAnimeList = animeList;
- originalMangaList = mangaList;
- }
-
- if (excludedKeywordsInput.length > 0)
- excludedKeywords = excludedKeywordsInput
- .split(',')
- .map((k) => k.trim())
- .filter((k) => k.length > 0);
+ if (excludedKeywordsInput.length <= 0 && excludedKeywords.length > 0) {
+ animeList = originalAnimeList;
+ mangaList = originalMangaList;
+ excludedKeywords = [];
+ } else if (
+ excludedKeywordsInput.length >= 0 &&
+ excludedKeywords.length <= 0
+ ) {
+ originalAnimeList = animeList;
+ originalMangaList = mangaList;
+ }
+
+ if (excludedKeywordsInput.length > 0)
+ excludedKeywords = excludedKeywordsInput
+ .split(",")
+ .map((k) => k.trim())
+ .filter((k) => k.length > 0);
};
function excludeKeywords(media: Media[]) {
- if (excludedKeywords.length <= 0) return media;
-
- return media.filter((m) => {
- for (const keyword of excludedKeywords) {
- if (m.title.english?.toLowerCase().includes(keyword.toLowerCase())) return false;
- if (m.title.romaji?.toLowerCase().includes(keyword.toLowerCase())) return false;
- if (m.title.native?.toLowerCase().includes(keyword.toLowerCase())) return false;
- }
-
- return true;
- });
+ if (excludedKeywords.length <= 0) return media;
+
+ return media.filter((m) => {
+ for (const keyword of excludedKeywords) {
+ if (m.title.english?.toLowerCase().includes(keyword.toLowerCase()))
+ return false;
+ if (m.title.romaji?.toLowerCase().includes(keyword.toLowerCase()))
+ return false;
+ if (m.title.native?.toLowerCase().includes(keyword.toLowerCase()))
+ return false;
+ }
+
+ return true;
+ });
}
const pruneFullYear = async () => {
- await database.activities.bulkDelete((await database.activities.toArray()).map((m) => m.page));
+ await database.activities.bulkDelete(
+ (await database.activities.toArray()).map((m) => m.page),
+ );
};
// const mergeArraySort = (a: any, b: any, mode: 'tags' | 'genres') => {
diff --git a/src/lib/Tools/Wrapped/Top/Activity.svelte b/src/lib/Tools/Wrapped/Top/Activity.svelte
index fdfd90e0..ce0b1b00 100644
--- a/src/lib/Tools/Wrapped/Top/Activity.svelte
+++ b/src/lib/Tools/Wrapped/Top/Activity.svelte
@@ -1,8 +1,8 @@
<script lang="ts">
-import type { ActivityHistoryEntry } from '$lib/Data/AniList/activity';
-import identity from '$stores/identity';
-import type { Wrapped } from '$lib/Data/AniList/wrapped';
-import proxy from '$lib/Utility/proxy';
+import type { ActivityHistoryEntry } from "$lib/Data/AniList/activity";
+import identity from "$stores/identity";
+import type { Wrapped } from "$lib/Data/AniList/wrapped";
+import proxy from "$lib/Utility/proxy";
export let wrapped: Wrapped;
export let year: number;
diff --git a/src/lib/Tools/Wrapped/Top/Anime.svelte b/src/lib/Tools/Wrapped/Top/Anime.svelte
index 6caf4b8a..60ad9f52 100644
--- a/src/lib/Tools/Wrapped/Top/Anime.svelte
+++ b/src/lib/Tools/Wrapped/Top/Anime.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
-import type { Media } from '$lib/Data/AniList/media';
+import type { Media } from "$lib/Data/AniList/media";
export let minutesWatched: number;
export let animeList: Media[] | undefined;
diff --git a/src/lib/Tools/Wrapped/Top/Manga.svelte b/src/lib/Tools/Wrapped/Top/Manga.svelte
index 9fa4ab00..2861b5e4 100644
--- a/src/lib/Tools/Wrapped/Top/Manga.svelte
+++ b/src/lib/Tools/Wrapped/Top/Manga.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
-import type { Media } from '$lib/Data/AniList/media';
-import { estimatedDayReading } from '$lib/Media/Manga/time';
+import type { Media } from "$lib/Data/AniList/media";
+import { estimatedDayReading } from "$lib/Media/Manga/time";
export let mangaList: Media[] | undefined;
export let chapters: number;
diff --git a/src/lib/Tools/Wrapped/wrapped.css b/src/lib/Tools/Wrapped/wrapped.css
index 72ea09fc..e965f873 100644
--- a/src/lib/Tools/Wrapped/wrapped.css
+++ b/src/lib/Tools/Wrapped/wrapped.css
@@ -2,129 +2,129 @@
@import url("https://proxy.due.moe/?q=https://fonts.googleapis.com/css?family=Overpass:400,600,700,800");
.categories-grid {
- display: flex;
- flex-wrap: wrap;
- row-gap: 1.5em;
- column-gap: 1.5em;
- padding: 2%;
- justify-content: center;
- font-family:
- Roboto,
- -apple-system,
- BlinkMacSystemFont,
- Segoe UI,
- Oxygen,
- Ubuntu,
- Cantarell,
- Fira Sans,
- Droid Sans,
- Helvetica Neue,
- sans-serif;
- background-color: #0b1622;
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 1.5em;
+ column-gap: 1.5em;
+ padding: 2%;
+ justify-content: center;
+ font-family:
+ Roboto,
+ -apple-system,
+ BlinkMacSystemFont,
+ Segoe UI,
+ Oxygen,
+ Ubuntu,
+ Cantarell,
+ Fira Sans,
+ Droid Sans,
+ Helvetica Neue,
+ sans-serif;
+ background-color: #0b1622;
}
.categories-grid b {
- font-family:
- Overpass,
- -apple-system,
- BlinkMacSystemFont,
- Segoe UI,
- Oxygen,
- Ubuntu,
- Cantarell,
- Fira Sans,
- Droid Sans,
- Helvetica Neue,
- sans-serif;
- font-weight: 600;
+ font-family:
+ Overpass,
+ -apple-system,
+ BlinkMacSystemFont,
+ Segoe UI,
+ Oxygen,
+ Ubuntu,
+ Cantarell,
+ Fira Sans,
+ Droid Sans,
+ Helvetica Neue,
+ sans-serif;
+ font-weight: 600;
}
.category-grid,
.image-grid {
- background-color: #151f2e;
- border-radius: 4px;
- color: rgb(159, 173, 189);
+ background-color: #151f2e;
+ border-radius: 4px;
+ color: rgb(159, 173, 189);
}
li::marker {
- color: rgb(159, 173, 189) !important;
+ color: rgb(159, 173, 189) !important;
}
.pure-category,
.avatar-grid {
- padding: 1.5%;
+ padding: 1.5%;
}
.category-grid {
- display: grid;
+ display: grid;
}
.image-grid {
- display: flex;
- column-gap: 1em;
- flex-wrap: wrap;
+ display: flex;
+ column-gap: 1em;
+ flex-wrap: wrap;
}
.image-grid img {
- width: 6em;
- height: auto;
- border-radius: 3px;
+ width: 6em;
+ height: auto;
+ border-radius: 3px;
}
.categories-grid a {
- text-decoration: none;
- color: unset;
+ text-decoration: none;
+ color: unset;
}
.transparent .categories-grid {
- background-color: transparent !important;
+ background-color: transparent !important;
}
.light-theme .categories-grid {
- background-color: #edf1f5;
+ background-color: #edf1f5;
}
.light-theme .category-grid {
- background-color: #fafafa;
- color: rgb(92, 114, 138);
+ background-color: #fafafa;
+ color: rgb(92, 114, 138);
}
.light-theme .image-grid {
- background-color: #fafafa;
- color: rgb(92, 114, 138);
+ background-color: #fafafa;
+ color: rgb(92, 114, 138);
}
ol {
- margin: 0 !important;
+ margin: 0 !important;
}
#watermark {
- color: rgb(61, 180, 242);
+ color: rgb(61, 180, 242);
}
#wrapped-final {
- height: auto;
- width: 50%;
+ height: auto;
+ width: 50%;
}
#list-container {
- display: flex;
- gap: 1rem;
- flex-wrap: wrap;
- align-items: start;
+ display: flex;
+ gap: 1rem;
+ flex-wrap: wrap;
+ align-items: start;
}
#list-container > .card {
- overflow-x: auto;
- min-width: 0;
+ overflow-x: auto;
+ min-width: 0;
}
.list {
- flex-grow: 1;
- flex-basis: 1%;
- min-width: 0;
+ flex-grow: 1;
+ flex-basis: 1%;
+ min-width: 0;
}
#wrapped {
- overflow-y: scroll;
+ overflow-y: scroll;
}
diff --git a/src/lib/Tools/tools.ts b/src/lib/Tools/tools.ts
index c5af7e34..cc11050b 100644
--- a/src/lib/Tools/tools.ts
+++ b/src/lib/Tools/tools.ts
@@ -1,116 +1,119 @@
-import type { CommandPaletteAction } from '$lib/CommandPalette/actions';
-import locale from '$stores/locale';
-import { get } from 'svelte/store';
+import type { CommandPaletteAction } from "$lib/CommandPalette/actions";
+import locale from "$stores/locale";
+import { get } from "svelte/store";
export const toolsAsCommandPaletteActions = (): CommandPaletteAction[] =>
- Object.entries(tools)
- .filter(([id, tool]) => id !== 'default' && !tool.hidden)
- .map(([id, tool]) => ({
- name: tool.name(),
- url: `/tools/${id}`
- }));
+ Object.entries(tools)
+ .filter(([id, tool]) => id !== "default" && !tool.hidden)
+ .map(([id, tool]) => ({
+ name: tool.name(),
+ url: `/tools/${id}`,
+ }));
export const tools: {
- [key: string]: {
- name: () => string;
- short?: string;
- description?: () => string;
- id: string;
- hidden?: boolean;
- };
+ [key: string]: {
+ name: () => string;
+ short?: string;
+ description?: () => string;
+ id: string;
+ hidden?: boolean;
+ };
} = {
- default: {
- name: () => 'Tools',
- description: () => 'A collection of tools to help you get the most out of AniList.',
- id: 'default'
- },
- wrapped: {
- name: () => 'AniList Wrapped & Statistics Panel',
- short: 'AniList Wrapped',
- description: () =>
- 'Instantly generate an AniList themed Wrapped for your profile, doubling as a statistics panel for your bio',
- id: 'wrapped'
- },
- birthdays: {
- name: () => {
- return get(locale)().tools.tool.characterBirthdays.long;
- },
- description: () =>
- 'Find and display the birthdays of all characters for today, or any other day of the year',
- id: 'birthdays'
- },
- sequel_spy: {
- name: () => 'Sequel Spy',
- description: () =>
- "Find media with prequels you haven't seen yet for any given simulcast season",
- id: 'sequel_spy'
- },
- tracker: {
- name: () => 'Tracker',
- description: () =>
- "Track your anime and manga progress with ease, intended for media that doesn't qualify for an AniList entry",
- id: 'tracker',
- hidden: true
- },
- uma_musume_birthdays: {
- name: () => {
- return 'Uma Musume: Pretty Derby Character Birthdays';
- },
- description: () =>
- 'Find and display the birthdays of all Uma Musume characters for today, or any other day of the year',
- id: 'uma_musume_birthdays'
- },
- hololive_birthdays: {
- name: () => 'hololive Birthdays',
- description: () =>
- 'Find and display the birthdays of all hololive talents for today, or any other day of the year',
- id: 'hololive_birthdays'
- },
- nijisanji_birthdays: {
- name: () => 'NIJISANJI Birthdays',
- description: () =>
- 'Find and display the birthdays of all NIJISANJI talents for today, or any other day of the year',
- id: 'nijisanji_birthdays'
- },
- hayai: {
- name: () => '早い',
- description: () => 'Read light novels at 1.5x speed!',
- id: 'hayai'
- },
- discussions: {
- name: () => 'Episode Discussion Collector',
- description: () => 'Find and display all episode discussions created by a given user',
- id: 'discussions'
- },
- random_follower: {
- name: () => 'Random Follower Finder',
- description: () => "Generate random followers from any user's following list",
- id: 'random_follower'
- },
- // dump_profile: {
- // name: () => 'Dump Profile',
- // description: () => "Dump a user's profile to JSON",
- // id: 'dump_profile'
- // },
- likes: {
- name: () => 'Likes',
- description: () => 'Get all likes of an activity or forum thread',
- id: 'likes'
- },
- activity_history: {
- name: () => 'Activity History Analyser',
- id: 'activity_history',
- description: () => 'Activity history utilities & image exporter'
- },
- girls: {
- name: () => 'Anime Girls Holding Programming Books',
- id: 'girls',
- description: () => 'Find anime girls holding programming books by language'
- },
- sequel_catcher: {
- name: () => 'Sequel Catcher',
- description: () =>
- 'Check if any completed anime on your lists have sequels you have not yet seen',
- id: 'sequel_catcher'
- }
+ default: {
+ name: () => "Tools",
+ description: () =>
+ "A collection of tools to help you get the most out of AniList.",
+ id: "default",
+ },
+ wrapped: {
+ name: () => "AniList Wrapped & Statistics Panel",
+ short: "AniList Wrapped",
+ description: () =>
+ "Instantly generate an AniList themed Wrapped for your profile, doubling as a statistics panel for your bio",
+ id: "wrapped",
+ },
+ birthdays: {
+ name: () => {
+ return get(locale)().tools.tool.characterBirthdays.long;
+ },
+ description: () =>
+ "Find and display the birthdays of all characters for today, or any other day of the year",
+ id: "birthdays",
+ },
+ sequel_spy: {
+ name: () => "Sequel Spy",
+ description: () =>
+ "Find media with prequels you haven't seen yet for any given simulcast season",
+ id: "sequel_spy",
+ },
+ tracker: {
+ name: () => "Tracker",
+ description: () =>
+ "Track your anime and manga progress with ease, intended for media that doesn't qualify for an AniList entry",
+ id: "tracker",
+ hidden: true,
+ },
+ uma_musume_birthdays: {
+ name: () => {
+ return "Uma Musume: Pretty Derby Character Birthdays";
+ },
+ description: () =>
+ "Find and display the birthdays of all Uma Musume characters for today, or any other day of the year",
+ id: "uma_musume_birthdays",
+ },
+ hololive_birthdays: {
+ name: () => "hololive Birthdays",
+ description: () =>
+ "Find and display the birthdays of all hololive talents for today, or any other day of the year",
+ id: "hololive_birthdays",
+ },
+ nijisanji_birthdays: {
+ name: () => "NIJISANJI Birthdays",
+ description: () =>
+ "Find and display the birthdays of all NIJISANJI talents for today, or any other day of the year",
+ id: "nijisanji_birthdays",
+ },
+ hayai: {
+ name: () => "早い",
+ description: () => "Read light novels at 1.5x speed!",
+ id: "hayai",
+ },
+ discussions: {
+ name: () => "Episode Discussion Collector",
+ description: () =>
+ "Find and display all episode discussions created by a given user",
+ id: "discussions",
+ },
+ random_follower: {
+ name: () => "Random Follower Finder",
+ description: () =>
+ "Generate random followers from any user's following list",
+ id: "random_follower",
+ },
+ // dump_profile: {
+ // name: () => 'Dump Profile',
+ // description: () => "Dump a user's profile to JSON",
+ // id: 'dump_profile'
+ // },
+ likes: {
+ name: () => "Likes",
+ description: () => "Get all likes of an activity or forum thread",
+ id: "likes",
+ },
+ activity_history: {
+ name: () => "Activity History Analyser",
+ id: "activity_history",
+ description: () => "Activity history utilities & image exporter",
+ },
+ girls: {
+ name: () => "Anime Girls Holding Programming Books",
+ id: "girls",
+ description: () => "Find anime girls holding programming books by language",
+ },
+ sequel_catcher: {
+ name: () => "Sequel Catcher",
+ description: () =>
+ "Check if any completed anime on your lists have sequels you have not yet seen",
+ id: "sequel_catcher",
+ },
};