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
+18
View File
@@ -130,6 +130,24 @@ describe('download locations', () => {
expect(await resolveCategoryDestination(automatic, 'Movies')).toBe('/Volumes/Media');
});
it('defaults Torrent downloads to the Torrents folder and respects overrides', async () => {
const settings = normalizeDownloadLocationSettings({
baseDownloadFolder: '/Users/test/Downloads'
});
expect(settings.categorySubfolders.Torrents).toBe('Torrents');
expect(await resolveCategoryDestination(settings, 'Torrents'))
.toBe('/Users/test/Downloads/Torrents');
settings.categoryDirectoryOverrides.Torrents = '/Volumes/Archive/Torrents';
expect(await resolveCategoryDestination(settings, 'Torrents'))
.toBe('/Volumes/Archive/Torrents');
settings.categorySubfoldersEnabled = false;
expect(await resolveCategoryDestination(settings, 'Torrents'))
.toBe('/Users/test/Downloads');
});
it('defaults category subfolders on and sends every category to the base folder when disabled', async () => {
const automatic = normalizeDownloadLocationSettings({
baseDownloadFolder: '/Users/test/Downloads'
+3
View File
@@ -19,6 +19,7 @@ export const DOWNLOAD_CATEGORIES: DownloadCategory[] = [
'Documents',
'Pictures',
'Applications',
'Torrents',
'Other'
];
@@ -29,6 +30,7 @@ export const DEFAULT_CATEGORY_SUBFOLDERS: Record<DownloadCategory, string> = {
Documents: 'Documents',
Pictures: 'Pictures',
Applications: 'Applications',
Torrents: 'Torrents',
Other: 'Other'
};
@@ -245,6 +247,7 @@ export const normalizeDownloadLocationSettings = (
Documents: 'Documents',
Pictures: 'Images',
Applications: 'Apps',
Torrents: 'Torrents',
Other: 'Other'
};
+13
View File
@@ -6,6 +6,8 @@ import {
downloadMediaKindsMatch,
MAX_DOWNLOAD_FILENAME_BYTES,
canonicalizeDownloadFileName,
categoryForDownload,
categoryForFileName,
isValidTorrentExcludeTrackerList,
isValidTorrentTrackerList,
normalizeTorrentEncryptionPolicy,
@@ -33,6 +35,17 @@ const item = (status: DownloadItem['status']): DownloadItem => ({
totalIsEstimate: false
});
describe('download category detection', () => {
it('classifies torrent files and explicit Torrent rows separately from filename types', () => {
expect(categoryForFileName('Example.torrent')).toBe('Torrents');
expect(categoryForFileName('Example', true)).toBe('Torrents');
expect(categoryForFileName('Example.mkv', true)).toBe('Torrents');
expect(categoryForFileName('Example.mkv')).toBe('Movies');
expect(categoryForDownload('Renamed', true, 'Other')).toBe('Other');
expect(categoryForDownload('Renamed', true, 'Torrents')).toBe('Torrents');
});
});
describe('download persistence progress snapshots', () => {
it('does not write active byte counters on every progress event', () => {
const persisted = redactDownloadForPersistence(item('downloading'));
+14 -1
View File
@@ -417,7 +417,11 @@ export const initMediaDomains = async () => {
}
};
export const categoryForFileName = (fileName: string): DownloadCategory => {
export const categoryForFileName = (
fileName: string,
isTorrent = false
): DownloadCategory => {
if (isTorrent || fileName.trim().toLowerCase().endsWith('.torrent')) return 'Torrents';
const ext = fileName.split('.').pop()?.toLowerCase() || '';
if (['mp4', 'mkv', 'avi', 'mov', 'wmv', 'flv', 'webm', 'm4v', 'mpeg', 'mpg', '3gp', 'ts', 'vob'].includes(ext)) return 'Movies';
if (['mp3', 'wav', 'aac', 'flac', 'ogg', 'm4a', 'wma', 'alac', 'ape', 'mid', 'midi'].includes(ext)) return 'Musics';
@@ -428,6 +432,15 @@ export const categoryForFileName = (fileName: string): DownloadCategory => {
return 'Other';
};
export const categoryForDownload = (
fileName: string,
isTorrent: boolean,
existingCategory?: DownloadCategory
): DownloadCategory => {
if (isTorrent && existingCategory === 'Other') return existingCategory;
return categoryForFileName(fileName, isTorrent);
};
export const fileNameFromUrl = (rawUrl: string): string => {
try {
const url = new URL(rawUrl);