diff options
| author | Fuwn <[email protected]> | 2023-11-06 10:01:57 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2023-11-06 10:09:34 -0800 |
| commit | 4e2742b3850b9f8567732316971d1b71975b5994 (patch) | |
| tree | d1679e2dcd2e7ef435f10a594dd73c7fcfd2b946 | |
| parent | feat(wrapped): fix total episode and chapter count (diff) | |
| download | due.moe-4e2742b3850b9f8567732316971d1b71975b5994.tar.xz due.moe-4e2742b3850b9f8567732316971d1b71975b5994.zip | |
feat(manga): estimate settings
| -rw-r--r-- | src/lib/AniList/media.ts | 90 | ||||
| -rw-r--r-- | src/lib/Media/manga.ts | 5 | ||||
| -rw-r--r-- | src/routes/settings/+page.svelte | 10 | ||||
| -rw-r--r-- | src/stores/settings.ts | 4 |
4 files changed, 76 insertions, 33 deletions
diff --git a/src/lib/AniList/media.ts b/src/lib/AniList/media.ts index 55e3e453..a1f17fb6 100644 --- a/src/lib/AniList/media.ts +++ b/src/lib/AniList/media.ts @@ -190,7 +190,8 @@ export const publicMediaListCollection = async (userId: number, type: Type): Pro export const recentMediaActivities = async ( userIdentity: UserIdentity, - media: Media + media: Media, + method: 'median' | 'trimmed_mean' | 'weighted_average' = 'trimmed_mean' ): Promise<number | null> => { const activities = await ( await fetch('https://graphql.anilist.co', { @@ -212,8 +213,7 @@ export const recentMediaActivities = async ( }) }) ).json(); - // Essentially, just Automail estimation. All credit to hoh and the Automail contributors. - let guesses: number[] = []; + const guesses: number[] = []; activities['data']['Page']['activities'].forEach((activity: { progress: string }) => { if (activity.progress !== null) { @@ -229,38 +229,68 @@ export const recentMediaActivities = async ( if (guesses.length) { let bestGuess = guesses[0]; - if (guesses.length > 2) { - if (guesses.filter((val) => val < 7000).length) { - guesses = guesses.filter((val) => val < 7000); - } + switch (method) { + case 'median': + { + const sortedGuesses = guesses.slice().sort((a, b) => a - b); - const difference = guesses[0] - guesses[1]; - const inverseDifference = 1 + Math.ceil(25 / (difference + 1)); - - if (guesses.length >= inverseDifference) { - if ( - guesses[1] === guesses[inverseDifference] || - guesses[0] - guesses[1] > 500 || - (guesses[0] - guesses[1] > 100 && guesses[1] >= guesses[inverseDifference] - 1) - ) { - bestGuess = guesses[1]; - - if ( - guesses.length > 15 && - guesses[1] - guesses[2] > 50 && - guesses[2] === guesses[guesses.length - 1] - ) { - bestGuess = guesses[2]; - } + bestGuess = sortedGuesses[Math.floor(sortedGuesses.length / 2)]; } - } + break; + case 'trimmed_mean': + { + const sortedGuesses = guesses.slice().sort((a, b) => a - b); + const trimmedGuesses = sortedGuesses.slice(1, -1); + bestGuess = trimmedGuesses.reduce((a, b) => a + b) / trimmedGuesses.length; + } + break; + case 'weighted_average': + { + const countMap: { [key: number]: number } = {}; + guesses.forEach((g) => { + countMap[g] = (countMap[g] || 0) + 1; + }); + + bestGuess = + Object.entries(countMap).reduce((acc: number, [val, count]: [string, number]) => { + return acc + Number(val) * Math.log(count); + }, 0) / Object.values(countMap).reduce((a: number, b: number) => a + Math.log(b), 0); + } + break; } - if (activities['data']['MediaList']['progress'] !== null) { - if (activities['data']['MediaList']['progress'] > bestGuess) { - bestGuess = activities['data']['MediaList']['progress']; - } + // if (guesses.length > 2) { + // if (guesses.filter((val) => val < 7000).length) { + // guesses = guesses.filter((val) => val < 7000); + // } + + // const difference = guesses[0] - guesses[1]; + // const inverseDifference = 1 + Math.ceil(25 / (difference + 1)); + + // if (guesses.length >= inverseDifference) { + // if ( + // guesses[1] === guesses[inverseDifference] || + // guesses[0] - guesses[1] > 500 || + // (guesses[0] - guesses[1] > 100 && guesses[1] >= guesses[inverseDifference] - 1) + // ) { + // bestGuess = guesses[1]; + + // if ( + // guesses.length > 15 && + // guesses[1] - guesses[2] > 50 && + // guesses[2] === guesses[guesses.length - 1] + // ) { + // bestGuess = guesses[2]; + // } + // } + // } + // } + + // if (activities['data']['MediaList']['progress'] !== null) { + if (activities['data']['MediaList']['progress'] > bestGuess) { + bestGuess = activities['data']['MediaList']['progress']; } + // } return bestGuess; } diff --git a/src/lib/Media/manga.ts b/src/lib/Media/manga.ts index 13f251eb..ab33f124 100644 --- a/src/lib/Media/manga.ts +++ b/src/lib/Media/manga.ts @@ -1,5 +1,6 @@ import { recentMediaActivities, type Media } from '$lib/AniList/media'; import manga from '../../stores/manga'; +import settings from '../../stores/settings'; import type { UserIdentity } from '../AniList/identity'; import { chapterDatabase } from './chapters'; @@ -35,7 +36,7 @@ export const chapterCount = async ( return null; } - const anilistData = await recentMediaActivities(identity, manga); + const anilistData = await recentMediaActivities(identity, manga, settings.get().guessMethod); await chapterDatabase.chapters.put({ id: manga.id, @@ -71,7 +72,7 @@ export const chapterCount = async ( let completedVolumes = null; if ((manga.mediaListEntry || { progress: 0 }).progress > lastChapter) { - const anilistData = await recentMediaActivities(identity, manga); + const anilistData = await recentMediaActivities(identity, manga, settings.get().guessMethod); if (anilistData !== null && anilistData > lastChapter) { lastChapter = anilistData; diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte index 372baa10..346d275b 100644 --- a/src/routes/settings/+page.svelte +++ b/src/routes/settings/+page.svelte @@ -102,6 +102,16 @@ unresolved manga chapter counts </SettingHint> </SettingCheckboxToggle> + + {#if !$settings.disableGuessing} + <br /> + + <select bind:value={$settings.guessMethod} on:change={pruneAllManga}> + <option value="median">Median (fastest, reasonably accurate)</option> + <option value="trimmed_median">Trimmed Median (fast, very accurate)</option> + <option value="weighted_average">Weighted Average (acceptably fast, most accurate)</option> + </select> + {/if} </details> <p /> diff --git a/src/stores/settings.ts b/src/stores/settings.ts index 12ac5d49..d5a854d6 100644 --- a/src/stores/settings.ts +++ b/src/stores/settings.ts @@ -18,6 +18,7 @@ export interface Settings { disableGuessing: boolean; hoverNavigation: boolean; displayNativeTitles: boolean; + guessMethod: 'median' | 'trimmed_mean' | 'weighted_average'; } const defaultSettings: Settings = { @@ -36,7 +37,8 @@ const defaultSettings: Settings = { displaySocialButton: false, disableGuessing: false, hoverNavigation: false, - displayNativeTitles: false + displayNativeTitles: false, + guessMethod: 'trimmed_mean' }; const createStore = () => { |