use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SyncContext { pub region: String, #[serde(default)] pub export: RegionExportConfig, #[serde(default)] pub asset_version: Option, #[serde(default)] pub asset_hash: Option, #[serde(default)] pub app_version: Option, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(default)] pub struct RegionFiltersConfig { #[serde(default)] pub start_app: Vec, #[serde(default)] pub on_demand: Vec, #[serde(default)] pub skip: Vec, #[serde(default)] pub file_ext: Vec, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(default)] pub struct RegionExportConfig { #[serde(default)] pub usm: UsmExportConfig, #[serde(default)] pub acb: AcbExportConfig, #[serde(default)] pub hca: HcaExportConfig, #[serde(default)] pub images: ImageExportConfig, #[serde(default)] pub video: VideoExportConfig, #[serde(default)] pub audio: AudioExportConfig, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] pub struct UsmExportConfig { pub export: bool, pub decode: bool, } impl Default for UsmExportConfig { fn default() -> Self { Self { export: true, decode: true, } } } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] pub struct AcbExportConfig { pub export: bool, pub decode: bool, } impl Default for AcbExportConfig { fn default() -> Self { Self { export: true, decode: true, } } } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] pub struct HcaExportConfig { pub decode: bool, } impl Default for HcaExportConfig { fn default() -> Self { Self { decode: true } } } #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(default)] pub struct ImageExportConfig { pub convert_to_webp: bool, pub remove_png: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] pub struct VideoExportConfig { pub convert_to_mp4: bool, pub direct_usm_to_mp4_with_ffmpeg: bool, pub remove_m2v: bool, } impl Default for VideoExportConfig { fn default() -> Self { Self { convert_to_mp4: true, direct_usm_to_mp4_with_ffmpeg: false, remove_m2v: true, } } } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] pub struct AudioExportConfig { pub convert_to_mp3: bool, pub convert_to_flac: bool, pub remove_wav: bool, } impl Default for AudioExportConfig { fn default() -> Self { Self { convert_to_mp3: true, convert_to_flac: false, remove_wav: true, } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DownloadTask { pub download_path: String, pub bundle_path: String, pub bundle_hash: String, pub category: AssetCategory, } #[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub enum AssetCategory { StartApp, OnDemand, Other(String), } impl<'de> Deserialize<'de> for AssetCategory { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { // Treat nil/null as Other("") — matches Go's zero-value coercion. let raw = Option::::deserialize(deserializer)?.unwrap_or_default(); Ok(match raw.as_str() { "StartApp" | "startApp" => Self::StartApp, "OnDemand" | "onDemand" => Self::OnDemand, other => Self::Other(other.to_string()), }) } }