diff options
| author | Fuwn <[email protected]> | 2024-01-08 15:27:28 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-01-08 15:27:28 -0800 |
| commit | 6620bc00fdf5173ffb20a9057a4580b59410dbd7 (patch) | |
| tree | 57f149d20ce28960909bda1bba1d6fcbbd0ef515 /src | |
| parent | fix(badges): loading order (diff) | |
| download | due.moe-6620bc00fdf5173ffb20a9057a4580b59410dbd7.tar.xz due.moe-6620bc00fdf5173ffb20a9057a4580b59410dbd7.zip | |
feat(tools): new tools url method
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/Birthday/ACDB.ts | 4 | ||||
| -rw-r--r-- | src/lib/Birthday/aniSearch.ts | 4 | ||||
| -rw-r--r-- | src/lib/Error/path.ts | 18 | ||||
| -rw-r--r-- | src/lib/Tools/Picker.svelte | 24 | ||||
| -rw-r--r-- | src/lib/Tools/tools.ts | 43 | ||||
| -rw-r--r-- | src/lib/Utility/proxy.ts | 4 | ||||
| -rw-r--r-- | src/lib/Utility/root.ts | 8 | ||||
| -rw-r--r-- | src/routes/birthdays/+server.ts | 12 | ||||
| -rw-r--r-- | src/routes/tools/+page.svelte | 150 | ||||
| -rw-r--r-- | src/routes/tools/[tool]/+page.server.ts | 5 | ||||
| -rw-r--r-- | src/routes/tools/[tool]/+page.svelte | 63 | ||||
| -rw-r--r-- | src/routes/wrapped/+server.ts | 10 |
12 files changed, 197 insertions, 148 deletions
diff --git a/src/lib/Birthday/ACDB.ts b/src/lib/Birthday/ACDB.ts index 700b13e1..cb71880d 100644 --- a/src/lib/Birthday/ACDB.ts +++ b/src/lib/Birthday/ACDB.ts @@ -1,3 +1,5 @@ +import root from '$lib/Utility/root'; + export interface ACDBBirthday { character_image: string; name: string; @@ -7,7 +9,7 @@ export interface ACDBBirthday { export const ACDBBirthdays = async (month: number, day: number): Promise<ACDBBirthday[]> => ( await ( - await fetch(`/api/birthdays/acdb?month=${month}&day=${day}`, { + await fetch(root(`/api/birthdays/acdb?month=${month}&day=${day}`), { headers: { Accept: 'application/json', 'Content-Type': 'application/json', diff --git a/src/lib/Birthday/aniSearch.ts b/src/lib/Birthday/aniSearch.ts index a938f7ba..3fa77f61 100644 --- a/src/lib/Birthday/aniSearch.ts +++ b/src/lib/Birthday/aniSearch.ts @@ -1,3 +1,5 @@ +import root from '$lib/Utility/root'; + export interface aniSearchBirthday { name: string; image: string; @@ -7,4 +9,4 @@ export const aniSearchBirthdays = async ( month: number, day: number ): Promise<aniSearchBirthday[]> => - await (await fetch(`/api/birthdays/anisearch?month=${month}&day=${day}`, {})).json(); + await (await fetch(root(`/api/birthdays/anisearch?month=${month}&day=${day}`), {})).json(); diff --git a/src/lib/Error/path.ts b/src/lib/Error/path.ts index f493726b..40f50b7c 100644 --- a/src/lib/Error/path.ts +++ b/src/lib/Error/path.ts @@ -1,17 +1,11 @@ -import levenshtein from 'fast-levenshtein'; - export const closest = (path: string, suggestions: string[]) => { - let closest = ''; - let lowestDistance = Infinity; + const partialMatch = suggestions.find((suggestion) => suggestion.includes(path)); - [...suggestions, '...'].forEach((suggestion) => { - const distance = levenshtein.get(path, suggestion); + if (partialMatch) return partialMatch; - if (distance < lowestDistance) { - lowestDistance = distance; - closest = suggestion; - } - }); + const closestMatch = suggestions.reduce((prev, curr) => { + return prev.length > curr.length ? prev : curr; + }, ''); - return closest; + return closestMatch; }; diff --git a/src/lib/Tools/Picker.svelte b/src/lib/Tools/Picker.svelte new file mode 100644 index 00000000..6ead9624 --- /dev/null +++ b/src/lib/Tools/Picker.svelte @@ -0,0 +1,24 @@ +<script lang="ts"> + import { browser } from '$app/environment'; + import { goto } from '$app/navigation'; + + export let tool: string; +</script> + +<blockquote> + <select + bind:value={tool} + on:change={() => { + if (browser) goto(`/tools/${tool}`); + }} + > + <option value="default" selected disabled hidden>Select a tool to continue</option> + <option value="wrapped">AniList Wrapped</option> + <option value="birthdays">Today's Character Birthdays</option> + <option value="sequel_spy">Sequel Spy</option> + <option value="discussions">Episode Discussion Collector</option> + <option value="random_follower">Random Follower Finder</option> + <option value="dump_profile">Dump Profile</option> + <option value="activity_history">Activity History Analyser</option> + </select> +</blockquote> diff --git a/src/lib/Tools/tools.ts b/src/lib/Tools/tools.ts new file mode 100644 index 00000000..c0e499b2 --- /dev/null +++ b/src/lib/Tools/tools.ts @@ -0,0 +1,43 @@ +export const tools: { [key: string]: { name: string; description?: string; id: string } } = { + default: { + name: 'Tools', + description: 'A collection of tools to help you get the most out of AniList.', + id: 'default' + }, + wrapped: { + name: 'AniList Wrapped & Statistics Panel', + description: + 'Instantly generate an AniList themed Wrapped for your profile, doubling as a statistics panel for your bio', + id: 'wrapped' + }, + birthdays: { + name: "Today's Character Birthdays", + description: + 'Find and display the birthdays of all characters for today, or any other day of the year', + id: 'birthdays' + }, + sequel_spy: { + name: 'Sequel Spy (Missing Prequel Finder)', + description: "Find media with prequels you haven't seen yet for any given simulcast season", + id: 'sequel_spy' + }, + discussions: { + name: 'Episode Discussion Collector', + description: 'Find and display all episode discussions for a given user', + id: 'discussions' + }, + random_follower: { + name: 'Random Follower Finder', + description: 'Find a random follower of any given user', + id: 'random_follower' + }, + dump_profile: { + name: 'Dump Profile', + description: "Dump a user's profile to JSON", + id: 'dump_profile' + }, + activity_history: { + name: 'Activity History Analyser', + id: 'activity_history' + } +}; diff --git a/src/lib/Utility/proxy.ts b/src/lib/Utility/proxy.ts index ec9c289b..3337fe29 100644 --- a/src/lib/Utility/proxy.ts +++ b/src/lib/Utility/proxy.ts @@ -1,7 +1,7 @@ import { env } from '$env/dynamic/public'; -export const proxy = (url: string, disable = true) => - env.PUBLIC_ANILIST_REDIRECT_URI?.includes('192.168') && !disable +export const proxy = (url: string, enable = false) => + env.PUBLIC_ANILIST_REDIRECT_URI?.includes('localhost') || enable ? url : `https://proxy.due.moe/?q=${url}`; diff --git a/src/lib/Utility/root.ts b/src/lib/Utility/root.ts new file mode 100644 index 00000000..3f9ea07d --- /dev/null +++ b/src/lib/Utility/root.ts @@ -0,0 +1,8 @@ +import { env } from '$env/dynamic/public'; + +export const root = (path: string, enable = false) => + env.PUBLIC_ANILIST_REDIRECT_URI?.includes('localhost') || enable + ? `http://localhost:5173${path}` + : `https://due.moe${path}`; + +export default root; diff --git a/src/routes/birthdays/+server.ts b/src/routes/birthdays/+server.ts index 2b9219b5..7f0fd833 100644 --- a/src/routes/birthdays/+server.ts +++ b/src/routes/birthdays/+server.ts @@ -1,7 +1,11 @@ +import root from '$lib/Utility/root.js'; + export const GET = ({ url }) => Response.redirect( - `https://due.moe/tools?tool=birthdays${ - url.searchParams.values.length > 0 ? `&${url.searchParams.toString()}` : '' - }`, - 301 + root( + `/tools/birthdays${ + url.searchParams.values.length > 0 ? `&${url.searchParams.toString()}` : '' + }` + ), + 307 ); diff --git a/src/routes/tools/+page.svelte b/src/routes/tools/+page.svelte index e5bda954..6293d0b1 100644 --- a/src/routes/tools/+page.svelte +++ b/src/routes/tools/+page.svelte @@ -1,133 +1,35 @@ <script lang="ts"> - import ActivityHistory from '$lib/Tools/ActivityHistory/Tool.svelte'; - import Wrapped from '$lib/Tools/Wrapped.svelte'; - import { browser } from '$app/environment'; - import EpisodeDiscussionCollector from '$lib/Tools/EpisodeDiscussionCollector.svelte'; - import CharacterBirthdays from '$lib/Tools/Birthdays.svelte'; - import { page } from '$app/stores'; - import SequelSpy from '$lib/Tools/SequelSpy.svelte'; - import { closest } from '$lib/Error/path'; import HeadTitle from '$lib/HeadTitle.svelte'; - import RandomFollower from '$lib/Tools/RandomFollower.svelte'; - import DumpProfile from '$lib/Tools/DumpProfile.svelte'; + import Picker from '$lib/Tools/Picker.svelte'; + import { tools } from '$lib/Tools/tools.js'; - export let data; - - let tool = - browser && $page.url.searchParams.size !== 0 - ? $page.url.searchParams.get('tool') || 'default' - : 'default'; - const tools: { [key: string]: { name: string; description?: string } } = { - default: { - name: 'Tools', - description: 'A collection of tools to help you get the most out of AniList.' - }, - wrapped: { - name: 'AniList Wrapped & Statistics Panel', - description: - 'Instantly generate an AniList themed Wrapped for your profile, doubling as a statistics panel for your bio' - }, - birthdays: { - name: "Today's Character Birthdays", - description: - 'Find and display the birthdays of all characters for today, or any other day of the year' - }, - sequel_spy: { - name: 'Sequel Spy (Missing Prequel Finder)', - description: "Find media with prequels you haven't seen yet for any given simulcast season" - }, - discussions: { - name: 'Episode Discussion Collector', - description: 'Find and display all episode discussions for a given user' - }, - random_follower: { - name: 'Random Follower Finder', - description: 'Find a random follower of any given user' - }, - dump_profile: { - name: 'Dump Profile', - description: "Dump a user's profile to JSON" - }, - activity_history: { - name: 'Activity History Analyser' - } - }; - - $: { - if (browser) { - $page.url.searchParams.set('tool', tool); - history.replaceState(null, '', `?${$page.url.searchParams.toString()}`); - } - } - $: suggestion = closest(browser ? tool : '...', Object.keys(tools)); + let tool = 'default'; </script> -<blockquote> - <select bind:value={tool}> - <option value="default" selected disabled hidden>Tool</option> - <option value="wrapped">AniList Wrapped</option> - <option value="birthdays">Today's Character Birthdays</option> - <option value="sequel_spy">Sequel Spy</option> - <option value="discussions">Episode Discussion Collector</option> - <option value="random_follower">Random Follower Finder</option> - <option value="dump_profile">Dump Profile</option> - <option value="activity_history">Activity History Analyser</option> - </select> -</blockquote> - -{#if !Object.keys(tools).includes(tool)} - <HeadTitle route="Tools" path="/tools" /> - <div class="card"> - <p>Tool not found.</p> +<Picker {tool} /> - <blockquote> - Did you mean "<a - href={`#`} - style={suggestion === '...' ? 'pointer-events: none; color: inherit;' : ''} - on:click={() => (tool = suggestion)} - > - {suggestion === '...' ? '...' : tools[suggestion]}</a - >"? - </blockquote> - </div> -{:else} - <HeadTitle route={tools[tool].name} path={`/tools?tool=${tool}`} /> +<HeadTitle route={tools[tool].name} path={`/tools?tool=${tool}`} /> - {#if tool === 'default'} - <div class="card"> - <p>Select a tool to continue.</p> +<div class="card"> + <p>Select a tool to continue.</p> - <ul> - {#each Object.keys(tools) as t} - {#if t !== 'default'} - <li> - <a href={`#`} on:click={() => (tool = t)}>{tools[t].name}</a> - {#if tools[t].description} - <blockquote>{tools[t].description}</blockquote> - {/if} - </li> + <ul> + {#each Object.keys(tools) as t} + {#if t !== 'default'} + <li> + <a href={`/tools/${tools[t].id}`} on:click={() => (tool = t)}>{tools[t].name}</a> + {#if tools[t].description} + <blockquote>{tools[t].description}</blockquote> {/if} - {/each} - </ul> - - <p /> - - Have any requests for cool tools that you think others might find useful? Send a message to - <a href="https://anilist.co/user/fuwn" target="_blank" rel="noopener">@fuwn</a> on AniList! - </div> - {:else if tool === 'activity_history'} - <ActivityHistory user={data.user} /> - {:else if tool === 'wrapped'} - <Wrapped user={data.user} /> - {:else if tool === 'discussions'} - <EpisodeDiscussionCollector /> - {:else if tool === 'birthdays'} - <CharacterBirthdays /> - {:else if tool === 'sequel_spy'} - <SequelSpy user={data.user} /> - {:else if tool === 'random_follower'} - <RandomFollower /> - {:else if tool === 'dump_profile'} - <DumpProfile /> - {/if} -{/if} + </li> + {/if} + {/each} + </ul> + + <p /> + + <blockquote style="margin: 0 0 0 1.5rem;"> + Have any requests for cool tools that you think others might find useful? Send a message to + <a href="https://anilist.co/user/fuwn" target="_blank" rel="noopener">@fuwn</a> on AniList! + </blockquote> +</div> diff --git a/src/routes/tools/[tool]/+page.server.ts b/src/routes/tools/[tool]/+page.server.ts new file mode 100644 index 00000000..c7e72d18 --- /dev/null +++ b/src/routes/tools/[tool]/+page.server.ts @@ -0,0 +1,5 @@ +export const load = ({ params }) => { + return { + tool: params.tool + }; +}; diff --git a/src/routes/tools/[tool]/+page.svelte b/src/routes/tools/[tool]/+page.svelte new file mode 100644 index 00000000..bd236d11 --- /dev/null +++ b/src/routes/tools/[tool]/+page.svelte @@ -0,0 +1,63 @@ +<script lang="ts"> + import ActivityHistory from '$lib/Tools/ActivityHistory/Tool.svelte'; + import Wrapped from '$lib/Tools/Wrapped.svelte'; + import EpisodeDiscussionCollector from '$lib/Tools/EpisodeDiscussionCollector.svelte'; + import CharacterBirthdays from '$lib/Tools/Birthdays.svelte'; + import SequelSpy from '$lib/Tools/SequelSpy.svelte'; + import { closest } from '$lib/Error/path'; + import HeadTitle from '$lib/HeadTitle.svelte'; + import RandomFollower from '$lib/Tools/RandomFollower.svelte'; + import DumpProfile from '$lib/Tools/DumpProfile.svelte'; + import { tools } from '$lib/Tools/tools.js'; + import { onMount } from 'svelte'; + import { goto } from '$app/navigation'; + import Picker from '$lib/Tools/Picker.svelte'; + + export let data; + + let tool = data.tool ?? 'default'; + + onMount(() => { + if (tool === 'default') goto('/tools'); + }); + + $: suggestion = closest(tool, Object.keys(tools)); +</script> + +<Picker bind:tool /> + +{#if !Object.keys(tools).includes(tool)} + <HeadTitle route="Tools" path="/tools" /> + + <div class="card"> + <p>Tool not found.</p> + + <blockquote style="margin: 0 0 0 1.5rem;"> + Did you mean "<a + href={`/tools/${tools[suggestion].id}`} + on:click={() => (tool = suggestion)} + style={suggestion === '...' ? 'pointer-events: none; color: inherit;' : ''} + > + {suggestion === '...' ? '...' : tools[suggestion].name}</a + >"? + </blockquote> + </div> +{:else} + <HeadTitle route={tools[tool].name} path={`/tools?tool=${tool}`} /> + + {#if tool === 'activity_history'} + <ActivityHistory user={data.user} /> + {:else if tool === 'wrapped'} + <Wrapped user={data.user} /> + {:else if tool === 'discussions'} + <EpisodeDiscussionCollector /> + {:else if tool === 'birthdays'} + <CharacterBirthdays /> + {:else if tool === 'sequel_spy'} + <SequelSpy user={data.user} /> + {:else if tool === 'random_follower'} + <RandomFollower /> + {:else if tool === 'dump_profile'} + <DumpProfile /> + {/if} +{/if} diff --git a/src/routes/wrapped/+server.ts b/src/routes/wrapped/+server.ts index 2eee34f0..cc070af0 100644 --- a/src/routes/wrapped/+server.ts +++ b/src/routes/wrapped/+server.ts @@ -1,7 +1,9 @@ +import root from '$lib/Utility/root.js'; + export const GET = ({ url }) => Response.redirect( - `https://due.moe/tools?tool=wrapped${ - url.searchParams.values.length > 0 ? `&${url.searchParams.toString()}` : '' - }`, - 301 + root( + `/tools/wrapped${url.searchParams.values.length > 0 ? `&${url.searchParams.toString()}` : ''}` + ), + 307 ); |