diff --git a/src/components/UserMenu.tsx b/src/components/UserMenu.tsx
index c4e07a1..7ffdfa5 100644
--- a/src/components/UserMenu.tsx
+++ b/src/components/UserMenu.tsx
@@ -130,6 +130,7 @@ export const UserMenu: React.FC = () => {
const [searchTraditionalToSimplified, setSearchTraditionalToSimplified] = useState(false);
const [exactSearch, setExactSearch] = useState(true);
const [maxConcurrentDownloads, setMaxConcurrentDownloads] = useState(6);
+ const [downloadThreadsPerTask, setDownloadThreadsPerTask] = useState(6);
// 邮件通知设置
const [userEmail, setUserEmail] = useState('');
@@ -161,6 +162,7 @@ export const UserMenu: React.FC = () => {
// TMDB 图片设置
const [tmdbImageBaseUrl, setTmdbImageBaseUrl] = useState('https://image.tmdb.org');
const [isUsageSectionOpen, setIsUsageSectionOpen] = useState(false);
+ const [isDownloadSectionOpen, setIsDownloadSectionOpen] = useState(false);
const [isBufferSectionOpen, setIsBufferSectionOpen] = useState(false);
const [isDanmakuSectionOpen, setIsDanmakuSectionOpen] = useState(false);
const [isHomepageSectionOpen, setIsHomepageSectionOpen] = useState(false);
@@ -562,6 +564,12 @@ export const UserMenu: React.FC = () => {
if (savedMaxConcurrentDownloads !== null) {
setMaxConcurrentDownloads(Number(savedMaxConcurrentDownloads));
}
+
+ // 加载单任务线程数设置
+ const savedDownloadThreadsPerTask = localStorage.getItem('downloadThreadsPerTask');
+ if (savedDownloadThreadsPerTask !== null) {
+ setDownloadThreadsPerTask(Number(savedDownloadThreadsPerTask));
+ }
}
}, []);
@@ -917,6 +925,13 @@ export const UserMenu: React.FC = () => {
}
};
+ const handleDownloadThreadsPerTaskChange = (value: number) => {
+ setDownloadThreadsPerTask(value);
+ if (typeof window !== 'undefined') {
+ localStorage.setItem('downloadThreadsPerTask', String(value));
+ }
+ };
+
const handleFluidSearchToggle = (value: boolean) => {
setFluidSearch(value);
if (typeof window !== 'undefined') {
@@ -2034,10 +2049,30 @@ export const UserMenu: React.FC = () => {
+
+ )}
+
- {/* 分割线 */}
-
-
+ {/* 下载设置 */}
+
+
+ {isDownloadSectionOpen && (
+
{/* 最大同时下载限制 */}
@@ -2097,6 +2132,72 @@ export const UserMenu: React.FC = () => {
+
+ {/* 单任务线程数 */}
+
+
+
+ 单任务线程数
+
+
+ 控制每个下载任务使用的线程数量,线程越多下载越快但占用资源越多
+
+
+
+
+ 线程数量
+
+
+ {downloadThreadsPerTask}个
+
+
+
+ handleDownloadThreadsPerTaskChange(Number(e.target.value))}
+ className='flex-1 h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700'
+ style={{
+ background: `linear-gradient(to right, #10b981 0%, #10b981 ${((downloadThreadsPerTask - 1) / (32 - 1)) * 100}%, #e5e7eb ${((downloadThreadsPerTask - 1) / (32 - 1)) * 100}%, #e5e7eb 100%)`
+ }}
+ />
+
+
+
+
+
+
+
+
+
)}
diff --git a/src/lib/m3u8-downloader.ts b/src/lib/m3u8-downloader.ts
index 3e792aa..a3fc4d8 100644
--- a/src/lib/m3u8-downloader.ts
+++ b/src/lib/m3u8-downloader.ts
@@ -347,8 +347,13 @@ export class M3U8Downloader {
}
};
- // 并发下载 6 个片段
- const concurrency = Math.min(6, task.rangeDownload.targetSegment - task.finishNum);
+ // 从localStorage读取单任务线程数设置,默认6个
+ const threadsPerTask = typeof window !== 'undefined'
+ ? Number(localStorage.getItem('downloadThreadsPerTask') || 6)
+ : 6;
+
+ // 并发下载片段
+ const concurrency = Math.min(threadsPerTask, task.rangeDownload.targetSegment - task.finishNum);
for (let i = 0; i < concurrency; i++) {
download();
}