rs_plugin_common_interfaces/
lib.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use strum_macros::EnumString;
4
5pub use domain::{element_type::ElementType, external_images::{ExternalImage, ImageType}};
6pub use request::{RsRequest, RsCookie, RsCookies, RsRequestFiles, RsRequestPluginRequest, RsRequestStatus};
7pub use url::{RsLink, RsLinkType};
8pub use lookup::{RsLookupEpisode, RsLookupBook, RsLookupMovie, RsLookupMedia, RsLookupPerson, RsLookupSerie, RsLookupSerieSeason, RsLookupSong, RsLookupQuery, RsLookupSourceResult, RsLookupWrapper};
9
10pub use video::{RsAudio, RsResolution, RsVideoCodec, RsVideoFormat};
11
12#[cfg(feature = "rusqlite")]
13pub mod rusqlite;
14
15pub mod request;
16pub mod url;
17pub mod lookup;
18pub mod provider;
19
20pub mod video;
21
22pub mod domain;
23
24pub const INTERFACE_VERSION: u16 = 1;
25
26#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
27#[serde(rename_all = "camelCase")] 
28pub struct CustomParam {
29    pub name: String,
30    pub param: CustomParamTypes,
31    pub description: Option<String>,
32    #[serde(default)]
33    pub required: bool
34}
35
36
37
38#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
39#[serde(rename_all = "camelCase")] 
40pub struct PluginInformation {
41    pub name: String,
42    pub capabilities: Vec<PluginType>,
43    pub publisher: String,
44    pub description: String,
45    pub credential_kind: Option<CredentialType>,
46    pub repo: Option<String>,
47    pub oauth_url: Option<String>,
48    pub version: u16,
49    
50    #[serde(default)]
51    pub settings: Vec<CustomParam>,
52
53    pub interface_version: u16,
54}
55
56impl PluginInformation {
57    pub fn capabilities_tostring(&self) -> String {
58        self.capabilities.iter()
59        .map(|plugin| plugin.to_string())
60        .collect::<Vec<_>>()
61        .join(", ")
62    }
63}
64
65
66
67
68#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display,EnumString, Default)]
69#[serde(rename_all = "camelCase")] 
70#[strum(serialize_all = "camelCase")]
71pub enum PluginType {
72	ImageClassification,
73    UrlParser,
74    Request,
75    Lookup,
76    Provider,
77    VideoConvert,
78    #[default]
79    Other,
80}
81
82#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
83#[serde(rename_all = "camelCase")] 
84pub struct RsRemainingCredits {
85    pub number: u64,
86    pub unit: String,
87}
88
89#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display,EnumString, Default)]
90#[serde(rename_all = "camelCase", tag = "type")] 
91#[strum(serialize_all = "camelCase")]
92pub enum CredentialType {
93	Url,
94	Password,
95    Oauth {
96        /// Oauth url to get code from user; use #redirecturi# in the url
97        url: String
98    },
99    #[default]
100    Token,
101}
102
103#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display,EnumString)]
104#[serde(rename_all = "camelCase")] 
105#[strum(serialize_all = "camelCase")]
106pub enum CustomParamTypes {
107	Text(Option<String>),
108    Url(Option<String>),
109    Integer(Option<i64>),
110    UInteger(Option<u64>),
111    Float(Option<f64>),
112}
113
114#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
115#[serde(rename_all = "camelCase")] 
116pub struct PluginCredential {
117    pub kind: CredentialType,
118    pub login: Option<String>,
119    pub password: Option<String>,
120    pub settings: Value,
121    pub user_ref: Option<String>,
122    pub refresh_token: Option<String>,
123    pub expires: Option<i64>,
124}
125
126#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display,EnumString, Default)]
127#[strum(serialize_all = "camelCase")]
128#[serde(rename_all = "camelCase")]
129pub enum RsFileType {
130    Directory,
131    Photo,
132    Video,
133    Archive,
134    Album,
135    #[default]
136    Other
137}
138
139#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display, EnumString, Default)]
140#[serde(rename_all = "camelCase")] 
141#[strum(serialize_all = "camelCase")]
142pub enum MediaType {
143	Movie,
144	Episode,
145    Book,
146    Song,
147    #[strum(default)]
148    Custom(String),
149    #[default]
150    Unknown,
151}
152
153#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display, EnumString, Default)]
154#[serde(rename_all = "camelCase")] 
155#[strum(serialize_all = "camelCase")]
156pub enum Gender {
157	Male,
158	Female,
159    Animal,
160    Other,
161    #[strum(default)]
162    Custom(String),
163    #[default]
164    Unknown,
165}
166
167
168
169#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
170#[serde(rename_all = "camelCase")] 
171pub struct RsPluginRequest<T> {
172    pub request: T,
173    pub plugin_settings: Value,
174    pub credential: Option<PluginCredential>
175}
176
177
178
179
180#[cfg(test)]
181mod tests {
182    use std::str::FromStr;
183
184    use super::*;
185
186    #[test]
187    fn resolution_parsing() {
188        assert_eq!(RsResolution::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsResolution::FullHD);
189        assert_eq!(RsResolution::from_filename("Test.2024.S01E01_720p VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsResolution::HD);  
190        assert_eq!(RsResolution::from_filename("TestIn4k.2024.S01E01_VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsResolution::Unknown);
191        assert_eq!(RsResolution::from_filename("TestIn4k.2024.S01E01_4K_VOSTFR.DSNP.WEB-DL.DDP5.Atmos.1.H.264"), RsResolution::UHD);
192    }
193
194
195    #[test]
196    fn resolution_string() {
197        assert_eq!("4K", RsResolution::UHD.to_string());
198        assert_eq!(RsResolution::from_str("1080p").unwrap(), RsResolution::FullHD);
199        assert_eq!(RsResolution::from_str("erzr").unwrap(), RsResolution::Custom("erzr".to_owned()));
200    }
201    #[test]
202    fn audio_parsing() {
203        assert_eq!(RsAudio::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsAudio::DDP51);
204        assert_eq!(RsAudio::from_filename("Test.2024.S01E01_720p VOSTFR.DSNP.WEB-DL.DDP5.1._atmos_H.264"), RsAudio::Atmos);  
205        let list = RsAudio::list_from_filename("TestIn4k.2024.S01E01_4K_VOSTFR.DSNP.WEB-DL.DDP5.1.Atmos.H.264");
206        assert_eq!(list.len(), 2);
207        assert!(list.contains(&RsAudio::Atmos));
208        assert!(list.contains(&RsAudio::DDP51));
209    }
210
211    #[test]
212    fn videocodec_parsing() {
213        assert_eq!(RsVideoCodec::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsVideoCodec::H264);
214        assert_eq!(RsVideoCodec::from_filename("Test.2024.S01E01_720p VOSTFR.DSNP.WEB-DL.DDP5.1.HEVC"), RsVideoCodec::H265);  
215        assert_eq!(RsVideoCodec::from_filename("TestIn4k.2024.S01E01_VOSTFR.DSNP.WEB-DL.DDP5.1.X.265"), RsVideoCodec::H265);
216        
217    }
218
219    #[test]
220    fn video_format_parsing() {
221        assert_eq!(RsVideoFormat::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264.mp4"), RsVideoFormat::Mp4);
222        assert_eq!(RsVideoFormat::from_filename("Test.2024.S01E01_720p VOSTFR.DSNP.WEB-DL.DDP5.1._atmos_H.264"), RsVideoFormat::Other);  
223        assert_eq!(RsVideoFormat::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264.WMV"), RsVideoFormat::Wmv);
224        
225        assert_eq!(RsVideoFormat::Mp4.to_string(), "mp4");
226        assert_eq!(RsVideoFormat::from_str("mkv").unwrap(), RsVideoFormat::Mkv);
227    }
228}