feat(downloads): add dedicated Torrent category

This commit is contained in:
NimBold
2026-08-10 14:20:50 +03:30
parent 23991c3dea
commit 472da5a681
22 changed files with 150 additions and 25 deletions
+20 -12
View File
@@ -888,7 +888,7 @@ export const AddDownloadsModal = () => {
if (first.status !== 'ready' && first.status !== 'metadata-error') return;
void resolveCategoryDestination(
useSettingsStore.getState(),
categoryForFileName(first.file)
categoryForFileName(first.file, first.isTorrent === true)
).then(location => {
if (requestId === locationResolutionRequestRef.current) {
setSaveLocation(location);
@@ -940,8 +940,8 @@ export const AddDownloadsModal = () => {
}
};
const categoryLocationForFile = (fileName: string) => {
const category = categoryForFileName(fileName);
const categoryLocationForFile = (fileName: string, isTorrent = false) => {
const category = categoryForFileName(fileName, isTorrent);
return resolveCategoryDestination(useSettingsStore.getState(), category);
};
@@ -963,12 +963,13 @@ export const AddDownloadsModal = () => {
fileName: string,
finalLocation: string,
useSharedDestination: boolean,
destinationOverride?: string
destinationOverride?: string,
isTorrent = false
): Promise<string> => {
if (destinationOverride) return destinationOverride;
const root = useSharedDestination
? finalLocation
: await categoryLocationForFile(fileName);
: await categoryLocationForFile(fileName, isTorrent);
return saveInDedicatedFolder
? resolveSubfolderDestination(root, dedicatedFolderName)
: root;
@@ -1113,7 +1114,9 @@ export const AddDownloadsModal = () => {
const suggestedLocation = await destinationForFile(
item.file,
finalLocation,
isSaveLocationManual
isSaveLocationManual,
undefined,
item.isTorrent === true
);
const selected = await open({
directory: true,
@@ -1160,7 +1163,8 @@ export const AddDownloadsModal = () => {
finalFile,
finalLocation,
useSharedDestination,
destinationOverrides[i]
destinationOverrides[i],
item.isTorrent === true
);
const urlMatch = store.downloads.find(d =>
@@ -1342,7 +1346,8 @@ export const AddDownloadsModal = () => {
finalFile,
finalLocation,
useSharedDestination,
destinationOverrides[idx]
destinationOverrides[idx],
item.isTorrent === true
);
let count = 1;
@@ -1358,7 +1363,8 @@ export const AddDownloadsModal = () => {
candidateFile,
finalLocation,
useSharedDestination,
destinationOverrides[candidateIndex]
destinationOverrides[candidateIndex],
candidate.isTorrent === true
);
batchTargets.push({ location: candidateLocation, fileName: candidateFile });
}
@@ -1419,7 +1425,8 @@ export const AddDownloadsModal = () => {
finalFile,
finalLocation,
useSharedDestination,
destinationOverrides[idx]
destinationOverrides[idx],
item.isTorrent === true
);
const store = useDownloadStore.getState();
let existingItem = conflict?.existingDownloadId
@@ -1531,7 +1538,7 @@ export const AddDownloadsModal = () => {
? mediaFileNameForSelectedFormat(item.file, item)
: canonicalizeDownloadFileName(item.file);
let formatSelector = mediaFormatSelectorForRow(item);
const category = categoryForFileName(finalFile);
const category = categoryForFileName(finalFile, item.isTorrent === true);
const added = await addDownload({
id,
url: item.downloadUrl,
@@ -1559,7 +1566,8 @@ export const AddDownloadsModal = () => {
finalFile,
finalLocation,
useSharedDestination,
destinationOverrides[itemIndex]
destinationOverrides[itemIndex],
item.isTorrent === true
)
: undefined,
isMedia: item.isMedia,
+2 -2
View File
@@ -273,8 +273,8 @@ export const DownloadItem = React.memo<DownloadItemProps>(({
</span>
) : null}
{download.isTorrent ? (
<span className="download-quality-chip shrink-0" title={t($ => $.addDownloads.torrentFiles)}>
{t($ => $.addDownloads.torrentFiles)}
<span className="download-quality-chip shrink-0" title={t($ => $.addDownloads.torrent)}>
{t($ => $.addDownloads.torrent)}
</span>
) : null}
</div>
+3 -1
View File
@@ -6,7 +6,7 @@ import { useToast } from '../contexts/ToastContext';
import { useSettingsStore } from '../store/useSettingsStore';
import { SidebarFilter } from './Sidebar';
import {
Play, Pause, Plus, FileText, Image as ImageIcon, Music, Film, Box, Archive, FileQuestion,
Play, Pause, Plus, FileText, Image as ImageIcon, Music, Film, Box, Archive, FileQuestion, Magnet,
ArrowDownCircle, ArrowUp, ArrowDown, Command, ChevronUp, ChevronDown, MoreHorizontal,
AlignLeft, AlignCenter, AlignRight, GripVertical
} from 'lucide-react';
@@ -1850,6 +1850,7 @@ export const DownloadTable: React.FC<DownloadTableProps> = ({ filter, onSummaryC
case 'Documents': return t($ => $.navigation.categories.documents);
case 'Pictures': return t($ => $.navigation.categories.pictures);
case 'Applications': return t($ => $.navigation.categories.applications);
case 'Torrents': return t($ => $.navigation.categories.torrents);
case 'Other': return t($ => $.navigation.categories.other);
default: return filter;
}
@@ -2008,6 +2009,7 @@ export const DownloadTable: React.FC<DownloadTableProps> = ({ filter, onSummaryC
case 'Applications': return <Box size={16} className="text-indigo-400" />;
case 'Pictures': return <ImageIcon size={16} className="text-purple-400" />;
case 'Compressed': return <Archive size={16} className="text-amber-600" />;
case 'Torrents': return <Magnet size={16} className="text-violet-400" />;
case 'Other': return <FileQuestion size={16} className="text-gray-400" />;
default: return <FileQuestion size={16} className="text-gray-400" />;
}
+1
View File
@@ -813,6 +813,7 @@ runEngineChecks(false);
case 'Documents': return t($ => $.navigation.categories.documents);
case 'Pictures': return t($ => $.navigation.categories.pictures);
case 'Applications': return t($ => $.navigation.categories.applications);
case 'Torrents': return t($ => $.navigation.categories.torrents);
default: return t($ => $.navigation.categories.other);
}
};
+2 -1
View File
@@ -2,7 +2,7 @@ import React, { useState, useEffect, useLayoutEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import {
Inbox, Zap, CheckCircle2, CircleDashed,
Film, Music, FileText, Box, Image as ImageIcon, Archive, FileQuestion,
Film, Music, FileText, Box, Image as ImageIcon, Archive, FileQuestion, Magnet,
List, CalendarClock, Gauge, Bug, Settings, Plus, Play, Pause, Edit2, Trash2, PanelLeft,
ChevronDown,
type LucideIcon
@@ -403,6 +403,7 @@ export const Sidebar: React.FC<SidebarProps> = (props) => {
<NavItem icon={FileText} label={t($ => $.navigation.categories.documents)} filter="Documents" />
<NavItem icon={ImageIcon} label={t($ => $.navigation.categories.pictures)} filter="Pictures" />
<NavItem icon={Box} label={t($ => $.navigation.categories.applications)} filter="Applications" />
<NavItem icon={Magnet} label={t($ => $.navigation.categories.torrents)} filter="Torrents" />
<NavItem icon={FileQuestion} label={t($ => $.navigation.categories.other)} filter="Other" />
</div>
</div>