From 29b12dd2942235d3464efdefabdc73a6a1a8093f Mon Sep 17 00:00:00 2001 From: Yakumo Date: Thu, 24 Jul 2025 00:35:32 +0800 Subject: [PATCH] one --- .gitignore | 1 + .idea/.gitignore | 8 +++ .idea/modules.xml | 8 +++ .idea/to.iml | 11 ++++ .idea/vcs.xml | 6 ++ Cargo.lock | 54 ++++++++++++++++ Cargo.toml | 7 +++ src/main.rs | 157 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 252 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/to.iml create mode 100644 .idea/vcs.xml create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9257a0c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/to.iml b/.idea/to.iml new file mode 100644 index 0000000..cf84ae4 --- /dev/null +++ b/.idea/to.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..9e50938 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,54 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "to" +version = "0.1.0" +dependencies = [ + "regex", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..55a988e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "to" +version = "0.1.0" +edition = "2024" + +[dependencies] +regex = "1.10" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8115580 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,157 @@ +use std::env; +use std::path::Path; +use std::process::{Command, Stdio}; +use std::io::{BufRead, BufReader, Write}; +use regex::Regex; + +fn main() { + let args: Vec = env::args().collect(); + + if args.len() < 2 { + println!("使用方法: 将.ts文件拖拽到此程序上,或者通过命令行传入文件路径"); + println!("例如: {} input.ts", args[0]); + std::process::exit(1); + } + + let input_path = &args[1]; + + // 检查输入文件是否存在 + if !Path::new(input_path).exists() { + eprintln!("错误: 文件 '{}' 不存在", input_path); + std::process::exit(1); + } + + // 检查是否为ts文件 + if !input_path.to_lowercase().ends_with(".ts") { + eprintln!("错误: 只支持.ts格式的文件"); + std::process::exit(1); + } + + // 生成输出文件路径(同目录同名不同后缀) + let output_path = input_path.replace(".ts", ".mp4").replace(".TS", ".mp4"); + + println!("输入文件: {}", input_path); + println!("输出文件: {}", output_path); + println!("开始转换...\n"); + + // 执行转换 + match convert_ts_to_mp4(input_path, &output_path) { + Ok(_) => { + println!("\n✅ 转换完成!"); + println!("输出文件: {}", output_path); + } + Err(e) => { + eprintln!("\n❌ 转换失败: {}", e); + std::process::exit(1); + } + } + + // 等待用户按键后退出(防止窗口立即关闭) + println!("\n按回车键退出..."); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); +} + +fn convert_ts_to_mp4(input_path: &str, output_path: &str) -> Result<(), Box> { + // 首先获取视频总时长 + let duration = get_video_duration(input_path)?; + println!("视频总时长: {:.2}秒", duration); + + // 启动ffmpeg进程 + let mut child = Command::new("ffmpeg") + // .args(&[ + // "-i", input_path, + // "-c:v", "libx264", // 视频编码器 + // "-c:a", "aac", // 音频编码器 + // "-preset", "medium", // 编码速度预设 + // "-crf", "23", // 视频质量 + // "-movflags", "+faststart", // 优化网络播放 + // "-progress", "pipe:1", // 输出进度到stdout + // "-y", // 覆盖输出文件 + // output_path + // ]) + .args(&[ + "-i", input_path, + "-codec", "copy", + "-progress", "pipe:1", // 输出进度到stdout + "-y", // 覆盖输出文件 + output_path + ]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + // 读取进度信息 + if let Some(stdout) = child.stdout.take() { + let reader = BufReader::new(stdout); + let time_regex = Regex::new(r"out_time_ms=(\d+)")?; + + for line in reader.lines() { + let line = line?; + + // 解析当前处理时间 + if let Some(captures) = time_regex.captures(&line) { + if let Ok(time_ms) = captures[1].parse::() { + let current_seconds = time_ms / 1_000_000.0; // 转换为秒 + let progress = if duration > 0.0 { + (current_seconds / duration * 100.0).min(100.0) + } else { + 0.0 + }; + + // 显示进度条 + print_progress_bar(progress); + } + } + + // 检查是否完成 + if line.contains("progress=end") { + print_progress_bar(100.0); + break; + } + } + } + + // 等待进程结束 + let status = child.wait()?; + + if !status.success() { + return Err("FFmpeg转换失败".into()); + } + + Ok(()) +} + +fn get_video_duration(input_path: &str) -> Result> { + let output = Command::new("ffprobe") + .args(&[ + "-v", "quiet", + "-show_entries", "format=duration", + "-of", "csv=p=0", + input_path + ]) + .output()?; + + let duration_str = String::from_utf8(output.stdout)?; + let duration: f64 = duration_str.trim().parse().unwrap_or(0.0); + + Ok(duration) +} + +fn print_progress_bar(percentage: f64) { + let bar_length = 40; + let filled_length = (bar_length as f64 * percentage / 100.0) as usize; + let empty_length = bar_length - filled_length; + + let filled_bar = "█".repeat(filled_length); + let empty_bar = "░".repeat(empty_length); + + print!("\r进度: [{}{}] {:.1}%", filled_bar, empty_bar, percentage); + std::io::stdout().flush().unwrap(); +} + +// 需要在Cargo.toml中添加依赖 +/* +[dependencies] +regex = "1.10" +*/