Create a basic frontend and an endpoint to get video stream.
This commit is contained in:
@@ -17,5 +17,5 @@ log = "0.4.33"
|
||||
rand = "0.10.2"
|
||||
rusqlite = { version = "0.39.0", features = ["bundled"] }
|
||||
sysinfo = "0.39.6"
|
||||
tokio = { version = "1.52.3", features = ["fs"] }
|
||||
tokio = { version = "1.52.3", features = ["fs", "rt-multi-thread"] }
|
||||
uuid = { version = "1.23.1", features = ["v4"] }
|
||||
@@ -7,8 +7,10 @@ use std::env;
|
||||
use std::fs;
|
||||
use std::fs::DirEntry;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use LibraryItemType::FOLDER;
|
||||
use lumiere_domain::video::model::library_item::LibraryItemType::VIDEO;
|
||||
use lumiere_domain::video::model::video::VideoFormat::{AVI, MKV, MP4, WEBM};
|
||||
use crate::video::model::LibraryItemEntity;
|
||||
use crate::video::model::{LibraryItemEntity, TokioVideoFile};
|
||||
use crate::video::repository::LibraryItemSqliteRepository;
|
||||
use crate::video::video_format_detector::get_content_type;
|
||||
|
||||
@@ -46,7 +48,7 @@ impl LibraryItemAdapter {
|
||||
|
||||
fn map_file_into_library_raw_item(file: DirEntry) -> Result<LibraryRawItem, VideoError> {
|
||||
let item_type = if file.path().is_dir() {
|
||||
LibraryItemType::FOLDER
|
||||
FOLDER
|
||||
} else {
|
||||
LibraryItemType::VIDEO
|
||||
};
|
||||
@@ -74,6 +76,12 @@ impl LibraryItemAdapter {
|
||||
database_items.iter()
|
||||
.any(|database_item| database_item.name == file_system_item.name)
|
||||
}
|
||||
|
||||
fn find_library_item_by_id(&self, library_item_id: Uuid) -> Result<Option<LibraryItem>, VideoError> {
|
||||
self.repository.find_by_id(library_item_id)
|
||||
.map_err(|_| VideoError::FileReadingTechnicalIssue)
|
||||
.map(|entity_opt| entity_opt.map(LibraryItemEntity::to_library_item))
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoPort for LibraryItemAdapter {
|
||||
@@ -102,7 +110,28 @@ impl VideoPort for LibraryItemAdapter {
|
||||
}
|
||||
|
||||
fn get_video_stream(&self, video_id: Uuid) -> Result<Video, VideoError> {
|
||||
todo!()
|
||||
let video_item = self.find_library_item_by_id(video_id)?;
|
||||
|
||||
match video_item {
|
||||
None => Err(VideoError::VideoDoesNotExists),
|
||||
Some(video) => {
|
||||
match video.r#type {
|
||||
VIDEO => {
|
||||
let root_folder = env::var("ROOT_FOLDER").map_err(|_| VideoError::FolderBrowsingTechnicalIssue)?;
|
||||
let video_file_path = String::from(format!("{root_folder}/{}", video.name));
|
||||
let result = Video {
|
||||
id: video.id,
|
||||
name: video.name,
|
||||
format: AVI,
|
||||
file: Box::new(TokioVideoFile::new(&video_file_path).map_err(|_| VideoError::FileReadingTechnicalIssue)?)
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
},
|
||||
FOLDER => Err(VideoError::VideoDoesNotExists)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn save(&self, library_item: &LibraryItem) -> Result<(), VideoError> {
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
use std::fs::File;
|
||||
use std::any::Any;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use tokio::fs::File;
|
||||
use uuid::Uuid;
|
||||
use lumiere_domain::video::model::library_item::{LibraryItem, LibraryItemType, LibraryRawItem};
|
||||
use lumiere_domain::video::model::video::VideoFile;
|
||||
|
||||
pub struct TokioVideoFile {
|
||||
pub file: File
|
||||
}
|
||||
|
||||
impl TokioVideoFile {
|
||||
pub fn new(file_path: &String) -> Self {
|
||||
Self {
|
||||
file: File::open(file_path).expect(format!("Failed to open file {file_path}").as_str())
|
||||
}
|
||||
pub fn new(file_path: &String) -> Result<Self, Error> {
|
||||
let rt = tokio::runtime::Runtime::new()?;
|
||||
let file = rt.block_on(async { File::open(file_path).await })?;
|
||||
Ok(Self { file })
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoFile for TokioVideoFile {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +56,15 @@ impl LibraryItemEntity {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_library_raw_item(self) -> Result<LibraryRawItem, Error> {
|
||||
pub fn to_library_item(self) -> LibraryItem {
|
||||
LibraryItem {
|
||||
id: self.id.clone(),
|
||||
name: self.name.clone(),
|
||||
r#type: Self::map_type_from_i8(self.r#type).expect(""),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_library_raw_item(self) -> Result<LibraryRawItem, Error> {
|
||||
let library_item = LibraryRawItem {
|
||||
id: Some(self.id.clone()),
|
||||
name: self.name.clone(),
|
||||
|
||||
@@ -53,10 +53,10 @@ impl LibraryItemSqliteRepository {
|
||||
WHERE parent_folder_id IS NULL",
|
||||
)?;
|
||||
let rows = prepared_statement.query([])?;
|
||||
rows.map(Self::map_to_library_item).collect::<Vec<LibraryItemEntity>>()
|
||||
rows.map(Self::map_to_entity).collect::<Vec<LibraryItemEntity>>()
|
||||
}
|
||||
|
||||
fn map_to_library_item(row: &Row) -> Result<LibraryItemEntity, Error> {
|
||||
fn map_to_entity(row: &Row) -> Result<LibraryItemEntity, Error> {
|
||||
let id_text: String = row.get(0)?;
|
||||
let type_as_number: i8 = row.get(2)?;
|
||||
Ok(
|
||||
@@ -185,6 +185,26 @@ impl LibraryItemSqliteRepository {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
pub fn find_by_id(&self, library_item_id: Uuid) -> Result<Option<LibraryItemEntity>, Error> {
|
||||
let database_connection = self.get_connection();
|
||||
|
||||
let mut prepared_statement = database_connection.prepare(
|
||||
"SELECT
|
||||
id,
|
||||
name,
|
||||
type,
|
||||
parent_folder_id
|
||||
FROM library_item
|
||||
WHERE id = ?1;"
|
||||
)?;
|
||||
let mut rows = prepared_statement.query([library_item_id.to_string()])?;
|
||||
|
||||
if let Some(row) = rows.next()? {
|
||||
Ok(Some(Self::map_to_entity(&row)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn map_to_raw_entity(row: &Row) -> Result<LibraryItemRawEntity, Error> {
|
||||
let id_text: String = row.get(0)?;
|
||||
@@ -199,4 +219,4 @@ impl LibraryItemSqliteRepository {
|
||||
};
|
||||
Ok(raw_entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user