use lumiere_domain::video::error::VideoError; use lumiere_domain::video::model::library_item::{LibraryItem, LibraryItemType, LibraryRawItem}; use lumiere_domain::video::model::video::Video; use lumiere_domain::video::port::VideoPort; use uuid::Uuid; use std::env; use std::fs; use std::fs::DirEntry; use std::io::{Error, ErrorKind}; use lumiere_domain::video::model::video::VideoFormat::{AVI, MKV, MP4, WEBM}; use crate::video::model::LibraryItemEntity; use crate::video::repository::LibraryItemSqliteRepository; use crate::video::video_format_detector::get_content_type; #[derive(Clone)] pub struct LibraryItemAdapter { pub repository: LibraryItemSqliteRepository } impl LibraryItemAdapter { pub fn new(repository: LibraryItemSqliteRepository) -> Self { Self { repository } } fn get_root_folder_read_library_items(&self) -> Result, VideoError> { let root_folder = env::var("ROOT_FOLDER").map_err(|_| VideoError::FolderBrowsingTechnicalIssue)?; let root_folder_files = fs::read_dir(root_folder) .map_err(|_| VideoError::FolderBrowsingTechnicalIssue)?; root_folder_files.into_iter() .flat_map(Result::ok) .filter(Self::file_is_video_or_folder) .map(Self::map_file_into_library_raw_item) .collect() } fn file_is_video_or_folder(file_entry: &DirEntry) -> bool { if file_entry.path().is_dir() { true } else { let content_type = get_content_type(&file_entry.path()); matches!(content_type, AVI | MKV | MP4 | WEBM) } } fn map_file_into_library_raw_item(file: DirEntry) -> Result { let item_type = if file.path().is_dir() { LibraryItemType::FOLDER } else { LibraryItemType::VIDEO }; let library_raw_item = LibraryRawItem::new(None, file.file_name().to_string_lossy().into_owned(), item_type); Ok(library_raw_item) } fn get_all_library_items_from_db(&self) -> Result, Error> { self.repository.get_all_of_root_folder().map_err(|error| Error::new(ErrorKind::Other, "Unable to retrieve the library items of root folder from database.")) .and_then(|entities| entities.into_iter() .map(LibraryItemEntity::to_library_raw_item) .collect::, _>>()) } fn merge_item_lists(file_system_items: Vec, db_items: Vec) -> Vec { let file_system_items_which_are_not_in_database = file_system_items.into_iter() .filter(|file_system_item| !Self::does_item_belong_to_db_items(&db_items, &file_system_item)) .collect::>(); db_items.into_iter().chain(file_system_items_which_are_not_in_database).collect() } fn does_item_belong_to_db_items(database_items: &Vec, file_system_item: &LibraryRawItem) -> bool { database_items.iter() .any(|database_item| database_item.id == file_system_item.id) } } impl VideoPort for LibraryItemAdapter { fn list_root_folder(&self) -> Result, VideoError> { let file_system_items = self.get_root_folder_read_library_items()?; let db_items = self.get_all_library_items_from_db() .map_err(|_| VideoError::FileReadingTechnicalIssue)?; let merged = Self::merge_item_lists(file_system_items, db_items); Ok(merged) } fn list_folder(&self, folder_id: Uuid) -> Result, VideoError> { todo!() } fn get_video_stream(&self, video_id: Uuid) -> Result { todo!() } fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError> { todo!() } fn save_all(&self, library_items: &Vec) -> Result<(), VideoError> { let entities = library_items.iter() .map(LibraryItemEntity::from_library_item) .collect::>(); self.repository.save_all(entities)?; Ok(()) } fn clone_box(&self) -> Box { Box::new(self.clone()) } }