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