Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions apps/desktop/src-tauri/src/http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ pub struct HttpClient(reqwest::Client);

impl Default for HttpClient {
fn default() -> Self {
Self(reqwest::Client::new())
Self(
reqwest::Client::builder()
.connect_timeout(std::time::Duration::from_secs(10))
.timeout(std::time::Duration::from_secs(30))
.build()
.expect("Failed to build HTTP client"),
)
}
}

Expand All @@ -26,21 +32,17 @@ impl Default for RetryableHttpClient {
fn default() -> Self {
Self(
reqwest::Client::builder()
.connect_timeout(std::time::Duration::from_secs(10))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RetryableHttpClient has a connect timeout but no overall request timeout. A stalled request could hang for a long time even with retries. Consider adding .timeout(...) like HttpClient.

Suggested change
.connect_timeout(std::time::Duration::from_secs(10))
reqwest::Client::builder()
.connect_timeout(std::time::Duration::from_secs(10))
.timeout(std::time::Duration::from_secs(30))
.retry(

.retry(
reqwest::retry::always()
.classify_fn(|req_rep| {
match req_rep.status() {
// Server errors
Some(s)
if s.is_server_error()
|| s == StatusCode::TOO_MANY_REQUESTS =>
{
req_rep.retryable()
}
// Network errors
None => req_rep.retryable(),
_ => req_rep.success(),
.classify_fn(|req_rep| match req_rep.status() {
Some(s)
if s.is_server_error() || s == StatusCode::TOO_MANY_REQUESTS =>
{
req_rep.retryable()
}
None => req_rep.retryable(),
_ => req_rep.success(),
})
.max_retries_per_request(5)
.max_extra_load(5.0),
Expand Down
49 changes: 49 additions & 0 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1645,6 +1645,55 @@ pub(crate) async fn create_screenshot(
result
}

pub(crate) async fn create_screenshot_source_from_segments(
segments_dir: &std::path::Path,
) -> Result<PathBuf, String> {
let init_path = segments_dir.join("init.mp4");
if !init_path.exists() {
return Err(format!("init.mp4 not found in {}", segments_dir.display()));
}

let first_segment = find_first_segment(segments_dir)
.ok_or_else(|| format!("No .m4s segments found in {}", segments_dir.display()))?;

let temp_path = segments_dir.join(".screenshot_source.mp4");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_screenshot_source_from_segments writes .screenshot_source.mp4 into the segments directory. If any upload/cleanup path ever scans that directory, this temp file could get picked up accidentally. Consider writing the temp MP4 under the OS temp dir instead and returning that path.

let mut out = tokio::fs::File::create(&temp_path)
.await
.map_err(|e| format!("Failed to create screenshot source: {e}"))?;

let mut init_file = tokio::fs::File::open(&init_path)
.await
.map_err(|e| format!("Failed to open init.mp4: {e}"))?;
tokio::io::copy(&mut init_file, &mut out)
.await
.map_err(|e| format!("Failed to copy init.mp4: {e}"))?;

let mut seg_file = tokio::fs::File::open(&first_segment)
.await
.map_err(|e| format!("Failed to open {}: {e}", first_segment.display()))?;
tokio::io::copy(&mut seg_file, &mut out)
.await
.map_err(|e| format!("Failed to copy segment: {e}"))?;

Ok(temp_path)
}

fn find_first_segment(dir: &std::path::Path) -> Option<PathBuf> {
let mut segments: Vec<PathBuf> = std::fs::read_dir(dir)
.ok()?
.filter_map(|e| {
let path = e.ok()?.path();
if path.extension().is_some_and(|ext| ext == "m4s") {
Some(path)
} else {
None
}
})
.collect();
segments.sort();
segments.into_iter().next()
}

// async fn create_thumbnail(input: PathBuf, output: PathBuf, size: (u32, u32)) -> Result<(), String> {
// println!("Creating thumbnail: input={input:?}, output={output:?}, size={size:?}");

Expand Down
Loading
Loading