diff --git a/backend/package.json b/backend/package.json
index d55abdb..0406bcb 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -9,7 +9,7 @@
"build": "npm run build -w packages/reiverr-plugin && nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
- "start:dev": "set NODE_ENV=development&& nest start --watch",
+ "start:dev": "export NODE_ENV=development || set NODE_ENV=development&& nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "npm run typeorm:run-migrations && node dist/src/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
@@ -99,4 +99,4 @@
"packages/jellyfin.plugin",
"packages/torrent-stream.plugin"
]
-}
\ No newline at end of file
+}
diff --git a/src/App.svelte b/src/App.svelte
index ede651a..3cb02a8 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -105,8 +105,10 @@
{#if import.meta.env.DEV}
{/if}
-
+/> -->
+
+
diff --git a/src/lib/components/MediaManager/DownloadList.svelte b/src/lib/components/MediaManager/DownloadList.svelte
deleted file mode 100644
index 768e02b..0000000
--- a/src/lib/components/MediaManager/DownloadList.svelte
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
- {#await downloads}
- {#each new Array(5) as _, index}
-
-
-
- {/each}
- {:then downloads}
- {#each downloads as download, index}
-
-
-
- {:else}
- No downloads found
- {/each}
- {/await}
-
diff --git a/src/lib/components/MediaManager/MediaManagerMenuLayout.svelte b/src/lib/components/MediaManager/MediaManagerMenuLayout.svelte
deleted file mode 100644
index 91f6bdc..0000000
--- a/src/lib/components/MediaManager/MediaManagerMenuLayout.svelte
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
- Header is missing
-
- Content is missing
-
diff --git a/src/lib/components/MediaManager/modals/FileActionsModal.svelte b/src/lib/components/MediaManager/modals/FileActionsModal.svelte
deleted file mode 100644
index 63205d1..0000000
--- a/src/lib/components/MediaManager/modals/FileActionsModal.svelte
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
- {file.relativePath}
-
- {formatSize(file.size || 0)}
-
-
-
-
-
-
-
-
diff --git a/src/lib/components/MediaManager/modals/ReleaseActionsModal.svelte b/src/lib/components/MediaManager/modals/ReleaseActionsModal.svelte
deleted file mode 100644
index 3c3b2a1..0000000
--- a/src/lib/components/MediaManager/modals/ReleaseActionsModal.svelte
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
- {release.title}
-
- {formatSize(release.size || 0)}
-
-
-
-
-
-
-
-
diff --git a/src/lib/components/MediaManager/modals/ReleaseListModal.svelte b/src/lib/components/MediaManager/modals/ReleaseListModal.svelte
deleted file mode 100644
index 3fe04f3..0000000
--- a/src/lib/components/MediaManager/modals/ReleaseListModal.svelte
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
diff --git a/src/lib/components/MediaManager/radarr/RadarrMediaMangerModal.svelte b/src/lib/components/MediaManager/radarr/RadarrMediaMangerModal.svelte
deleted file mode 100644
index c230f73..0000000
--- a/src/lib/components/MediaManager/radarr/RadarrMediaMangerModal.svelte
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
- Download
- radarrApi.getReleases(id)}
- selectRelease={handleSelectRelease}
- />
-
-
- Local Files
-
-
-
- Downloads
-
-
-
diff --git a/src/lib/components/MediaManager/sonarr/SeasonList.svelte b/src/lib/components/MediaManager/sonarr/SeasonList.svelte
deleted file mode 100644
index 4d4def3..0000000
--- a/src/lib/components/MediaManager/sonarr/SeasonList.svelte
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
- {#await $sonarrSeries then series}
- {#if series?.seasons}
- {#each series.seasons.filter((s) => s.seasonNumber !== 0) as season, i}
-
-
-
- {/each}
- {/if}
- {/await}
-
diff --git a/src/lib/components/MediaManager/sonarr/SonarrMediaMangerModal.svelte b/src/lib/components/MediaManager/sonarr/SonarrMediaMangerModal.svelte
deleted file mode 100644
index 976b7c7..0000000
--- a/src/lib/components/MediaManager/sonarr/SonarrMediaMangerModal.svelte
+++ /dev/null
@@ -1,89 +0,0 @@
-
-
-
-
- Download
-
-
-
- Local Files
-
-
-
- Downloads
-
-
-
diff --git a/src/lib/components/MediaManager/sonarr/modals/EpisodeListModal.svelte b/src/lib/components/MediaManager/sonarr/modals/EpisodeListModal.svelte
deleted file mode 100644
index c8e4d27..0000000
--- a/src/lib/components/MediaManager/sonarr/modals/EpisodeListModal.svelte
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-
-
-
- Episodes
-
- {#await $episodes then episodes}
- {#each episodes as episode}
-
-
-
- {/each}
- {/await}
-
-
-
diff --git a/src/lib/components/StackRouter/StackRouter.ts b/src/lib/components/StackRouter/StackRouter.ts
index 9eef6b6..f46256b 100644
--- a/src/lib/components/StackRouter/StackRouter.ts
+++ b/src/lib/components/StackRouter/StackRouter.ts
@@ -1,19 +1,18 @@
-import { derived, get, writable } from 'svelte/store';
import { type ComponentType } from 'svelte';
+import { derived, get, writable } from 'svelte/store';
+import LibraryPage from '../../pages/LibraryPage.svelte';
+import ManagePage from '../../pages/ManagePage/ManagePage.svelte';
+import MoviesHomePage from '../../pages/MoviesHomePage.svelte';
+import PageNotFound from '../../pages/PageNotFound.svelte';
+import PersonPage from '../../pages/PersonPage.svelte';
+import SearchPage from '../../pages/SearchPage.svelte';
import SeriesHomePage from '../../pages/SeriesHomePage.svelte';
import EpisodePage from '../../pages/TitlePages/EpisodePage.svelte';
-import { modalStack } from '../Modal/modal.store';
-import MoviesHomePage from '../../pages/MoviesHomePage.svelte';
-import LibraryPage from '../../pages/LibraryPage.svelte';
-import SearchPage from '../../pages/SearchPage.svelte';
-import PageNotFound from '../../pages/PageNotFound.svelte';
-import ManagePage from '../../pages/ManagePage/ManagePage.svelte';
-import PersonPage from '../../pages/PersonPage.svelte';
-import UsersPage from '../../pages/UsersPage.svelte';
-import StreamSelectorPage from '../../pages/TitlePages/StreamSelectorModal.svelte';
-import SeriesPage from '../../pages/TitlePages/SeriesPage/SeriesPage.svelte';
import MoviePage from '../../pages/TitlePages/MoviePage/MoviePage.svelte';
+import SeriesPage from '../../pages/TitlePages/SeriesPage/SeriesPage.svelte';
import UiComponents from '../../pages/UIComponents.svelte';
+import UsersPage from '../../pages/UsersPage.svelte';
+import { modalStack } from '../Modal/modal.store';
interface Page {
id: symbol;
diff --git a/src/lib/pages/TitlePages/EpisodePage.svelte b/src/lib/pages/TitlePages/EpisodePage.svelte
index 7346476..9c6ca82 100644
--- a/src/lib/pages/TitlePages/EpisodePage.svelte
+++ b/src/lib/pages/TitlePages/EpisodePage.svelte
@@ -1,34 +1,23 @@
- {#await tmdbEpisode then tmdbEpisode}
+ {#await $tmdbEpisode then tmdbEpisode}
-
-
Season {tmdbEpisode?.season_number} Episode {tmdbEpisode?.episode_number}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{#if PLATFORM_WEB}
@@ -413,121 +207,6 @@
{/await}
-
-
-
-
diff --git a/src/lib/pages/TitlePages/SeriesPage/SeriesPage.svelte b/src/lib/pages/TitlePages/SeriesPage/SeriesPage.svelte
index c3e13c1..f07269f 100644
--- a/src/lib/pages/TitlePages/SeriesPage/SeriesPage.svelte
+++ b/src/lib/pages/TitlePages/SeriesPage/SeriesPage.svelte
@@ -10,10 +10,9 @@
import ScrollHelper from '$lib/components/ScrollHelper.svelte';
import { PLATFORM_WEB, TMDB_IMAGES_ORIGINAL } from '$lib/constants';
import { scrollIntoView, useRegistrar } from '$lib/selectable';
- import { tmdbSeriesDataStore, useRequest } from '$lib/stores/data.store';
+ import { tmdbSeriesDataStore } from '$lib/stores/data.store';
import { useSeriesUserData } from '$lib/stores/media-user-data.store';
import { formatThousands } from '$lib/utils';
- import classNames from 'classnames';
import { Bookmark, ExternalLink, Minus, Play } from 'radix-icons-svelte';
import { onDestroy } from 'svelte';
import TitleProperties from '../HeroTitleInfo.svelte';
@@ -22,9 +21,8 @@
export let id: string;
const tmdbId = Number(id);
- const { promise: tmdbSeries, ...tmdbSeriesData } = tmdbSeriesDataStore.subscribe(tmdbId);
-
const {
+ tmdbSeries,
inLibrary,
handleAddToLibrary,
handleRemoveFromLibrary,
@@ -36,207 +34,38 @@
unsubscribe
} = useSeriesUserData(id);
- // const streams = getStreams();
- // streams.forEach((p) =>
- // p.streams.then((s) => availableForStreaming.update((p) => p || s.length > 0))
- // );
-
- // let tmdbSeasons = $tmdbSeries.then((series) =>
- // tmdbApi.getTmdbSeriesSeasons(tmdbId, series?.seasons?.length ?? 1)
- // );
- const { promise: recommendations } = useRequest(tmdbApi.getSeriesRecommendations, tmdbId);
- // let sonarrItem = sonarrApi.getSeriesByTmdbId(tmdbId);
-
- // $: sonarrDownloads = getDownloads(sonarrItem);
- // $: sonarrFiles = getFiles(sonarrItem);
- // $: sonarrSeasonNumbers = Promise.all([sonarrFiles, sonarrDownloads]).then(
- // ([files, downloads]) => [
- // ...new Set(files.map((item) => item.seasonNumber || -1)),
- // ...new Set(downloads.map((item) => item.seasonNumber || -1))
- // ]
- // );
- // $: sonarrEpisodes = Promise.all([sonarrItem, sonarrSeasonNumbers])
- // .then(([item, seasons]) =>
- // Promise.all(seasons.map((s) => sonarrApi.getEpisodes(item?.id || -1, s)))
- // )
- // .then((items) => items.flat());
-
- // const jellyfinSeries = getJellyfinSeries(id);
-
- // const jellyfinEpisodes = jellyfinSeries.then(
- // (s) => (s && jellyfinApi.getJellyfinEpisodes(s.Id)) || []
- // );
-
- // const nextJellyfinEpisode = jellyfinEpisodes.then((items) =>
- // items.find((i) => i.UserData?.Played === false)
- // );
+ $: recommendations = tmdbApi.getSeriesRecommendations(tmdbId);
const episodeCards = useRegistrar();
let scrollTop: number;
let titleProperties: { href?: string; label: string }[] = [];
- $: {
- $tmdbSeries.then((series) => {
- if (series && series.status !== 'Ended') {
- titleProperties.push({
- label: `Since ${new Date(series.first_air_date || Date.now())?.getFullYear()}`
- });
- } else if (series) {
- titleProperties.push({
- label: `Ended ${new Date(series.last_air_date || Date.now())?.getFullYear()}`
- });
- }
+ $tmdbSeries.then((series) => {
+ if (series && series.status !== 'Ended') {
+ titleProperties.push({
+ label: `Since ${new Date(series.first_air_date || Date.now())?.getFullYear()}`
+ });
+ } else if (series) {
+ titleProperties.push({
+ label: `Ended ${new Date(series.last_air_date || Date.now())?.getFullYear()}`
+ });
+ }
- if (series?.vote_average) {
- titleProperties.push({
- label: `${series.vote_average.toFixed(1)} TMDB (${formatThousands(
- series.vote_count ?? 0
- )})`,
- href: `https://www.themoviedb.org/tv/${id}`
- });
- }
+ if (series?.vote_average) {
+ titleProperties.push({
+ label: `${series.vote_average.toFixed(1)} TMDB (${formatThousands(
+ series.vote_count ?? 0
+ )})`,
+ href: `https://www.themoviedb.org/tv/${id}`
+ });
+ }
- if (series?.genres) {
- titleProperties.push({
- label: series.genres.map((g) => g.name).join(', ')
- });
- }
- });
- }
-
- // let hideInterface = false;
- // modalStack.top.subscribe((modal) => {
- // hideInterface = !!modal;
- // });
-
- // function getStreams() {
- // const out: { source: MediaSource; streams: Promise }[] = [];
-
- // for (const source of get(sources)) {
- // out.push({
- // source: source.source,
- // streams: showUserData.then((userData) => {
- // const { season, episode } = userData.playState ?? {};
-
- // return reiverrApiNew.sources
- // .getEpisodeStreams(source.source.id, id, season ?? 1, episode ?? 1)
- // .then((r) => r.data?.streams ?? []);
- // })
- // });
- // }
-
- // return out;
- // }
-
- // function getJellyfinSeries(id: string) {
- // return jellyfinApi.getLibraryItemFromTmdbId(id);
- // }
-
- // const onGrabRelease = () => setTimeout(() => (sonarrDownloads = getDownloads(sonarrItem)), 8000);
-
- // function handleAddedToSonarr() {
- // sonarrItem = sonarrApi.getSeriesByTmdbId(tmdbId);
- // sonarrItem.then(
- // (sonarrItem) =>
- // sonarrItem &&
- // createModal(SonarrMediaManagerModal, {
- // season: 1,
- // sonarrItem,
- // onGrabRelease
- // })
- // );
- // }
-
- // async function handleRequestSeason(season: number) {
- // return sonarrItem.then((sonarrItem) => {
- // const tmdbSeries = get(tmdbSeriesData);
- // if (sonarrItem) {
- // createModal(SonarrMediaManagerModal, {
- // season,
- // sonarrItem,
- // onGrabRelease
- // });
- // } else if (tmdbSeries) {
- // createModal(MmAddToSonarrDialog, {
- // title: tmdbSeries.name || '',
- // tmdbId: tmdbSeries.id || -1,
- // backdropUri: tmdbSeries.backdrop_path || '',
- // onComplete: handleAddedToSonarr
- // });
- // } else {
- // console.error('No series found');
- // }
- // });
- // }
-
- // async function getFiles(item: typeof sonarrItem) {
- // return item.then((item) => (item ? sonarrApi.getFilesBySeriesId(item?.id || -1) : []));
- // }
-
- // async function getDownloads(item: typeof sonarrItem) {
- // return item.then((item) => (item ? sonarrApi.getDownloadsBySeriesId(item?.id || -1) : []));
- // }
-
- // function createConfirmDeleteSeasonDialog(files: EpisodeFileResource[]) {
- // createModal(ConfirmDialog, {
- // header: 'Delete Season Files?',
- // body: `Are you sure you want to delete all ${files.length} file(s) from season ${files[0]?.seasonNumber}?`,
- // confirm: () =>
- // sonarrApi
- // .deleteSonarrEpisodes(files.map((f) => f.id || -1))
- // .then(() => (sonarrFiles = getFiles(sonarrItem)))
- // });
- // }
-
- // function createConfirmCancelDownloadsDialog(downloads: EpisodeDownload[]) {
- // createModal(ConfirmDialog, {
- // header: 'Cancel Season Downloads?',
- // body: `Are you sure you want to cancel all ${downloads.length} download(s) from season ${downloads[0]?.seasonNumber}?`,
- // confirm: () =>
- // sonarrApi
- // .cancelDownloads(downloads.map((f) => f.id || -1))
- // .then(() => (sonarrDownloads = getDownloads(sonarrItem)))
- // });
- // }
-
- // async function handlePlay() {
- // const awaitedStreams = await Promise.all(
- // streams.map(async (p) => ({ ...p, streams: await p.streams }))
- // ).then((d) => d.filter((p) => p.streams.length > 0));
-
- // if (awaitedStreams.length > 1) {
- // modalStack.create(SelectDialog, {
- // title: 'Select Media Source',
- // subtitle: 'Select the media source you want to use',
- // options: awaitedStreams.map((p) => p.source.id),
- // handleSelectOption: (sourceId) => {
- // const s = awaitedStreams.find((p) => p.source.id === sourceId);
- // const key = s?.streams[0]?.key;
- // showUserData.then((userData) =>
- // playerState.streamEpisode(
- // id,
- // userData.playState?.season ?? 1,
- // userData.playState?.episode ?? 1,
- // { userData, sourceId, key }
- // )
- // );
- // }
- // });
- // } else if (awaitedStreams.length === 1) {
- // const asd = awaitedStreams.find((p) => p.streams.length > 0);
- // const sourceId = asd?.source.id;
- // const key = asd?.streams[0]?.key;
-
- // showUserData.then((userData) =>
- // playerState.streamEpisode(
- // id,
- // userData.playState?.season ?? 1,
- // userData.playState?.episode ?? 1,
- // { userData, sourceId, key }
- // )
- // );
- // }
- // }
+ if (series?.genres) {
+ titleProperties.push({
+ label: series.genres.map((g) => g.name).join(', ')
+ });
+ }
+ });
onDestroy(() => {
unsubscribe();
@@ -269,48 +98,11 @@
{#await $tmdbSeries then series}
{#if series}
-
-
-
{/if}
{/await}
{/if}
-
-
-
-
-
-
-
{#if PLATFORM_WEB}
-
-
+
{/await}
- {#await $recommendations then recommendations}
+ {#await recommendations then recommendations}
Recommendations
{#each recommendations || [] as recommendation}
@@ -449,120 +208,6 @@
{/await}
-
diff --git a/src/lib/stores/data.store.ts b/src/lib/stores/data.store.ts
index 72115c9..f107dee 100644
--- a/src/lib/stores/data.store.ts
+++ b/src/lib/stores/data.store.ts
@@ -1,11 +1,5 @@
-import { derived, get, type Readable, writable } from 'svelte/store';
-import { jellyfinApi } from '../apis/jellyfin/jellyfin-api';
-import {
- tmdbApi,
- type TmdbMovieFull2,
- type TmdbSeries2,
- type TmdbSeriesFull2
-} from '../apis/tmdb/tmdb-api';
+import { derived, get, writable } from 'svelte/store';
+import { tmdbApi, type TmdbMovieFull2, type TmdbSeriesFull2 } from '../apis/tmdb/tmdb-api';
import { awaitAppInitialization, reiverrApiNew, user } from './user.store';
type AwaitableStoreValue = {
@@ -14,86 +8,7 @@ type AwaitableStoreValue = {
promise: Promise;
};
-export const useDependantRequest = Promise, A extends any[], S>(
- fn: P,
- store: Readable,
- subscribeFn: (store: S) => Parameters | undefined
-) => {
- const isLoading = writable(true);
- const r = useActionRequest
(fn);
-
- store.subscribe(($data) => {
- const args = subscribeFn($data);
- if (!args) return;
- r.send(...args).finally(() => isLoading.set(false));
- });
-
- return {
- ...r,
- refresh: r.send,
- isLoading: {
- subscribe: isLoading.subscribe
- }
- };
-};
-
-export const useRequest =
Promise, A extends any[]>(
- fn: P,
- ...args: Parameters
-) => {
- const isLoading = writable(true);
- const r = useActionRequest
(fn);
-
- r.send(...args).finally(() => isLoading.set(false));
-
- return {
- ...r,
- refresh: r.send,
- isLoading: {
- subscribe: isLoading.subscribe
- }
- };
-};
-
-export const useActionRequest =
Promise, A extends any[]>(
- fn: P
-) => {
- const request = writable>(undefined);
- const data = writable> | undefined>(undefined);
- const isFetching = writable(false);
-
- function send(...args: Parameters): ReturnType
{
- isFetching.set(true);
- // @ts-ignore
- const p: ReturnType
= fn(...args)
- .then((res) => {
- data.set(res);
- return res;
- })
- .finally(() => {
- isFetching.set(false);
- });
-
- request.set(p);
- return p;
- }
-
- return {
- promise: {
- subscribe: request.subscribe
- },
- data: {
- subscribe: data.subscribe
- },
-
- isFetching: {
- subscribe: isFetching.subscribe
- },
- send
- };
-};
-
-export function useRequest3(fn: () => Promise) {
+export function useRequest(fn: () => Promise) {
async function _createPromise() {
return awaitAppInitialization().then(() => fn());
}
@@ -142,7 +57,7 @@ export function useRequestsStore, TResponse>(
fn: (...args: TArgs) => Promise,
options: { persistant?: boolean } = {}
) {
- type Res = ReturnType>;
+ type Res = ReturnType>;
const requests: Map = new Map();
function subscribe(...args: TArgs): Res & { unsubscribe: () => void } {
@@ -150,7 +65,7 @@ export function useRequestsStore, TResponse>(
let request = requests.get(JSON.stringify(args))?.request;
if (!request) {
- request = useRequest3(() => fn(...args));
+ request = useRequest(() => fn(...args));
requests.set(JSON.stringify(args), {
subscribers: [id],
request
@@ -198,6 +113,9 @@ export function useRequestsStore, TResponse>(
export const tmdbMovieDataStore = useRequestsStore((id: number) => tmdbApi.getTmdbMovie(id));
export const tmdbSeriesDataStore = useRequestsStore((id: number) => tmdbApi.getTmdbSeries(id));
+export const tmdbEpisodeDataStore = useRequestsStore(
+ (tmdbId: number, season: number, episode: number) => tmdbApi.getEpisode(tmdbId, season, episode)
+);
export const movieUserDataStore = useRequestsStore((id: string) =>
reiverrApiNew.users.getMovieUserData(get(user)?.id as string, id).then((r) => r.data)
diff --git a/src/lib/stores/media-user-data.store.ts b/src/lib/stores/media-user-data.store.ts
index ee77d5f..481bc0f 100644
--- a/src/lib/stores/media-user-data.store.ts
+++ b/src/lib/stores/media-user-data.store.ts
@@ -226,6 +226,7 @@ export function useSeriesUserData(tmdbId: string) {
});
return {
+ tmdbSeries: tmdbSeriesRequest.promise,
...libraryStore,
...canStreamStore,
nextEpisode,