mirror of
https://github.com/lanyeeee/bilibili-video-downloader.git
synced 2026-09-09 09:36:46 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c849409cf |
@@ -1,4 +1,4 @@
|
|||||||
use std::{io, path::PathBuf, sync::Arc};
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use eyre::{WrapErr, eyre};
|
use eyre::{WrapErr, eyre};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -98,29 +98,54 @@ impl VideoProcessTask {
|
|||||||
|
|
||||||
let output_path = episode_dir.join(format!("{filename}-merged.mp4"));
|
let output_path = episode_dir.join(format!("{filename}-merged.mp4"));
|
||||||
|
|
||||||
let mut command = std::process::Command::new(ffmpeg_program);
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||||
|
let video_path_clone = video_path.clone();
|
||||||
|
let audio_path_clone = audio_path.clone();
|
||||||
|
let metadata_path_clone = metadata_path.clone();
|
||||||
|
let output_path_clone = output_path.clone();
|
||||||
|
|
||||||
command.arg("-i").arg(&video_path);
|
let current_span = tracing::Span::current();
|
||||||
command.arg("-i").arg(&audio_path);
|
tauri::async_runtime::spawn_blocking(move || {
|
||||||
if let Some(metadata_path) = &metadata_path {
|
let _enter = current_span.enter();
|
||||||
command.arg("-i").arg(metadata_path);
|
|
||||||
command.arg("-map_metadata").arg("2");
|
let mut command = std::process::Command::new(ffmpeg_program);
|
||||||
|
|
||||||
|
command.arg("-i").arg(video_path_clone);
|
||||||
|
command.arg("-i").arg(audio_path_clone);
|
||||||
|
if let Some(metadata_path) = metadata_path_clone {
|
||||||
|
command.arg("-i").arg(metadata_path);
|
||||||
|
command.arg("-map_metadata").arg("2");
|
||||||
|
}
|
||||||
|
|
||||||
|
command.arg("-c").arg("copy");
|
||||||
|
command.arg("-map").arg("0:v:0");
|
||||||
|
command.arg("-map").arg("1:a:0");
|
||||||
|
|
||||||
|
command.arg(output_path_clone).arg("-y");
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
// 隐藏窗口
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
command.creation_flags(0x0800_0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = command.output();
|
||||||
|
|
||||||
|
let _ = tx.send(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = rx.await??;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let err = eyre!(format!("STDOUT: {stdout}"))
|
||||||
|
.wrap_err(format!("STDERR: {stderr}"))
|
||||||
|
.wrap_err("原因可能是视频或音频文件损坏,建议[重来]试试");
|
||||||
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
command.arg("-c").arg("copy");
|
|
||||||
command.arg("-map").arg("0:v:0");
|
|
||||||
command.arg("-map").arg("1:a:0");
|
|
||||||
command.arg(&output_path).arg("-y");
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
{
|
|
||||||
// 隐藏窗口
|
|
||||||
use std::os::windows::process::CommandExt;
|
|
||||||
command.creation_flags(0x0800_0000);
|
|
||||||
}
|
|
||||||
|
|
||||||
execute_ffmpeg(command).await.wrap_err("执行FFmpeg失败")?;
|
|
||||||
|
|
||||||
std::fs::remove_file(&video_path)
|
std::fs::remove_file(&video_path)
|
||||||
.wrap_err(format!("删除视频文件`{}`失败", video_path.display()))?;
|
.wrap_err(format!("删除视频文件`{}`失败", video_path.display()))?;
|
||||||
std::fs::remove_file(&audio_path)
|
std::fs::remove_file(&audio_path)
|
||||||
@@ -167,24 +192,49 @@ impl VideoProcessTask {
|
|||||||
|
|
||||||
let ffmpeg_program = utils::get_ffmpeg_program().wrap_err("获取FFmpeg程序路径失败")?;
|
let ffmpeg_program = utils::get_ffmpeg_program().wrap_err("获取FFmpeg程序路径失败")?;
|
||||||
|
|
||||||
let mut command = std::process::Command::new(ffmpeg_program);
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||||
|
let video_path_clone = video_path.clone();
|
||||||
|
let audio_path_clone = audio_path.clone();
|
||||||
|
let output_path_clone = output_path.clone();
|
||||||
|
|
||||||
command.arg("-i").arg(&video_path);
|
let current_span = tracing::Span::current();
|
||||||
command.arg("-i").arg(&audio_path);
|
tauri::async_runtime::spawn_blocking(move || {
|
||||||
command.arg("-c").arg("copy");
|
let _enter = current_span.enter();
|
||||||
command.arg("-map").arg("0:v:0");
|
|
||||||
command.arg("-map").arg("1:a:0");
|
|
||||||
command.arg(&output_path).arg("-y");
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
let mut command = std::process::Command::new(ffmpeg_program);
|
||||||
{
|
|
||||||
// 隐藏窗口
|
command.arg("-i").arg(video_path_clone);
|
||||||
use std::os::windows::process::CommandExt;
|
command.arg("-i").arg(audio_path_clone);
|
||||||
command.creation_flags(0x0800_0000);
|
|
||||||
|
command.arg("-c").arg("copy");
|
||||||
|
command.arg("-map").arg("0:v:0");
|
||||||
|
command.arg("-map").arg("1:a:0");
|
||||||
|
|
||||||
|
command.arg(output_path_clone).arg("-y");
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
// 隐藏窗口
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
command.creation_flags(0x0800_0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = command.output();
|
||||||
|
|
||||||
|
let _ = tx.send(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = rx.await??;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let err = eyre!(format!("STDOUT: {stdout}"))
|
||||||
|
.wrap_err(format!("STDERR: {stderr}"))
|
||||||
|
.wrap_err("原因可能是视频或音频文件损坏,建议[重来]试试");
|
||||||
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
execute_ffmpeg(command).await.wrap_err("执行FFmpeg失败")?;
|
|
||||||
|
|
||||||
std::fs::remove_file(&video_path)
|
std::fs::remove_file(&video_path)
|
||||||
.wrap_err(format!("删除视频文件`{}`失败", video_path.display()))?;
|
.wrap_err(format!("删除视频文件`{}`失败", video_path.display()))?;
|
||||||
std::fs::remove_file(&audio_path)
|
std::fs::remove_file(&audio_path)
|
||||||
@@ -229,23 +279,48 @@ impl VideoProcessTask {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut command = std::process::Command::new(ffmpeg_program);
|
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||||
|
let video_path_clone = video_path.clone();
|
||||||
|
let metadata_path_clone = metadata_path.clone();
|
||||||
|
let output_path_clone = output_path.clone();
|
||||||
|
|
||||||
command.arg("-i").arg(&video_path);
|
let current_span = tracing::Span::current();
|
||||||
command.arg("-i").arg(&metadata_path);
|
tauri::async_runtime::spawn_blocking(move || {
|
||||||
command.arg("-map_metadata").arg("1");
|
let _enter = current_span.enter();
|
||||||
command.arg("-c").arg("copy");
|
|
||||||
command.arg(&output_path).arg("-y");
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
let mut command = std::process::Command::new(ffmpeg_program);
|
||||||
{
|
|
||||||
// 隐藏窗口
|
command.arg("-i").arg(video_path_clone);
|
||||||
use std::os::windows::process::CommandExt;
|
command.arg("-i").arg(metadata_path_clone);
|
||||||
command.creation_flags(0x0800_0000);
|
|
||||||
|
command.arg("-map_metadata").arg("1");
|
||||||
|
command.arg("-c").arg("copy");
|
||||||
|
|
||||||
|
command.arg(output_path_clone).arg("-y");
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
// 隐藏窗口
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
command.creation_flags(0x0800_0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = command.output();
|
||||||
|
|
||||||
|
let _ = tx.send(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = rx.await??;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let err = eyre!(format!("STDOUT: {stdout}"))
|
||||||
|
.wrap_err(format!("STDERR: {stderr}"))
|
||||||
|
.wrap_err("原因可能是视频或音频文件损坏,建议[重来]试试");
|
||||||
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
execute_ffmpeg(command).await.wrap_err("执行FFmpeg失败")?;
|
|
||||||
|
|
||||||
std::fs::remove_file(&video_path)
|
std::fs::remove_file(&video_path)
|
||||||
.wrap_err(format!("删除视频文件`{}`失败", video_path.display()))?;
|
.wrap_err(format!("删除视频文件`{}`失败", video_path.display()))?;
|
||||||
std::fs::rename(&output_path, &video_path).wrap_err(format!(
|
std::fs::rename(&output_path, &video_path).wrap_err(format!(
|
||||||
@@ -292,10 +367,7 @@ impl VideoProcessTask {
|
|||||||
let bili_client = app.get_bili_client();
|
let bili_client = app.get_bili_client();
|
||||||
let cid = Some(progress.cid);
|
let cid = Some(progress.cid);
|
||||||
|
|
||||||
let skip_segments = bili_client
|
let skip_segments = bili_client.get_skip_segments(bvid, cid).await?;
|
||||||
.get_skip_segments(bvid, cid)
|
|
||||||
.await
|
|
||||||
.wrap_err("获取广告片段失败,请[继续]以重试。如果重试多次依旧失败,请在设置中取消勾选[标记广告]")?;
|
|
||||||
for segment in skip_segments.0 {
|
for segment in skip_segments.0 {
|
||||||
if let Some(chapter_segment) = segment.into_chapter_segment() {
|
if let Some(chapter_segment) = segment.into_chapter_segment() {
|
||||||
chapter_segments.insert(chapter_segment);
|
chapter_segments.insert(chapter_segment);
|
||||||
@@ -316,32 +388,3 @@ impl VideoProcessTask {
|
|||||||
Ok(Some(metadata_path))
|
Ok(Some(metadata_path))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "error", skip_all)]
|
|
||||||
async fn execute_ffmpeg(mut command: std::process::Command) -> eyre::Result<()> {
|
|
||||||
let span = tracing::Span::current();
|
|
||||||
|
|
||||||
tauri::async_runtime::spawn_blocking(move || {
|
|
||||||
let _enter = span.enter();
|
|
||||||
|
|
||||||
let program = command.get_program().to_string_lossy().into_owned();
|
|
||||||
let output = command.output().map_err(|err| {
|
|
||||||
if err.kind() == io::ErrorKind::NotFound {
|
|
||||||
eyre!(err).wrap_err(format!("找不到FFmpeg `{program}`"))
|
|
||||||
} else {
|
|
||||||
eyre!(err)
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if output.status.success() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
Err(eyre!(format!("STDOUT: {stdout}")))
|
|
||||||
.wrap_err(format!("STDERR: {stderr}"))
|
|
||||||
.wrap_err("原因可能是视频或音频文件损坏,建议[重来]试试")
|
|
||||||
})
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user