aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFuwn <[email protected]>2023-09-14 02:43:44 -0700
committerFuwn <[email protected]>2023-09-14 02:43:44 -0700
commitb220eddf448643fcf3c8f08adbb2b44103abf373 (patch)
tree310a8868720859cf45e428d1048022cdda73008e /src
parentfeat(updates): change loading style (diff)
downloaddue.moe-b220eddf448643fcf3c8f08adbb2b44103abf373.tar.xz
due.moe-b220eddf448643fcf3c8f08adbb2b44103abf373.zip
feat(manga): best guess estimation
Diffstat (limited to 'src')
-rw-r--r--src/lib/AniList/media.ts80
-rw-r--r--src/lib/List/Due/MangaList.svelte2
-rw-r--r--src/lib/mangadex.ts47
3 files changed, 114 insertions, 15 deletions
diff --git a/src/lib/AniList/media.ts b/src/lib/AniList/media.ts
index 341e09a4..6187094d 100644
--- a/src/lib/AniList/media.ts
+++ b/src/lib/AniList/media.ts
@@ -170,3 +170,83 @@ export const publicMediaListCollection = async (userId: number, type: Type): Pro
return flattenLists(userIdResponse['data']['MediaListCollection']['lists']);
};
+
+export const recentMediaActivities = async (
+ userIdentity: UserIdentity,
+ media: Media
+): Promise<number | null> => {
+ const activities = await (
+ await fetch('https://graphql.anilist.co', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Accept: 'application/json'
+ },
+ body: JSON.stringify({
+ query: `{
+ Page(page: 1) {
+ activities(mediaId: ${media.id}, sort: ID_DESC) {
+ ... on ListActivity { progress }
+ }
+ }
+
+ MediaList(userId: ${userIdentity.id}, mediaId: ${media.id}) { progress }
+ }`
+ })
+ })
+ ).json();
+ // Essentially, just Automail estimation. All credit to hoh and the Automail contributors.
+ let guesses: number[] = [];
+
+ activities['data']['Page']['activities'].forEach((activity: { progress: string }) => {
+ if (activity.progress !== null) {
+ const progress = Number((activity.progress.match(/\d+$/) || [0])[0]);
+
+ if (progress !== 65535) {
+ guesses.push(progress);
+ }
+ }
+ });
+ guesses.sort((a, b) => b - a);
+
+ if (guesses.length) {
+ let bestGuess = guesses[0];
+
+ 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;
+ }
+
+ return null;
+};
diff --git a/src/lib/List/Due/MangaList.svelte b/src/lib/List/Due/MangaList.svelte
index 836899fc..e13a4747 100644
--- a/src/lib/List/Due/MangaList.svelte
+++ b/src/lib/List/Due/MangaList.svelte
@@ -62,7 +62,7 @@
);
let finalMedia = releasingMedia;
- const chapterPromises = finalMedia.map((m: Media) => chapterCount(m));
+ const chapterPromises = finalMedia.map((m: Media) => chapterCount(identity, m));
const chapterCounts = await Promise.all(chapterPromises);
finalMedia.forEach((m: Media, i) => {
diff --git a/src/lib/mangadex.ts b/src/lib/mangadex.ts
index b7656b43..d2eb8c3b 100644
--- a/src/lib/mangadex.ts
+++ b/src/lib/mangadex.ts
@@ -1,26 +1,50 @@
-import type { Media } from '$lib/AniList/media';
+import { recentMediaActivities, type Media } from '$lib/AniList/media';
+import type { UserIdentity } from './AniList/identity';
import { chapterDatabase } from './chapterDatabase';
-export const chapterCount = async (manga: Media): Promise<number | null> => {
+export const chapterCount = async (
+ identity: UserIdentity,
+ manga: Media,
+ preferActivity = false
+): Promise<number | null> => {
const chapters = await chapterDatabase.chapters.get(manga.id);
if (chapters !== undefined) {
return chapters.chapters === -1 ? null : chapters.chapters;
}
- const mangadexData = await (
- await fetch(
- `/api/mangadex/manga?english=${manga.title.english}&year=${manga.startDate.year}&romaji=${manga.title.romaji}&native=${manga.title.native}`
- )
- ).json();
+ if (preferActivity) {
+ return await recentMediaActivities(identity, manga);
+ }
+
+ const tryRecentMediaActivities = async () => {
+ const anilistData = await recentMediaActivities(identity, manga);
+
+ if (anilistData !== null) {
+ await chapterDatabase.chapters.put({
+ id: manga.id,
+ chapters: anilistData
+ });
+
+ return anilistData;
+ }
- if (mangadexData['data'] === undefined || mangadexData['data'].length === 0) {
await chapterDatabase.chapters.put({
id: manga.id,
chapters: -1
});
return null;
+ };
+
+ const mangadexData = await (
+ await fetch(
+ `/api/mangadex/manga?english=${manga.title.english}&year=${manga.startDate.year}&romaji=${manga.title.romaji}&native=${manga.title.native}`
+ )
+ ).json();
+
+ if (mangadexData['data'] === undefined || mangadexData['data'].length === 0) {
+ return await tryRecentMediaActivities();
}
const lastChapterData = await (
@@ -28,12 +52,7 @@ export const chapterCount = async (manga: Media): Promise<number | null> => {
).json();
if (lastChapterData['data'] === undefined || lastChapterData['data'].length === 0) {
- await chapterDatabase.chapters.put({
- id: manga.id,
- chapters: -1
- });
-
- return null;
+ return await tryRecentMediaActivities();
}
let lastChapter = lastChapterData['data'][0]['attributes']['chapter'];