diff options
| author | Fuwn <[email protected]> | 2026-03-01 16:20:51 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-03-01 16:21:02 -0800 |
| commit | eae5d24d9e79e59a19d4721caaeaa0ca650ecb33 (patch) | |
| tree | 1b685bb248e051dfa26d2bfdebe6689402dd93c5 /src/lib/Tools | |
| parent | chore(tooling): remove legacy eslint and prettier (diff) | |
| download | due.moe-eae5d24d9e79e59a19d4721caaeaa0ca650ecb33.tar.xz due.moe-eae5d24d9e79e59a19d4721caaeaa0ca650ecb33.zip | |
chore(biome): drop formatter style overrides
Diffstat (limited to 'src/lib/Tools')
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", + }, }; |