aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2023-11-06 10:01:57 -0800
committerFuwn <[email protected]>2023-11-06 10:09:34 -0800
commit4e2742b3850b9f8567732316971d1b71975b5994 (patch)
treed1679e2dcd2e7ef435f10a594dd73c7fcfd2b946
parentfeat(wrapped): fix total episode and chapter count (diff)
downloaddue.moe-4e2742b3850b9f8567732316971d1b71975b5994.tar.xz
due.moe-4e2742b3850b9f8567732316971d1b71975b5994.zip
feat(manga): estimate settings
-rw-r--r--src/lib/AniList/media.ts90
-rw-r--r--src/lib/Media/manga.ts5
-rw-r--r--src/routes/settings/+page.svelte10
-rw-r--r--src/stores/settings.ts4
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 = () => {