diff --git a/src/lib/components/ui/player/player.svelte b/src/lib/components/ui/player/player.svelte
index f60d412..6bef40e 100644
--- a/src/lib/components/ui/player/player.svelte
+++ b/src/lib/components/ui/player/player.svelte
@@ -33,6 +33,7 @@
import { episodes } from '$lib/modules/anizip'
import { page } from '$app/stores'
import { isPlaying } from '$lib/modules/idle'
+ import { authAggregator } from '$lib/modules/auth'
export let mediaInfo: MediaInfo
export let files: TorrentFile[]
@@ -216,6 +217,22 @@
}
}
+ let completed = false
+ function checkCompletion () {
+ if (!completed && $settings.playerAutocomplete) {
+ checkCompletionByTime(currentTime, safeduration)
+ }
+ }
+ let externalPlayerReady = false
+ function checkCompletionByTime (currentTime: number, safeduration: number) {
+ const fromend = Math.max(180, safeduration / 10)
+ if (safeduration && currentTime && (video.readyState || externalPlayerReady) && safeduration - fromend < currentTime) {
+ authAggregator.watch(mediaInfo.media, mediaInfo.episode)
+ completed = true
+ externalPlayerReady = false
+ }
+ }
+
// other
$: if (ended && $settings.playerAutoplay) next?.()
@@ -551,6 +568,7 @@
on:dblclick={fullscreen}
on:loadeddata={checkAudio}
on:timeupdate={checkSkippableChapters}
+ on:timeupdate={checkCompletion}
/>
{#if seeking}
diff --git a/src/lib/modules/auth/client.ts b/src/lib/modules/auth/client.ts
index 2ffdb34..117cdc5 100644
--- a/src/lib/modules/auth/client.ts
+++ b/src/lib/modules/auth/client.ts
@@ -2,7 +2,7 @@ import { readable } from 'simple-store-svelte'
import { persisted } from 'svelte-persisted-store'
import { get } from 'svelte/store'
-import { client } from '../anilist'
+import { client, episodes, type Media } from '../anilist'
import local from './local'
@@ -31,7 +31,7 @@ export default new class AuthAggregator {
}
id () {
- if (this.anilist()) return client.viewer.value?.viewer?.id
+ if (this.anilist()) return client.viewer.value!.viewer?.id
return -1
}
@@ -75,6 +75,27 @@ export default new class AuthAggregator {
return client.sequelIDs
}
+ watch (media: Media, progress: number) {
+ // TODO: auto re-watch status
+ // if (media.status !== 'FINISHED' && media.status !== 'RELEASING') return // this turned out to be a bad idea, anilist sometimes delays status changes by up to a day... yikes
+ const totalEps = episodes(media) ?? 1 // episodes or movie which is single episode
+ if (totalEps < progress) return // woah, bad data from resolver?!
+
+ const currentProgress = media.mediaListEntry?.progress ?? 0
+ if (currentProgress <= progress) return
+
+ const status =
+ totalEps === progress
+ ? 'COMPLETED'
+ : media.mediaListEntry?.status === 'REPEATING' ? 'REPEATING' : 'CURRENT'
+
+ const repeat = media.mediaListEntry?.repeat ?? 0 + (totalEps === progress ? 1 : 0)
+
+ const lists = (media.mediaListEntry?.customLists as Array<{enabled: boolean, name: string}> | undefined)?.filter(list => list.enabled).map(list => list.name) ?? []
+
+ this.entry({ id: media.id, progress, repeat, status, lists })
+ }
+
entry (variables: VariablesOf) {
const syncSettings = get(this.syncSettings)
variables.lists ??= []