OpenRouter Support, Insight Chat and User injection #56

Merged
cameron merged 24 commits from 005-llm-client-trait into master 2026-04-26 23:01:35 +00:00
Showing only changes of commit 21e624da6b - Show all commits

View File

@@ -55,6 +55,16 @@ pub fn playlist_file_for(playlist_dir: &str, video_path: &Path) -> PathBuf {
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> {
if Path::new(playlist_file).exists() {
debug!("Playlist already exists: {}", playlist_file);
@@ -319,7 +329,10 @@ impl Handler<ScanDirectoryMessage> for VideoPlaylistManager {
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
.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>>();
let scan_dir_name = msg.directory.clone();
@@ -393,7 +406,8 @@ impl Handler<QueueVideosMessage> for VideoPlaylistManager {
let playlist_generator = self.playlist_generator.clone();
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;
}
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);
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()));
Err(std::io::Error::other(detail))
}