004 Multi-library Support #54
@@ -74,8 +74,11 @@ impl AppState {
|
|||||||
let video_playlist_manager =
|
let video_playlist_manager =
|
||||||
VideoPlaylistManager::new(video_path.clone(), playlist_generator.start());
|
VideoPlaylistManager::new(video_path.clone(), playlist_generator.start());
|
||||||
|
|
||||||
let preview_clip_generator =
|
let preview_clip_generator = PreviewClipGenerator::new(
|
||||||
PreviewClipGenerator::new(preview_clips_path.clone(), base_path.clone(), preview_dao);
|
preview_clips_path.clone(),
|
||||||
|
libraries_vec.clone(),
|
||||||
|
preview_dao,
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
stream_manager,
|
stream_manager,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::database::PreviewDao;
|
use crate::database::PreviewDao;
|
||||||
use crate::is_video;
|
use crate::is_video;
|
||||||
|
use crate::libraries::Library;
|
||||||
use crate::otel::global_tracer;
|
use crate::otel::global_tracer;
|
||||||
use crate::video::ffmpeg::generate_preview_clip;
|
use crate::video::ffmpeg::generate_preview_clip;
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
@@ -500,23 +501,40 @@ pub struct GeneratePreviewClipMessage {
|
|||||||
pub struct PreviewClipGenerator {
|
pub struct PreviewClipGenerator {
|
||||||
semaphore: Arc<Semaphore>,
|
semaphore: Arc<Semaphore>,
|
||||||
preview_clips_dir: String,
|
preview_clips_dir: String,
|
||||||
base_path: String,
|
libraries: Vec<Library>,
|
||||||
preview_dao: Arc<Mutex<Box<dyn PreviewDao>>>,
|
preview_dao: Arc<Mutex<Box<dyn PreviewDao>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreviewClipGenerator {
|
impl PreviewClipGenerator {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
preview_clips_dir: String,
|
preview_clips_dir: String,
|
||||||
base_path: String,
|
libraries: Vec<Library>,
|
||||||
preview_dao: Arc<Mutex<Box<dyn PreviewDao>>>,
|
preview_dao: Arc<Mutex<Box<dyn PreviewDao>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
PreviewClipGenerator {
|
PreviewClipGenerator {
|
||||||
semaphore: Arc::new(Semaphore::new(2)),
|
semaphore: Arc::new(Semaphore::new(2)),
|
||||||
preview_clips_dir,
|
preview_clips_dir,
|
||||||
base_path,
|
libraries,
|
||||||
preview_dao,
|
preview_dao,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Strip whichever library root actually contains `video_path`.
|
||||||
|
/// Falls back to the first library if none match, so we never
|
||||||
|
/// accidentally emit the absolute input path as the output path
|
||||||
|
/// (which ffmpeg rejects as "cannot edit existing files in place").
|
||||||
|
fn relativize(&self, video_path: &str) -> String {
|
||||||
|
for lib in &self.libraries {
|
||||||
|
if let Some(stripped) = video_path.strip_prefix(&lib.root_path) {
|
||||||
|
return stripped
|
||||||
|
.trim_start_matches(['/', '\\'])
|
||||||
|
.replace('\\', "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
video_path
|
||||||
|
.trim_start_matches(['/', '\\'])
|
||||||
|
.replace('\\', "/")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Actor for PreviewClipGenerator {
|
impl Actor for PreviewClipGenerator {
|
||||||
@@ -533,9 +551,10 @@ impl Handler<GeneratePreviewClipMessage> for PreviewClipGenerator {
|
|||||||
) -> Self::Result {
|
) -> Self::Result {
|
||||||
let semaphore = self.semaphore.clone();
|
let semaphore = self.semaphore.clone();
|
||||||
let preview_clips_dir = self.preview_clips_dir.clone();
|
let preview_clips_dir = self.preview_clips_dir.clone();
|
||||||
let base_path = self.base_path.clone();
|
|
||||||
let preview_dao = self.preview_dao.clone();
|
let preview_dao = self.preview_dao.clone();
|
||||||
let video_path = msg.video_path;
|
let video_path = msg.video_path;
|
||||||
|
// Resolve against whichever library actually owns this video.
|
||||||
|
let relative_path = self.relativize(&video_path);
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let permit = semaphore
|
let permit = semaphore
|
||||||
@@ -543,13 +562,6 @@ impl Handler<GeneratePreviewClipMessage> for PreviewClipGenerator {
|
|||||||
.await
|
.await
|
||||||
.expect("Unable to acquire preview semaphore");
|
.expect("Unable to acquire preview semaphore");
|
||||||
|
|
||||||
// Compute relative path (from BASE_PATH) for DB operations, consistent with EXIF convention
|
|
||||||
let relative_path = video_path
|
|
||||||
.strip_prefix(&base_path)
|
|
||||||
.unwrap_or(&video_path)
|
|
||||||
.trim_start_matches(['/', '\\'])
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
// Update status to processing
|
// Update status to processing
|
||||||
{
|
{
|
||||||
let otel_ctx = opentelemetry::Context::current();
|
let otel_ctx = opentelemetry::Context::current();
|
||||||
|
|||||||
Reference in New Issue
Block a user