diff --git a/package.json b/package.json index 970e511..37f9321 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ui", - "version": "6.4.55", + "version": "6.4.56", "license": "BUSL-1.1", "private": true, "packageManager": "pnpm@9.15.5", diff --git a/src/lib/components/EpisodesList.svelte b/src/lib/components/EpisodesList.svelte index 74e7117..43236fc 100644 --- a/src/lib/components/EpisodesList.svelte +++ b/src/lib/components/EpisodesList.svelte @@ -11,7 +11,7 @@ import type { EpisodesResponse } from '$lib/modules/anizip/types' - import { episodes as _episodes, dedupeAiring, notes, type Media } from '$lib/modules/anilist' + import { episodes as _episodes, notes, type Media } from '$lib/modules/anilist' import { authAggregator, list, progress } from '$lib/modules/auth' import { makeEpisodeList } from '$lib/modules/extensions' import { click, dragScroll } from '$lib/modules/navigate' @@ -23,19 +23,11 @@ $: episodeCount = _episodes(media) ?? eps?.episodeCount ?? 0 - const alSchedule: Record = {} - - $: { - for (const { a: airingAt, e: episode } of dedupeAiring(media)) { - alSchedule[episode] = new Date(airingAt * 1000) - } - } - $: episodeList = media && makeEpisodeList(media, eps) const perPage = 16 - function getPage (page: number, list: typeof episodeList = episodeList) { + function getPage (page: number, list = episodeList) { return list.slice((page - 1) * perPage, page * perPage) } diff --git a/src/lib/modules/anilist/util.ts b/src/lib/modules/anilist/util.ts index d5ec9c6..1211e1e 100644 --- a/src/lib/modules/anilist/util.ts +++ b/src/lib/modules/anilist/util.ts @@ -1,6 +1,5 @@ import type { ScheduleMedia } from './queries' import type { Media, MediaEdge } from './types' -import type { Episode, Episodes } from '../anizip/types' import type { ResultOf } from 'gql.tada' export function banner (media: Pick): string | undefined { @@ -145,31 +144,6 @@ export const nextYear = date.getFullYear() + (nextSeason === 'WINTER' ? 1 : 0) export const lastSeason = ['WINTER', 'SPRING', 'SUMMER', 'FALL'].at(Math.floor(((date.getMonth() - 3) / 12) * 4) % 4) as 'WINTER' | 'SPRING' | 'SUMMER' | 'FALL' export const lastYear = date.getFullYear() - (lastSeason === 'FALL' ? 1 : 0) -export function episodeByAirDate (alDate: Date | undefined, episodes: Episodes, episode: number): Episode | undefined { - if (!alDate || !+alDate) return episodes[Number(episode)] ?? episodes[episode] - // 1 is key for episod 1, not index - - // find closest episodes by air date, multiple episodes can have the same air date distance - const closestEpisodes: Episode[] = Object.values(episodes).reduce((prev, curr) => { - if (!prev[0]) return [curr] - const prevDate = Math.abs(+new Date(prev[0].airdate ?? 0) - +alDate) - const currDate = Math.abs(+new Date(curr.airdate ?? 0) - +alDate) - if (prevDate === currDate) { - prev.push(curr) - return prev - } - if (currDate < prevDate) return [curr] - return prev - }, []) - - if (!closestEpisodes.length) return episodes[Number(episode)] ?? episodes[episode] - - // if multiple episodes have the same air date, return the one closest to the requested episode number - return closestEpisodes.reduce((prev, curr) => { - return Math.abs(Number(curr.episode) - episode) < Math.abs(Number(prev.episode) - episode) ? curr : prev - }) -} - export function dedupeAiring (media: ResultOf) { return [...media.aired?.n ?? [], ...media.notaired?.n ?? []].filter((v, i, a) => v != null && a.findIndex(s => s?.e === v.e) === i) as Array<{ a: number, e: number }> } diff --git a/src/lib/modules/extensions/extensions.ts b/src/lib/modules/extensions/extensions.ts index 59549ea..146c17a 100644 --- a/src/lib/modules/extensions/extensions.ts +++ b/src/lib/modules/extensions/extensions.ts @@ -1,14 +1,14 @@ import anitomyscript, { type AnitomyResult } from 'anitomyscript' import { get } from 'svelte/store' -import { dedupeAiring, episodeByAirDate, episodes, isMovie, type Media, getParentForSpecial, isSingleEpisode } from '../anilist' +import { dedupeAiring, episodes, isMovie, type Media, getParentForSpecial, isSingleEpisode } from '../anilist' import { episodes as _episodes } from '../anizip' import native from '../native' import { settings, type videoResolutions } from '../settings' import { storage } from './storage' -import type { EpisodesResponse, Titles } from '../anizip/types' +import type { EpisodesResponse, Titles, Episode } from '../anizip/types' import type { TorrentResult } from 'hayase-extensions' import { dev } from '$app/environment' @@ -52,6 +52,31 @@ export interface SingleEpisode { anidbEid?: number } +export function episodeByAirDate (alDate: Date | undefined, episodes: Map, episode: number): Episode & { airdatems?: number } | undefined { + if (!alDate || !+alDate) return episodes.get('' + episode) + // 1 is key for episod 1, not index + + // find closest episodes by air date, multiple episodes can have the same air date distance + const closestEpisodes: Episode[] = Object.values(episodes).reduce((prev, curr) => { + if (!prev[0]) return [curr] + const prevDate = Math.abs(+new Date(prev[0].airdate ?? 0) - +alDate) + const currDate = Math.abs(+new Date(curr.airdate ?? 0) - +alDate) + if (prevDate === currDate) { + prev.push(curr) + return prev + } + if (currDate < prevDate) return [curr] + return prev + }, []) + + if (!closestEpisodes.length) return episodes.get('' + episode) + + // if multiple episodes have the same air date, return the one closest to the requested episode number + return closestEpisodes.reduce((prev, curr) => { + return Math.abs(Number(curr.episode) - episode) < Math.abs(Number(prev.episode) - episode) ? curr : prev + }) +} + // TODO: https://anilist.co/anime/13055/ export function makeEpisodeList (media: Media, episodesRes?: EpisodesResponse | null) { const count = episodes(media) ?? episodesRes?.episodeCount ?? 0 @@ -66,7 +91,12 @@ export function makeEpisodeList (media: Media, episodesRes?: EpisodesResponse | } const episodeList: SingleEpisode[] = [] - const filtered = { ...episodesRes?.episodes ?? {} } + const filtered = new Map() + const now = Date.now() + for (const [key, value] of Object.entries(episodesRes?.episodes ?? {})) { + filtered.set(key, { ...value, airdatems: value.airdate ? +new Date(value.airdate) : undefined }) + } + const hasSpecial = !!episodesRes?.specialCount const hasCountMatch = (episodes(media) ?? 0) === (episodesRes?.episodeCount ?? 0) // this code... doesn't scale well into the thousands, it takes almost a second or two to run for one piece @@ -85,16 +115,15 @@ export function makeEpisodeList (media: Media, episodesRes?: EpisodesResponse | // return false // }))) - const resolvedEpisode = (needsValidation ? episodeByAirDate(airingAt, filtered, episode) : episodesRes?.episodes?.[Number(episode)]) + const resolvedEpisode = needsValidation ? episodeByAirDate(airingAt, filtered, episode) : filtered.get('' + episode) // we want to exclude episodes which were previously consumed if (needsValidation && resolvedEpisode) { - for (const [key, value] of Object.entries(filtered)) { + for (const [key, value] of filtered.entries()) { if ( (value.anidbEid != null && value.anidbEid === resolvedEpisode.anidbEid) || - (value.airdate != null && new Date(value.airdate) < new Date(resolvedEpisode.airdate ?? Date.now())) + (value.airdatems != null && value.airdatems < (resolvedEpisode.airdatems ?? now)) ) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete filtered[key as keyof typeof filtered] + filtered.delete(key) } } }