mirror of
https://github.com/aleksilassila/reiverr.git
synced 2026-04-21 16:25:11 +02:00
feat: List and delete local files
This commit is contained in:
@@ -132,6 +132,16 @@ export class RadarrApi implements Api<paths> {
|
||||
})
|
||||
.then((res) => res.response.ok) || Promise.resolve(false);
|
||||
|
||||
getMovieFilesByMovieId = (movieId: number): Promise<MovieFileResource[]> =>
|
||||
this.getClient()
|
||||
?.GET('/api/v3/moviefile', {
|
||||
params: {
|
||||
query: {
|
||||
movieId
|
||||
}
|
||||
}
|
||||
})
|
||||
.then((r) => r.data || []) || Promise.resolve([]);
|
||||
deleteRadarrMovieFile = (id: number) =>
|
||||
this.getClient()
|
||||
?.DELETE('/api/v3/moviefile/{id}', {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import UiCarousel from '../../lib/components/Carousel/UICarousel.svelte';
|
||||
import EpisodeCard from '../../lib/components/EpisodeCard/EpisodeCard.svelte';
|
||||
import PersonCard from '../../lib/components/PersonCard/PersonCard.svelte';
|
||||
import SeriesRequestModal from '../../lib/components/RequestModal/SeriesRequestModal.svelte';
|
||||
import SeriesRequestModal from '../components/ManageMedia/SeriesRequestModal.svelte';
|
||||
import OpenInButton from '../../lib/components/TitlePageLayout/OpenInButton.svelte';
|
||||
import TitlePageLayout from '../../lib/components/TitlePageLayout/TitlePageLayout.svelte';
|
||||
import { playerState } from '../../lib/components/VideoPlayer/VideoPlayer';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Container from '../../../Container.svelte';
|
||||
import { modalStack } from './modal.store';
|
||||
import { modalStack } from '../Modal/modal.store';
|
||||
|
||||
export let modalId: symbol;
|
||||
</script>
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="max-h-full mx-auto flex flex-col py-32 max-w-2xl">
|
||||
<h1 class="tracking-wide text-2xl font-semibold mb-4">
|
||||
<slot name="header">Header is missing</slot>
|
||||
</h1>
|
||||
<slot>Content is missing</slot>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import type { MovieFileResource } from '../../../apis/radarr/radarr-api';
|
||||
import Button from '../../Button.svelte';
|
||||
export let file: MovieFileResource;
|
||||
export let handleDeleteFile: (fileId: number) => Promise<boolean>;
|
||||
</script>
|
||||
|
||||
<div class="-my-1">
|
||||
<Button focusOnMount on:click={() => file.id && handleDeleteFile(file.id)}>Delete File</Button>
|
||||
</div>
|
||||
28
src/lib/components/ManageMedia/LocalFiles/FilesList.svelte
Normal file
28
src/lib/components/ManageMedia/LocalFiles/FilesList.svelte
Normal file
@@ -0,0 +1,28 @@
|
||||
<script lang="ts">
|
||||
import { useRequest } from '../../../stores/data.store';
|
||||
import type { MovieFileResource } from '../../../apis/radarr/radarr-api';
|
||||
import ButtonGhost from '../../Ghosts/ButtonGhost.svelte';
|
||||
import Button from '../../Button.svelte';
|
||||
|
||||
export let id: number;
|
||||
export let getFiles: (movieId: number) => Promise<MovieFileResource[]>;
|
||||
export let handleSelectFile: (file: MovieFileResource) => void;
|
||||
|
||||
const { data: files, isLoading } = useRequest(getFiles, id);
|
||||
</script>
|
||||
|
||||
<div class="-my-1">
|
||||
{#if $isLoading}
|
||||
{#each new Array(5) as _, index}
|
||||
<div class="flex-1 my-1">
|
||||
<ButtonGhost />
|
||||
</div>
|
||||
{/each}
|
||||
{:else if $files}
|
||||
{#each $files as file, index}
|
||||
<Button focusOnMount={index === 0} on:click={() => handleSelectFile(file)}>
|
||||
{file.relativePath}
|
||||
</Button>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import FullScreenModal from '../FullScreenModal.svelte';
|
||||
import FullScreenModalContainer from '../FullScreenModalContainer.svelte';
|
||||
import Container from '../../../../Container.svelte';
|
||||
import FilesList from './FilesList.svelte';
|
||||
import { type MovieFileResource, radarrApi } from '../../../apis/radarr/radarr-api';
|
||||
import FileActionsList from './FileActionsList.svelte';
|
||||
import { formatSize } from '../../../utils';
|
||||
|
||||
export let id: number;
|
||||
export let modalId: symbol;
|
||||
|
||||
let selectedFile: MovieFileResource | undefined = undefined;
|
||||
|
||||
function handleSelectFile(file: MovieFileResource) {
|
||||
selectedFile = file;
|
||||
}
|
||||
</script>
|
||||
|
||||
<FullScreenModal {modalId}>
|
||||
{#if !selectedFile}
|
||||
<FullScreenModalContainer>
|
||||
<h1 slot="header">Local Files</h1>
|
||||
<Container>
|
||||
<FilesList getFiles={radarrApi.getMovieFilesByMovieId} {handleSelectFile} {id} />
|
||||
</Container>
|
||||
</FullScreenModalContainer>
|
||||
{:else}
|
||||
<FullScreenModalContainer>
|
||||
<div slot="header" class="flex">
|
||||
<h1 class="line-clamp-1 flex-1 mr-4">
|
||||
{selectedFile.relativePath}
|
||||
</h1>
|
||||
<h1 class="text-zinc-300">{formatSize(selectedFile.size || 0)}</h1>
|
||||
</div>
|
||||
<Container>
|
||||
<FileActionsList file={selectedFile} handleDeleteFile={radarrApi.deleteRadarrMovieFile} />
|
||||
</Container>
|
||||
</FullScreenModalContainer>
|
||||
{/if}
|
||||
</FullScreenModal>
|
||||
@@ -1,17 +1,18 @@
|
||||
<script lang="ts">
|
||||
import FullScreenModal from '../Modal/FullScreenModal.svelte';
|
||||
import { radarrApi } from '../../apis/radarr/radarr-api';
|
||||
import FullScreenModal from '../FullScreenModal.svelte';
|
||||
import { radarrApi } from '../../../apis/radarr/radarr-api';
|
||||
import ReleaseList from './ReleaseList.svelte';
|
||||
import Container from '../../../Container.svelte';
|
||||
import { scrollWithOffset } from '../../selectable';
|
||||
import Container from '../../../../Container.svelte';
|
||||
import { scrollWithOffset } from '../../../selectable';
|
||||
import FullScreenModalContainer from '../FullScreenModalContainer.svelte';
|
||||
|
||||
export let id: number;
|
||||
export let modalId: symbol;
|
||||
</script>
|
||||
|
||||
<FullScreenModal {modalId}>
|
||||
<div class="max-h-full mx-auto flex flex-col py-32 max-w-2xl">
|
||||
<h1 class="tracking-wide text-2xl font-semibold mb-4">Download</h1>
|
||||
<FullScreenModalContainer>
|
||||
<h1 slot="header">Download</h1>
|
||||
<Container
|
||||
childrenRevealStrategy={scrollWithOffset('all', 10)}
|
||||
class="flex-1 overflow-y-scroll"
|
||||
@@ -22,5 +23,5 @@
|
||||
getReleases={radarrApi.fetchRadarrReleases}
|
||||
/>
|
||||
</Container>
|
||||
</div>
|
||||
</FullScreenModalContainer>
|
||||
</FullScreenModal>
|
||||
@@ -1,15 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { type RadarrRelease } from '../../apis/radarr/radarr-api';
|
||||
import type { SonarrRelease } from '../../apis/sonarr/sonarrApi';
|
||||
import { type RadarrRelease } from '../../../apis/radarr/radarr-api';
|
||||
import type { SonarrRelease } from '../../../apis/sonarr/sonarrApi';
|
||||
import classNames from 'classnames';
|
||||
import { useRequest } from '../../stores/data.store';
|
||||
import Button from '../Button.svelte';
|
||||
import { useRequest } from '../../../stores/data.store';
|
||||
import Button from '../../Button.svelte';
|
||||
import { DotFilled, Download, Plus } from 'radix-icons-svelte';
|
||||
import { formatMinutesToTime, formatSize } from '../../utils';
|
||||
import { formatMinutesToTime, formatSize } from '../../../utils';
|
||||
import { derived } from 'svelte/store';
|
||||
import ButtonGhost from '../Ghosts/ButtonGhost.svelte';
|
||||
import Container from '../../../Container.svelte';
|
||||
import { scrollWithOffset } from '../../selectable';
|
||||
import ButtonGhost from '../../Ghosts/ButtonGhost.svelte';
|
||||
|
||||
export let id: number;
|
||||
export let getReleases: (id: number) => Promise<(RadarrRelease | SonarrRelease)[]>;
|
||||
18
src/lib/components/Modal/Modal.svelte
Normal file
18
src/lib/components/Modal/Modal.svelte
Normal file
@@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import Container from '../../../Container.svelte';
|
||||
import { modalStack } from './modal.store';
|
||||
|
||||
export let modalId: symbol;
|
||||
|
||||
function handleShortcuts(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
modalStack.close(modalId);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Container focusOnMount trapFocus class="fixed inset-0">
|
||||
<slot />
|
||||
</Container>
|
||||
|
||||
<svelte:window on:keypress={handleShortcuts} />
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import FullScreenModal from '../Modal/FullScreenModal.svelte';
|
||||
import FullScreenModal from '../ManageMedia/FullScreenModal.svelte';
|
||||
import VideoPlayer from './VideoPlayer.svelte';
|
||||
export let modalId: symbol;
|
||||
export let id: string;
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
import { useActionRequests, useRequest } from '../stores/data.store';
|
||||
import DetachedPage from '../components/DetachedPage/DetachedPage.svelte';
|
||||
import { modalStack } from '../components/Modal/modal.store';
|
||||
import RequestModal from '../components/RequestModal/RadarrRequestModal.svelte';
|
||||
import RequestModal from '../components/ManageMedia/RequestMedia/RadarrRequestModal.svelte';
|
||||
import { playerState } from '../components/VideoPlayer/VideoPlayer';
|
||||
import ManageFilesModal from '../components/ManageMedia/LocalFiles/ManageFilesModal.svelte';
|
||||
|
||||
export let id: string;
|
||||
|
||||
@@ -98,7 +99,7 @@
|
||||
{#if jellyfinItem}
|
||||
<Button
|
||||
class="mr-2"
|
||||
on:click={() => modalStack.create(RequestModal, { id: radarrItem.id })}
|
||||
on:click={() => modalStack.create(ManageFilesModal, { id: radarrItem.id })}
|
||||
>
|
||||
Manage Files
|
||||
<File size={19} slot="icon" />
|
||||
|
||||
@@ -279,7 +279,7 @@ export const useRequest = <P extends (...args: A) => Promise<any>, A extends any
|
||||
return p;
|
||||
}
|
||||
|
||||
refresh(...initialArgs).finally(() => isLoading.set(false));
|
||||
if (initialArgs) refresh(...initialArgs).finally(() => isLoading.set(false));
|
||||
|
||||
return {
|
||||
promise: {
|
||||
|
||||
Reference in New Issue
Block a user