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 ??= []