diff --git a/crates/bili_sync/src/config/args.rs b/crates/bili_sync/src/config/args.rs index 78c4c60..b03b158 100644 --- a/crates/bili_sync/src/config/args.rs +++ b/crates/bili_sync/src/config/args.rs @@ -20,6 +20,9 @@ pub struct Args { #[arg(short, long, env = "BILI_SYNC_CONFIG_DIR")] pub config_dir: Option, + + #[arg(short, long, env = "BILI_SYNC_FFMPEG_PATH")] + pub ffmpeg_path: Option, } mod built_info { diff --git a/crates/bili_sync/src/downloader.rs b/crates/bili_sync/src/downloader.rs index 2d0dd8f..45798e3 100644 --- a/crates/bili_sync/src/downloader.rs +++ b/crates/bili_sync/src/downloader.rs @@ -14,7 +14,7 @@ use tokio::task::JoinSet; use tokio_util::io::StreamReader; use crate::bilibili::Client; -use crate::config::ConcurrentDownloadLimit; +use crate::config::{ARGS, ConcurrentDownloadLimit}; pub struct Downloader { client: Client, @@ -70,7 +70,7 @@ impl Downloader { self.multi_fetch_internal(audio_urls, true, concurrent_download) )?; let final_temp_file = TempFile::new().await?; - let output = Command::new("ffmpeg") + let output = Command::new(ARGS.ffmpeg_path.as_deref().unwrap_or("ffmpeg")) .args([ "-i", video_temp_file.file_path().to_string_lossy().as_ref(), diff --git a/crates/bili_sync/src/main.rs b/crates/bili_sync/src/main.rs index 82565c0..6c2396b 100644 --- a/crates/bili_sync/src/main.rs +++ b/crates/bili_sync/src/main.rs @@ -18,10 +18,12 @@ use std::fmt::Debug; use std::future::Future; use std::sync::Arc; +use anyhow::{Context, Result, bail}; use bilibili::BiliClient; use parking_lot::RwLock; use sea_orm::DatabaseConnection; use task::{http_server, video_downloader}; +use tokio::process::Command; use tokio_util::sync::CancellationToken; use tokio_util::task::TaskTracker; @@ -33,8 +35,13 @@ use crate::utils::signal::terminate; #[tokio::main] async fn main() { - let (connection, log_writer) = init().await; - let bili_client = Arc::new(BiliClient::new()); + let (bili_client, connection, log_writer) = match init().await { + Ok(res) => res, + Err(e) => { + error!("初始化失败:{:#}", e); + return; + } + }; let token = CancellationToken::new(); let tracker = TaskTracker::new(); @@ -77,7 +84,7 @@ fn spawn_task( } /// 初始化日志系统、打印欢迎信息,初始化数据库连接和全局配置 -async fn init() -> (DatabaseConnection, LogHelper) { +async fn init() -> Result<(Arc, DatabaseConnection, LogHelper)> { let (tx, _rx) = tokio::sync::broadcast::channel(30); let log_history = Arc::new(RwLock::new(VecDeque::with_capacity(MAX_HISTORY_LOGS + 1))); let log_writer = LogHelper::new(tx, log_history.clone()); @@ -85,14 +92,26 @@ async fn init() -> (DatabaseConnection, LogHelper) { init_logger(&ARGS.log_level, Some(log_writer.clone())); info!("欢迎使用 Bili-Sync,当前程序版本:{}", config::version()); info!("项目地址:https://github.com/amtoaer/bili-sync"); + + let ffmpeg_path = ARGS.ffmpeg_path.as_deref().unwrap_or("ffmpeg"); + let ffmpeg_exists = Command::new(ffmpeg_path) + .arg("-version") + .output() + .await + .map(|output| output.status.success()) + .unwrap_or(false); + if !ffmpeg_exists { + bail!("ffmpeg 不存在或无法执行,请确保已正确安装 ffmpeg,并且 {ffmpeg_path} 命令可用"); + } + let connection = setup_database(&CONFIG_DIR.join("data.sqlite")) .await - .expect("数据库初始化失败"); + .context("数据库初始化失败")?; info!("数据库初始化完成"); - VersionedConfig::init(&connection).await.expect("配置初始化失败"); + VersionedConfig::init(&connection).await.context("配置初始化失败")?; info!("配置初始化完成"); - (connection, log_writer) + Ok((Arc::new(BiliClient::new()), connection, log_writer)) } async fn handle_shutdown(connection: DatabaseConnection, tracker: TaskTracker, token: CancellationToken) {