1
0
Fork 0
mirror of https://github.com/sussy-code/smov.git synced 2025-01-04 16:47:40 +01:00
smov/src/stores/progress/index.ts
2023-12-23 18:24:43 +13:00

181 lines
4.4 KiB
TypeScript

import { create } from "zustand";
import { persist } from "zustand/middleware";
import { immer } from "zustand/middleware/immer";
import { PlayerMeta } from "@/stores/player/slices/source";
export interface ProgressItem {
watched: number;
duration: number;
}
export interface ProgressSeasonItem {
title: string;
number: number;
id: string;
}
export interface ProgressEpisodeItem {
title: string;
number: number;
id: string;
seasonId: string;
updatedAt: number;
progress: ProgressItem;
}
export interface ProgressMediaItem {
title: string;
year?: number;
poster?: string;
type: "show" | "movie";
progress?: ProgressItem;
updatedAt: number;
seasons: Record<string, ProgressSeasonItem>;
episodes: Record<string, ProgressEpisodeItem>;
}
export interface ProgressUpdateItem {
title?: string;
year?: number;
poster?: string;
type?: "show" | "movie";
progress?: ProgressItem;
tmdbId: string;
id: string;
episodeId?: string;
seasonId?: string;
episodeNumber?: number;
seasonNumber?: number;
action: "upsert" | "delete";
}
export interface UpdateItemOptions {
meta: PlayerMeta;
progress: ProgressItem;
}
export interface ProgressStore {
items: Record<string, ProgressMediaItem>;
updateQueue: ProgressUpdateItem[];
updateItem(ops: UpdateItemOptions): void;
removeItem(id: string): void;
replaceItems(items: Record<string, ProgressMediaItem>): void;
clear(): void;
clearUpdateQueue(): void;
removeUpdateItem(id: string): void;
}
let updateId = 0;
export const useProgressStore = create(
persist(
immer<ProgressStore>((set) => ({
items: {},
updateQueue: [],
removeItem(id) {
set((s) => {
updateId += 1;
s.updateQueue.push({
id: updateId.toString(),
action: "delete",
tmdbId: id,
});
delete s.items[id];
});
},
replaceItems(items: Record<string, ProgressMediaItem>) {
set((s) => {
s.items = items;
});
},
updateItem({ meta, progress }) {
set((s) => {
// add to updateQueue
updateId += 1;
s.updateQueue.push({
tmdbId: meta.tmdbId,
title: meta.title,
year: meta.releaseYear,
poster: meta.poster,
type: meta.type,
progress: { ...progress },
id: updateId.toString(),
episodeId: meta.episode?.tmdbId,
seasonId: meta.season?.tmdbId,
seasonNumber: meta.season?.number,
episodeNumber: meta.episode?.number,
action: "upsert",
});
// add to progress store
if (!s.items[meta.tmdbId])
s.items[meta.tmdbId] = {
type: meta.type,
episodes: {},
seasons: {},
updatedAt: 0,
title: meta.title,
year: meta.releaseYear,
poster: meta.poster,
};
const item = s.items[meta.tmdbId];
item.updatedAt = Date.now();
if (meta.type === "movie") {
if (!item.progress)
item.progress = {
duration: 0,
watched: 0,
};
item.progress = { ...progress };
return;
}
if (!meta.episode || !meta.season) return;
if (!item.seasons[meta.season.tmdbId])
item.seasons[meta.season.tmdbId] = {
id: meta.season.tmdbId,
number: meta.season.number,
title: meta.season.title,
};
if (!item.episodes[meta.episode.tmdbId])
item.episodes[meta.episode.tmdbId] = {
id: meta.episode.tmdbId,
number: meta.episode.number,
title: meta.episode.title,
seasonId: meta.season.tmdbId,
updatedAt: Date.now(),
progress: {
duration: 0,
watched: 0,
},
};
item.episodes[meta.episode.tmdbId].progress = { ...progress };
});
},
clear() {
set((s) => {
s.items = {};
});
},
clearUpdateQueue() {
set((s) => {
s.updateQueue = [];
});
},
removeUpdateItem(id: string) {
set((s) => {
s.updateQueue = [...s.updateQueue.filter((v) => v.id !== id)];
});
},
})),
{
name: "__MW::progress",
},
),
);