OpenRouter Support, Insight Chat and User injection #56
@@ -55,6 +55,16 @@ pub fn playlist_file_for(playlist_dir: &str, video_path: &Path) -> PathBuf {
|
|||||||
PathBuf::from(format!("{}/{}.m3u8", playlist_dir, filename))
|
PathBuf::from(format!("{}/{}.m3u8", playlist_dir, filename))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sentinel path written next to a would-be playlist when ffmpeg cannot
|
||||||
|
/// transcode the source (e.g. truncated mp4 with no moov atom). Its presence
|
||||||
|
/// causes future scans to skip the file instead of re-running ffmpeg every
|
||||||
|
/// pass. Delete the `.unsupported` file to force a retry.
|
||||||
|
pub fn playlist_unsupported_sentinel(playlist_file: &Path) -> PathBuf {
|
||||||
|
let mut s = playlist_file.as_os_str().to_owned();
|
||||||
|
s.push(".unsupported");
|
||||||
|
PathBuf::from(s)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_playlist(video_path: &str, playlist_file: &str) -> Result<Child> {
|
pub async fn create_playlist(video_path: &str, playlist_file: &str) -> Result<Child> {
|
||||||
if Path::new(playlist_file).exists() {
|
if Path::new(playlist_file).exists() {
|
||||||
debug!("Playlist already exists: {}", playlist_file);
|
debug!("Playlist already exists: {}", playlist_file);
|
||||||
@@ -319,7 +329,10 @@ impl Handler<ScanDirectoryMessage> for VideoPlaylistManager {
|
|||||||
.filter_map(|e| e.ok())
|
.filter_map(|e| e.ok())
|
||||||
.filter(|e| e.file_type().is_file())
|
.filter(|e| e.file_type().is_file())
|
||||||
.filter(is_video)
|
.filter(is_video)
|
||||||
.filter(|e| !playlist_file_for(&playlist_dir_str, e.path()).exists())
|
.filter(|e| {
|
||||||
|
let playlist = playlist_file_for(&playlist_dir_str, e.path());
|
||||||
|
!playlist.exists() && !playlist_unsupported_sentinel(&playlist).exists()
|
||||||
|
})
|
||||||
.collect::<Vec<DirEntry>>();
|
.collect::<Vec<DirEntry>>();
|
||||||
|
|
||||||
let scan_dir_name = msg.directory.clone();
|
let scan_dir_name = msg.directory.clone();
|
||||||
@@ -393,7 +406,8 @@ impl Handler<QueueVideosMessage> for VideoPlaylistManager {
|
|||||||
let playlist_generator = self.playlist_generator.clone();
|
let playlist_generator = self.playlist_generator.clone();
|
||||||
|
|
||||||
for video_path in msg.video_paths {
|
for video_path in msg.video_paths {
|
||||||
if playlist_file_for(&playlist_dir_str, &video_path).exists() {
|
let playlist = playlist_file_for(&playlist_dir_str, &video_path);
|
||||||
|
if playlist.exists() || playlist_unsupported_sentinel(&playlist).exists() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let path_str = video_path.to_string_lossy().to_string();
|
let path_str = video_path.to_string_lossy().to_string();
|
||||||
@@ -683,6 +697,20 @@ impl Handler<GeneratePlaylistMessage> for PlaylistGenerator {
|
|||||||
};
|
};
|
||||||
error!("ffmpeg failed for {}: {}", video_file, detail);
|
error!("ffmpeg failed for {}: {}", video_file, detail);
|
||||||
cleanup_partial_hls(&playlist_tmp, playlist_path.as_str(), video_stem).await;
|
cleanup_partial_hls(&playlist_tmp, playlist_path.as_str(), video_stem).await;
|
||||||
|
let sentinel = playlist_unsupported_sentinel(Path::new(&playlist_file));
|
||||||
|
if let Err(se) = tokio::fs::write(&sentinel, b"").await {
|
||||||
|
warn!(
|
||||||
|
"Failed to write playlist sentinel {}: {}",
|
||||||
|
sentinel.display(),
|
||||||
|
se
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!(
|
||||||
|
"Wrote playlist sentinel {} so future scans skip {}",
|
||||||
|
sentinel.display(),
|
||||||
|
video_file
|
||||||
|
);
|
||||||
|
}
|
||||||
span.set_status(Status::error(detail.clone()));
|
span.set_status(Status::error(detail.clone()));
|
||||||
Err(std::io::Error::other(detail))
|
Err(std::io::Error::other(detail))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user