@@ -99,12 +99,12 @@ const QuickSelectModal = ({ onClose, seriesId, show, type }: Props) => {
{type === ReleaseManagementItemType.DuplicateFiles && (
<>
- Import Folder:
- {`${importFolder.Name} (ID: ${importFolder.ID})`}
+ Managed Folder:
+ {`${managedFolder.Name} (ID: ${managedFolder.ID})`}
Location:
- {group.FileLocation?.replace(importFolder.Path, '')}
+ {group.FileLocation?.replace(managedFolder.Path, '')}
{group.Episodes?.length}
@@ -138,8 +138,8 @@ const QuickSelectModal = ({ onClose, seriesId, show, type }: Props) => {
{`v${group.FileVersion}`}
- Import Folder:
- {`${importFolder.Name} (ID: ${importFolder.ID})`}
+ Managed Folder:
+ {`${managedFolder.Name} (ID: ${managedFolder.ID})`}
{group.FileSource}
diff --git a/src/components/Utilities/constants.tsx b/src/components/Utilities/constants.tsx
index 4bad515c9..ddf7a73d2 100644
--- a/src/components/Utilities/constants.tsx
+++ b/src/components/Utilities/constants.tsx
@@ -18,7 +18,7 @@ export type UtilityHeaderType;
export const criteriaMap = {
- importFolder: FileSortCriteriaEnum.ImportFolderName,
+ managedFolder: FileSortCriteriaEnum.ManagedFolderName,
filename: FileSortCriteriaEnum.FileName,
crc32: FileSortCriteriaEnum.CRC32,
size: FileSortCriteriaEnum.FileSize,
@@ -56,7 +56,7 @@ export const staticColumns: UtilityHeaderType[] = [
id: 'crc32',
name: 'CRC32',
className: 'w-32',
- item: file => file.Hashes.CRC32,
+ item: file => file.Hashes.find(hash => hash.Type === 'CRC32')?.Value,
},
{
id: 'size',
diff --git a/src/core/patches.ts b/src/core/patches.ts
index 121177ee0..6346d2aed 100644
--- a/src/core/patches.ts
+++ b/src/core/patches.ts
@@ -45,5 +45,17 @@ export const webuiSettingsPatches = {
webuiSettings.collection.anidb.filterDescription = false;
return { ...webuiSettings, settingsRevision: 10 };
},
+ 11: (oldWebuiSettings) => {
+ const webuiSettings = oldWebuiSettings;
+ webuiSettings.dashboard.hideManagedFolders = webuiSettings.dashboard.hideImportFolders;
+ delete webuiSettings.dashboard.hideImportFolders;
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ let layoutItem = webuiSettings.layout.dashboard.lg.find(item => item.i === 'importFolders');
+ if (layoutItem) layoutItem.i = 'managedFolders';
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ layoutItem = webuiSettings.layout.dashboard.md.find(item => item.i === 'importFolders');
+ if (layoutItem) layoutItem.i = 'managedFolders';
+ return { ...webuiSettings, settingsRevision: 11 };
+ },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as Record WebUISettingsType>;
diff --git a/src/core/quick-actions.ts b/src/core/quick-actions.ts
index 510441bb6..645201c89 100644
--- a/src/core/quick-actions.ts
+++ b/src/core/quick-actions.ts
@@ -66,7 +66,7 @@ const quickActions = {
'import-new-files': {
name: 'Import New Files',
functionName: 'ImportNewFiles',
- info: 'Queues a task to import only new files found in the import folder',
+ info: 'Queues a task to import only new files found in the managed folders.',
},
'avdump-mismatched-files': {
name: 'AVDump Mismatched Files',
diff --git a/src/core/react-query/dashboard/helpers.ts b/src/core/react-query/dashboard/helpers.ts
index 70149c4d0..3e65a2a9f 100644
--- a/src/core/react-query/dashboard/helpers.ts
+++ b/src/core/react-query/dashboard/helpers.ts
@@ -2,8 +2,10 @@ import type { DashboardSeriesSummaryType } from '@/core/types/api/dashboard';
export const transformSeriesSummary = (response: DashboardSeriesSummaryType) => {
const result = response;
- result.Other += (result?.Special ?? 0) + (result?.None ?? 0);
+ result.Other += (result?.Special ?? 0) + (result?.MusicVideo ?? 0) + (result?.Unknown ?? 0) + (result?.None ?? 0);
delete result.Special;
+ delete result.MusicVideo;
+ delete result.Unknown;
delete result.None;
return result;
};
diff --git a/src/core/react-query/import-folder/mutations.ts b/src/core/react-query/import-folder/mutations.ts
deleted file mode 100644
index da02b6fb8..000000000
--- a/src/core/react-query/import-folder/mutations.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useMutation } from '@tanstack/react-query';
-
-import { axios } from '@/core/axios';
-import { invalidateQueries } from '@/core/react-query/queryClient';
-
-import type { DeleteImportFolderRequestType } from '@/core/react-query/import-folder/types';
-import type { ImportFolderType } from '@/core/types/api/import-folder';
-
-export const useCreateImportFolderMutation = () =>
- useMutation({
- mutationFn: (folder: ImportFolderType) => axios.post('ImportFolder', folder),
- onSuccess: () => invalidateQueries(['import-folder']),
- });
-
-export const useDeleteImportFolderMutation = () =>
- useMutation({
- mutationFn: ({ folderId, ...data }: DeleteImportFolderRequestType) =>
- axios.delete(`ImportFolder/${folderId}`, { data }),
- onSuccess: () => invalidateQueries(['import-folder']),
- });
-
-export const useRescanImportFolderMutation = () =>
- useMutation({
- mutationFn: (folderId: number) => axios.get(`ImportFolder/${folderId}/Scan`),
- });
-
-export const useUpdateImportFolderMutation = () =>
- useMutation({
- mutationFn: (folder: ImportFolderType) => axios.put('ImportFolder', folder),
- onSuccess: () => invalidateQueries(['import-folder']),
- });
diff --git a/src/core/react-query/import-folder/queries.ts b/src/core/react-query/import-folder/queries.ts
deleted file mode 100644
index 516981f74..000000000
--- a/src/core/react-query/import-folder/queries.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { useQuery } from '@tanstack/react-query';
-
-import { axios } from '@/core/axios';
-
-import type { ImportFolderType } from '@/core/types/api/import-folder';
-
-export const useImportFoldersQuery = () =>
- useQuery({
- queryKey: ['import-folder'],
- queryFn: () => axios.get('ImportFolder'),
- });
diff --git a/src/core/react-query/managed-folder/mutations.ts b/src/core/react-query/managed-folder/mutations.ts
new file mode 100644
index 000000000..041df53f4
--- /dev/null
+++ b/src/core/react-query/managed-folder/mutations.ts
@@ -0,0 +1,31 @@
+import { useMutation } from '@tanstack/react-query';
+
+import { axios } from '@/core/axios';
+import { invalidateQueries } from '@/core/react-query/queryClient';
+
+import type { DeleteManagedFolderRequestType } from '@/core/react-query/managed-folder/types';
+import type { ManagedFolderType } from '@/core/types/api/managed-folder';
+
+export const useCreateManagedFolderMutation = () =>
+ useMutation({
+ mutationFn: (folder: ManagedFolderType) => axios.post('ManagedFolder', folder),
+ onSuccess: () => invalidateQueries(['managed-folder']),
+ });
+
+export const useDeleteManagedFolderMutation = () =>
+ useMutation({
+ mutationFn: ({ folderId, ...data }: DeleteManagedFolderRequestType) =>
+ axios.delete(`ManagedFolder/${folderId}`, { data }),
+ onSuccess: () => invalidateQueries(['managed-folder']),
+ });
+
+export const useRescanManagedFolderMutation = () =>
+ useMutation({
+ mutationFn: (folderId: number) => axios.get(`ManagedFolder/${folderId}/Scan`),
+ });
+
+export const useUpdateManagedFolderMutation = () =>
+ useMutation({
+ mutationFn: (folder: ManagedFolderType) => axios.put('ManagedFolder', folder),
+ onSuccess: () => invalidateQueries(['managed-folder']),
+ });
diff --git a/src/core/react-query/managed-folder/queries.ts b/src/core/react-query/managed-folder/queries.ts
new file mode 100644
index 000000000..5aed13b22
--- /dev/null
+++ b/src/core/react-query/managed-folder/queries.ts
@@ -0,0 +1,11 @@
+import { useQuery } from '@tanstack/react-query';
+
+import { axios } from '@/core/axios';
+
+import type { ManagedFolderType } from '@/core/types/api/managed-folder';
+
+export const useManagedFoldersQuery = () =>
+ useQuery({
+ queryKey: ['managed-folder'],
+ queryFn: () => axios.get('ManagedFolder'),
+ });
diff --git a/src/core/react-query/import-folder/types.ts b/src/core/react-query/managed-folder/types.ts
similarity index 61%
rename from src/core/react-query/import-folder/types.ts
rename to src/core/react-query/managed-folder/types.ts
index 6d7948a13..f3afdf5c1 100644
--- a/src/core/react-query/import-folder/types.ts
+++ b/src/core/react-query/managed-folder/types.ts
@@ -1,4 +1,4 @@
-export type DeleteImportFolderRequestType = {
+export type DeleteManagedFolderRequestType = {
folderId: number;
removeRecords?: boolean;
updateMyList?: boolean;
diff --git a/src/core/react-query/settings/helpers.ts b/src/core/react-query/settings/helpers.ts
index cc7c48b8e..470aa378c 100644
--- a/src/core/react-query/settings/helpers.ts
+++ b/src/core/react-query/settings/helpers.ts
@@ -67,7 +67,7 @@ const initialLayout = {
static: false,
},
{
- i: 'importFolders',
+ i: 'managedFolders',
x: 6,
y: 37,
w: 3,
@@ -190,7 +190,7 @@ const initialLayout = {
static: false,
},
{
- i: 'importFolders',
+ i: 'managedFolders',
x: 5,
y: 51,
w: 5,
@@ -298,7 +298,7 @@ export const initialSettings: SettingsType = {
hideRecentlyImported: false,
hideCollectionStats: false,
hideMediaType: false,
- hideImportFolders: false,
+ hideManagedFolders: false,
hideShokoNews: false,
hideContinueWatching: false,
hideNextUp: false,
diff --git a/src/core/router/index.tsx b/src/core/router/index.tsx
index 42c3df537..67fa7fc81 100644
--- a/src/core/router/index.tsx
+++ b/src/core/router/index.tsx
@@ -22,8 +22,8 @@ import Acknowledgement from '@/pages/firstrun/Acknowledgement';
import AniDBAccount from '@/pages/firstrun/AniDBAccount';
import DataCollection from '@/pages/firstrun/DataCollection';
import FirstRunPage from '@/pages/firstrun/FirstRunPage';
-import ImportFolders from '@/pages/firstrun/ImportFolders';
import LocalAccount from '@/pages/firstrun/LocalAccount';
+import ManagedFolders from '@/pages/firstrun/ManagedFolders';
import MetadataSources from '@/pages/firstrun/MetadataSources';
import StartServer from '@/pages/firstrun/StartServer';
import LoginPage from '@/pages/login/LoginPage';
@@ -69,7 +69,7 @@ const router = sentryCreateBrowserRouter(
} />
} />
} />
- } />
+ } />
} />
} />
diff --git a/src/core/signalr/eventHandlers.ts b/src/core/signalr/eventHandlers.ts
index ac8095af3..4be5d4463 100644
--- a/src/core/signalr/eventHandlers.ts
+++ b/src/core/signalr/eventHandlers.ts
@@ -14,8 +14,8 @@ const invalidateFiles = debounce(
1000,
);
-const invalidateImportFolders = debounce(
- () => invalidateQueries(['import-folder']),
+const invalidateManagedFolders = debounce(
+ () => invalidateQueries(['managed-folder']),
1000,
);
@@ -47,12 +47,12 @@ export const handleEvent = (event: string, data?: SeriesUpdateEventType) => {
case 'FileMatched':
invalidateDashboard();
invalidateFiles();
- invalidateImportFolders();
+ invalidateManagedFolders();
invalidateReleaseManagement();
break;
case 'FileMoved':
invalidateFiles();
- invalidateImportFolders();
+ invalidateManagedFolders();
break;
case 'FileRenamed':
invalidateFiles();
@@ -62,7 +62,7 @@ export const handleEvent = (event: string, data?: SeriesUpdateEventType) => {
break;
case 'SeriesUpdated':
invalidateDashboard();
- invalidateImportFolders();
+ invalidateManagedFolders();
if (!data?.ShokoGroupIDs || !data?.ShokoSeriesIDs) return;
invalidateSeries(data.ShokoSeriesIDs[0], data.ShokoGroupIDs);
break;
diff --git a/src/core/slices/modals.ts b/src/core/slices/modals.ts
index d550c509d..1cbd53d36 100644
--- a/src/core/slices/modals.ts
+++ b/src/core/slices/modals.ts
@@ -3,12 +3,12 @@ import { combineReducers } from '@reduxjs/toolkit';
import browseFolderReducer from './modals/browseFolder';
import editGroupReducer from './modals/editGroup';
import editSeriesReducer from './modals/editSeries';
-import importFolderReducer from './modals/importFolder';
+import managedFolderReducer from './modals/managedFolder';
import profileReducer from './modals/profile';
export default combineReducers({
browseFolder: browseFolderReducer,
- importFolder: importFolderReducer,
+ managedFolder: managedFolderReducer,
profile: profileReducer,
editSeries: editSeriesReducer,
editGroup: editGroupReducer,
diff --git a/src/core/slices/modals/importFolder.ts b/src/core/slices/modals/managedFolder.ts
similarity index 75%
rename from src/core/slices/modals/importFolder.ts
rename to src/core/slices/modals/managedFolder.ts
index bdaaa1651..a9f09343d 100644
--- a/src/core/slices/modals/importFolder.ts
+++ b/src/core/slices/modals/managedFolder.ts
@@ -2,8 +2,8 @@ import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
-const importFolderSlice = createSlice({
- name: 'importFolder',
+const managedFolderSlice = createSlice({
+ name: 'managedFolder',
initialState: {
status: false,
edit: false,
@@ -23,6 +23,6 @@ const importFolderSlice = createSlice({
},
});
-export const { setEdit, setStatus } = importFolderSlice.actions;
+export const { setEdit, setStatus } = managedFolderSlice.actions;
-export default importFolderSlice.reducer;
+export default managedFolderSlice.reducer;
diff --git a/src/core/slices/utilities/renamer.ts b/src/core/slices/utilities/renamer.ts
index 80fe4c6f1..46155ff02 100644
--- a/src/core/slices/utilities/renamer.ts
+++ b/src/core/slices/utilities/renamer.ts
@@ -34,7 +34,7 @@ const renamerSlice = createSlice({
if (!file) return;
if (result.RelativePath) file.Locations[0].RelativePath = result.RelativePath;
if (result.AbsolutePath) file.Locations[0].AbsolutePath = result.AbsolutePath;
- if (result.ImportFolderID) file.Locations[0].ImportFolderID = result.ImportFolderID;
+ if (result.ManagedFolderID) file.Locations[0].ManagedFolderID = result.ManagedFolderID;
});
},
addRenameResults(sliceState, action: PayloadAction>) {
diff --git a/src/core/types/api/collection.ts b/src/core/types/api/collection.ts
index 0d79b04d4..a09fa708c 100644
--- a/src/core/types/api/collection.ts
+++ b/src/core/types/api/collection.ts
@@ -32,6 +32,7 @@ export type GroupSizesSeriesTypesType = {
Web: number;
Movie: number;
OVA: number;
+ MusicVideo: number;
};
export type CollectionFilterType = {
diff --git a/src/core/types/api/dashboard.ts b/src/core/types/api/dashboard.ts
index 3079a2a6b..523a3eb7e 100644
--- a/src/core/types/api/dashboard.ts
+++ b/src/core/types/api/dashboard.ts
@@ -8,6 +8,8 @@ export type DashboardSeriesSummaryType = {
Special?: number;
Web: number;
Other: number;
+ MusicVideo?: number;
+ Unknown?: number;
None?: number;
};
diff --git a/src/core/types/api/file.ts b/src/core/types/api/file.ts
index 0acf23146..d85471630 100644
--- a/src/core/types/api/file.ts
+++ b/src/core/types/api/file.ts
@@ -11,7 +11,7 @@ type XRefsType = {
type FileTypeLocation = {
ID: number;
FileID: number;
- ImportFolderID: number;
+ ManagedFolderID: number;
RelativePath: string;
AbsolutePath?: string;
IsAccessible: boolean;
@@ -20,12 +20,7 @@ type FileTypeLocation = {
export type FileType = {
ID: number;
Size: number;
- Hashes: {
- ED2K: string;
- SHA1: string;
- CRC32: string;
- MD5: string;
- };
+ Hashes: FileHashDigestType[];
Locations: FileTypeLocation[];
Duration: string;
ResumePosition: string | null;
@@ -35,30 +30,68 @@ export type FileType = {
Updated: string;
IsVariation: boolean;
SeriesIDs?: XRefsType[];
- AniDB?: FileAniDBType;
+ ReleaseInfo?: ReleaseInfoType;
MediaInfo?: FileMediaInfoType;
AVDump: FileAVDumpType;
};
-export type FileAniDBType = {
+export type ReleaseInfoType = {
+ ID: string | null;
+ ProviderName: string;
+ ReleaseURI: string | null;
+ Revision: number;
+ FileSize: number | null;
+ Comment: string | null;
+ OriginalFilename: string | null;
+ IsCensored: boolean | null;
+ IsChaptered: boolean | null;
+ IsCorrupted: boolean;
+ Source: ReleaseSource;
+ Group: ReleaseGroupType | null;
+ Hashes: FileHashDigestType[] | null;
+ MediaInfo: ReleaseMediaInfoType | null;
+ CrossReferences: ReleaseCrossReferenceType[];
+ Released: string | null;
+ Updated: string;
+ Created: string;
+};
+
+export enum ReleaseSource {
+ Unknown = 'Unknown',
+ Other = 'Other',
+ TV = 'TV',
+ DVD = 'DVD',
+ BluRay = 'BluRay',
+ Web = 'Web',
+ VHS = 'VHS',
+ VCD = 'VCD',
+ LaserDisc = 'LaserDisc',
+ Camera = 'Camera',
+}
+
+export type ReleaseGroupType = {
ID: number;
- Source: FileSourceEnum;
- ReleaseGroup: FileAniDBReleaseGroupType;
- ReleaseDate: string | null;
- Version: number;
- IsDeprecated: boolean;
- IsCensored: boolean;
- OriginalFileName: string;
- FileSize: bigint;
- Duration: string;
- Resolution: string;
- Description: string;
- AudioCodecs: string[];
+ Name: string;
+ ShortName: string;
+ Source: string;
+};
+
+export type ReleaseCrossReferenceType = {
+ AnidbEpisodeID: number;
+ AnidbAnimeID: number | null;
+ PercentageStart: number;
+ PercentageEnd: number;
+};
+
+export type ReleaseMediaInfoType = {
AudioLanguages: string[];
- SubLanguages: string[];
- VideoCodec: string;
- Chaptered: boolean;
- Updated: string;
+ SubtitleLanguages: string[];
+};
+
+export type FileHashDigestType = {
+ Type: string;
+ Value: string;
+ Metadata?: string;
};
export type FileAVDumpType = {
@@ -214,8 +247,8 @@ export type FileMediaInfoChapterType = {
export enum FileSortCriteriaEnum {
None = 0,
- ImportFolderName = 1,
- ImportFolderID = 2,
+ ManagedFolderName = 1,
+ ManagedFolderID = 2,
AbsolutePath = 3,
RelativePath = 4,
FileSize = 5,
diff --git a/src/core/types/api/import-folder.ts b/src/core/types/api/managed-folder.ts
similarity index 84%
rename from src/core/types/api/import-folder.ts
rename to src/core/types/api/managed-folder.ts
index f0c93d58f..57aa714bb 100644
--- a/src/core/types/api/import-folder.ts
+++ b/src/core/types/api/managed-folder.ts
@@ -1,4 +1,4 @@
-export type ImportFolderType = {
+export type ManagedFolderType = {
ID: number;
WatchForNewFiles?: boolean;
DropFolderType?: 'None' | 'Source' | 'Destination' | 'Both';
diff --git a/src/core/types/api/renamer.ts b/src/core/types/api/renamer.ts
index 194f26d9c..96683fa61 100644
--- a/src/core/types/api/renamer.ts
+++ b/src/core/types/api/renamer.ts
@@ -58,7 +58,7 @@ export type RenamerResultType = {
FileID: number;
FileLocationID?: number;
ConfigName?: string;
- ImportFolderID?: number;
+ ManagedFolderID?: number;
IsSuccess: boolean;
IsRelocated?: boolean;
IsPreview?: boolean;
diff --git a/src/core/types/api/series.ts b/src/core/types/api/series.ts
index 243590d7d..8d6d6e011 100644
--- a/src/core/types/api/series.ts
+++ b/src/core/types/api/series.ts
@@ -75,6 +75,7 @@ export const enum SeriesTypeEnum {
Web = 'Web',
Movie = 'Movie',
OVA = 'OVA',
+ MusicVideo = 'MusicVideo',
}
export const enum SeriesRelationTypeEnum {
diff --git a/src/core/types/api/settings.ts b/src/core/types/api/settings.ts
index d8b3f07c9..4466df545 100644
--- a/src/core/types/api/settings.ts
+++ b/src/core/types/api/settings.ts
@@ -420,7 +420,7 @@ export type WebUISettingsType = {
hideRecentlyImported: boolean;
hideCollectionStats: boolean;
hideMediaType: boolean;
- hideImportFolders: boolean;
+ hideManagedFolders: boolean;
hideShokoNews: boolean;
hideContinueWatching: boolean;
hideNextUp: boolean;
diff --git a/src/core/types/api/webui.ts b/src/core/types/api/webui.ts
index 40862a63d..c7712d343 100644
--- a/src/core/types/api/webui.ts
+++ b/src/core/types/api/webui.ts
@@ -41,7 +41,7 @@ export type WebuiSeriesFileSummaryGroupType = {
FileSource?: string;
FileLocation?: string;
FileIsDeprecated?: boolean;
- ImportFolder?: number;
+ ManagedFolder?: number;
VideoCodecs?: string;
VideoBitDepth?: number;
VideoResolution?: string;
diff --git a/src/core/utilities/getEd2kLink.ts b/src/core/utilities/getEd2kLink.ts
index 072dc0d07..b6b616a9e 100644
--- a/src/core/utilities/getEd2kLink.ts
+++ b/src/core/utilities/getEd2kLink.ts
@@ -1,6 +1,8 @@
import type { FileType } from '@/core/types/api/file';
const getEd2kLink = (file: FileType) =>
- `ed2k://|file|${file.Locations[0]?.RelativePath?.split(/[\\/]+/g).pop() ?? ''}|${file.Size}|${file.Hashes.ED2K}|/`;
+ `ed2k://|file|${file.Locations[0]?.RelativePath?.split(/[\\/]+/g).pop() ?? ''}|${file.Size}|${
+ file.Hashes.find(hash => hash.Type === 'ED2K')!.Value
+ }|/`;
export default getEd2kLink;
diff --git a/src/hooks/useMediaInfo.ts b/src/hooks/useMediaInfo.ts
index c64138b55..6add4b2b1 100644
--- a/src/hooks/useMediaInfo.ts
+++ b/src/hooks/useMediaInfo.ts
@@ -58,9 +58,9 @@ const useMediaInfo = (file: FileType): FileInfo =>
const fileName = absolutePath.split(/[/\\]+/).pop();
const folderPath = absolutePath.slice(0, absolutePath.replaceAll('\\', '/').lastIndexOf('/') + 1);
- const groupInfo = [file.AniDB?.ReleaseGroup?.Name ?? 'Unknown'];
- if (file.AniDB?.Source) groupInfo.push(file.AniDB.Source);
- if (file.AniDB?.Version) groupInfo.push(`v${file.AniDB.Version}`);
+ const groupInfo = [file.ReleaseInfo?.Group?.Name ?? 'Unknown'];
+ if (file.ReleaseInfo?.Source) groupInfo.push(file.ReleaseInfo.Source);
+ if (file.ReleaseInfo?.Revision) groupInfo.push(`v${file.ReleaseInfo.Revision}`);
return {
Name: fileName ?? '',
@@ -68,14 +68,14 @@ const useMediaInfo = (file: FileType): FileInfo =>
Size: file.Size ?? 0,
Group: groupInfo.join(' | '),
Hashes: {
- ED2K: file.Hashes?.ED2K ?? '',
- SHA1: file.Hashes?.SHA1 ?? '',
- CRC32: file.Hashes?.CRC32 ?? '',
- MD5: file.Hashes?.MD5 ?? '',
+ ED2K: file.Hashes?.find(hash => hash.Type === 'ED2K')?.Value ?? '',
+ SHA1: file.Hashes?.find(hash => hash.Type === 'SHA1')?.Value ?? '',
+ CRC32: file.Hashes?.find(hash => hash.Type === 'CRC32')?.Value ?? '',
+ MD5: file.Hashes?.find(hash => hash.Type === 'MD5')?.Value ?? '',
},
VideoInfo: videoInfo,
AudioInfo: audioInfo,
- Chapters: file.AniDB?.Chaptered ?? false,
+ Chapters: file.ReleaseInfo?.IsChaptered ?? false,
};
}, [file]);
diff --git a/src/pages/dashboard/DashboardPage.tsx b/src/pages/dashboard/DashboardPage.tsx
index f68065356..da675f1ee 100644
--- a/src/pages/dashboard/DashboardPage.tsx
+++ b/src/pages/dashboard/DashboardPage.tsx
@@ -17,7 +17,7 @@ import WelcomeModal from '@/pages/dashboard/components/WelcomeModal';
import CollectionStats from './panels/CollectionStats';
import ContinueWatching from './panels/ContinueWatching';
-import ImportFolders from './panels/ImportFolders';
+import ManagedFolders from './panels/ManagedFolders';
import MediaType from './panels/MediaType';
import NextUp from './panels/NextUp';
import QueueProcessor from './panels/QueueProcessor';
@@ -69,7 +69,7 @@ function DashboardPage() {
combineContinueWatching,
hideCollectionStats,
hideContinueWatching,
- hideImportFolders,
+ hideManagedFolders,
hideMediaType,
hideNextUp,
hideQueueProcessor,
@@ -189,9 +189,9 @@ function DashboardPage() {
)}
- {!hideImportFolders && (
-
-
+ {!hideManagedFolders && (
+
+
)}
{!hideShokoNews && (
diff --git a/src/pages/dashboard/panels/ImportFolders.tsx b/src/pages/dashboard/panels/ManagedFolders.tsx
similarity index 66%
rename from src/pages/dashboard/panels/ImportFolders.tsx
rename to src/pages/dashboard/panels/ManagedFolders.tsx
index 9dfc68a83..c2a522330 100644
--- a/src/pages/dashboard/panels/ImportFolders.tsx
+++ b/src/pages/dashboard/panels/ManagedFolders.tsx
@@ -7,12 +7,12 @@ import prettyBytes from 'pretty-bytes';
import Button from '@/components/Input/Button';
import ShokoPanel from '@/components/Panels/ShokoPanel';
import toast from '@/components/Toast';
-import { useRescanImportFolderMutation } from '@/core/react-query/import-folder/mutations';
-import { useImportFoldersQuery } from '@/core/react-query/import-folder/queries';
-import { setEdit, setStatus } from '@/core/slices/modals/importFolder';
+import { useRescanManagedFolderMutation } from '@/core/react-query/managed-folder/mutations';
+import { useManagedFoldersQuery } from '@/core/react-query/managed-folder/queries';
+import { setEdit, setStatus } from '@/core/slices/modals/managedFolder';
import type { RootState } from '@/core/store';
-import type { ImportFolderType } from '@/core/types/api/import-folder';
+import type { ManagedFolderType } from '@/core/types/api/managed-folder';
const Options = ({ onClick }: { onClick: () => void }) => (
void }) => (
);
-function ImportFolders() {
+function ManagedFolders() {
const dispatch = useDispatch();
const layoutEditMode = useSelector((state: RootState) => state.mainpage.layoutEditMode);
- const { mutate: rescanImportFolder } = useRescanImportFolderMutation();
- const importFolderQuery = useImportFoldersQuery();
- const importFolders = importFolderQuery?.data ?? [] as ImportFolderType[];
+ const { mutate: rescanManagedFolder } = useRescanManagedFolderMutation();
+ const managedFolderQuery = useManagedFoldersQuery();
+ const managedFolders = managedFolderQuery?.data ?? [] as ManagedFolderType[];
const rescanFolder = (ID: number, name: string) => {
- rescanImportFolder(ID, {
- onSuccess: () => toast.success('Scan Import Folder Success', `Import Folder ${name} queued for scanning.`),
+ rescanManagedFolder(ID, {
+ onSuccess: () => toast.success('Scan Managed Folder Success', `Managed Folder ${name} queued for scanning.`),
});
};
- const setImportFolderModalStatus = (status: boolean) => dispatch(setStatus(status));
- const openImportFolderModalEdit = (ID: number) => dispatch(setEdit(ID));
+ const setManagedFolderModalStatus = (status: boolean) => dispatch(setStatus(status));
+ const openManagedFolderModalEdit = (ID: number) => dispatch(setEdit(ID));
- const renderFolder = (folder: ImportFolderType) => {
+ const renderFolder = (folder: ManagedFolderType) => {
let flags = '';
if (folder.DropFolderType === 'Both') flags = 'Source, Destination';
@@ -63,7 +63,7 @@ function ImportFolders() {
rotate={180}
/>
-
openImportFolderModalEdit(folder.ID)} tooltip="Edit Folder">
+ openManagedFolderModalEdit(folder.ID)} tooltip="Edit Folder">
setImportFolderModalStatus(true)} />}
- isFetching={importFolderQuery.isPending}
+ title="Managed Folders"
+ options={ setManagedFolderModalStatus(true)} />}
+ isFetching={managedFolderQuery.isPending}
editMode={layoutEditMode}
- contentClassName={importFolders.length > 2 && ('pr-4')}
+ contentClassName={managedFolders.length > 2 && ('pr-4')}
>
- {importFolders.length === 0
- ? No Import Folders Added!
- : importFolders.map(importFolder => renderFolder(importFolder))}
+ {managedFolders.length === 0
+ ? No Managed Folders Added!
+ : managedFolders.map(folder => renderFolder(folder))}
);
}
-export default ImportFolders;
+export default ManagedFolders;
diff --git a/src/pages/firstrun/FirstRunPage.tsx b/src/pages/firstrun/FirstRunPage.tsx
index a24c44c05..fd114e46b 100644
--- a/src/pages/firstrun/FirstRunPage.tsx
+++ b/src/pages/firstrun/FirstRunPage.tsx
@@ -112,7 +112,7 @@ function FirstRunPage() {
-
+
diff --git a/src/pages/firstrun/ImportFolders.tsx b/src/pages/firstrun/ManagedFolders.tsx
similarity index 61%
rename from src/pages/firstrun/ImportFolders.tsx
rename to src/pages/firstrun/ManagedFolders.tsx
index 05c20ca14..2f4bd53ca 100644
--- a/src/pages/firstrun/ImportFolders.tsx
+++ b/src/pages/firstrun/ManagedFolders.tsx
@@ -3,23 +3,20 @@ import { useDispatch } from 'react-redux';
import { mdiMinusCircleOutline, mdiPencilCircleOutline } from '@mdi/js';
import { Icon } from '@mdi/react';
-import ImportFolderModal from '@/components/Dialogs/ImportFolderModal';
+import ManagedFolderModal from '@/components/Dialogs/ManagedFolderModal';
import Button from '@/components/Input/Button';
import toast from '@/components/Toast';
import TransitionDiv from '@/components/TransitionDiv';
-import { useDeleteImportFolderMutation } from '@/core/react-query/import-folder/mutations';
-import { useImportFoldersQuery } from '@/core/react-query/import-folder/queries';
+import { useDeleteManagedFolderMutation } from '@/core/react-query/managed-folder/mutations';
+import { useManagedFoldersQuery } from '@/core/react-query/managed-folder/queries';
import { setSaved as setFirstRunSaved } from '@/core/slices/firstrun';
-import {
- setEdit as setImportFolderModalEdit,
- setStatus as setImportFolderModalStatus,
-} from '@/core/slices/modals/importFolder';
+import { setEdit as setFolderModalEdit, setStatus as setFolderModalStatus } from '@/core/slices/modals/managedFolder';
import Footer from './Footer';
-import type { ImportFolderType } from '@/core/types/api/import-folder';
+import type { ManagedFolderType } from '@/core/types/api/managed-folder';
-const Folder = (props: ImportFolderType) => {
+const Folder = (props: ManagedFolderType) => {
const {
DropFolderType,
ID,
@@ -29,11 +26,11 @@ const Folder = (props: ImportFolderType) => {
} = props;
const dispatch = useDispatch();
- const { mutate: deleteFolder } = useDeleteImportFolderMutation();
+ const { mutate: deleteFolder } = useDeleteManagedFolderMutation();
const handleDeleteFolder = (folderId: number) => {
deleteFolder({ folderId }, {
- onSuccess: () => toast.success('Import folder deleted!'),
+ onSuccess: () => toast.success('Managed folder deleted!'),
});
};
@@ -53,7 +50,7 @@ const Folder = (props: ImportFolderType) => {
{Name}
-
dispatch(setImportFolderModalEdit(ID))}>
+ dispatch(setFolderModalEdit(ID))}>
handleDeleteFolder(ID)}>
@@ -73,45 +70,45 @@ const Folder = (props: ImportFolderType) => {
);
};
-function ImportFolders() {
+function ManagedFolders() {
const dispatch = useDispatch();
- const importFolderQuery = useImportFoldersQuery();
- const importFolders = importFolderQuery?.data ?? [] as ImportFolderType[];
+ const managedFolderQuery = useManagedFoldersQuery();
+ const managedFolders = managedFolderQuery?.data ?? [] as ManagedFolderType[];
return (
<>
- First Run > Import Folders | Shoko
+ First Run > Managed Folders | Shoko
- Import Folders
+ Managed Folders
- For Shoko to function correctly, at least one import folder is required. However, you can add as many import
+ For Shoko to function correctly, at least one managed folder is required. However, you can add as many import
folders as you desire. It's important to note that you can only select one folder to be the designated
drop destination.
- dispatch(setImportFolderModalStatus(true))} buttonType="primary" className="px-6 py-2">
- Add Import Folder
+ dispatch(setFolderModalStatus(true))} buttonType="primary" className="px-6 py-2">
+ Add Managed Folder
- {importFolders.length > 0
+ {managedFolders.length > 0
? (
<>
- Current Import Folders
+ Current Managed Folders
- {importFolders.map(folder => )}
+ {managedFolders.map(folder => )}
>
)
- : No Import Folders Added
}
- dispatch(setFirstRunSaved('import-folders'))} />
+ : No Managed Folders Added
}
+ dispatch(setFirstRunSaved('managed-folders'))} />
-
+
>
);
}
-export default ImportFolders;
+export default ManagedFolders;
diff --git a/src/pages/firstrun/StartServer.tsx b/src/pages/firstrun/StartServer.tsx
index 5ec914df9..11af2e4ca 100644
--- a/src/pages/firstrun/StartServer.tsx
+++ b/src/pages/firstrun/StartServer.tsx
@@ -42,7 +42,7 @@ function StartServer() {
rememberUser: false,
},
{
- onSuccess: () => navigate('../import-folders'),
+ onSuccess: () => navigate('../managed-folders'),
},
);
};
@@ -66,7 +66,7 @@ function StartServer() {
Start Server
On this page you can try and start the server, startup progress will be reported below. After the startup and
- database creation process is complete you will be able to setup import folders.
+ database creation process is complete you will be able to setup managed folders.
diff --git a/src/pages/main/MainPage.tsx b/src/pages/main/MainPage.tsx
index ca2007a6b..507b1368d 100644
--- a/src/pages/main/MainPage.tsx
+++ b/src/pages/main/MainPage.tsx
@@ -6,7 +6,7 @@ import { Tooltip } from 'react-tooltip';
import { mdiLoading } from '@mdi/js';
import { Icon } from '@mdi/react';
-import ImportFolderModal from '@/components/Dialogs/ImportFolderModal';
+import ManagedFolderModal from '@/components/Dialogs/ManagedFolderModal';
import TopNav from '@/components/Layout/TopNav';
import Events from '@/core/events';
import { useSettingsQuery } from '@/core/react-query/settings/queries';
@@ -58,7 +58,7 @@ function MainPage() {
className="z-[10000]"
/>
-
+
diff --git a/src/pages/utilities/FileSearch.tsx b/src/pages/utilities/FileSearch.tsx
index c0d53147a..5538520f5 100644
--- a/src/pages/utilities/FileSearch.tsx
+++ b/src/pages/utilities/FileSearch.tsx
@@ -289,8 +289,8 @@ const FileDetails = React.memo(({ fileId }: { fileId: number }) => {
File Name
- {file.AniDB?.ID && (
-
+ {file.ReleaseInfo?.ReleaseURI?.startsWith('https://anidb.net/file/') && (
+
AniDB File
diff --git a/src/pages/utilities/Renamer.tsx b/src/pages/utilities/Renamer.tsx
index 293bc8121..db497c1b8 100644
--- a/src/pages/utilities/Renamer.tsx
+++ b/src/pages/utilities/Renamer.tsx
@@ -31,7 +31,7 @@ import RenamerScript from '@/components/Utilities/Renamer/RenamerScript';
import RenamerSettings from '@/components/Utilities/Renamer/RenamerSettings';
import MenuButton from '@/components/Utilities/Unrecognized/MenuButton';
import UtilitiesTable from '@/components/Utilities/UtilitiesTable';
-import { useImportFoldersQuery } from '@/core/react-query/import-folder/queries';
+import { useManagedFoldersQuery } from '@/core/react-query/managed-folder/queries';
import {
useRenamerDeleteConfigMutation,
useRenamerPreviewMutation,
@@ -48,10 +48,10 @@ import useRowSelection from '@/hooks/useRowSelection';
import type { UtilityHeaderType } from '@/components/Utilities/constants';
import type { RootState } from '@/core/store';
import type { FileType } from '@/core/types/api/file';
-import type { ImportFolderType } from '@/core/types/api/import-folder';
+import type { ManagedFolderType } from '@/core/types/api/managed-folder';
import type { RenamerConfigSettingsType, RenamerConfigType, RenamerResultType } from '@/core/types/api/renamer';
-const getFileColumn = (importFolders: ImportFolderType[]) => ({
+const getFileColumn = (managedFolders: ManagedFolderType[]) => ({
id: 'filename',
name: 'Original Filename',
className: 'line-clamp-2 grow basis-0 overflow-hidden',
@@ -59,9 +59,9 @@ const getFileColumn = (importFolders: ImportFolderType[]) => ({
const path = file.Locations[0]?.RelativePath ?? '';
const match = /[/\\](?=[^/\\]*$)/g.exec(path);
const relativePath = match ? path?.substring(0, match.index) : 'Root Level';
- const importFolder = find(
- importFolders,
- { ID: file?.Locations[0]?.ImportFolderID ?? -1 },
+ const managedFolder = find(
+ managedFolders,
+ { ID: file?.Locations[0]?.ManagedFolderID ?? -1 },
)?.Name ?? '
';
return (
({
data-tooltip-delay-show={500}
>
- {`${importFolder} - ${relativePath}`}
+ {`${managedFolder} - ${relativePath}`}
{path?.split(/[/\\]/g).pop()}
@@ -83,7 +83,7 @@ const getFileColumn = (importFolders: ImportFolderType[]) => ({
const getResultColumn = (
renameResults: Record,
- importFolders: ImportFolderType[],
+ managedFolders: ManagedFolderType[],
) => ({
id: 'result',
name: 'Result',
@@ -114,9 +114,9 @@ const getResultColumn = (
const path = result.RelativePath ?? '';
const match = /[/\\](?=[^/\\]*$)/g.exec(path);
const relativePath = match ? path?.substring(0, match.index) : 'Root Level';
- const importFolder = find(
- importFolders,
- { ID: result.ImportFolderID ?? -1 },
+ const managedFolder = find(
+ managedFolders,
+ { ID: result.ManagedFolderID ?? -1 },
)?.Name ?? '';
const fileName = path ? path?.split(/[/\\]/g).pop() : 'No change!';
@@ -128,7 +128,7 @@ const getResultColumn = (
data-tooltip-delay-show={500}
>
- {`${importFolder} - ${relativePath}`}
+ {`${managedFolder} - ${relativePath}`}
{fileName}
@@ -175,7 +175,7 @@ const getStatusIcon = (result?: RenamerResultType, noChange = false) => {
const getStatusColumn = (
renameResults: Record,
- importFolders: ImportFolderType[],
+ managedFolders: ManagedFolderType[],
moveFiles: boolean,
) => ({
id: 'status',
@@ -189,20 +189,20 @@ const getStatusColumn = (
const path = file.Locations[0]?.RelativePath ?? '';
const match = /[/\\](?=[^/\\]*$)/g.exec(path);
const relativePath = match ? path?.substring(0, match.index) : 'Root Level';
- const importFolder = find(
- importFolders,
- { ID: file?.Locations[0]?.ImportFolderID ?? -1 },
+ const managedFolder = find(
+ managedFolders,
+ { ID: file?.Locations[0]?.ManagedFolderID ?? -1 },
)?.Name ?? '';
const newPath = result.RelativePath ?? '';
const newRelativePath = match ? newPath?.substring(0, match.index) : 'Root Level';
- const newImportFolder = find(
- importFolders,
- { ID: result.ImportFolderID ?? -1 },
+ const newManagedFolder = find(
+ managedFolders,
+ { ID: result.ManagedFolderID ?? -1 },
)?.Name ?? '';
noChange = (path === newPath) && (!moveFiles
- || (importFolder === newImportFolder && relativePath === newRelativePath));
+ || (managedFolder === newManagedFolder && relativePath === newRelativePath));
}
return (
@@ -298,7 +298,7 @@ const Renamer = () => {
const renameResults = useSelector((state: RootState) => state.utilities.renamer.renameResults);
const settings = useSettingsQuery().data;
- const importFolderQuery = useImportFoldersQuery();
+ const managedFolderQuery = useManagedFoldersQuery();
const renamerConfigsQuery = useRenamerConfigsQuery();
const [
@@ -467,13 +467,13 @@ const Renamer = () => {
} = useRowSelection(addedFiles);
const columns = useMemo(() => {
- const importFolders = importFolderQuery?.data ?? [];
+ const managedFolders = managedFolderQuery?.data ?? [];
return [
- getFileColumn(importFolders),
- getResultColumn(renameResults, importFolders),
- getStatusColumn(renameResults, importFolders, moveFiles),
+ getFileColumn(managedFolders),
+ getResultColumn(renameResults, managedFolders),
+ getStatusColumn(renameResults, managedFolders, moveFiles),
];
- }, [importFolderQuery?.data, moveFiles, renameResults]);
+ }, [managedFolderQuery?.data, moveFiles, renameResults]);
const renamerSettingsExist = useMemo(
() =>
diff --git a/src/pages/utilities/UnrecognizedUtilityTabs/IgnoredFilesTab.tsx b/src/pages/utilities/UnrecognizedUtilityTabs/IgnoredFilesTab.tsx
index 60e636284..b2cbbc931 100644
--- a/src/pages/utilities/UnrecognizedUtilityTabs/IgnoredFilesTab.tsx
+++ b/src/pages/utilities/UnrecognizedUtilityTabs/IgnoredFilesTab.tsx
@@ -14,7 +14,7 @@ import UtilitiesTable from '@/components/Utilities/UtilitiesTable';
import { staticColumns } from '@/components/Utilities/constants';
import { useIgnoreFileMutation } from '@/core/react-query/file/mutations';
import { useFilesInfiniteQuery } from '@/core/react-query/file/queries';
-import { useImportFoldersQuery } from '@/core/react-query/import-folder/queries';
+import { useManagedFoldersQuery } from '@/core/react-query/managed-folder/queries';
import { invalidateQueries } from '@/core/react-query/queryClient';
import { FileSortCriteriaEnum, type FileType } from '@/core/types/api/file';
import useEventCallback from '@/hooks/useEventCallback';
@@ -86,10 +86,10 @@ function IgnoredFilesTab() {
setSearch,
setSortCriteria,
sortCriteria,
- } = useTableSearchSortCriteria(FileSortCriteriaEnum.ImportFolderName);
+ } = useTableSearchSortCriteria(FileSortCriteriaEnum.ManagedFolderName);
- const importFolderQuery = useImportFoldersQuery();
- const importFolders = useMemo(() => importFolderQuery?.data ?? [], [importFolderQuery.data]);
+ const managedFolderQuery = useManagedFoldersQuery();
+ const managedFolders = useMemo(() => managedFolderQuery?.data ?? [], [managedFolderQuery.data]);
const sortOrder = useMemo(() => {
if (!sortCriteria) return undefined;
@@ -110,18 +110,18 @@ function IgnoredFilesTab() {
const columns = useMemo[]>(
() => [
{
- id: 'importFolder',
- name: 'Import Folder',
+ id: 'managedFolder',
+ name: 'Managed Folder',
className: 'w-40',
item: file =>
find(
- importFolders,
- { ID: file?.Locations[0]?.ImportFolderID ?? -1 },
+ managedFolders,
+ { ID: file?.Locations[0]?.ManagedFolderID ?? -1 },
)?.Name ?? '',
},
...staticColumns,
],
- [importFolders],
+ [managedFolders],
);
const {
diff --git a/src/pages/utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx b/src/pages/utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx
index 565b0358d..de2254b55 100644
--- a/src/pages/utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx
+++ b/src/pages/utilities/UnrecognizedUtilityTabs/UnrecognizedTab.tsx
@@ -41,7 +41,7 @@ import {
useRescanFileMutation,
} from '@/core/react-query/file/mutations';
import { useFilesInfiniteQuery } from '@/core/react-query/file/queries';
-import { useImportFoldersQuery } from '@/core/react-query/import-folder/queries';
+import { useManagedFoldersQuery } from '@/core/react-query/managed-folder/queries';
import { invalidateQueries } from '@/core/react-query/queryClient';
import { addFiles } from '@/core/slices/utilities/renamer';
import { FileSortCriteriaEnum } from '@/core/types/api/file';
@@ -248,13 +248,13 @@ function UnrecognizedTab() {
setSearch,
setSortCriteria,
sortCriteria,
- } = useTableSearchSortCriteria(FileSortCriteriaEnum.ImportFolderName);
+ } = useTableSearchSortCriteria(FileSortCriteriaEnum.ManagedFolderName);
const [seriesSelectModal, setSeriesSelectModal] = useState(false);
const { mutate: avdumpFiles } = useAvdumpFilesMutation();
- const importFolderQuery = useImportFoldersQuery();
- const importFolders = useMemo(() => importFolderQuery?.data ?? [], [importFolderQuery.data]);
+ const managedFolderQuery = useManagedFoldersQuery();
+ const managedFolders = useMemo(() => managedFolderQuery?.data ?? [], [managedFolderQuery.data]);
const sortOrder = useMemo(() => {
if (!sortCriteria) return undefined;
@@ -275,23 +275,23 @@ function UnrecognizedTab() {
const columns = useMemo[]>(
() => [
{
- id: 'importFolder',
- name: 'Import Folder',
+ id: 'managedFolder',
+ name: 'Managed Folder',
className: 'w-40',
item: (file) => {
- const importFolder = find(
- importFolders,
- { ID: file?.Locations[0]?.ImportFolderID ?? -1 },
+ const managedFolder = find(
+ managedFolders,
+ { ID: file?.Locations[0]?.ManagedFolderID ?? -1 },
)?.Name ?? '';
return (
- {importFolder}
+ {managedFolder}
);
},
@@ -304,7 +304,7 @@ function UnrecognizedTab() {
item: file => ,
},
],
- [importFolders],
+ [managedFolders],
);
const avdumpList = useSelector((state: RootState) => state.utilities.avdump);