Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81407b51ee | ||
|
|
a3a45cb308 | ||
|
|
e0e1638327 | ||
|
|
c4fffad027 | ||
|
|
618edf65ab | ||
|
|
c5b8eb06c6 |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "voice-to-notes",
|
"name": "voice-to-notes",
|
||||||
"version": "0.2.43",
|
"version": "0.2.46",
|
||||||
"description": "Desktop app for transcribing audio/video with speaker identification",
|
"description": "Desktop app for transcribing audio/video with speaker identification",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "voice-to-notes"
|
name = "voice-to-notes"
|
||||||
version = "0.2.43"
|
version = "0.2.46"
|
||||||
description = "Voice to Notes — desktop transcription with speaker identification"
|
description = "Voice to Notes — desktop transcription with speaker identification"
|
||||||
authors = ["Voice to Notes Contributors"]
|
authors = ["Voice to Notes Contributors"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@@ -50,9 +50,37 @@ pub fn extract_audio(file_path: String, output_path: Option<String>) -> Result<S
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
cmd.creation_flags(0x08000000);
|
cmd.creation_flags(0x08000000);
|
||||||
|
|
||||||
let status = cmd
|
let status = match cmd.status() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) if e.raw_os_error() == Some(13) => {
|
||||||
|
// Permission denied — fix permissions and retry
|
||||||
|
eprintln!("[media] Permission denied on ffmpeg, fixing permissions and retrying...");
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
if let Ok(meta) = std::fs::metadata(&ffmpeg) {
|
||||||
|
let mut perms = meta.permissions();
|
||||||
|
perms.set_mode(0o755);
|
||||||
|
let _ = std::fs::set_permissions(&ffmpeg, perms);
|
||||||
|
}
|
||||||
|
// Also fix ffprobe if it exists
|
||||||
|
let ffprobe = ffmpeg.replace("ffmpeg", "ffprobe");
|
||||||
|
if let Ok(meta) = std::fs::metadata(&ffprobe) {
|
||||||
|
let mut perms = meta.permissions();
|
||||||
|
perms.set_mode(0o755);
|
||||||
|
let _ = std::fs::set_permissions(&ffprobe, perms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Command::new(&ffmpeg)
|
||||||
|
.args(["-y", "-i", &file_path, "-vn", "-acodec", "pcm_s16le", "-ar", "22050", "-ac", "1"])
|
||||||
|
.arg(output.to_str().unwrap())
|
||||||
|
.stdout(std::process::Stdio::null())
|
||||||
|
.stderr(std::process::Stdio::piped())
|
||||||
.status()
|
.status()
|
||||||
.map_err(|e| format!("Failed to run ffmpeg: {e}"))?;
|
.map_err(|e| format!("Failed to run ffmpeg after chmod: {e}"))?
|
||||||
|
}
|
||||||
|
Err(e) => return Err(format!("Failed to run ffmpeg: {e}")),
|
||||||
|
};
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
return Err(format!("ffmpeg exited with status {status}"));
|
return Err(format!("ffmpeg exited with status {status}"));
|
||||||
|
|||||||
@@ -113,23 +113,8 @@ impl SidecarManager {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make all binaries executable on Unix (sidecar, ffmpeg, ffprobe, etc.)
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
Self::set_executable_permissions(&extract_dir);
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
if let Ok(entries) = std::fs::read_dir(&extract_dir) {
|
|
||||||
for entry in entries.flatten() {
|
|
||||||
let path = entry.path();
|
|
||||||
if path.is_file() {
|
|
||||||
if let Ok(meta) = std::fs::metadata(&path) {
|
|
||||||
let mut perms = meta.permissions();
|
|
||||||
perms.set_mode(0o755);
|
|
||||||
let _ = std::fs::set_permissions(&path, perms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::cleanup_old_sidecars(data_dir, ¤t_version);
|
Self::cleanup_old_sidecars(data_dir, ¤t_version);
|
||||||
Ok(binary_path)
|
Ok(binary_path)
|
||||||
@@ -214,6 +199,24 @@ impl SidecarManager {
|
|||||||
|
|
||||||
/// Remove old sidecar-* directories that don't match the current version.
|
/// Remove old sidecar-* directories that don't match the current version.
|
||||||
/// Called after the current version's sidecar is confirmed ready.
|
/// Called after the current version's sidecar is confirmed ready.
|
||||||
|
/// Set execute permissions on all files in a directory (Unix only).
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn set_executable_permissions(dir: &Path) {
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
if let Ok(entries) = std::fs::read_dir(dir) {
|
||||||
|
for entry in entries.flatten() {
|
||||||
|
let path = entry.path();
|
||||||
|
if path.is_file() {
|
||||||
|
if let Ok(meta) = std::fs::metadata(&path) {
|
||||||
|
let mut perms = meta.permissions();
|
||||||
|
perms.set_mode(0o755);
|
||||||
|
let _ = std::fs::set_permissions(&path, perms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn cleanup_old_sidecars(data_dir: &Path, current_version: &str) {
|
pub(crate) fn cleanup_old_sidecars(data_dir: &Path, current_version: &str) {
|
||||||
let current_dir_name = format!("sidecar-{}", current_version);
|
let current_dir_name = format!("sidecar-{}", current_version);
|
||||||
|
|
||||||
@@ -328,13 +331,41 @@ impl SidecarManager {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
cmd.creation_flags(0x08000000);
|
cmd.creation_flags(0x08000000);
|
||||||
|
|
||||||
let child = cmd
|
match cmd.spawn() {
|
||||||
.spawn()
|
Ok(child) => {
|
||||||
.map_err(|e| format!("Failed to start sidecar binary: {e}"))?;
|
|
||||||
|
|
||||||
self.attach(child)?;
|
self.attach(child)?;
|
||||||
self.wait_for_ready()
|
self.wait_for_ready()
|
||||||
}
|
}
|
||||||
|
Err(e) if e.raw_os_error() == Some(13) => {
|
||||||
|
// Permission denied — fix permissions and retry once
|
||||||
|
eprintln!("[sidecar-rs] Permission denied, fixing permissions and retrying...");
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Some(dir) = path.parent() {
|
||||||
|
Self::set_executable_permissions(dir);
|
||||||
|
}
|
||||||
|
let mut retry_cmd = Command::new(path);
|
||||||
|
retry_cmd
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(if let Some(data_dir) = DATA_DIR.get() {
|
||||||
|
let log_path = data_dir.join("sidecar.log");
|
||||||
|
std::fs::File::create(&log_path)
|
||||||
|
.map(Stdio::from)
|
||||||
|
.unwrap_or_else(|_| Stdio::inherit())
|
||||||
|
} else {
|
||||||
|
Stdio::inherit()
|
||||||
|
});
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
retry_cmd.creation_flags(0x08000000);
|
||||||
|
let child = retry_cmd
|
||||||
|
.spawn()
|
||||||
|
.map_err(|e| format!("Failed to start sidecar binary after chmod: {e}"))?;
|
||||||
|
self.attach(child)?;
|
||||||
|
self.wait_for_ready()
|
||||||
|
}
|
||||||
|
Err(e) => Err(format!("Failed to start sidecar binary: {e}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Spawn the Python sidecar in dev mode (system Python).
|
/// Spawn the Python sidecar in dev mode (system Python).
|
||||||
fn start_python_dev(&self) -> Result<(), String> {
|
fn start_python_dev(&self) -> Result<(), String> {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Voice to Notes",
|
"productName": "Voice to Notes",
|
||||||
"version": "0.2.43",
|
"version": "0.2.46",
|
||||||
"identifier": "com.voicetonotes.app",
|
"identifier": "com.voicetonotes.app",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "npm run dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
|
|||||||
Reference in New Issue
Block a user