refactor(pixiv): keep the artwork type as the API's string

TypeModel's Illust and Manga variants existed only so serde would accept
those values -- both call sites ask a single question (is this ugoira?), so
the field is a String and the check is a comparison. Same for a type the API
adds later: it no longer fails the whole parse.
This commit is contained in:
2026-09-21 17:19:26 +08:00
parent 7dd0e8f2d6
commit 7a61077d80
3 changed files with 8 additions and 15 deletions
+2 -2
View File
@@ -4,7 +4,7 @@
//! `app-api.pixiv.net`, deserialized with the kept `model.rs` types. //! `app-api.pixiv.net`, deserialized with the kept `model.rs` types.
use super::interface::Illustration; use super::interface::Illustration;
use super::model::{IllustrationModel, TypeModel, UgoiraMetadataModel}; use super::model::{IllustrationModel, UgoiraMetadataModel};
use crate::media::Media; use crate::media::Media;
use crate::site::FetchError; use crate::site::FetchError;
use std::env; use std::env;
@@ -139,7 +139,7 @@ impl PixivAPI {
pub async fn fetch(&self, illust_id: u64) -> Result<Illustration, FetchError> { pub async fn fetch(&self, illust_id: u64) -> Result<Illustration, FetchError> {
let model = self.illust_detail(illust_id).await?; let model = self.illust_detail(illust_id).await?;
let mut illustration = Illustration::from_model(&model); let mut illustration = Illustration::from_model(&model);
if matches!(&model.r#type, TypeModel::Ugoira) { if model.r#type == "ugoira" {
// Real ugoira support: download the frame zip and encode an MP4. // Real ugoira support: download the frame zip and encode an MP4.
// Without ffmpeg the post stays unsupported (empty media, like // Without ffmpeg the post stays unsupported (empty media, like
// Python) — but a *failed* download/encode is reported instead: // Python) — but a *failed* download/encode is reported instead:
+2 -2
View File
@@ -1,4 +1,4 @@
use super::model::{IllustrationModel, TypeModel}; use super::model::IllustrationModel;
use crate::media::Media; use crate::media::Media;
use crate::site::{FetchError, Fetched, PixivError, Site, SiteFuture}; use crate::site::{FetchError, Fetched, PixivError, Site, SiteFuture};
use html_escape::{encode_double_quoted_attribute, encode_text}; use html_escape::{encode_double_quoted_attribute, encode_text};
@@ -225,7 +225,7 @@ impl Illustration {
tags.insert(0, "AI".to_string()); tags.insert(0, "AI".to_string());
} }
let mut media = vec![]; let mut media = vec![];
if matches!(&model.r#type, TypeModel::Ugoira) { if model.r#type == "ugoira" {
// No static images for ugoira; the fetch path encodes an MP4 via // No static images for ugoira; the fetch path encodes an MP4 via
// ffmpeg and appends it as a Video item (api.rs). This fallback // ffmpeg and appends it as a Video item (api.rs). This fallback
// keeps media empty when encoding fails or ffmpeg is missing. // keeps media empty when encoding fails or ffmpeg is missing.
+4 -11
View File
@@ -10,7 +10,10 @@ pub struct IllustrationModel {
/// works (`<br />`, `<a href>`, sometimes `<p>`), empty for many. /// works (`<br />`, `<a href>`, sometimes `<p>`), empty for many.
#[serde(default)] #[serde(default)]
pub caption: String, pub caption: String,
pub r#type: TypeModel, /// `"illust"` / `"manga"` / `"ugoira"`; only ugoira changes how the
/// artwork is fetched (a zip of frames to encode), so the rest is kept as
/// the string the API sent rather than as variants nothing matches.
pub r#type: String,
pub image_urls: ImageUrlsModel, pub image_urls: ImageUrlsModel,
pub user: UserInfoModel, pub user: UserInfoModel,
pub tags: Vec<IllustrationTagModel>, pub tags: Vec<IllustrationTagModel>,
@@ -22,16 +25,6 @@ pub struct IllustrationModel {
pub meta_pages: Vec<MetaPageModel>, pub meta_pages: Vec<MetaPageModel>,
} }
#[derive(Deserialize, Debug)]
pub enum TypeModel {
#[serde(rename = "illust")]
Illust,
#[serde(rename = "manga")]
Manga,
#[serde(rename = "ugoira")]
Ugoira,
}
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct UserInfoModel { pub struct UserInfoModel {
pub id: u64, pub id: u64,