diff --git a/rbx_asset/src/cookie.rs b/rbx_asset/src/cookie.rs index 3557c7d..b58c684 100644 --- a/rbx_asset/src/cookie.rs +++ b/rbx_asset/src/cookie.rs @@ -114,19 +114,31 @@ impl std::fmt::Display for AssetVersionsPageError{ } impl std::error::Error for AssetVersionsPageError{} -pub struct InventoryPageRequest{ - pub group:u64, +pub enum Owner{ + User(u64), + Group(u64), +} +impl Owner{ + fn get_url_info(&self)->(&str,u64){ + match self{ + &Owner::User(id)=>("user",id), + &Owner::Group(id)=>("group",id), + } + } +} +pub struct CreationsPageRequest{ + pub owner:Owner, pub cursor:Option, } #[derive(serde::Deserialize,serde::Serialize)] #[allow(nonstandard_style,dead_code)] -pub struct InventoryItem{ +pub struct CreationsItem{ pub id:u64, pub name:String, } #[derive(serde::Deserialize,serde::Serialize)] #[allow(nonstandard_style,dead_code)] -pub struct InventoryPageResponse{ +pub struct CreationsPageResponse{ pub totalResults:u64,//up to 50 pub filteredKeyword:Option,//"" pub searchDebugInfo:Option,//null @@ -135,19 +147,19 @@ pub struct InventoryPageResponse{ pub imageSearchStatus:Option,//null pub previousPageCursor:Option, pub nextPageCursor:Option, - pub data:Vec, + pub data:Vec, } #[derive(Debug)] -pub enum InventoryPageError{ +pub enum CreationsPageError{ ParseError(url::ParseError), Reqwest(reqwest::Error), } -impl std::fmt::Display for InventoryPageError{ +impl std::fmt::Display for CreationsPageError{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f,"{self:?}") } } -impl std::error::Error for InventoryPageError{} +impl std::error::Error for CreationsPageError{} //idk how to do this better enum ReaderType{ @@ -305,8 +317,9 @@ impl CookieContext{ .error_for_status().map_err(AssetVersionsPageError::Reqwest)? .json::().await.map_err(AssetVersionsPageError::Reqwest) } - pub async fn get_inventory_page(&self,config:InventoryPageRequest)->Result{ - let mut url=reqwest::Url::parse(format!("https://apis.roblox.com/toolbox-service/v1/creations/group/{}/10?limit=50",config.group).as_str()).map_err(InventoryPageError::ParseError)?; + pub async fn get_creations_page(&self,config:&CreationsPageRequest)->Result{ + let (owner,id)=config.owner.get_url_info(); + let mut url=reqwest::Url::parse(format!("https://apis.roblox.com/toolbox-service/v1/creations/{}/{}/10?limit=50",owner,id).as_str()).map_err(CreationsPageError::ParseError)?; //url borrow scope { let mut query=url.query_pairs_mut();//borrow here @@ -315,8 +328,8 @@ impl CookieContext{ } } - self.get(url).await.map_err(InventoryPageError::Reqwest)? - .error_for_status().map_err(InventoryPageError::Reqwest)? - .json::().await.map_err(InventoryPageError::Reqwest) + self.get(url).await.map_err(CreationsPageError::Reqwest)? + .error_for_status().map_err(CreationsPageError::Reqwest)? + .json::().await.map_err(CreationsPageError::Reqwest) } } diff --git a/src/main.rs b/src/main.rs index a525d7a..418a9a4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use clap::{Args,Parser,Subcommand}; use anyhow::{anyhow,Result as AResult}; use futures::StreamExt; use rbx_asset::cloud::{ApiKey,CloudContext}; -use rbx_asset::cookie::{Cookie,CookieContext,AssetVersion,InventoryItem}; +use rbx_asset::cookie::{Cookie,CookieContext,AssetVersion,CreationsItem}; type AssetID=u64; type AssetIDFileMap=Vec<(AssetID,PathBuf)>; @@ -23,7 +23,7 @@ enum Commands{ DownloadHistory(DownloadHistorySubcommand), Download(DownloadSubcommand), DownloadDecompile(DownloadDecompileSubcommand), - DownloadGroupInventoryJson(DownloadGroupInventoryJsonSubcommand), + DownloadCreationsJson(DownloadCreationsJsonSubcommand), CreateAsset(CreateAssetSubcommand), CreateAssetMedia(CreateAssetMediaSubcommand), CreateAssetMedias(CreateAssetMediasSubcommand), @@ -72,9 +72,9 @@ struct DownloadSubcommand{ #[arg(required=true)] asset_ids:Vec, } -/// Download the list of asset ids (not the assets themselves) in a group inventory. The output is written to `output_folder/versions.json` +/// Download the list of asset ids (not the assets themselves) created by a group or user. The output is written to `output_folder/versions.json` #[derive(Args)] -struct DownloadGroupInventoryJsonSubcommand{ +struct DownloadCreationsJsonSubcommand{ #[arg(long,group="cookie",required=true)] cookie_literal:Option, #[arg(long,group="cookie",required=true)] @@ -83,8 +83,10 @@ struct DownloadGroupInventoryJsonSubcommand{ cookie_file:Option, #[arg(long)] output_folder:Option, - #[arg(long)] - group:u64, + #[arg(long,group="owner",required=true)] + group_id:Option, + #[arg(long,group="owner",required=true)] + user_id:Option, } /// Upload a (.rbxm, .rbxmx) model file, creating a new asset. Can be any type of model, including modulescripts. #[derive(Args)] @@ -427,13 +429,16 @@ async fn main()->AResult<()>{ write_scripts:subcommand.write_scripts.unwrap_or(true), }).await }, - Commands::DownloadGroupInventoryJson(subcommand)=>download_group_inventory_json( + Commands::DownloadCreationsJson(subcommand)=>download_creations_json( cookie_from_args( subcommand.cookie_literal, subcommand.cookie_envvar, subcommand.cookie_file, ).await?, - subcommand.group, + owner_from_args( + subcommand.user_id, + subcommand.group_id, + )?, subcommand.output_folder.unwrap_or_else(||std::env::current_dir().unwrap()), ).await, Commands::CreateAsset(subcommand)=>create_asset(CreateAssetConfig{ @@ -603,6 +608,14 @@ async fn api_key_from_args(literal:Option,environment:Option,fil }; Ok(ApiKey::new(api_key)) } +fn owner_from_args(user_id:Option,group_id:Option)->AResult{ + let owner=match (user_id,group_id){ + (Some(id),None)=>rbx_asset::cookie::Owner::User(id), + (None,Some(id))=>rbx_asset::cookie::Owner::Group(id), + _=>Err(anyhow::Error::msg("Illegal owner argument pair"))?, + }; + Ok(owner) +} struct CreateAssetConfig{ cookie:Cookie, @@ -890,23 +903,26 @@ async fn download_list(cookie:Cookie,asset_id_file_map:AssetIDFileMap)->AResult< Ok(()) } -async fn get_inventory_pages(context:&CookieContext,group:u64)->AResult>{ - let mut cursor:Option=None; +async fn get_creations_pages(context:&CookieContext,owner:rbx_asset::cookie::Owner)->AResult>{ + let mut config=rbx_asset::cookie::CreationsPageRequest{ + owner, + cursor:None, + }; let mut asset_list=Vec::new(); loop{ - let mut page=context.get_inventory_page(rbx_asset::cookie::InventoryPageRequest{group,cursor}).await?; + let mut page=context.get_creations_page(&config).await?; asset_list.append(&mut page.data); if page.nextPageCursor.is_none(){ break; } - cursor=page.nextPageCursor; + config.cursor=page.nextPageCursor; } Ok(asset_list) } -async fn download_group_inventory_json(cookie:Cookie,group:u64,output_folder:PathBuf)->AResult<()>{ +async fn download_creations_json(cookie:Cookie,owner:rbx_asset::cookie::Owner,output_folder:PathBuf)->AResult<()>{ let context=CookieContext::new(cookie); - let item_list=get_inventory_pages(&context,group).await?; + let item_list=get_creations_pages(&context,owner).await?; let mut path=output_folder.clone(); path.set_file_name("versions.json");