fix: 修复 没分段没广告 的视频会嵌入一个空章节元数据的问题

This commit is contained in:
lanyeeee
2025-09-03 04:03:14 +08:00
parent 8372b05143
commit f49340a42b
@@ -1,4 +1,4 @@
use std::sync::Arc; use std::{path::PathBuf, sync::Arc};
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -65,6 +65,8 @@ impl VideoProcessTask {
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let (episode_dir, filename) = (&progress.episode_dir, &progress.filename); let (episode_dir, filename) = (&progress.episode_dir, &progress.filename);
let ffmpeg_program = utils::get_ffmpeg_program().context("获取FFmpeg程序路径失败")?;
let video_path = episode_dir.join(format!("{filename}.mp4")); let video_path = episode_dir.join(format!("{filename}.mp4"));
if !video_path.exists() { if !video_path.exists() {
download_task.update_progress(|p| p.video_process_task.completed = true); download_task.update_progress(|p| p.video_process_task.completed = true);
@@ -80,19 +82,13 @@ impl VideoProcessTask {
return Ok(()); return Ok(());
} }
let chapter_segments = self let metadata_path = self
.create_chapter_segments(&download_task.app, progress, player_info) .create_chapter_metadata(&download_task.app, progress, player_info)
.await?; .await
let metadata_content = chapter_segments.generate_chapter_metadata(progress.duration); .context("创建章节元数据失败")?;
let metadata_path = episode_dir.join(format!("{filename}.FFMETA.ini"));
std::fs::write(&metadata_path, metadata_content)
.context(format!("保存章节元数据到`{}`失败", metadata_path.display()))?;
let output_path = episode_dir.join(format!("{filename}-merged.mp4")); let output_path = episode_dir.join(format!("{filename}-merged.mp4"));
let ffmpeg_program = utils::get_ffmpeg_program().context("获取FFmpeg程序路径失败")?;
let (tx, rx) = tokio::sync::oneshot::channel(); let (tx, rx) = tokio::sync::oneshot::channel();
let video_path_clone = video_path.clone(); let video_path_clone = video_path.clone();
let audio_path_clone = audio_path.clone(); let audio_path_clone = audio_path.clone();
@@ -106,19 +102,25 @@ impl VideoProcessTask {
.arg("-i") .arg("-i")
.arg(video_path_clone) .arg(video_path_clone)
.arg("-i") .arg("-i")
.arg(audio_path_clone) .arg(audio_path_clone);
.arg("-i")
.arg(metadata_path_clone) if let Some(metadata_path) = metadata_path_clone {
.arg("-map_metadata") command
.arg("2") .arg("-i")
.arg(metadata_path)
.arg("-map_metadata")
.arg("2");
}
command
.arg("-c") .arg("-c")
.arg("copy") .arg("copy")
.arg("-map") .arg("-map")
.arg("0:v:0") .arg("0:v:0")
.arg("-map") .arg("-map")
.arg("1:a:0") .arg("1:a:0");
.arg(output_path_clone)
.arg("-y"); command.arg(output_path_clone).arg("-y");
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {
@@ -152,10 +154,13 @@ impl VideoProcessTask {
output_path.display(), output_path.display(),
video_path.display() video_path.display()
))?; ))?;
std::fs::remove_file(&metadata_path).context(format!(
"删除章节元数据文件`{}`失败", if let Some(metadata_path) = metadata_path {
metadata_path.display() std::fs::remove_file(&metadata_path).context(format!(
))?; "删除章节元数据文件`{}`失败",
metadata_path.display()
))?;
}
download_task.update_progress(|p| p.video_process_task.completed = true); download_task.update_progress(|p| p.video_process_task.completed = true);
@@ -253,23 +258,25 @@ impl VideoProcessTask {
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let (episode_dir, filename) = (&progress.episode_dir, &progress.filename); let (episode_dir, filename) = (&progress.episode_dir, &progress.filename);
let ffmpeg_program = utils::get_ffmpeg_program().context("获取FFmpeg程序路径失败")?;
let video_path = episode_dir.join(format!("{filename}.mp4")); let video_path = episode_dir.join(format!("{filename}.mp4"));
if !video_path.exists() { if !video_path.exists() {
download_task.update_progress(|p| p.video_process_task.completed = true); download_task.update_progress(|p| p.video_process_task.completed = true);
return Ok(()); return Ok(());
} }
let ffmpeg_program = utils::get_ffmpeg_program().context("获取FFmpeg程序路径失败")?;
let output_path = episode_dir.join(format!("{filename}-embed.mp4")); let output_path = episode_dir.join(format!("{filename}-embed.mp4"));
let chapter_segments = self let metadata_path = self
.create_chapter_segments(&download_task.app, progress, player_info) .create_chapter_metadata(&download_task.app, progress, player_info)
.await?; .await
let metadata_content = chapter_segments.generate_chapter_metadata(progress.duration); .context("创建章节元数据失败")?;
let metadata_path = episode_dir.join(format!("{filename}.FFMETA.ini"));
std::fs::write(&metadata_path, metadata_content) let Some(metadata_path) = metadata_path else {
.context(format!("保存章节元数据到`{}`失败", metadata_path.display()))?; download_task.update_progress(|p| p.video_process_task.completed = true);
return Ok(());
};
let (tx, rx) = tokio::sync::oneshot::channel(); let (tx, rx) = tokio::sync::oneshot::channel();
let video_path_clone = video_path.clone(); let video_path_clone = video_path.clone();
@@ -331,12 +338,12 @@ impl VideoProcessTask {
Ok(()) Ok(())
} }
async fn create_chapter_segments( async fn create_chapter_metadata(
&self, &self,
app: &AppHandle, app: &AppHandle,
progress: &DownloadProgress, progress: &DownloadProgress,
player_info: &mut Option<PlayerInfo>, player_info: &mut Option<PlayerInfo>,
) -> anyhow::Result<ChapterSegments> { ) -> anyhow::Result<Option<PathBuf>> {
let mut chapter_segments = ChapterSegments { let mut chapter_segments = ChapterSegments {
segments: Vec::new(), segments: Vec::new(),
}; };
@@ -355,11 +362,8 @@ impl VideoProcessTask {
chapter_segments = ChapterSegments { segments }; chapter_segments = ChapterSegments { segments };
} }
if self.embed_skip_selected { if let (true, Some(bvid)) = (self.embed_skip_selected, &progress.bvid) {
let bili_client = app.get_bili_client(); let bili_client = app.get_bili_client();
let Some(bvid) = &progress.bvid else {
return Ok(chapter_segments);
};
let cid = Some(progress.cid); let cid = Some(progress.cid);
let skip_segments = bili_client.get_skip_segments(bvid, cid).await?; let skip_segments = bili_client.get_skip_segments(bvid, cid).await?;
@@ -370,6 +374,16 @@ impl VideoProcessTask {
} }
} }
Ok(chapter_segments) if chapter_segments.segments.is_empty() {
return Ok(None);
}
let metadata_content = chapter_segments.generate_chapter_metadata(progress.duration);
let (episode_dir, filename) = (&progress.episode_dir, &progress.filename);
let metadata_path = episode_dir.join(format!("{filename}.FFMETA.ini"));
std::fs::write(&metadata_path, metadata_content)
.context(format!("保存章节元数据到`{}`失败", metadata_path.display()))?;
Ok(Some(metadata_path))
} }
} }