Skip to content

Commit

Permalink
feat: ytdlp progress
Browse files Browse the repository at this point in the history
  • Loading branch information
thewh1teagle committed Dec 4, 2024
1 parent 7ae85a2 commit 977ecc9
Show file tree
Hide file tree
Showing 16 changed files with 124 additions and 28 deletions.
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/en-US/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "Download and transcribe",
"download-model": "Download model",
"download-models-link": "Download Models",
"downloading": "Downloading... {{progress}}%",
"downloading-ai-models": "Downloading AI models...",
"downloading-model": "Downloading OpenAI Model...",
"downloading-ytdlp": "Downloading ytdlp",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/es-MX/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "Descargar y transcribir",
"download-model": "Descargar modelo",
"download-models-link": "Descargar Modelos",
"downloading": "Descargando... {{progreso}}%",
"downloading-ai-models": "Descargando modelos de IA...",
"downloading-model": "Descargando Modelo de OpenAI...",
"downloading-ytdlp": "Descargando ytdlp",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/fr-FR/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "Télécharger l'audio",
"download-model": "Télécharger le modèle",
"download-models-link": "Télécharger les modèles",
"downloading": "Téléchargement... {{progress}} %",
"downloading-ai-models": "Téléchargement de modèles d'IA...",
"downloading-model": "Téléchargement du modèle OpenAI en cours…",
"downloading-ytdlp": "Téléchargement de ytdlp",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/he-IL/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "הורד ותמלל",
"download-model": "הורד מודל",
"download-models-link": "הורדת מודלים",
"downloading": "מוריד... {{progress}}%",
"downloading-ai-models": "מוריד מודלים...",
"downloading-model": "מוריד מודל בינה מלאכותית",
"downloading-ytdlp": "מוריד ytdlp",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/hi-IN/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "डाउनलोड करें और प्रतिलेखित करें",
"download-model": "मॉडल डाउनलोड करें",
"download-models-link": "मॉडल डाउनलोड करें",
"downloading": "डाउनलोड हो रहा है... {{प्रगति}}%",
"downloading-ai-models": "AI मॉडल डाउनलोड हो रहा है...",
"downloading-model": "OpenAI मॉडल डाउनलोड हो रहा है...",
"downloading-ytdlp": "Ytdlp डाउनलोड हो रहा है",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/it-IT/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "Scarica e trascrivi",
"download-model": "Scarica modello",
"download-models-link": "Scarica modelli",
"downloading": "Download in corso... {{progress}}%",
"downloading-ai-models": "Scaricando i modelli AI...",
"downloading-model": "Scaricando i modelli di OpenAI...",
"downloading-ytdlp": "Scaricando i modelli ytdlp",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/pl-PL/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "Pobierz i transkrybuj",
"download-model": "Pobierz model",
"download-models-link": "Pobierz modele",
"downloading": "Pobieram... {{postęp}}%",
"downloading-ai-models": "Pobieranie modeli AI...",
"downloading-model": "Pobieram modele od OpenAI...",
"downloading-ytdlp": "Pobieram ytdlp",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/pt-BR/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "Baixe e transcreva",
"download-model": "Baixar modelo",
"download-models-link": "Baixar modelos",
"downloading": "Baixando... {{progresso}}%",
"downloading-ai-models": "Baixando modelos de IA...",
"downloading-model": "Baixando o modelo OpenAI....",
"downloading-ytdlp": "Baixando ytdlp",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/sv-SE/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "Ladda ner och transkribera",
"download-model": "Ladda ner modell",
"download-models-link": "Hämta Modeller",
"downloading": "Laddar ned... {{progress}}%",
"downloading-ai-models": "Laddar ner AI-modeller...",
"downloading-model": "Hämtar OpenAI Model...",
"downloading-ytdlp": "Laddar ner ytdlp",
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/locales/zh-CN/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"download-file": "下载并转录",
"download-model": "下载模型",
"download-models-link": "下载模型",
"downloading": "正在下载... {{progress}}%",
"downloading-ai-models": "正在下载 AI 模型...",
"downloading-model": "正在下载 OpenAI 模型...",
"downloading-ytdlp": "下载 ytdlp",
Expand Down
95 changes: 76 additions & 19 deletions desktop/src-tauri/src/cmd/ytdlp.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
use eyre::{bail, Context, Result};
use tauri::{AppHandle, Manager};
use serde_json::Value;
use std::{
io::{BufRead, BufReader},
sync::atomic::{AtomicBool, Ordering},
};
use tauri::{AppHandle, Emitter, Listener, Manager};
use vibe_core::get_vibe_temp_folder;

use crate::utils::LogError;

use super::get_ffmpeg_path;

#[cfg(windows)]
use std::os::windows::process::CommandExt;
use std::process::Stdio;

#[cfg(windows)]
const CREATE_NO_WINDOW: u32 = 0x08000000;
Expand Down Expand Up @@ -33,7 +41,7 @@ pub fn get_temp_path(app_handle: AppHandle, ext: String, in_documents: Option<bo
}

#[tauri::command]
pub async fn download_audio(app_handle: AppHandle, url: String, out_path: String) -> Result<String> {
pub async fn download_audio(app_handle: AppHandle, url: String, out_path: String) -> Result<()> {
tracing::debug!("download audio {}", url);
let name = get_binary_name();
let path = app_handle.path().app_local_data_dir().context("Can't get data directory")?;
Expand All @@ -53,26 +61,75 @@ pub async fn download_audio(app_handle: AppHandle, url: String, out_path: String
}

let mut cmd = std::process::Command::new(path);
let cmd = cmd.args([
"--no-playlist",
"-x",
"--audio-format",
"m4a",
"--ffmpeg-location",
&ffmpeg_path,
&url,
"-o",
&out_path,
]);
let cmd = cmd
.args([
"--progress-template",
"{\"progress\": \"%(progress.percent)s\", \"total_bytes\": \"%(progress.total_bytes)s\", \"progress_str\": \"%(progress._percent_str)s\"}\n",
"--no-playlist",
"-x",
"--audio-format",
"m4a",
"--ffmpeg-location",
&ffmpeg_path,
&url,
"-o",
&out_path,
])
.stdout(Stdio::piped())
.stderr(Stdio::piped());

#[cfg(windows)]
let cmd = cmd.creation_flags(CREATE_NO_WINDOW);

let output = cmd.output()?;
if !output.status.success() {
let stderr = String::from_utf8(output.stderr)?;
bail!("Failed to download audio: {}", stderr);
let cancel_flag = std::sync::Arc::new(AtomicBool::new(false));
let cancel_flag_c = cancel_flag.clone();
app_handle.once("ytdlp-cancel", move |_| {
cancel_flag_c.store(true, Ordering::Relaxed);
});

let mut child = cmd.spawn()?;

if let Some(stdout) = child.stdout.take() {
let reader = BufReader::new(stdout);

for line in reader.lines() {
if cancel_flag.load(Ordering::Relaxed) {
let _ = child.kill();
break;
}

let mut line = line?;
line = line.replace("\r", "").trim().to_string();

if line.starts_with("{\"progress") {
// try parse progress
let result: Result<Value, _> = serde_json::from_str(&line);
if let Ok(value) = result {
// remove % and parse to number
let percentage_str = value["progress_str"].as_str().unwrap_or_default().trim().replace("%", "");
if let Ok(percentage_number) = percentage_str.parse::<f32>() {
app_handle
.emit("ytdlp-progress", percentage_number)
.context("failed to emit")
.log_error();
}
}
}
}
}

let ret = child.wait()?;
if !ret.success() && !cancel_flag.load(Ordering::Relaxed) {
let mut stderr_output: String = "".to_string();
if let Some(stderr) = child.stderr.take() {
stderr_output = BufReader::new(stderr)
.lines()
.filter_map(|line| line.ok())
.collect::<Vec<_>>()
.join("\n");
eprintln!("Error: {}", stderr_output);
}
bail!("Failed to download audio: {}", stderr_output);
}
let output = String::from_utf8(output.stdout)?;
Ok(output)
Ok(())
}
1 change: 0 additions & 1 deletion desktop/src/lib/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ export async function collectLogs() {
.slice(-10) // Take the last 3 lines
.map((line) => {
try {
console.log('line => ', line)
const parsed = JSON.parse(line) // Deserialize JSON
return parsed?.fields?.message || 'No message found' // Extract .message or fallback
} catch (e) {
Expand Down
5 changes: 1 addition & 4 deletions desktop/src/lib/ytdlp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ async function getBinaryPath() {

export async function exists() {
const binaryPath = await getBinaryPath()
console.log('checking', binaryPath)
return await fs.exists(binaryPath)
}

Expand All @@ -26,8 +25,6 @@ export async function downloadYtDlp() {

export async function downloadAudio(url: string, inDocuments?: boolean) {
const outPath = await invoke<string>('get_temp_path', { ext: 'm4a', inDocuments })
console.log('outPath is ', outPath)
let result = await invoke<string>('download_audio', { url, outPath })
console.log(result)
await invoke<string>('download_audio', { url, outPath })
return outPath
}
14 changes: 11 additions & 3 deletions desktop/src/pages/home/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,17 @@ export default function Home() {
/>

{vm.downloadingAudio ? (
<button className="btn relative btn-success mt-3">
<span className="loading loading-spinner"></span>
</button>
<>
<div className="w-full flex flex-col items-center mt-5">
<div className="flex flex-row items-center text-center gap-3 bg-base-200 p-4 rounded-2xl">
<span className="loading loading-spinner text-primary"></span>
<p>{t('common.downloading', { progress: vm.ytdlpProgress })}</p>
<button onClick={() => vm.cancelYtDlpDownload()} className="btn btn-primary btn-ghost btn-sm text-red-500">
{t('common.cancel')}
</button>
</div>
</div>
</>
) : (
<>
<label className="label cursor-pointer mt-2 mb-5">
Expand Down
26 changes: 26 additions & 0 deletions desktop/src/pages/home/viewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export function viewModel() {
const [outputDevice, setOutputDevice] = useState<AudioDevice | null>(null)
const [audioUrl, setAudioUrl] = useState<string>('')
const [downloadingAudio, setDownloadingAudio] = useState(false)
const [ytdlpProgress, setYtDlpProgress] = useState<number | null>(null)
const cancelYtDlpRef = useRef<boolean>(false)

const { updateApp, availableUpdate } = useContext(UpdaterContext)
const { setState: setErrorModal } = useContext(ErrorModalContext)
Expand All @@ -82,6 +84,20 @@ export function viewModel() {
}
}, [preference.llmConfig])

useEffect(() => {
listen<number>('ytdlp-progress', ({ payload }) => {
const newProgress = Math.ceil(payload)
if (!ytdlpProgress || newProgress > ytdlpProgress) {
setYtDlpProgress(newProgress)
}
})
}, [])

async function cancelYtDlpDownload() {
cancelYtDlpRef.current = true
event.emit('ytdlp-cancel')
}

async function switchToLinkTab() {
const exists = await ytDlp.exists()
if (!exists) {
Expand Down Expand Up @@ -361,9 +377,14 @@ export function viewModel() {

async function downloadAudio() {
if (audioUrl) {
setYtDlpProgress(0)
setDownloadingAudio(true)
try {
const outPath = await ytDlp.downloadAudio(audioUrl, preference.storeRecordInDocuments)
if (cancelYtDlpRef.current) {
cancelYtDlpRef.current = false
return
}
preference.setHomeTabIndex(1)
setFiles([{ name: 'audio.m4a', path: outPath }])
transcribe(outPath)
Expand All @@ -373,10 +394,15 @@ export function viewModel() {
} finally {
setDownloadingAudio(false)
}
setYtDlpProgress(null)
}
}

return {
cancelYtDlpRef,
cancelYtDlpDownload,
ytdlpProgress,
setYtDlpProgress,
transcriptTab,
setTranscriptTab,
summarizeSegments,
Expand Down
1 change: 0 additions & 1 deletion desktop/src/pages/settings/viewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ async function reportIssue() {
.slice(-10) // Take the last 3 lines
.map((line) => {
try {
console.log('line => ', line)
const parsed = JSON.parse(line) // Deserialize JSON
return parsed?.fields?.message || 'No message found' // Extract .message or fallback
} catch (e) {
Expand Down

0 comments on commit 977ecc9

Please sign in to comment.