Skip to main content

nexus_common/media/processors/
mod.rs

1use crate::{media::FileVariant, models::file::FileDetails, types::DynError};
2use async_trait::async_trait;
3use std::path::PathBuf;
4
5mod image;
6mod video;
7
8pub use image::*;
9pub use video::*;
10
11pub trait BaseProcessingOptions: Send + Sync {
12    fn content_type(&self) -> String;
13}
14
15#[async_trait]
16pub trait VariantProcessor {
17    type ProcessingOptions: BaseProcessingOptions;
18
19    /// Returns a list of valid variants for a given content type
20    /// If there are no valid variants for the content type, return an empty list
21    fn get_valid_variants_for_content_type(content_type: &str) -> Vec<FileVariant>;
22
23    /// Returns the content type for a given variant
24    fn get_content_type_for_variant(file: &FileDetails, variant: &FileVariant) -> String;
25
26    /// Returns the processing options for a given variant
27    /// If there are no options for this variant, return an error
28    fn get_options_for_variant(
29        file: &FileDetails,
30        variant: &FileVariant,
31    ) -> Result<Self::ProcessingOptions, DynError>;
32
33    /// Processes the origin file and saves the output to the output_file_path based on the passed options
34    /// Returns the content type of the processed file or the original content type if no processing was done
35    async fn process(
36        origin_file_path: &str,
37        output_file_path: &str,
38        options: &Self::ProcessingOptions,
39    ) -> Result<String, DynError>;
40
41    /// Creates a variant for the given file
42    /// If there are no options for this variant, return with the original content type
43    async fn create_variant(
44        file: &FileDetails,
45        variant: &FileVariant,
46        file_path: PathBuf,
47    ) -> Result<String, DynError> {
48        // if there are no options for this variant, return with the original content type
49        let options = match Self::get_options_for_variant(file, variant) {
50            Ok(options) => options,
51            Err(_) => return Ok(file.content_type.clone()),
52        };
53
54        let origin_path = file_path
55            .join(file.owner_id.as_str())
56            .join(file.id.as_str());
57
58        let origin_file = origin_path.join(FileVariant::Main.to_string());
59
60        let origin_file_path = match origin_file.to_str() {
61            Some(path) => path,
62            None => return Err("Invalid original file path".into()),
63        };
64
65        let output = origin_path.join(variant.to_string());
66        let output_path = match output.to_str() {
67            Some(path) => path,
68            None => return Err("Invalid output path".into()),
69        };
70
71        Self::process(origin_file_path, output_path, &options).await?;
72
73        Ok(options.content_type())
74    }
75}