diff options
| author | Fuwn <[email protected]> | 2026-03-01 16:04:11 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-03-01 16:04:11 -0800 |
| commit | 48f0c30d47d62e4f35706edb93a1bb2f97eba14c (patch) | |
| tree | 44866d7a61adfdf01a780e0108c370294d3db78b /src/lib/Tools | |
| parent | chore(biome): re-enable useAltText rule (diff) | |
| download | due.moe-48f0c30d47d62e4f35706edb93a1bb2f97eba14c.tar.xz due.moe-48f0c30d47d62e4f35706edb93a1bb2f97eba14c.zip | |
chore(biome): enable svelte formatting
Diffstat (limited to 'src/lib/Tools')
26 files changed, 1260 insertions, 1285 deletions
diff --git a/src/lib/Tools/ActivityHistory/Grid.svelte b/src/lib/Tools/ActivityHistory/Grid.svelte index b693f912..84c182fa 100644 --- a/src/lib/Tools/ActivityHistory/Grid.svelte +++ b/src/lib/Tools/ActivityHistory/Grid.svelte @@ -1,35 +1,35 @@ <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'; +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'; - export let user: AniListAuthorisation; - export let activityData: ActivityHistoryEntry[] | null = null; - export let currentYear = new Date().getFullYear(); +export let user: AniListAuthorisation; +export let activityData: ActivityHistoryEntry[] | null = null; +export let currentYear = new Date().getFullYear(); - let activityHistoryData: ActivityHistoryEntry[]; - let baseHue = Math.floor(Math.random() * 360); +let activityHistoryData: ActivityHistoryEntry[]; +let baseHue = Math.floor(Math.random() * 360); - onMount(async () => { - clearAllParameters(); +onMount(async () => { + 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 gradientColour = (amount: number, maxAmount: number, baseHue: number) => { + const lightness = 100 - Math.round((amount / maxAmount) * 50); - return `hsl(${baseHue}, 100%, ${lightness}%)`; - }; + return `hsl(${baseHue}, 100%, ${lightness}%)`; +}; </script> {#if user === undefined} diff --git a/src/lib/Tools/ActivityHistory/Tool.svelte b/src/lib/Tools/ActivityHistory/Tool.svelte index 6f6282a6..06924b22 100644 --- a/src/lib/Tools/ActivityHistory/Tool.svelte +++ b/src/lib/Tools/ActivityHistory/Tool.svelte @@ -1,69 +1,69 @@ <script lang="ts"> - 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'; - - export let user: AniListAuthorisation; - - let activityHistoryData: Promise<ActivityHistoryEntry[]>; - let generated = false; - - onMount(async () => { - clearAllParameters(); - - if (user !== undefined) activityHistoryData = activityHistory($userIdentity); - }); - - // const incrementDate = (date: Date): Date => { - // date.setDate(date.getDate() + 1); - - // return date; - // }; - - const screenshot = async () => { - 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); - - downloadWrapper.href = object; - downloadWrapper.target = '_blank'; - image.src = object; - - downloadWrapper.appendChild(image); - - const gridFinal = document.getElementById('grid-final'); - - if (gridFinal !== null) { - gridFinal.innerHTML = ''; - - gridFinal.appendChild(downloadWrapper); - - generated = true; - } - - downloadWrapper.click(); - }); - } - }; +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'; + +export let user: AniListAuthorisation; + +let activityHistoryData: Promise<ActivityHistoryEntry[]>; +let generated = false; + +onMount(async () => { + clearAllParameters(); + + if (user !== undefined) activityHistoryData = activityHistory($userIdentity); +}); + +// const incrementDate = (date: Date): Date => { +// date.setDate(date.getDate() + 1); + +// return date; +// }; + +const screenshot = async () => { + 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); + + downloadWrapper.href = object; + downloadWrapper.target = '_blank'; + image.src = object; + + downloadWrapper.appendChild(image); + + const gridFinal = document.getElementById('grid-final'); + + if (gridFinal !== null) { + gridFinal.innerHTML = ''; + + gridFinal.appendChild(downloadWrapper); + + generated = true; + } + + downloadWrapper.click(); + }); + } +}; </script> {#if user === undefined} diff --git a/src/lib/Tools/Birthdays.svelte b/src/lib/Tools/Birthdays.svelte index e6654833..6c81a233 100644 --- a/src/lib/Tools/Birthdays.svelte +++ b/src/lib/Tools/Birthdays.svelte @@ -1,111 +1,111 @@ <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 Error 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; +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 Error 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; +} + +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 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()}`); } +} - 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 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()}`); - } - } +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 fixName = (name: string): string => { - 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[] +): Birthday[] => { + const nameMap = new Map<string, Birthday>(); - const combineBirthdaySources = ( - 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)); + 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 + }); + } - if (!nameMap.has(normalisedName)) - nameMap.set(normalisedName, { - name: entry.name, - image: entry.character_image, - origin: entry.origin - }); - } + for (const entry of acdb) { + const normalisedName = normaliseName(fixName(entry.name)); - return Array.from(nameMap.values()); - }; + if (!nameMap.has(normalisedName)) + nameMap.set(normalisedName, { + name: entry.name, + image: entry.character_image, + origin: entry.origin + }); + } - const resolveBirthdays = async ( - 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' - }; + return Array.from(nameMap.values()); +}; + +const resolveBirthdays = async ( + 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' }; +}; </script> {#await birthdays} diff --git a/src/lib/Tools/BirthdaysTemplate.svelte b/src/lib/Tools/BirthdaysTemplate.svelte index 5f476275..0ec937c4 100644 --- a/src/lib/Tools/BirthdaysTemplate.svelte +++ b/src/lib/Tools/BirthdaysTemplate.svelte @@ -1,36 +1,36 @@ <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 Error 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 Error from '$lib/Error/RateLimited.svelte'; +import Skeleton from '$lib/Loading/Skeleton.svelte'; - export let remoteURL: string; +export let remoteURL: string; - 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()); - const remoteBirthdays = fetch(remoteURL); +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()); +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 717814d2..a111028c 100644 --- a/src/lib/Tools/DumpProfile.svelte +++ b/src/lib/Tools/DumpProfile.svelte @@ -1,30 +1,30 @@ <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'; - - let submission = ''; - - // Credit: @hoh - const decodeJSON = (about: string): JSON | null => { - const match = (about || '').match(/^\[\]\(json([A-Za-z0-9+/=]+)\)/); - - if (match) +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 = ''; + +// 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(atob(match[1])); + return JSON.parse(LZString.decompressFromBase64(match[1])); } catch { - try { - return JSON.parse(LZString.decompressFromBase64(match[1])); - } catch { - return null; - } + return null; } + } - return null; - }; + return null; +}; </script> <InputTemplate field="Username" bind:submission event="Dump User" submitText="Dump"> diff --git a/src/lib/Tools/EpisodeDiscussionCollector.svelte b/src/lib/Tools/EpisodeDiscussionCollector.svelte index 71e13add..99c53f20 100644 --- a/src/lib/Tools/EpisodeDiscussionCollector.svelte +++ b/src/lib/Tools/EpisodeDiscussionCollector.svelte @@ -1,15 +1,15 @@ <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); +onMount(clearAllParameters); </script> <InputTemplate diff --git a/src/lib/Tools/FollowFix.svelte b/src/lib/Tools/FollowFix.svelte index 62548379..a0e9902a 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; +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 1ba99d86..aa1112da 100644 --- a/src/lib/Tools/Hayai.svelte +++ b/src/lib/Tools/Hayai.svelte @@ -1,83 +1,83 @@ <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; +let fileInput: HTMLInputElement | null = null; - const handleFileUpload = async () => { - if (!fileInput || !fileInput.files || fileInput.files.length === 0) return; +const handleFileUpload = async () => { + if (!fileInput || !fileInput.files || fileInput.files.length === 0) return; - const file = fileInput.files[0]; - const reader = new FileReader(); + 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(); + 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]; + 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')); - } + 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); + downloadEPUB( + await newZip.generateAsync({ type: 'blob' }), + `${file.name.split('.epub')[0]}_hayai.epub` + ); }; - const applyBionicReadingToHTML = (content: string) => { - const contentParser = new DOMParser().parseFromString(content, 'text/html'); + reader.readAsArrayBuffer(file); +}; - for (const paragraph of contentParser.getElementsByTagName('p')) - paragraph.innerHTML = applyBionicReadingToString(paragraph.textContent ?? ''); +const applyBionicReadingToHTML = (content: string) => { + const contentParser = new DOMParser().parseFromString(content, 'text/html'); - return contentParser.documentElement.outerHTML; - }; + for (const paragraph of contentParser.getElementsByTagName('p')) + paragraph.innerHTML = applyBionicReadingToString(paragraph.textContent ?? ''); - const applyBionicReadingToString = (text: string) => - text - .split(/\s+/) - .map((word) => { - if (/^\W+$/.test(word) || word.length <= 2) return word; + return contentParser.documentElement.outerHTML; +}; - let boldLength; +const applyBionicReadingToString = (text: string) => + text + .split(/\s+/) + .map((word) => { + if (/^\W+$/.test(word) || word.length <= 2) return word; - 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); - } + let boldLength; - return `<strong>${word.slice(0, boldLength)}</strong>${word.slice(boldLength)}`; - }) - .join(' '); + 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); + } - const downloadEPUB = (blob: Blob | MediaSource, fileName: string) => { - const link = document.createElement('a'); + return `<strong>${word.slice(0, boldLength)}</strong>${word.slice(boldLength)}`; + }) + .join(' '); - link.href = URL.createObjectURL(blob); - link.download = fileName; +const downloadEPUB = (blob: Blob | MediaSource, fileName: string) => { + const link = document.createElement('a'); - link.click(); - URL.revokeObjectURL(link.href); - }; + link.href = URL.createObjectURL(blob); + link.download = fileName; + + 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 48913646..af77b296 100644 --- a/src/lib/Tools/InputTemplate.svelte +++ b/src/lib/Tools/InputTemplate.svelte @@ -1,26 +1,26 @@ <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; - export let event: string | undefined = undefined; - export let submitText: string; - export let saveParameters: string[] = []; - export let onSubmit = () => { - return; - }; - export let preserveCase = false; - export let prompt = `Enter a ${ - preserveCase ? field : field.toLowerCase() - } to search for to continue.`; - export let hint: string | undefined = undefined; +export let field: string; +export let submission: string; +export let event: string | undefined = undefined; +export let submitText: string; +export let saveParameters: string[] = []; +export let onSubmit = () => { + return; +}; +export let preserveCase = false; +export let prompt = `Enter a ${ + preserveCase ? field : field.toLowerCase() +} to search for to continue.`; +export let hint: string | undefined = undefined; - let input = ''; +let input = ''; - onMount(() => clearAllParameters(saveParameters)); +onMount(() => clearAllParameters(saveParameters)); </script> <div class="card"> diff --git a/src/lib/Tools/Likes.svelte b/src/lib/Tools/Likes.svelte index 46d1edaf..d8545c39 100644 --- a/src/lib/Tools/Likes.svelte +++ b/src/lib/Tools/Likes.svelte @@ -1,22 +1,22 @@ <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'); - $: likesPromise = - submissionType === 'activity' - ? activityLikes(Number(normalisedSubmission)) - : submissionType === 'thread' - ? threadLikes(Number(normalisedSubmission)) - : Promise.resolve(null); +$: 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); </script> <InputTemplate diff --git a/src/lib/Tools/Picker.svelte b/src/lib/Tools/Picker.svelte index dab74599..df11eef5 100644 --- a/src/lib/Tools/Picker.svelte +++ b/src/lib/Tools/Picker.svelte @@ -1,10 +1,10 @@ <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; +export let tool: string; </script> <blockquote> diff --git a/src/lib/Tools/RandomFollower.svelte b/src/lib/Tools/RandomFollower.svelte index 34a9b48e..628f1b35 100644 --- a/src/lib/Tools/RandomFollower.svelte +++ b/src/lib/Tools/RandomFollower.svelte @@ -1,13 +1,13 @@ <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 randomSeed = 0; +let submission = ''; +let randomSeed = 0; </script> <InputTemplate diff --git a/src/lib/Tools/SequelCatcher/List.svelte b/src/lib/Tools/SequelCatcher/List.svelte index a7e03ed0..79e28703 100644 --- a/src/lib/Tools/SequelCatcher/List.svelte +++ b/src/lib/Tools/SequelCatcher/List.svelte @@ -1,28 +1,28 @@ <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[]; +export let mediaListUnchecked: Media[]; - let includeCurrent = false; - let includeSideStories = false; +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; +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; </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 05227ac4..01742d6f 100644 --- a/src/lib/Tools/SequelCatcher/Tool.svelte +++ b/src/lib/Tools/SequelCatcher/Tool.svelte @@ -1,39 +1,32 @@ <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; +export let user: AniListAuthorisation; - let mediaList: Promise<Media[]>; +let mediaList: Promise<Media[]>; - onMount(async () => { - if (user === undefined || $identity.id === -2) return; +onMount(async () => { + 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> {#if user === undefined || $identity.id === -2} diff --git a/src/lib/Tools/SequelSpy/Prequels.svelte b/src/lib/Tools/SequelSpy/Prequels.svelte index b22db3af..5929821e 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[]; +export let currentPrequels: MediaPrequel[]; - const prequelAiringTime = (prequel: MediaPrequel) => - airingTime(prequel as unknown as Media, null, false, true); +const prequelAiringTime = (prequel: MediaPrequel) => + 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 998cab13..0a862984 100644 --- a/src/lib/Tools/SequelSpy/Tool.svelte +++ b/src/lib/Tools/SequelSpy/Tool.svelte @@ -1,38 +1,38 @@ <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'; - - 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()); - - $: { - 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()}`); - } +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()); + +$: { + 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()}`); } +} - 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 a3705fbe..1849cbb1 100644 --- a/src/lib/Tools/Tracker/Tool.svelte +++ b/src/lib/Tools/Tracker/Tool.svelte @@ -1,70 +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'; +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 masterList: TrackerEntry[] | null = null; - let confirmDelete = 0; +let url = ''; +let title = ''; +let progress = 0; +let error = ''; +let masterList: TrackerEntry[] | null = null; +let confirmDelete = 0; - $: listAccess = masterList || []; +$: listAccess = masterList || []; - onMount(async () => { - masterList = await database.entries.toArray(); - }); +onMount(async () => { + masterList = await database.entries.toArray(); +}); - const adjustEntry = (id: string, to: number) => { - const entry = listAccess.find((entry) => entry.id === id); +const adjustEntry = (id: string, to: number) => { + 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'; +const addEntry = async (url: string, title: string, progress: number) => { + 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'; +const deleteEntry = async (id: string) => { + 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> <div class="card"> diff --git a/src/lib/Tools/UmaMusumeBirthdays.svelte b/src/lib/Tools/UmaMusumeBirthdays.svelte index 8ee6697b..cc8c1513 100644 --- a/src/lib/Tools/UmaMusumeBirthdays.svelte +++ b/src/lib/Tools/UmaMusumeBirthdays.svelte @@ -1,51 +1,51 @@ <script lang="ts"> - import { browser } from '$app/environment'; - import { page } from '$app/stores'; - import Error 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 Error 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; - } +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; +} - 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 umapyoi: Promise<Birthday[]>; +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 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']); +onMount(() => { + 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> {#await umapyoi} diff --git a/src/lib/Tools/Wrapped/ActivityHistory.svelte b/src/lib/Tools/Wrapped/ActivityHistory.svelte index 3da401d4..f1f1a28a 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 user: AniListAuthorisation; +export let activities: ActivityHistoryEntry[]; +export let year: number; +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 9c99b4a4..6063f349 100644 --- a/src/lib/Tools/Wrapped/DataLoader.svelte +++ b/src/lib/Tools/Wrapped/DataLoader.svelte @@ -1,7 +1,7 @@ <script lang="ts"> - import { onMount } from 'svelte'; +import { onMount } from 'svelte'; - export let onLoad: () => void; +export let onLoad: () => void; - onMount(() => onLoad()); +onMount(() => onLoad()); </script> diff --git a/src/lib/Tools/Wrapped/Media.svelte b/src/lib/Tools/Wrapped/Media.svelte index 90e0cde3..bbd7ee5b 100644 --- a/src/lib/Tools/Wrapped/Media.svelte +++ b/src/lib/Tools/Wrapped/Media.svelte @@ -1,17 +1,17 @@ <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; - export let wrapped: Wrapped; - export let updateWidth: () => void; - export let highestRatedMediaPercentage: boolean; - export let highestRatedCount: number; - export let animeMostTitle: string; - export let mangaMostTitle: string; +export let animeList: Media[] | undefined; +export let mangaList: Media[] | undefined; +export let wrapped: Wrapped; +export let updateWidth: () => void; +export let highestRatedMediaPercentage: boolean; +export let highestRatedCount: number; +export let animeMostTitle: string; +export let mangaMostTitle: string; </script> {#if animeList !== undefined || mangaList !== undefined} diff --git a/src/lib/Tools/Wrapped/MediaExtras.svelte b/src/lib/Tools/Wrapped/MediaExtras.svelte index 78b89e36..d9dc8efb 100644 --- a/src/lib/Tools/Wrapped/MediaExtras.svelte +++ b/src/lib/Tools/Wrapped/MediaExtras.svelte @@ -1,11 +1,11 @@ <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; - export let highestRatedGenreTagPercentage: boolean; - export let genreTagTitle: string; +export let topMedia: TopMedia; +export let updateWidth: () => void; +export let highestRatedGenreTagPercentage: boolean; +export let genreTagTitle: string; </script> <div class="categories-grid" style="padding-top: 0;"> diff --git a/src/lib/Tools/Wrapped/Tool.svelte b/src/lib/Tools/Wrapped/Tool.svelte index 3985b4c0..3f13b483 100644 --- a/src/lib/Tools/Wrapped/Tool.svelte +++ b/src/lib/Tools/Wrapped/Tool.svelte @@ -1,748 +1,730 @@ <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 { - 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 Error 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; - - const currentYear = new Date(Date.now()).getFullYear(); - let selectedYear = new Date(Date.now()).getFullYear(); - let episodes = 0; - let chapters = 0; - let minutesWatched = 0; - let animeList: Media[] | undefined = undefined; - let mangaList: Media[] | undefined = undefined; - let calculatedAnimeList: Media[] | undefined = undefined; - let calculatedMangaList: Media[] | undefined = undefined; - let originalAnimeList: Media[] | undefined = undefined; - let originalMangaList: Media[] | undefined = undefined; - let transparency = false; - let lightTheme = true; - let watermark = false; - let includeMusic = false; - let includeSpecials = true; - let includeRepeats = false; - let width = 1920; - let lightMode = false; - let highestRatedCount = 5; - let genreTagCount = 5; - let mounted = false; - let generated = false; - let disableActivityHistory = true; - let excludedKeywordsInput = ''; - let excludedKeywords: string[] = []; - let useFullActivityHistory = false; - let disableLoopingActivityCounter = false; - let topGenresTags = true; - let topMedia: TopMedia; - let highestRatedMediaPercentage = true; - let highestRatedGenreTagPercentage = true; - let genreTagsSort = SortOptions.SCORE; - let mediaSort = SortOptions.SCORE; - let includeMovies = true; - let includeOVAs = true; - let activityHistoryPosition: 'TOP' | 'BELOW_TOP' | 'ORIGINAL' = 'ORIGINAL'; - let includeOngoingMediaFromPreviousYears = false; - let excludeUnratedUnwatched = true; - let startDateFilter: Date | null = null; - let endDateFilter: Date | null = null; - let dateTicked = false; - let shouldFetchData = false; - let needsRefetch = false; - let dataFetched = false; - let fetchKey = 0; - let lastSelectedYear = selectedYear; - let lastUseFullActivityHistory = useFullActivityHistory; - let lastDisableLoopingActivityCounter = disableLoopingActivityCounter; - let lastStartDateFilter: Date | null = startDateFilter; - let lastEndDateFilter: Date | null = endDateFilter; - - $: { - 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()}`); - } - } +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 { + 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 Error 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; + +const currentYear = new Date(Date.now()).getFullYear(); +let selectedYear = new Date(Date.now()).getFullYear(); +let episodes = 0; +let chapters = 0; +let minutesWatched = 0; +let animeList: Media[] | undefined = undefined; +let mangaList: Media[] | undefined = undefined; +let calculatedAnimeList: Media[] | undefined = undefined; +let calculatedMangaList: Media[] | undefined = undefined; +let originalAnimeList: Media[] | undefined = undefined; +let originalMangaList: Media[] | undefined = undefined; +let transparency = false; +let lightTheme = true; +let watermark = false; +let includeMusic = false; +let includeSpecials = true; +let includeRepeats = false; +let width = 1920; +let lightMode = false; +let highestRatedCount = 5; +let genreTagCount = 5; +let mounted = false; +let generated = false; +let disableActivityHistory = true; +let excludedKeywordsInput = ''; +let excludedKeywords: string[] = []; +let useFullActivityHistory = false; +let disableLoopingActivityCounter = false; +let topGenresTags = true; +let topMedia: TopMedia; +let highestRatedMediaPercentage = true; +let highestRatedGenreTagPercentage = true; +let genreTagsSort = SortOptions.SCORE; +let mediaSort = SortOptions.SCORE; +let includeMovies = true; +let includeOVAs = true; +let activityHistoryPosition: 'TOP' | 'BELOW_TOP' | 'ORIGINAL' = 'ORIGINAL'; +let includeOngoingMediaFromPreviousYears = false; +let excludeUnratedUnwatched = true; +let startDateFilter: Date | null = null; +let endDateFilter: Date | null = null; +let dateTicked = false; +let shouldFetchData = false; +let needsRefetch = false; +let dataFetched = false; +let fetchKey = 0; +let lastSelectedYear = selectedYear; +let lastUseFullActivityHistory = useFullActivityHistory; +let lastDisableLoopingActivityCounter = disableLoopingActivityCounter; +let lastStartDateFilter: Date | null = startDateFilter; +let lastEndDateFilter: Date | null = endDateFilter; + +$: { + 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() + ); - $: { - 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; - } + 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; + } +} + +$: { + includeMusic = includeMusic; + includeSpecials = includeSpecials; + includeRepeats = includeRepeats; + disableActivityHistory = disableActivityHistory; + highestRatedMediaPercentage = highestRatedMediaPercentage; + highestRatedGenreTagPercentage = highestRatedGenreTagPercentage; + topGenresTags = topGenresTags; + genreTagsSort = genreTagsSort; + mediaSort = mediaSort; + includeMovies = includeMovies; + includeOVAs = includeOVAs; + selectedYear = selectedYear; + includeOngoingMediaFromPreviousYears = includeOngoingMediaFromPreviousYears; + excludeUnratedUnwatched = excludeUnratedUnwatched; + + if (shouldFetchData) update().then(updateWidth).catch(updateWidth); +} +$: { + animeList = animeList; + mangaList = mangaList; + highestRatedCount = highestRatedCount; + + new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth); +} +$: { + genreTagCount = genreTagCount; + + if (animeList && mangaList) + topMedia = tops( + [...(animeList || []), ...(mangaList || [])], + genreTagCount, + genreTagsSort, + excludedKeywords + ); - $: { - includeMusic = includeMusic; - includeSpecials = includeSpecials; - includeRepeats = includeRepeats; - disableActivityHistory = disableActivityHistory; - highestRatedMediaPercentage = highestRatedMediaPercentage; - highestRatedGenreTagPercentage = highestRatedGenreTagPercentage; - topGenresTags = topGenresTags; - genreTagsSort = genreTagsSort; - mediaSort = mediaSort; - includeMovies = includeMovies; - includeOVAs = includeOVAs; - selectedYear = selectedYear; - includeOngoingMediaFromPreviousYears = includeOngoingMediaFromPreviousYears; - excludeUnratedUnwatched = excludeUnratedUnwatched; - - if (shouldFetchData) update().then(updateWidth).catch(updateWidth); + new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth); +} +$: { + excludedKeywords = excludedKeywords; + + if (excludedKeywords.length > 0 && animeList !== undefined && mangaList !== undefined) { + animeList = originalAnimeList; + mangaList = originalMangaList; + animeList = excludeKeywords(animeList as Media[]); + mangaList = excludeKeywords(mangaList as Media[]); } - $: { - animeList = animeList; - mangaList = mangaList; - highestRatedCount = highestRatedCount; - new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth); + updateWidth(); +} +$: genreTagTitle = (() => { + switch (genreTagsSort) { + case SortOptions.SCORE: + return 'Highest Rated'; + case SortOptions.MINUTES_WATCHED: + return 'Most Watched'; + case SortOptions.COUNT: + return 'Most Common'; } - $: { - genreTagCount = genreTagCount; - - if (animeList && mangaList) - topMedia = tops( - [...(animeList || []), ...(mangaList || [])], - genreTagCount, - genreTagsSort, - excludedKeywords - ); - - new Promise((resolve) => setTimeout(resolve, 1)).then(updateWidth); +})(); +$: animeMostTitle = (() => { + switch (mediaSort) { + case SortOptions.SCORE: + return 'Highest Rated'; + case SortOptions.MINUTES_WATCHED: + return 'Most Watched'; + case SortOptions.COUNT: + return 'Most Common'; } - $: { - excludedKeywords = excludedKeywords; - - if (excludedKeywords.length > 0 && animeList !== undefined && mangaList !== undefined) { - animeList = originalAnimeList; - mangaList = originalMangaList; - animeList = excludeKeywords(animeList as Media[]); - mangaList = excludeKeywords(mangaList as Media[]); - } - - updateWidth(); +})(); +$: mangaMostTitle = (() => { + switch (mediaSort) { + case SortOptions.SCORE: + return 'Highest Rated'; + case SortOptions.MINUTES_WATCHED: + return 'Most Read'; + case SortOptions.COUNT: + return 'Most Common'; } - $: genreTagTitle = (() => { - 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'; - } - })(); - $: mangaMostTitle = (() => { - switch (mediaSort) { - case SortOptions.SCORE: - return 'Highest Rated'; - case SortOptions.MINUTES_WATCHED: - return 'Most Read'; - case SortOptions.COUNT: - return 'Most Common'; - } - })(); - - const 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; +})(); + +const 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; + } + }); - if (!disableActivityHistory && bottomWidths > requiredWidth) requiredWidth = bottomWidths; + let requiredWidth = topWidths > middleWidths ? topWidths : middleWidths; - requiredWidth += wrappedContainer.offsetWidth - wrappedContainer.clientWidth; + if (!disableActivityHistory && bottomWidths > requiredWidth) requiredWidth = bottomWidths; - wrappedContainer.style.width = `${requiredWidth}px`; - width = requiredWidth; - }; + requiredWidth += wrappedContainer.offsetWidth - wrappedContainer.clientWidth; - reset(); - reset(); + wrappedContainer.style.width = `${requiredWidth}px`; + width = requiredWidth; }; - 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)); - }); - - const triggerFetch = () => { - shouldFetchData = true; - needsRefetch = false; - dataFetched = true; - fetchKey += 1; - lastSelectedYear = selectedYear; - lastUseFullActivityHistory = useFullActivityHistory; - lastDisableLoopingActivityCounter = disableLoopingActivityCounter; - lastStartDateFilter = startDateFilter; - lastEndDateFilter = endDateFilter; - }; + 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'; + } - 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: { + 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; +}; + +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 + month: 0, + day: 0 }, - endDate: { + completedAt: { year: 0, - month: 0 + month: 0, + day: 0 }, - coverImage: { - extraLarge: 'https://s4.anilist.co/file/anilistcdn/staff/large/default.jpg', - medium: 'https://s4.anilist.co/file/anilistcdn/staff/large/default.jpg' + 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: [] }, - tags: [], - genres: [], - season: 'WINTER', - isAdult: false, - relations: { - edges: [] + manga: { + startYears: [], + genres: [], + tags: [] } - }); - - 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' + }, + 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 update = async () => { + if ($userIdentity.id === -1) return; + + let rawAnimeList = await mediaListCollection( + user, + $userIdentity, + Type.Anime, + $anime, + $lastPruneTimes.anime, + { + forcePrune: dateTicked ? false : true, + includeCompleted: true, + all: true } - }; - - const dummyActivities: ActivityHistoryEntry[] = []; - const dummyAnimeList: Media[] = [createDummyMedia('ANIME')]; - const dummyMangaList: Media[] = [createDummyMedia('MANGA')]; - - const update = async () => { - 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 + ); + 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.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 + : 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.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 + : 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; } - ); - 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; + }); + + 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; + }); - for (const media of calculatedMangaList) chapters += media.mediaListEntry?.progress || 0; - }; + 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; + }); - /* eslint-disable @typescript-eslint/no-explicit-any */ - // const year = (statistic: { startYears: any }) => - // 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(); - }); - } - }; + episodes = 0; + minutesWatched = 0; + chapters = 0; + dateTicked = false; - // const abbreviate = (string: string, maxLength = 40, enabled = true) => { - // if (!enabled) { - // return string; - // } - - // if (string.length <= maxLength) { - // return string; - // } - - // return string.slice(0, maxLength - 3) + ' …'; - // }; - - 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; - } + for (const media of calculatedAnimeList) { + episodes += media.mediaListEntry?.progress || 0; + minutesWatched += (media.mediaListEntry?.progress || 0) * media.duration || 0; + } - if (excludedKeywordsInput.length > 0) - excludedKeywords = excludedKeywordsInput - .split(',') - .map((k) => k.trim()) - .filter((k) => k.length > 0); - }; + for (const media of calculatedMangaList) chapters += media.mediaListEntry?.progress || 0; +}; + +/* eslint-disable @typescript-eslint/no-explicit-any */ +// const year = (statistic: { startYears: any }) => +// 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); - const excludeKeywords = (media: Media[]) => { - if (excludedKeywords.length <= 0) return media; + // if (wrappedImageButton !== null) { + // wrappedImageButton.href = object; + // } - 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; + const wrappedFinal = document.getElementById('wrapped-final'); + + if (wrappedFinal !== null) { + wrappedFinal.innerHTML = ''; + + wrappedFinal.appendChild(downloadWrapper); + + generated = true; } - return true; + downloadWrapper.click(); }); - }; + } +}; + +// const abbreviate = (string: string, maxLength = 40, enabled = true) => { +// if (!enabled) { +// return string; +// } + +// if (string.length <= maxLength) { +// return string; +// } + +// return string.slice(0, maxLength - 3) + ' …'; +// }; + +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; + } - const pruneFullYear = async () => { - await database.activities.bulkDelete((await database.activities.toArray()).map((m) => m.page)); - }; + if (excludedKeywordsInput.length > 0) + excludedKeywords = excludedKeywordsInput + .split(',') + .map((k) => k.trim()) + .filter((k) => k.length > 0); +}; + +const 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; + } - // const mergeArraySort = (a: any, b: any, mode: 'tags' | 'genres') => { - // let merged = [...a, ...b].sort((a, b) => b.meanScore - a.meanScore); - - // merged = merged.filter( - // (item, index, self) => - // self.findIndex((itemToCompare) => - // mode === 'genres' - // ? itemToCompare.genre === item.genre - // : itemToCompare.tag.name === item.tag.name - // ) === index - // ); - - // return merged; - // }; - - // const randomCoverFromTop10 = ( - // statistics: { anime: any; manga: any }, - // mode: 'tags' | 'genres' - // ) => { - // const top = mergeArraySort(statistics.anime[mode], statistics.manga[mode], mode); - - // return mediaCover(top[Math.floor(Math.random() * top.length)].mediaIds[0]); - // }; + return true; + }); +}; + +const pruneFullYear = async () => { + await database.activities.bulkDelete((await database.activities.toArray()).map((m) => m.page)); +}; + +// const mergeArraySort = (a: any, b: any, mode: 'tags' | 'genres') => { +// let merged = [...a, ...b].sort((a, b) => b.meanScore - a.meanScore); + +// merged = merged.filter( +// (item, index, self) => +// self.findIndex((itemToCompare) => +// mode === 'genres' +// ? itemToCompare.genre === item.genre +// : itemToCompare.tag.name === item.tag.name +// ) === index +// ); + +// return merged; +// }; + +// const randomCoverFromTop10 = ( +// statistics: { anime: any; manga: any }, +// mode: 'tags' | 'genres' +// ) => { +// const top = mergeArraySort(statistics.anime[mode], statistics.manga[mode], mode); + +// return mediaCover(top[Math.floor(Math.random() * top.length)].mediaIds[0]); +// }; </script> {#if $userIdentity.id === -2 || user === undefined} diff --git a/src/lib/Tools/Wrapped/Top/Activity.svelte b/src/lib/Tools/Wrapped/Top/Activity.svelte index ea6ba592..fdfd90e0 100644 --- a/src/lib/Tools/Wrapped/Top/Activity.svelte +++ b/src/lib/Tools/Wrapped/Top/Activity.svelte @@ -1,16 +1,16 @@ <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; - export let activities: ActivityHistoryEntry[]; - export let useFullActivityHistory: boolean; - export let updateWidth: () => void; +export let wrapped: Wrapped; +export let year: number; +export let activities: ActivityHistoryEntry[]; +export let useFullActivityHistory: boolean; +export let updateWidth: () => void; - const currentYear = new Date(Date.now()).getFullYear(); +const currentYear = new Date(Date.now()).getFullYear(); </script> <div class="grid-item image-grid avatar-grid category top-category"> diff --git a/src/lib/Tools/Wrapped/Top/Anime.svelte b/src/lib/Tools/Wrapped/Top/Anime.svelte index 08df7fd3..6caf4b8a 100644 --- a/src/lib/Tools/Wrapped/Top/Anime.svelte +++ b/src/lib/Tools/Wrapped/Top/Anime.svelte @@ -1,9 +1,9 @@ <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; - export let episodes: number; +export let minutesWatched: number; +export let animeList: Media[] | undefined; +export let episodes: number; </script> <div class="category-grid pure-category category top-category"> diff --git a/src/lib/Tools/Wrapped/Top/Manga.svelte b/src/lib/Tools/Wrapped/Top/Manga.svelte index a36f7724..9fa4ab00 100644 --- a/src/lib/Tools/Wrapped/Top/Manga.svelte +++ b/src/lib/Tools/Wrapped/Top/Manga.svelte @@ -1,9 +1,9 @@ <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; +export let mangaList: Media[] | undefined; +export let chapters: number; </script> <div class="category-grid pure-category category top-category"> |