diff --git a/assets-updater/src/core/asset_execution.rs b/assets-updater/src/core/asset_execution.rs index 00b5a28..d1887d8 100644 --- a/assets-updater/src/core/asset_execution.rs +++ b/assets-updater/src/core/asset_execution.rs @@ -157,7 +157,7 @@ impl AssetExecutionContext { &self, task: &DownloadTask, app_config: &AppConfig, - ) -> Result { + ) -> Result<(PathBuf, /*single file*/ bool), AssetExecutionError> { let ctx = self.clone(); ctx.download_and_export_bundle(app_config, task).await } @@ -400,7 +400,7 @@ impl AssetExecutionContext { &self, app_config: &AppConfig, task: &DownloadTask, - ) -> Result { + ) -> Result<(PathBuf, bool), AssetExecutionError> { let bundle_url = self.render_bundle_url(task)?; let body = self.get_with_retry(&bundle_url).await?; let deobfuscated = deobfuscate(&body); diff --git a/assets-updater/src/core/export_pipeline.rs b/assets-updater/src/core/export_pipeline.rs index e3c1a0d..aa332d7 100644 --- a/assets-updater/src/core/export_pipeline.rs +++ b/assets-updater/src/core/export_pipeline.rs @@ -61,13 +61,13 @@ pub async fn extract_unity_asset_bundle( asset_bundle_file: &Path, export_path: &str, category: &str, -) -> Result { +) -> Result<(PathBuf, bool), ExportPipelineError> { let output_dir = std::env::temp_dir() .join("sekai-updater") .join("extract") .join(&sync_context.region); let Some(asset_studio_cli_path) = app_config.tools.asset_studio_cli_path.as_deref() else { - return Ok(asset_bundle_file.parent().unwrap().to_path_buf()); + return Ok((asset_bundle_file.parent().unwrap().to_path_buf(), true)); }; let exclude_path_prefix = if sync_context.export.by_category { @@ -125,8 +125,11 @@ pub async fn extract_unity_asset_bundle( ) .await?; + let mut count = 0; + walk(&actual_export_path, &mut |_| count += 1)?; + post_process_exported_files(app_config, sync_context, region, &actual_export_path).await?; - Ok(actual_export_path) + Ok((actual_export_path, count <= 1)) } pub async fn post_process_exported_files( diff --git a/common/src/stream.rs b/common/src/stream.rs index 03e56ee..735725c 100644 --- a/common/src/stream.rs +++ b/common/src/stream.rs @@ -4,24 +4,21 @@ use std::path::Path; use tokio::fs::File; use tokio::io::{AsyncRead, AsyncReadExt}; -pub async fn server_send_files>( +pub async fn server_send_files, S: AsRef>( mut send_stream: SendStream, - base: P, - files: &[P], + files: &[(P, S)], ) -> Result<(), Box> { let mut header = BytesMut::with_capacity(4); header.put_u32(files.len() as u32); send_stream.send_data(header.freeze(), false)?; for (i, path_ref) in files.iter().enumerate() { - let path = path_ref.as_ref(); + let path = path_ref.0.as_ref(); let mut file = File::open(path).await?; let metadata = file.metadata().await?; - let file_name = path - .strip_prefix(base.as_ref()) - .map(|n| n.to_string_lossy().to_string())?; - let name_bytes = file_name.as_bytes(); + let file_name = &path_ref.1; + let name_bytes = file_name.as_ref().as_bytes(); let file_size = metadata.len(); let mut meta_buf = BytesMut::with_capacity(2 + name_bytes.len() + 8); diff --git a/common/src/updater.rs b/common/src/updater.rs index 3184163..80f9ea2 100644 --- a/common/src/updater.rs +++ b/common/src/updater.rs @@ -11,10 +11,10 @@ pub struct SyncContext { pub asset_version: Option, #[serde(default)] pub asset_hash: Option, + #[serde(default)] + pub exact_single_file_bundle: bool, } - - #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(default)] pub struct RegionFiltersConfig { diff --git a/sekai-unpacker-client.yaml b/sekai-unpacker-client.yaml index f1381ea..bc8af83 100644 --- a/sekai-unpacker-client.yaml +++ b/sekai-unpacker-client.yaml @@ -13,11 +13,14 @@ profiles: cn: region: cn # interval: 3 # seconds + concurrent: 50 filters: start_app: - "thumbnail" + - "stamp" on_demand: - "thumbnail" + - "stamp" skip: [ ] file_ext: [ ] export: @@ -41,6 +44,7 @@ profiles: convert_to_mp3: false convert_to_flac: false remove_wav: false +# exact_single_file_bundle: true path: "./data/cn" jp: region: jp @@ -48,8 +52,10 @@ profiles: filters: start_app: - "thumbnail" + - "stamp" on_demand: - "thumbnail" + - "stamp" skip: [ ] file_ext: [ ] asset_version: 6.4.0.30 @@ -75,4 +81,5 @@ profiles: convert_to_mp3: false convert_to_flac: false remove_wav: false +# exact_single_file_bundle: true path: "./data/jp" \ No newline at end of file diff --git a/server/src/router/download.rs b/server/src/router/download.rs index b503839..eb56465 100644 --- a/server/src/router/download.rs +++ b/server/src/router/download.rs @@ -41,7 +41,12 @@ pub async fn download( send_error(send_response, error.into()); return Ok(()); } - let dir = dir.unwrap(); + let (dir, single_file) = dir.unwrap(); + + let dir_base = std::env::temp_dir() + .join("sekai-updater") + .join("extract") + .join(&context.sync_context.region); let files = if !dir.is_dir() { if context.sync_context.filters.file_ext.is_empty() @@ -53,7 +58,13 @@ pub async fn download( .contains(&t.to_str().unwrap().to_lowercase()) }) { - vec![dir.clone()] + vec![( + dir.clone(), + dir.strip_prefix(&dir_base) + .unwrap() + .to_string_lossy() + .to_string(), + )] } else { vec![] } @@ -67,7 +78,22 @@ pub async fn download( send_error(send_response, error.into()); return Ok(()); } - files.unwrap() + let base = dir.strip_prefix(&dir_base).unwrap(); + let base_str = if single_file { + base.parent().unwrap().to_str().unwrap() + } else { + base.to_str().unwrap() + }; + files + .unwrap() + .iter() + .map(|p| { + let raw = p.clone(); + let name = p.strip_prefix(&dir).unwrap(); + let path = format!("{}/{}", base_str, name.to_string_lossy()); + (raw, path) + }) + .collect::>() }; let response = Response::builder() @@ -76,13 +102,8 @@ pub async fn download( .body(()) .unwrap(); - let dir_base = std::env::temp_dir() - .join("sekai-updater") - .join("extract") - .join(&context.sync_context.region); - if let Ok(send_stream) = send_response.send_response(response, false) { - let _ = server_send_files(send_stream, dir_base, &files).await; + let _ = server_send_files(send_stream, &files).await; } let _ = std::fs::remove_file(dir);