1extern crate alloc;
2
3use alloc::vec;
4use alloc::{string::String, vec::Vec};
5
6use crate::std::{error::Result, PtrRef, ArrayRef, ObjectRef};
7use super::conversion::optional_str_ptr;
8
9use super::meta::{PlaylistItemsRequest, PlaylistItemsResponse};
10
11#[link(wasm_import_module = "structs_video")]
12extern "C" {
13 fn create_episode_source(
14 id_ptr: i32,
15 id_len: i32,
16 display_name_ptr: i32,
17 display_name_len: i32,
18 description_ptr: i32,
19 description_len: i32,
20 servers_ptr: i32
21 ) -> i32;
22
23 fn create_episode_server(
24 id_ptr: i32,
25 id_len: i32,
26 display_name_ptr: i32,
27 display_name_len: i32,
28 description_ptr: i32,
29 description_len: i32
30 ) -> i32;
31
32 fn create_episode_server_response(
33 links_ptr: i32,
34 subtitles_ptr: i32,
35 skip_times_ptr: i32,
36 headers_ptr: i32
37 ) -> i32;
38
39 fn create_episode_server_link(
40 url_ptr: i32,
41 url_len: i32,
42 quality: i32,
43 format: i32
44 ) -> i32;
45
46 fn create_episode_server_subtitle(
47 url_ptr: i32,
48 url_len: i32,
49 name_ptr: i32,
50 name_len: i32,
51 format: i32,
52 default: bool,
53 autoselect: bool
54 ) -> i32;
55
56 fn create_episode_server_skip_time(
57 start_time: f32,
58 end_time: f32,
59 skip_type: PlaylistEpisodeServerSkipType
60 ) -> i32;
61}
62
63pub trait Video {
64 fn playlist_episodes(request: PlaylistItemsRequest) -> Result<PlaylistItemsResponse>;
65 fn playlist_episode_sources(request: PlaylistEpisodeSourcesRequest) -> Result<PlaylistEpisodeSources>;
66 fn playlist_episode_server(request: PlaylistEpisodeServerRequest) -> Result<PlaylistEpisodeServerResponse>;
67}
68
69pub struct PlaylistEpisodeSourcesRequest {
70 pub playlist_id: String,
71 pub episode_id: String
72}
73
74pub struct PlaylistEpisodeSources(pub Vec<PlaylistEpisodeSource>);
75
76pub struct PlaylistEpisodeSource {
77 pub id: String,
78 pub display_name: String,
79 pub description: Option<String>,
80 pub servers: Vec<PlaylistEpisodeServer>
81}
82
83impl Default for PlaylistEpisodeSource {
84 fn default() -> Self {
85 Self {
86 id: "default".into(),
87 display_name: "Default".into(),
88 description: None,
89 servers: vec![]
90 }
91 }
92}
93
94pub struct PlaylistEpisodeServer {
95 pub id: String,
96 pub display_name: String,
97 pub description: Option<String>
98}
99
100pub struct PlaylistEpisodeServerRequest {
101 pub playlist_id: String,
102 pub episode_id: String,
103 pub source_id: String,
104 pub server_id: String
105}
106
107pub struct PlaylistEpisodeServerResponse {
108 pub links: Vec<PlaylistEpisodeServerLink>,
109 pub subtitles: Vec<PlaylistEpisodeServerSubtitle>,
110 pub skip_times: Vec<PlaylistEpisodeServerSkipTime>,
111 pub headers: Vec<PlaylistEpisodeServerHeader>
112}
113
114#[repr(C)]
115#[derive(PartialEq, Eq, Debug, Clone, Copy)]
116pub enum PlaylistEpisodeServerFormatType {
117 HLS,
118 DASH
119}
120
121pub struct PlaylistEpisodeServerLink {
122 pub url: String,
123 pub quality: PlaylistEpisodeServerQualityType,
124 pub format_type: PlaylistEpisodeServerFormatType,
125}
126
127#[repr(u32)]
128pub enum PlaylistEpisodeServerQualityType {
129 Auto,
130 Q1080p,
131 Q720p,
132 Q480p,
133 Q360p,
134 Custom(u32)
135}
136
137impl Into<i32> for PlaylistEpisodeServerQualityType {
138 fn into(self) -> i32 {
139 match self {
140 PlaylistEpisodeServerQualityType::Auto => 0,
141 PlaylistEpisodeServerQualityType::Q1080p => 1080,
142 PlaylistEpisodeServerQualityType::Q720p => 720,
143 PlaylistEpisodeServerQualityType::Q480p => 480,
144 PlaylistEpisodeServerQualityType::Q360p => 360,
145 PlaylistEpisodeServerQualityType::Custom(v) => v as i32,
146 }
147 }
148}
149
150pub struct PlaylistEpisodeServerSubtitle {
151 pub url: String,
152 pub name: String,
153 pub format: PlaylistEpisodeServerSubtitleFormat,
154 pub default: bool,
155 pub autoselect: bool,
156}
157
158#[repr(C)]
159#[derive(PartialEq, Eq, Debug, Clone, Copy)]
160pub enum PlaylistEpisodeServerSubtitleFormat {
161 VTT,
162 ASS,
163 SRT
164}
165
166pub struct PlaylistEpisodeServerSkipTime {
167 pub start_time: f32,
169
170 pub end_time: f32,
172
173 pub skip_type: PlaylistEpisodeServerSkipType
175}
176
177#[repr(C)]
178#[derive(PartialEq, Eq, Debug, Clone, Copy)]
179pub enum PlaylistEpisodeServerSkipType {
180 OPENING,
181 ENDING,
182 RECAP
183}
184
185pub struct PlaylistEpisodeServerHeader {
186 pub key: String,
187 pub value: String
188}
189
190impl Into<PlaylistEpisodeSourcesRequest> for PtrRef {
193 fn into(self) -> PlaylistEpisodeSourcesRequest {
194 if let Ok(obj_ref) = self.as_object() {
195 let playlist_id = obj_ref.get("playlistId").as_string()
196 .unwrap_or_default();
197 let episode_id = obj_ref.get("episodeId").as_string()
198 .unwrap_or_default();
199 PlaylistEpisodeSourcesRequest {
200 playlist_id,
201 episode_id
202 }
203 } else {
204 PlaylistEpisodeSourcesRequest {
205 playlist_id: "".into(),
206 episode_id: "".into(),
207 }
208 }
209 }
210}
211
212impl Into<PlaylistEpisodeServerRequest> for PtrRef {
213 fn into(self) -> PlaylistEpisodeServerRequest {
214 if let Ok(obj_ref) = self.as_object() {
215 let playlist_id = obj_ref.get("playlistId").as_string().unwrap_or_default();
216 let episode_id = obj_ref.get("episodeId").as_string().unwrap_or_default();
217 let source_id = obj_ref.get("sourceId").as_string().unwrap_or_default();
218 let server_id = obj_ref.get("serverId").as_string().unwrap_or_default();
219 PlaylistEpisodeServerRequest {
220 playlist_id,
221 episode_id,
222 source_id,
223 server_id
224 }
225 } else {
226 PlaylistEpisodeServerRequest {
227 playlist_id: "".into(),
228 episode_id: "".into(),
229 source_id: "".into(),
230 server_id: "".into()
231 }
232 }
233 }
234}
235
236impl From<PlaylistEpisodeSources> for PtrRef {
237 fn from(value: PlaylistEpisodeSources) -> Self {
238 let sources = ArrayRef::from(value.0);
239 let sources_id = sources.ptr();
240 core::mem::forget(sources);
241 PtrRef::new(sources_id)
242 }
243}
244
245impl From<PlaylistEpisodeSource> for PtrRef {
246 fn from(value: PlaylistEpisodeSource) -> Self {
247 let description = optional_str_ptr(value.description);
248
249 let servers = ArrayRef::from(value.servers);
250 let servers_ptr = servers.ptr();
251 core::mem::forget(servers);
252
253 let source_ptr = unsafe {
254 create_episode_source(
255 value.id.as_ptr() as i32,
256 value.id.len() as i32,
257 value.display_name.as_ptr() as i32,
258 value.display_name.len() as i32,
259 description.0,
260 description.1,
261 servers_ptr
262 )
263 };
264 PtrRef::new(source_ptr)
265 }
266}
267
268impl From<PlaylistEpisodeServer> for PtrRef {
269 fn from(value: PlaylistEpisodeServer) -> Self {
270 let description = optional_str_ptr(value.description);
271 let server_ptr = unsafe {
272 create_episode_server(
273 value.id.as_ptr() as i32,
274 value.id.len() as i32,
275 value.display_name.as_ptr() as i32,
276 value.display_name.len() as i32,
277 description.0,
278 description.1
279 )
280 };
281 PtrRef::new(server_ptr)
282 }
283}
284
285impl From<PlaylistEpisodeServerSkipTime> for PtrRef {
286 fn from(value: PlaylistEpisodeServerSkipTime) -> Self {
287 PtrRef::new(
288 unsafe {
289 create_episode_server_skip_time(
290 value.start_time,
291 value.end_time,
292 value.skip_type
293 )
294 }
295 )
296 }
297}
298
299impl From<PlaylistEpisodeServerResponse> for PtrRef {
300 fn from(value: PlaylistEpisodeServerResponse) -> Self {
301 let links = ArrayRef::from(value.links);
302 let links_ptr = links.ptr();
303 core::mem::forget(links);
304
305 let subtitles = ArrayRef::from(value.subtitles);
306 let subtitles_ptr = subtitles.ptr();
307 core::mem::forget(subtitles);
308
309 let skip_times = ArrayRef::from(value.skip_times);
310 let skip_times_ptr = skip_times.ptr();
311 core::mem::forget(skip_times);
312
313 let mut headers = ObjectRef::new();
314 for header in value.headers {
315 headers.set(&header.key, header.value.into())
316 }
317 let headers_ptr = headers.ptr();
318 core::mem::forget(headers);
319
320 let response_ptr = unsafe {
321 create_episode_server_response(
322 links_ptr,
323 subtitles_ptr,
324 skip_times_ptr,
325 headers_ptr
326 )
327 };
328 PtrRef::new(response_ptr)
329 }
330}
331
332impl From<PlaylistEpisodeServerLink> for PtrRef {
333 fn from(value: PlaylistEpisodeServerLink) -> Self {
334 let ptr = unsafe {
335 create_episode_server_link(
336 value.url.as_ptr() as i32,
337 value.url.len() as i32,
338 value.quality.into(),
339 value.format_type as i32
340 )
341 };
342 PtrRef::new(ptr)
343 }
344}
345
346impl From<PlaylistEpisodeServerSubtitle> for PtrRef {
347 fn from(value: PlaylistEpisodeServerSubtitle) -> Self {
348 let ptr = unsafe {
349 create_episode_server_subtitle(
350 value.url.as_ptr() as i32,
351 value.url.len() as i32,
352 value.name.as_ptr() as i32,
353 value.name.len() as i32,
354 value.format as i32,
355 value.default,
356 value.autoselect
357 )
358 };
359 PtrRef::new(ptr)
360 }
361}