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