feat: 后端支持修改下载内容

This commit is contained in:
lanyeeee
2026-01-27 05:04:17 +08:00
parent 747300ef30
commit 948fecb7cd
8 changed files with 109 additions and 7 deletions
+9
View File
@@ -25,6 +25,7 @@ use crate::{
normal_info::NormalInfo,
qrcode_data::QrcodeData,
qrcode_status::QrcodeStatus,
restart_download_task_params::RestartDownloadTaskParams,
search_params::SearchParams,
search_result::{
BangumiSearchResult, CheeseSearchResult, FavSearchResult, NormalSearchResult,
@@ -267,6 +268,14 @@ pub fn restart_download_tasks(app: AppHandle, task_ids: Vec<String>) {
download_manager.restart_download_tasks(&task_ids);
}
#[allow(clippy::needless_pass_by_value)]
#[tauri::command(async)]
#[specta::specta]
pub fn restart_download_task(app: AppHandle, params: RestartDownloadTaskParams) {
let download_manager = app.get_download_manager();
download_manager.restart_download_task(&params);
}
#[allow(clippy::needless_pass_by_value)]
#[tauri::command(async)]
#[specta::specta]
+47 -1
View File
@@ -17,7 +17,10 @@ use tokio::sync::Semaphore;
use crate::{
events::DownloadEvent,
extensions::{AnyhowErrorToStringChain, AppHandleExt},
types::create_download_task_params::CreateDownloadTaskParams,
types::{
create_download_task_params::CreateDownloadTaskParams,
restart_download_task_params::RestartDownloadTaskParams,
},
};
use super::{
@@ -182,6 +185,49 @@ impl DownloadManager {
}
}
pub fn restart_download_task(&self, params: &RestartDownloadTaskParams) {
let task_id = &params.task_id;
let tasks = self.download_tasks.read();
let Some(task) = tasks.get(task_id) else {
let err_title = "重来下载任务失败";
let err_msg = format!("未找到ID为`{task_id}`的下载任务");
tracing::error!(err_title, message = err_msg);
return;
};
{
let mut progress = task.progress.write();
progress.video_task.selected = params.video_task_selected;
progress.audio_task.selected = params.audio_task_selected;
progress.video_process_task.merge_selected = params.merge_selected;
progress.video_process_task.embed_chapter_selected = params.embed_chapter_selected;
progress.video_process_task.embed_skip_selected = params.embed_skip_selected;
progress.subtitle_task.selected = params.subtitle_task_selected;
progress.danmaku_task.xml_selected = params.xml_danmaku_selected;
progress.danmaku_task.ass_selected = params.ass_danmaku_selected;
progress.danmaku_task.json_selected = params.json_danmaku_selected;
progress.cover_task.selected = params.cover_task_selected;
progress.nfo_task.selected = params.nfo_task_selected;
progress.json_task.selected = params.json_task_selected;
progress.video_task.video_quality = params.video_quality;
progress.video_task.codec_type = params.codec_type;
progress.audio_task.audio_quality = params.audio_quality;
}
if let Err(err) = task.restart_sender.send(()).map_err(anyhow::Error::from) {
let err_title = "重来下载任务失败";
let err = err.context(format!("通知ID为`{task_id}`的下载任务重来失败"));
let string_chain = err.to_string_chain();
tracing::error!(err_title, message = string_chain);
return;
}
tracing::debug!("已通知ID为`{task_id}`的下载任务重来");
}
async fn emit_download_speed_loop(app: AppHandle, byte_per_sec: Arc<AtomicU64>) {
let mut interval = tokio::time::interval(Duration::from_secs(1));
+9 -3
View File
@@ -296,6 +296,7 @@ impl AudioTask {
!self.selected || self.completed
}
#[allow(clippy::too_many_lines)]
pub async fn process(
&self,
download_task: &Arc<DownloadTask>,
@@ -325,14 +326,19 @@ impl AudioTask {
"{filename}.m4a.com.lanyeeee.bilibili-video-downloader"
));
let file = if temp_file_path.exists() {
// 如果文件已存在,则打开它
let should_reuse_temp_file = temp_file_path
.metadata()
.map(|m| m.len() == audio_task.content_length)
.unwrap_or(false);
let file = if should_reuse_temp_file {
// 如果临时文件可以重用,则直接打开它
OpenOptions::new()
.read(true)
.write(true)
.open(&temp_file_path)?
} else {
// 如果文件不存在,创建它并预分配空间
// 如果临时文件不能重用,则创建个新的
let file = File::create(&temp_file_path)?;
file.allocate(audio_task.content_length)?;
file
+8 -3
View File
@@ -337,14 +337,19 @@ impl VideoTask {
"{filename}.mp4.com.lanyeeee.bilibili-video-downloader"
));
let file = if temp_file_path.exists() {
// 如果临时文件已存在,则打开它
let should_reuse_temp_file = temp_file_path
.metadata()
.map(|m| m.len() == video_task.content_length)
.unwrap_or(false);
let file = if should_reuse_temp_file {
// 如果临时文件可以重用,则直接打开它
OpenOptions::new()
.read(true)
.write(true)
.open(&temp_file_path)?
} else {
// 如果临时文件不存在,创建它并预分配空间
// 如果临时文件不能重用,则创建个新的
let file = File::create(&temp_file_path)?;
file.allocate(video_task.content_length)?;
file
+1
View File
@@ -53,6 +53,7 @@ pub fn run() {
resume_download_tasks,
delete_download_tasks,
restart_download_tasks,
restart_download_task,
restore_download_tasks,
search,
get_logs_dir_size,
+1
View File
@@ -22,6 +22,7 @@ pub mod normal_media_url;
pub mod player_info;
pub mod qrcode_data;
pub mod qrcode_status;
pub mod restart_download_task_params;
pub mod search_params;
pub mod search_result;
pub mod skip_segments;
@@ -0,0 +1,30 @@
use serde::{Deserialize, Serialize};
use specta::Type;
use crate::types::{
audio_quality::AudioQuality, codec_type::CodecType, video_quality::VideoQuality,
};
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
#[serde(default)]
#[allow(clippy::struct_excessive_bools)]
pub struct RestartDownloadTaskParams {
pub task_id: String,
pub video_task_selected: bool,
pub audio_task_selected: bool,
pub merge_selected: bool,
pub embed_chapter_selected: bool,
pub embed_skip_selected: bool,
pub subtitle_task_selected: bool,
pub xml_danmaku_selected: bool,
pub ass_danmaku_selected: bool,
pub json_danmaku_selected: bool,
pub cover_task_selected: bool,
pub nfo_task_selected: bool,
pub json_task_selected: bool,
pub video_quality: VideoQuality,
pub codec_type: CodecType,
pub audio_quality: AudioQuality,
}
+4
View File
@@ -119,6 +119,9 @@ async deleteDownloadTasks(taskIds: string[]) : Promise<void> {
async restartDownloadTasks(taskIds: string[]) : Promise<void> {
await TAURI_INVOKE("restart_download_tasks", { taskIds });
},
async restartDownloadTask(params: RestartDownloadTaskParams) : Promise<void> {
await TAURI_INVOKE("restart_download_task", { params });
},
async restoreDownloadTasks() : Promise<Result<null, CommandError>> {
try {
return { status: "ok", data: await TAURI_INVOKE("restore_download_tasks") };
@@ -359,6 +362,7 @@ export type QrcodeStatus = { url: string; refresh_token: string; timestamp: numb
export type RatingInBangumi = { count: number; score: number }
export type RatingInBangumiFollow = { score: number; count: number }
export type RecommendSeason = { cover: string; ep_count: string; id: number; season_url: string; subtitle: string; title: string; view: number }
export type RestartDownloadTaskParams = { task_id: string; video_task_selected: boolean; audio_task_selected: boolean; merge_selected: boolean; embed_chapter_selected: boolean; embed_skip_selected: boolean; subtitle_task_selected: boolean; xml_danmaku_selected: boolean; ass_danmaku_selected: boolean; json_danmaku_selected: boolean; cover_task_selected: boolean; nfo_task_selected: boolean; json_task_selected: boolean; video_quality: VideoQuality; codec_type: CodecType; audio_quality: AudioQuality }
export type Rights = { bp: number; elec: number; download: number; movie: number; pay: number; hd5: number; no_reprint: number; autoplay: number; ugc_pay: number; is_cooperation: number; ugc_pay_preview: number; no_background: number; clean_mode: number; is_stein_gate: number; is_360: number; no_share: number; arc_pay: number; free_watch: number }
export type RightsInBangumi = { allow_bp: number; allow_bp_rank: number; allow_download: number; allow_review: number; area_limit: number; ban_area_show: number; can_watch: number; copyright: string; forbid_pre: number; freya_white: number; is_cover_show: number; is_preview: number; only_vip_download: number; resource: string; watch_platform: number }
export type RightsInBangumiEp = { allow_dm: number; allow_download: number; area_limit: number }