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 oauth_url: Option<String>,
47    pub version: u16,
48    
49    #[serde(default)]
50    pub settings: Vec<CustomParam>,
51
52    pub interface_version: u16,
53}
54
55impl PluginInformation {
56    pub fn capabilities_tostring(&self) -> String {
57        self.capabilities.iter()
58        .map(|plugin| plugin.to_string())
59        .collect::<Vec<_>>()
60        .join(", ")
61    }
62}
63
64
65
66
67#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display,EnumString, Default)]
68#[serde(rename_all = "camelCase")] 
69#[strum(serialize_all = "camelCase")]
70pub enum PluginType {
71	ImageClassification,
72    UrlParser,
73    Request,
74    Lookup,
75    Provider,
76    #[default]
77    Other,
78}
79
80#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display,EnumString, Default)]
81#[serde(rename_all = "camelCase", tag = "type")] 
82#[strum(serialize_all = "camelCase")]
83pub enum CredentialType {
84	Url,
85	Password,
86    Oauth {
87        /// Oauth url to get code from user; use #redirecturi# in the url
88        url: String
89    },
90    #[default]
91    Token,
92}
93
94#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display,EnumString)]
95#[serde(rename_all = "camelCase")] 
96#[strum(serialize_all = "camelCase")]
97pub enum CustomParamTypes {
98	Text(Option<String>),
99    Url(Option<String>),
100    Integer(Option<i64>),
101    UInteger(Option<u64>),
102    Float(Option<f64>),
103}
104
105#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
106#[serde(rename_all = "camelCase")] 
107pub struct PluginCredential {
108    pub kind: CredentialType,
109    pub login: Option<String>,
110    pub password: Option<String>,
111    pub settings: Value,
112    pub user_ref: Option<String>,
113    pub refresh_token: Option<String>,
114    pub expires: Option<i64>,
115}
116
117#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display,EnumString, Default)]
118#[strum(serialize_all = "camelCase")]
119#[serde(rename_all = "camelCase")]
120pub enum RsFileType {
121    Directory,
122    Photo,
123    Video,
124    Archive,
125    Album,
126    #[default]
127    Other
128}
129
130#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display, EnumString, Default)]
131#[serde(rename_all = "camelCase")] 
132#[strum(serialize_all = "camelCase")]
133pub enum MediaType {
134	Movie,
135	Episode,
136    Book,
137    Song,
138    #[strum(default)]
139    Custom(String),
140    #[default]
141    Unknown,
142}
143
144#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, strum_macros::Display, EnumString, Default)]
145#[serde(rename_all = "camelCase")] 
146#[strum(serialize_all = "camelCase")]
147pub enum Gender {
148	Male,
149	Female,
150    Animal,
151    Other,
152    #[strum(default)]
153    Custom(String),
154    #[default]
155    Unknown,
156}
157
158
159
160#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
161#[serde(rename_all = "camelCase")] 
162pub struct RsPluginRequest<T> {
163    pub request: T,
164    pub plugin_settings: Value,
165    pub credential: Option<PluginCredential>
166}
167
168
169
170
171#[cfg(test)]
172mod tests {
173    use std::str::FromStr;
174
175    use super::*;
176
177    #[test]
178    fn resolution_parsing() {
179        assert_eq!(RsResolution::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsResolution::FullHD);
180        assert_eq!(RsResolution::from_filename("Test.2024.S01E01_720p VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsResolution::HD);  
181        assert_eq!(RsResolution::from_filename("TestIn4k.2024.S01E01_VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsResolution::Unknown);
182        assert_eq!(RsResolution::from_filename("TestIn4k.2024.S01E01_4K_VOSTFR.DSNP.WEB-DL.DDP5.Atmos.1.H.264"), RsResolution::UHD);
183    }
184
185
186    #[test]
187    fn resolution_string() {
188        assert_eq!("4K", RsResolution::UHD.to_string());
189        assert_eq!(RsResolution::from_str("1080p").unwrap(), RsResolution::FullHD);
190        assert_eq!(RsResolution::from_str("erzr").unwrap(), RsResolution::Custom("erzr".to_owned()));
191    }
192    #[test]
193    fn audio_parsing() {
194        assert_eq!(RsAudio::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsAudio::DDP51);
195        assert_eq!(RsAudio::from_filename("Test.2024.S01E01_720p VOSTFR.DSNP.WEB-DL.DDP5.1._atmos_H.264"), RsAudio::Atmos);  
196        let list = RsAudio::list_from_filename("TestIn4k.2024.S01E01_4K_VOSTFR.DSNP.WEB-DL.DDP5.1.Atmos.H.264");
197        assert_eq!(list.len(), 2);
198        assert!(list.contains(&RsAudio::Atmos));
199        assert!(list.contains(&RsAudio::DDP51));
200    }
201
202    #[test]
203    fn videocodec_parsing() {
204        assert_eq!(RsVideoCodec::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264"), RsVideoCodec::H264);
205        assert_eq!(RsVideoCodec::from_filename("Test.2024.S01E01_720p VOSTFR.DSNP.WEB-DL.DDP5.1.HEVC"), RsVideoCodec::H265);  
206        assert_eq!(RsVideoCodec::from_filename("TestIn4k.2024.S01E01_VOSTFR.DSNP.WEB-DL.DDP5.1.X.265"), RsVideoCodec::H265);
207        
208    }
209
210    #[test]
211    fn video_format_parsing() {
212        assert_eq!(RsVideoFormat::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264.mp4"), RsVideoFormat::Mp4);
213        assert_eq!(RsVideoFormat::from_filename("Test.2024.S01E01_720p VOSTFR.DSNP.WEB-DL.DDP5.1._atmos_H.264"), RsVideoFormat::Other);  
214        assert_eq!(RsVideoFormat::from_filename("Test.2024.S01E01.1080p.VOSTFR.DSNP.WEB-DL.DDP5.1.H.264.WMV"), RsVideoFormat::Wmv);
215        
216        assert_eq!(RsVideoFormat::Mp4.to_string(), "mp4");
217        assert_eq!(RsVideoFormat::from_str("mkv").unwrap(), RsVideoFormat::Mkv);
218    }
219}