diff --git a/sources/zh.se8/.cargo/config.toml b/sources/zh.se8/.cargo/config.toml deleted file mode 100644 index 1033ef098..000000000 --- a/sources/zh.se8/.cargo/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -[build] -target = "wasm32-unknown-unknown" - -[target.wasm32-unknown-unknown] -runner = "aidoku-test-runner" diff --git a/sources/zh.se8/Cargo.lock b/sources/zh.se8/Cargo.lock deleted file mode 100644 index 4b7d1711b..000000000 --- a/sources/zh.se8/Cargo.lock +++ /dev/null @@ -1,327 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aidoku" -version = "0.3.0" -source = "git+https://github.com/Aidoku/aidoku-rs.git#ae6485e3c14ecd1fd5497d170eae884c68d04a87" -dependencies = [ - "euclid", - "hashbrown", - "itoa", - "num-traits", - "paste", - "postcard", - "serde", - "talc", - "thiserror", -] - -[[package]] -name = "aidoku-test" -version = "1.0.0" -source = "git+https://github.com/Aidoku/aidoku-rs.git#ae6485e3c14ecd1fd5497d170eae884c68d04a87" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "euclid" -version = "0.22.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63" -dependencies = [ - "num-traits", -] - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", - "serde", - "serde_core", -] - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "itoa" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - -[[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "heapless", - "serde", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "se8" -version = "0.1.0" -dependencies = [ - "aidoku", - "aidoku-test", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "spin" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "talc" -version = "4.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ae828aa394de34c7de08f522d1b86bd1c182c668d27da69caadda00590f26d" -dependencies = [ - "lock_api", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/sources/zh.se8/Cargo.toml b/sources/zh.se8/Cargo.toml deleted file mode 100644 index 9f044303b..000000000 --- a/sources/zh.se8/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "se8" -version = "0.1.0" -edition = "2024" - -[dependencies] -aidoku = { git = "https://github.com/Aidoku/aidoku-rs.git", version = "0.3.0" } - -[dev-dependencies] -aidoku = { git = "https://github.com/Aidoku/aidoku-rs.git", features = ["test"] } -aidoku-test = { git = "https://github.com/Aidoku/aidoku-rs.git" } - -[lib] -crate-type = ["cdylib"] - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" -opt-level = "s" -strip = true -lto = true diff --git a/sources/zh.se8/res/filters.json b/sources/zh.se8/res/filters.json deleted file mode 100644 index ffb8567c0..000000000 --- a/sources/zh.se8/res/filters.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "type": "sort", - "title": "排序", - "options": ["热门人气", "更新时间"] - }, - { - "type": "select", - "title": "进度", - "options": ["全部", "连载", "完结"], - "ids": ["", "1", "2"] - } -] diff --git a/sources/zh.se8/res/icon.png b/sources/zh.se8/res/icon.png deleted file mode 100644 index d2e72f2e2..000000000 Binary files a/sources/zh.se8/res/icon.png and /dev/null differ diff --git a/sources/zh.se8/res/source.json b/sources/zh.se8/res/source.json deleted file mode 100644 index 51de8740d..000000000 --- a/sources/zh.se8/res/source.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "info": { - "id": "zh.se8", - "name": "韩漫库", - "version": 1, - "url": "https://se8.us", - "contentRating": 2, - "languages": ["zh"], - "minAppVersion": "0.7.1" - }, - "config": { - "hidesFiltersWhileSearching": true, - "supportsAuthorSearch": false, - "supportsTagSearch": true - } -} diff --git a/sources/zh.se8/src/html/mod.rs b/sources/zh.se8/src/html/mod.rs deleted file mode 100644 index 3ebad33fe..000000000 --- a/sources/zh.se8/src/html/mod.rs +++ /dev/null @@ -1,238 +0,0 @@ -use crate::{BASE_URL, USER_AGENT}; -use aidoku::{ - Chapter, ContentRating, Manga, MangaPageResult, MangaStatus, Page, PageContent, Result, - SelectFilter, Viewer, - alloc::{String, Vec, borrow::Cow, string::ToString as _}, - imports::{html::Document, net::Request}, - prelude::*, -}; - -pub trait MangaListPage { - fn manga_page_result(&self) -> Result; -} - -pub trait MangaDetailPage { - fn manga_details(&self, url: String, key: String) -> Result; -} - -pub trait TagsPage { - fn tags_filter(&self) -> Result; -} - -impl MangaListPage for Document { - fn manga_page_result(&self) -> Result { - let mut mangas: Vec = Vec::new(); - - let items = self - .select(".common-comic-item") - .ok_or_else(|| error!("No manga items found"))?; - - for item in items { - let a_node = match item.select_first("a.cover") { - Some(n) => n, - None => continue, - }; - let href = a_node.attr("abs:href").unwrap_or_default(); - let key = href - .trim_end_matches('/') - .split('/') - .next_back() - .unwrap_or_default() - .to_string(); - if key.is_empty() { - continue; - } - - let cover = item - .select_first("img.lazy") - .and_then(|img| img.attr("data-original")); - - let title = item - .select_first("p.comic__title") - .and_then(|p| p.select_first("a")) - .and_then(|a| a.text()) - .unwrap_or_default(); - - mangas.push(Manga { - key, - cover, - title, - ..Default::default() - }); - } - - let has_next_page = self.select_first("a.next").is_some(); - - Ok(MangaPageResult { - entries: mangas, - has_next_page, - }) - } -} - -impl MangaDetailPage for Document { - fn manga_details(&self, url: String, key: String) -> Result { - let cover = self - .select_first(".de-info__cover img") - .and_then(|img| img.attr("src")); - - let title = self - .select_first("p.comic-title.j-comic-title") - .and_then(|n| n.text()) - .unwrap_or_default(); - - let author_raw = self - .select_first(".comic-author .name a") - .and_then(|n| n.text()) - .unwrap_or_default(); - let authors: Vec = author_raw - .split('&') - .map(|a| a.trim().to_string()) - .filter(|a| !a.is_empty()) - .collect(); - - let description = self - .select_first(".comic-intro p.intro-total") - .and_then(|n| n.text()) - .map(|s| s.trim().to_string()); - - let tags: Vec = self - .select(".comic-status .text b a") - .map(|nodes| nodes.filter_map(|n| n.text()).collect()) - .unwrap_or_default(); - - let status_text = self - .select_first(".de-chapter__title span") - .and_then(|n| n.text()) - .unwrap_or_default(); - let status = if status_text.contains("完结") { - MangaStatus::Completed - } else { - MangaStatus::Ongoing - }; - - Ok(Manga { - key, - cover, - title, - authors: Some(authors), - description, - url: Some(url), - tags: if tags.is_empty() { None } else { Some(tags) }, - status, - content_rating: ContentRating::NSFW, - viewer: Viewer::Webtoon, - ..Default::default() - }) - } -} - -pub fn parse_chapter_list(doc: &Document) -> Result> { - let mut chapters: Vec = Vec::new(); - - let items = match doc.select("li.j-chapter-item") { - Some(v) => v, - None => return Ok(chapters), - }; - - for (index, item) in items.enumerate() { - let a_node = match item.select_first("a.j-chapter-link") { - Some(n) => n, - None => continue, - }; - let href = a_node.attr("href").unwrap_or_default(); - let key = href - .trim_end_matches('/') - .split('/') - .next_back() - .unwrap_or_default() - .to_string(); - if key.is_empty() { - continue; - } - let title = a_node - .text() - .map(|s| s.trim().to_string()) - .filter(|s| !s.is_empty()); - let chapter_number = (index + 1) as f32; - - chapters.push(Chapter { - key, - title, - chapter_number: Some(chapter_number), - url: if href.is_empty() { - None - } else { - Some(href.to_string()) - }, - ..Default::default() - }); - } - - chapters.reverse(); - Ok(chapters) -} - -impl TagsPage for Document { - fn tags_filter(&self) -> Result { - let links = self - .select(".cate-item a") - .ok_or_else(|| error!("Failed to select tag links"))?; - - let (mut options, mut ids): (Vec>, Vec>) = links - .filter_map(|a| { - let href = a.attr("href")?; - let tags_pos = href.find("/tags/")?; - let id = href[tags_pos + "/tags/".len()..] - .trim_end_matches('/') - .split('/') - .next()? - .to_string(); - if id.is_empty() { - return None; - } - let name = a.text()?.trim().to_string(); - if name.is_empty() { - return None; - } - Some((Cow::Owned(name), Cow::Owned(id))) - }) - .unzip(); - - options.insert(0, Cow::Borrowed("全部")); - ids.insert(0, Cow::Borrowed("")); - - Ok(SelectFilter { - id: "标签".into(), - title: Some("标签".into()), - is_genre: true, - options, - ids: Some(ids), - ..Default::default() - }) - } -} - -pub fn get_page_list(chapter_key: &str) -> Result> { - let url = format!("{}/chapter/{}", BASE_URL, chapter_key); - let html = Request::get(url)?.header("User-Agent", USER_AGENT).html()?; - let mut pages: Vec = Vec::new(); - - if let Some(imgs) = html.select("img.lazy-read") { - for img in imgs { - let img_url = img - .attr("data-original") - .map(|s| s.trim().to_string()) - .unwrap_or_default(); - if img_url.is_empty() { - continue; - } - pages.push(Page { - content: PageContent::url(img_url), - ..Default::default() - }); - } - } - - Ok(pages) -} diff --git a/sources/zh.se8/src/lib.rs b/sources/zh.se8/src/lib.rs deleted file mode 100644 index 91c2324ee..000000000 --- a/sources/zh.se8/src/lib.rs +++ /dev/null @@ -1,96 +0,0 @@ -#![no_std] - -mod html; -mod net; - -use aidoku::{ - Chapter, DeepLinkHandler, DeepLinkResult, DynamicFilters, Filter, FilterValue, - ImageRequestProvider, Manga, MangaPageResult, Page, PageContext, Result, Source, - alloc::{String, Vec, string::ToString as _}, - imports::net::Request, - prelude::*, -}; -use html::{MangaDetailPage as _, MangaListPage as _, TagsPage as _, parse_chapter_list}; -use net::Url; - -pub const BASE_URL: &str = "https://se8.us/index.php"; -pub const USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"; - -struct Se8; - -impl Source for Se8 { - fn new() -> Self { - Self - } - - fn get_search_manga_list( - &self, - query: Option, - page: i32, - filters: Vec, - ) -> Result { - let url = Url::from_query_or_filters(query.as_deref(), page, &filters)?; - let html = url.request()?.html()?; - html.manga_page_result() - } - - fn get_manga_update( - &self, - mut manga: Manga, - needs_details: bool, - needs_chapters: bool, - ) -> Result { - let detail_url = format!("{}/comic/{}", BASE_URL, manga.key); - - let html = Request::get(&detail_url)? - .header("User-Agent", USER_AGENT) - .html()?; - - if needs_details { - manga = html.manga_details(detail_url, manga.key.clone())?; - } - - if needs_chapters { - manga.chapters = Some(parse_chapter_list(&html)?); - } - - Ok(manga) - } - - fn get_page_list(&self, _manga: Manga, chapter: Chapter) -> Result> { - html::get_page_list(&chapter.key) - } -} - -impl ImageRequestProvider for Se8 { - fn get_image_request(&self, url: String, _context: Option) -> Result { - Ok(Request::get(url)?.header("User-Agent", USER_AGENT)) - } -} - -impl DeepLinkHandler for Se8 { - fn handle_deep_link(&self, url: String) -> Result> { - if url.contains("/comic/") { - let key = url - .trim_end_matches('/') - .split('/') - .next_back() - .unwrap_or_default() - .to_string(); - if !key.is_empty() { - return Ok(Some(DeepLinkResult::Manga { key })); - } - } - - Ok(None) - } -} - -impl DynamicFilters for Se8 { - fn get_dynamic_filters(&self) -> Result> { - let tags = Url::TagsPage.request()?.html()?.tags_filter()?.into(); - Ok([tags].into()) - } -} - -register_source!(Se8, ImageRequestProvider, DeepLinkHandler, DynamicFilters); diff --git a/sources/zh.se8/src/net/mod.rs b/sources/zh.se8/src/net/mod.rs deleted file mode 100644 index 68ba0a50a..000000000 --- a/sources/zh.se8/src/net/mod.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::{BASE_URL, USER_AGENT, html::TagsPage as _}; -use aidoku::{ - FilterValue, Result, - alloc::{String, string::ToString as _}, - helpers::uri::encode_uri, - imports::net::Request, - prelude::{error, format}, -}; -use core::fmt::{Display, Formatter, Result as FmtResult}; - -const FILTER_ORDER: &[&str] = &["hits", "addtime"]; - -#[derive(Clone)] -pub enum Url { - Search { - query: String, - page: i32, - }, - Filter { - tag: String, - finish: String, - order: String, - page: i32, - }, - TagsPage, -} - -impl Url { - pub fn from_query_or_filters( - query: Option<&str>, - page: i32, - filters: &[FilterValue], - ) -> Result { - if let Some(q) = query { - return Ok(Self::Search { - query: encode_uri(q), - page, - }); - } - - let mut tag = String::new(); - let mut finish = String::new(); - let mut order = String::from("hits"); - - for filter in filters { - match filter { - FilterValue::Text { value, .. } => { - return Ok(Self::Search { - query: encode_uri(value), - page, - }); - } - FilterValue::Select { id, value } => match id.as_str() { - "标签" => tag = value.to_string(), - "进度" => finish = value.to_string(), - "genre" => { - let tags = Self::TagsPage.request()?.html()?.tags_filter()?; - let tag_id = tags - .options - .iter() - .position(|option| option == value) - .and_then(|index| tags.ids?.into_iter().nth(index)) - .ok_or_else(|| error!("Tag ID not found for option: `{value}`"))?; - tag = tag_id.into(); - } - _ => continue, - }, - FilterValue::Sort { - id, - index, - ascending: _, - } => { - if id == "排序" - && let Some(o) = FILTER_ORDER.get(*index as usize) - { - order = o.to_string(); - } - } - _ => continue, - } - } - - Ok(Self::Filter { - tag, - finish, - order, - page, - }) - } - - pub fn request(&self) -> Result { - let url = self.to_string(); - Ok(Request::get(url)?.header("User-Agent", USER_AGENT)) - } -} - -impl Display for Url { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - match self { - Url::Search { query, page } => { - write!(f, "{}/search/{}/{}", BASE_URL, query, page) - } - Url::Filter { - tag, - finish, - order, - page, - } => { - let mut url = format!("{}/category", BASE_URL); - if !tag.is_empty() { - url.push_str(&format!("/tags/{}", tag)); - } - if !finish.is_empty() { - url.push_str(&format!("/finish/{}", finish)); - } - url.push_str(&format!("/order/{}/page/{}", order, page)); - write!(f, "{}", url) - } - Url::TagsPage => { - write!(f, "{}/category", BASE_URL) - } - } - } -}