feat: add local files provider with indexing and rescan functionality

- Implemented LocalFilesProvider to manage local video files.
- Added LocalIndex for in-memory and SQLite-backed indexing of video files.
- Introduced scanning functionality to detect video files and extract metadata.
- Added API endpoints for listing collections, genres, and series based on provider capabilities.
- Enhanced existing routes to check for provider capabilities before processing requests.
- Updated frontend to utilize provider capabilities for conditional rendering of UI elements.
- Implemented rescan functionality to refresh the local files index.
- Added database migration for local files index schema.
This commit is contained in:
2026-03-14 03:44:32 +01:00
parent 9b6bcfc566
commit 8f42164bce
30 changed files with 1033 additions and 59 deletions

View File

@@ -0,0 +1,13 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import { api } from "@/lib/api";
import type { ConfigResponse } from "@/lib/types";
export function useConfig() {
return useQuery<ConfigResponse>({
queryKey: ["config"],
queryFn: () => api.config.get(),
staleTime: 5 * 60 * 1000,
});
}

View File

@@ -1,6 +1,6 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "@/lib/api";
import { useAuthContext } from "@/context/auth-context";
import type { MediaFilter } from "@/lib/types";
@@ -23,27 +23,39 @@ export function useCollections() {
* All series are loaded upfront so the series picker can filter client-side
* without a request per keystroke.
*/
export function useSeries(collectionId?: string) {
export function useSeries(collectionId?: string, opts?: { enabled?: boolean }) {
const { token } = useAuthContext();
return useQuery({
queryKey: ["library", "series", collectionId ?? null],
queryFn: () => api.library.series(token!, collectionId),
enabled: !!token,
enabled: !!token && (opts?.enabled ?? true),
staleTime: STALE,
});
}
/** List available genres, optionally scoped to a content type. */
export function useGenres(contentType?: string) {
export function useGenres(contentType?: string, opts?: { enabled?: boolean }) {
const { token } = useAuthContext();
return useQuery({
queryKey: ["library", "genres", contentType ?? null],
queryFn: () => api.library.genres(token!, contentType),
enabled: !!token,
enabled: !!token && (opts?.enabled ?? true),
staleTime: STALE,
});
}
/** Trigger a local-files rescan. Only available when `provider_capabilities.rescan` is true. */
export function useRescanLibrary() {
const { token } = useAuthContext();
const queryClient = useQueryClient();
return useMutation({
mutationFn: () => api.files.rescan(token!),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["library"] });
},
});
}
/**
* Fetch items matching a filter for the block editor's "Preview results" panel.
* Pass `enabled: false` until the user explicitly requests a preview.