diff --git a/src/main.rs b/src/main.rs index f924f0b..a2b29fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ struct Cli{ enum Commands{ DownloadHistory(DownloadHistorySubcommand), Download(DownloadSubcommand), + DownloadGroupInventoryJson(DownloadGroupInventoryJsonSubcommand), Create(CreateSubcommand), Upload(UploadSubcommand), Compile(CompileSubcommand), @@ -59,6 +60,17 @@ struct DownloadSubcommand{ asset_ids:Vec, } #[derive(Args)] +struct DownloadGroupInventoryJsonSubcommand{ + #[arg(long)] + cookie_type:CookieType, + #[arg(long)] + cookie:String, + #[arg(long)] + output_folder:Option, + #[arg(long)] + group:u64, +} +#[derive(Args)] struct CreateSubcommand{ #[arg(long)] cookie_type:CookieType, @@ -187,6 +199,26 @@ struct AssetVersion{ isPublished:bool, } +#[derive(serde::Deserialize)] +#[allow(nonstandard_style,dead_code)] +struct InventoryPage{ + totalResults:u64,//up to 50 + filteredKeyword:Option,//"" + searchDebugInfo:Option,//null + spellCheckerResult:Option,//null + queryFacets:Option,//null + imageSearchStatus:Option,//null + previousPageCursor:Option, + nextPageCursor:Option, + data:Vec, +} +#[derive(serde::Deserialize,serde::Serialize)] +#[allow(nonstandard_style,dead_code)] +struct InventoryItem{ + id:u64, + name:String, +} + #[tokio::main] async fn main()->AResult<()>{ let cli=Cli::parse(); @@ -210,6 +242,11 @@ async fn main()->AResult<()>{ }).collect() ).await }, + Commands::DownloadGroupInventoryJson(subcommand)=>download_group_inventory_json( + Cookie::from_type(subcommand.cookie_type,subcommand.cookie).await?.0, + subcommand.group, + subcommand.output_folder.unwrap_or_else(||std::env::current_dir().unwrap()), + ).await, Commands::Create(subcommand)=>create( Cookie::from_type(subcommand.cookie_type,subcommand.cookie).await?.0, subcommand.group, @@ -426,6 +463,47 @@ async fn download_list(cookie:String,asset_id_file_map:AssetIDFileMap)->AResult< }).await; Ok(()) } +async fn download_inventory_page(client:&reqwest::Client,cookie:&str,group:u64,cursor:Option)->AResult{ + let mut url=reqwest::Url::parse(format!("https://apis.roblox.com/toolbox-service/v1/creations/group/{}/10?limit=50",group).as_str())?; + //url borrow scope + { + let mut query=url.query_pairs_mut();//borrow here + match cursor.as_deref(){ + Some(next_page)=>{query.append_pair("cursor",next_page);} + None=>(), + } + } + println!("page url={}",url); + let resp=client.get(url) + .header("Cookie",cookie) + .send().await?; + Ok(resp.json::().await?) +} + +async fn get_inventory_pages(client:&reqwest::Client,cookie:&str,group:u64)->AResult>{ + let mut cursor:Option=None; + let mut asset_list=Vec::new(); + loop{ + let mut page=download_inventory_page(client,cookie,group,cursor).await?; + asset_list.append(&mut page.data); + if page.nextPageCursor.is_none(){ + break; + } + cursor=page.nextPageCursor; + } + Ok(asset_list) +} + +async fn download_group_inventory_json(cookie:String,group:u64,output_folder:PathBuf)->AResult<()>{ + let client=reqwest::Client::new(); + let item_list=get_inventory_pages(&client,cookie.as_str(),group).await?; + + let mut path=output_folder.clone(); + path.set_file_name("versions.json"); + tokio::fs::write(path,serde_json::to_string(&item_list)?).await?; + + Ok(()) +} async fn download_page(client:&reqwest::Client,cookie:&str,asset_id:AssetID,cursor:Option)->AResult{ let mut url=reqwest::Url::parse(format!("https://develop.roblox.com/v1/assets/{}/saved-versions",asset_id).as_str())?;