thumbnails: stop video failures from re-logging every watcher tick
generate_video_thumbnail used .output().expect(...), which only catches spawn failure — non-zero ffmpeg exits were silently discarded. With no thumbnail and no .unsupported sentinel left behind, the watcher re-detected the file as missing every quick-scan tick and re-logged "New file detected (missing thumbnail)" forever. Mirror the image branch: return io::Result, check status.success(), and write the sentinel from create_thumbnails on failure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
11
src/main.rs
11
src/main.rs
@@ -1687,7 +1687,16 @@ fn create_thumbnails(libs: &[libraries::Library], excluded_dirs: &[String]) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
debug!("Generating video thumbnail: {:?}", thumb_path);
|
debug!("Generating video thumbnail: {:?}", thumb_path);
|
||||||
generate_video_thumbnail(src, &thumb_path);
|
if let Err(e) = generate_video_thumbnail(src, &thumb_path) {
|
||||||
|
let sentinel = unsupported_thumbnail_sentinel(&thumb_path);
|
||||||
|
error!(
|
||||||
|
"Unable to thumbnail video {:?}: {}. Writing sentinel {:?}",
|
||||||
|
src, e, sentinel
|
||||||
|
);
|
||||||
|
if let Err(se) = std::fs::write(&sentinel, b"") {
|
||||||
|
warn!("Failed to write sentinel {:?}: {}", sentinel, se);
|
||||||
|
}
|
||||||
|
}
|
||||||
video_span.end();
|
video_span.end();
|
||||||
} else if is_image(&entry) {
|
} else if is_image(&entry) {
|
||||||
match generate_image_thumbnail(src, &thumb_path) {
|
match generate_image_thumbnail(src, &thumb_path) {
|
||||||
|
|||||||
@@ -107,19 +107,27 @@ pub async fn create_playlist(video_path: &str, playlist_file: &str) -> Result<Ch
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_video_thumbnail(path: &Path, destination: &Path) {
|
pub fn generate_video_thumbnail(path: &Path, destination: &Path) -> std::io::Result<()> {
|
||||||
Command::new("ffmpeg")
|
let output = Command::new("ffmpeg")
|
||||||
.arg("-ss")
|
.arg("-ss")
|
||||||
.arg("3")
|
.arg("3")
|
||||||
.arg("-i")
|
.arg("-i")
|
||||||
.arg(path.to_str().unwrap())
|
.arg(path)
|
||||||
.arg("-vframes")
|
.arg("-vframes")
|
||||||
.arg("1")
|
.arg("1")
|
||||||
.arg("-f")
|
.arg("-f")
|
||||||
.arg("image2")
|
.arg("image2")
|
||||||
.arg(destination)
|
.arg(destination)
|
||||||
.output()
|
.output()?;
|
||||||
.expect("Failure to create video frame");
|
|
||||||
|
if !output.status.success() {
|
||||||
|
return Err(std::io::Error::other(format!(
|
||||||
|
"ffmpeg failed ({}): {}",
|
||||||
|
output.status,
|
||||||
|
String::from_utf8_lossy(&output.stderr).trim()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use ffmpeg to extract a 200px-wide thumbnail from formats the `image` crate
|
/// Use ffmpeg to extract a 200px-wide thumbnail from formats the `image` crate
|
||||||
|
|||||||
Reference in New Issue
Block a user