aidoku/structs/
source.rs

1use super::{
2	Chapter, Filter, FilterValue, HashMap, HomeLayout, Listing, Manga, MangaPageResult, Page,
3	PageContext, Setting,
4};
5use crate::alloc::{String, Vec};
6use crate::imports::{canvas::ImageRef, net::Request};
7use serde::{Deserialize, Serialize, ser::SerializeStruct};
8
9pub use crate::imports::error::{AidokuError, Result};
10
11/// The required functions an Aidoku source must implement.
12pub trait Source {
13	/// Called to initialize a source.
14	///
15	/// If a source requires any setup before other functions are called, it should happen here.
16	fn new() -> Self;
17
18	/// Returns the manga for a search query with filters.
19	fn get_search_manga_list(
20		&self,
21		query: Option<String>,
22		page: i32,
23		filters: Vec<FilterValue>,
24	) -> Result<MangaPageResult>;
25
26	/// Updates a given manga with new details and chapters, as requested.
27	fn get_manga_update(
28		&self,
29		manga: Manga,
30		needs_details: bool,
31		needs_chapters: bool,
32	) -> Result<Manga>;
33
34	/// Returns the pages for a given manga chapter.
35	fn get_page_list(&self, manga: Manga, chapter: Chapter) -> Result<Vec<Page>>;
36}
37
38/// A source that provides listings.
39pub trait ListingProvider: Source {
40	/// Returns the manga for the provided listing.
41	fn get_manga_list(&self, listing: Listing, page: i32) -> Result<MangaPageResult>;
42}
43
44/// A source that provides a home layout.
45pub trait Home: Source {
46	fn get_home(&self) -> Result<HomeLayout>;
47}
48
49/// A source that provides dynamic listings.
50pub trait DynamicListings: Source {
51	fn get_dynamic_listings(&self) -> Result<Vec<Listing>>;
52}
53
54/// A source that provides dynamic filters.
55pub trait DynamicFilters: Source {
56	fn get_dynamic_filters(&self) -> Result<Vec<Filter>>;
57}
58
59/// A source that provides dynamic settings.
60pub trait DynamicSettings: Source {
61	fn get_dynamic_settings(&self) -> Result<Vec<Setting>>;
62}
63
64/// A source that processes page image data after being fetched.
65pub trait PageImageProcessor: Source {
66	fn process_page_image(
67		&self,
68		response: ImageResponse,
69		context: Option<PageContext>,
70	) -> Result<ImageRef>;
71}
72
73/// A source that provides requests for images.
74///
75/// By default, Aidoku will request covers, thumbnails, and pages without headers.
76/// This trait can be used to override the requests for source images.
77pub trait ImageRequestProvider: Source {
78	fn get_image_request(&self, url: String, context: Option<PageContext>) -> Result<Request>;
79}
80
81/// A source that provides dynamic descriptions for pages.
82pub trait PageDescriptionProvider: Source {
83	fn get_page_description(&self, page: Page) -> Result<String>;
84}
85
86/// A source that provides multiple cover images.
87pub trait AlternateCoverProvider: Source {
88	fn get_alternate_covers(&self, manga: Manga) -> Result<Vec<String>>;
89}
90
91/// A source that provides a programmatic base url.
92///
93/// The use of this trait is discouraged in favor of providing the source url statically.
94pub trait BaseUrlProvider: Source {
95	fn get_base_url(&self) -> Result<String>;
96}
97
98/// A source that handles notification callbacks.
99///
100/// Notifications can be sent on source setting changes.
101pub trait NotificationHandler: Source {
102	fn handle_notification(&self, notification: String);
103}
104
105/// A source that handles deep links.
106///
107/// If a url that is contained in one of the source's provided base urls is opened
108/// in Aidoku, it will be sent to the given source to handle.
109pub trait DeepLinkHandler: Source {
110	fn handle_deep_link(&self, url: String) -> Result<Option<DeepLinkResult>>;
111}
112
113/// A source that handles basic login with username and password.
114///
115/// This function should return true if the login was successful.
116pub trait BasicLoginHandler: Source {
117	fn handle_basic_login(&self, key: String, username: String, password: String) -> Result<bool>;
118}
119
120/// A source that handles custom webview login.
121///
122/// This function will be called whenever cookies are updated, and should return true if the login was successful.
123pub trait WebLoginHandler: Source {
124	fn handle_web_login(&self, key: String, cookies: HashMap<String, String>) -> Result<bool>;
125}
126
127/// A source that handles key migration.
128///
129/// If a source provides a "breakingChangeVersion" in its configuration, these functions will be
130/// called with all of a user's local manga and chapter keys to migrate them after updating.
131/// These functions should return the new key to replace the old one.
132pub trait MigrationHandler: Source {
133	fn handle_manga_migration(&self, key: String) -> Result<String>;
134	fn handle_chapter_migration(&self, manga_key: String, chapter_key: String) -> Result<String>;
135}
136
137/// A result of a deep link handling.
138#[derive(Debug, Clone, PartialEq)]
139pub enum DeepLinkResult {
140	Manga { key: String },
141	Chapter { manga_key: String, key: String },
142	Listing(Listing),
143}
144
145impl Serialize for DeepLinkResult {
146	fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
147	where
148		S: serde::Serializer,
149	{
150		let mut state = serializer.serialize_struct("DeepLinkResult", 3)?;
151		match self {
152			DeepLinkResult::Manga { key } => {
153				state.serialize_field("manga_key", &Some(key))?;
154				state.serialize_field("chapter_key", &Option::<String>::None)?;
155				state.serialize_field("listing", &Option::<Listing>::None)?;
156			}
157			DeepLinkResult::Chapter { manga_key, key } => {
158				state.serialize_field("manga_key", &Some(manga_key))?;
159				state.serialize_field("chapter_key", &Some(key))?;
160				state.serialize_field("listing", &Option::<Listing>::None)?;
161			}
162			DeepLinkResult::Listing(listing) => {
163				state.serialize_field("manga_key", &Option::<String>::None)?;
164				state.serialize_field("chapter_key", &Option::<String>::None)?;
165				state.serialize_field("listing", &Some(listing))?;
166			}
167		}
168		state.end()
169	}
170}
171
172/// The details of a HTTP request.
173#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
174pub struct ImageRequest {
175	pub url: Option<String>,
176	pub headers: HashMap<String, String>,
177}
178
179/// A response from a network image request.
180#[derive(Debug, Serialize, Deserialize)]
181pub struct ImageResponse {
182	/// The HTTP status code.
183	pub code: u16,
184	/// The HTTP response headers.
185	pub headers: HashMap<String, String>,
186	/// The HTTP request details.
187	pub request: ImageRequest,
188	/// A reference to image data.
189	pub image: ImageRef,
190}