2022-03-13 14:34:32 +01:00
|
|
|
import { MWMediaMeta, getProviderMetadata, MWMediaType } from "providers";
|
2022-03-06 14:41:51 +01:00
|
|
|
import React, {
|
|
|
|
createContext,
|
|
|
|
ReactNode,
|
|
|
|
useCallback,
|
|
|
|
useContext,
|
|
|
|
useMemo,
|
|
|
|
useState,
|
|
|
|
} from "react";
|
2022-02-18 21:11:23 +01:00
|
|
|
import { VideoProgressStore } from "./store";
|
|
|
|
|
2022-02-28 00:08:20 +01:00
|
|
|
interface WatchedStoreItem extends MWMediaMeta {
|
2022-02-18 21:11:23 +01:00
|
|
|
progress: number;
|
|
|
|
percentage: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface WatchedStoreData {
|
|
|
|
items: WatchedStoreItem[];
|
|
|
|
}
|
|
|
|
|
|
|
|
interface WatchedStoreDataWrapper {
|
2022-02-28 00:08:20 +01:00
|
|
|
updateProgress(media: MWMediaMeta, progress: number, total: number): void;
|
2022-03-06 12:56:22 +01:00
|
|
|
getFilteredWatched(): WatchedStoreItem[];
|
2022-02-18 21:11:23 +01:00
|
|
|
watched: WatchedStoreData;
|
|
|
|
}
|
|
|
|
|
2022-03-06 14:41:51 +01:00
|
|
|
export function getWatchedFromPortable(
|
|
|
|
items: WatchedStoreItem[],
|
|
|
|
media: MWMediaMeta
|
|
|
|
): WatchedStoreItem | undefined {
|
|
|
|
return items.find(
|
|
|
|
(v) =>
|
|
|
|
v.mediaId === media.mediaId &&
|
|
|
|
v.providerId === media.providerId &&
|
|
|
|
v.episode === media.episode &&
|
|
|
|
v.season === media.season
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-02-18 21:11:23 +01:00
|
|
|
const WatchedContext = createContext<WatchedStoreDataWrapper>({
|
2022-02-20 16:45:46 +01:00
|
|
|
updateProgress: () => {},
|
2022-03-06 12:56:22 +01:00
|
|
|
getFilteredWatched: () => [],
|
2022-02-18 21:11:23 +01:00
|
|
|
watched: {
|
|
|
|
items: [],
|
|
|
|
},
|
|
|
|
});
|
|
|
|
WatchedContext.displayName = "WatchedContext";
|
|
|
|
|
|
|
|
export function WatchedContextProvider(props: { children: ReactNode }) {
|
|
|
|
const watchedLocalstorage = VideoProgressStore.get();
|
2022-02-20 16:45:46 +01:00
|
|
|
const [watched, setWatchedReal] = useState<WatchedStoreData>(
|
2022-02-18 21:11:23 +01:00
|
|
|
watchedLocalstorage as WatchedStoreData
|
|
|
|
);
|
2022-02-20 16:45:46 +01:00
|
|
|
|
2022-03-06 14:41:51 +01:00
|
|
|
const setWatched = useCallback(
|
|
|
|
(data: any) => {
|
|
|
|
setWatchedReal((old) => {
|
|
|
|
let newData = data;
|
|
|
|
if (data.constructor === Function) {
|
|
|
|
newData = data(old);
|
2022-02-18 21:11:23 +01:00
|
|
|
}
|
2022-03-06 14:41:51 +01:00
|
|
|
watchedLocalstorage.save(newData);
|
|
|
|
return newData;
|
2022-02-18 21:11:23 +01:00
|
|
|
});
|
|
|
|
},
|
2022-03-06 14:41:51 +01:00
|
|
|
[setWatchedReal, watchedLocalstorage]
|
|
|
|
);
|
|
|
|
|
|
|
|
const contextValue = useMemo(
|
|
|
|
() => ({
|
|
|
|
updateProgress(
|
|
|
|
media: MWMediaMeta,
|
|
|
|
progress: number,
|
|
|
|
total: number
|
|
|
|
): void {
|
|
|
|
setWatched((data: WatchedStoreData) => {
|
|
|
|
let item = getWatchedFromPortable(data.items, media);
|
|
|
|
if (!item) {
|
|
|
|
item = {
|
|
|
|
mediaId: media.mediaId,
|
|
|
|
mediaType: media.mediaType,
|
|
|
|
providerId: media.providerId,
|
|
|
|
title: media.title,
|
|
|
|
year: media.year,
|
|
|
|
percentage: 0,
|
|
|
|
progress: 0,
|
|
|
|
episode: media.episode,
|
|
|
|
season: media.season,
|
|
|
|
};
|
|
|
|
data.items.push(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
// update actual item
|
|
|
|
item.progress = progress;
|
|
|
|
item.percentage = Math.round((progress / total) * 100);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
getFilteredWatched() {
|
2022-03-13 14:34:32 +01:00
|
|
|
// remove disabled providers
|
|
|
|
let filtered = watched.items.filter(
|
2022-03-06 14:41:51 +01:00
|
|
|
(item) => getProviderMetadata(item.providerId)?.enabled
|
|
|
|
);
|
2022-03-13 14:34:32 +01:00
|
|
|
|
|
|
|
// get highest episode number for every anime/season
|
|
|
|
const highestEpisode: Record<string, [number, number]> = {};
|
|
|
|
const highestWatchedItem: Record<string, WatchedStoreItem> = {};
|
|
|
|
filtered = filtered.filter((item) => {
|
|
|
|
if (
|
|
|
|
[MWMediaType.ANIME, MWMediaType.SERIES].includes(item.mediaType)
|
|
|
|
) {
|
|
|
|
const key = `${item.mediaType}-${item.mediaId}`;
|
|
|
|
const current: [number, number] = [
|
|
|
|
item.season ?? -1,
|
|
|
|
item.episode ?? -1,
|
|
|
|
];
|
|
|
|
let existing = highestEpisode[key];
|
|
|
|
if (!existing) {
|
|
|
|
existing = current;
|
|
|
|
highestEpisode[key] = current;
|
|
|
|
highestWatchedItem[key] = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
current[0] > existing[0] ||
|
|
|
|
(current[0] === existing[0] && current[1] > existing[1])
|
|
|
|
) {
|
|
|
|
highestEpisode[key] = current;
|
|
|
|
highestWatchedItem[key] = item;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
return [...filtered, ...Object.values(highestWatchedItem)];
|
2022-03-06 14:41:51 +01:00
|
|
|
},
|
|
|
|
watched,
|
|
|
|
}),
|
|
|
|
[watched, setWatched]
|
|
|
|
);
|
2022-02-18 21:11:23 +01:00
|
|
|
|
|
|
|
return (
|
|
|
|
<WatchedContext.Provider value={contextValue}>
|
|
|
|
{props.children}
|
|
|
|
</WatchedContext.Provider>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function useWatchedContext() {
|
|
|
|
return useContext(WatchedContext);
|
|
|
|
}
|