v0.4.7 user inventory + git fix #8
@ -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<String>,
|
||||
}
|
||||
#[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<String>,//""
|
||||
pub searchDebugInfo:Option<String>,//null
|
||||
@ -135,19 +147,19 @@ pub struct InventoryPageResponse{
|
||||
pub imageSearchStatus:Option<String>,//null
|
||||
pub previousPageCursor:Option<String>,
|
||||
pub nextPageCursor:Option<String>,
|
||||
pub data:Vec<InventoryItem>,
|
||||
pub data:Vec<CreationsItem>,
|
||||
}
|
||||
#[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<R:std::io::Read>{
|
||||
@ -305,8 +317,9 @@ impl CookieContext{
|
||||
.error_for_status().map_err(AssetVersionsPageError::Reqwest)?
|
||||
.json::<AssetVersionsPageResponse>().await.map_err(AssetVersionsPageError::Reqwest)
|
||||
}
|
||||
pub async fn get_inventory_page(&self,config:InventoryPageRequest)->Result<InventoryPageResponse,InventoryPageError>{
|
||||
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<CreationsPageResponse,CreationsPageError>{
|
||||
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::<InventoryPageResponse>().await.map_err(InventoryPageError::Reqwest)
|
||||
self.get(url).await.map_err(CreationsPageError::Reqwest)?
|
||||
.error_for_status().map_err(CreationsPageError::Reqwest)?
|
||||
.json::<CreationsPageResponse>().await.map_err(CreationsPageError::Reqwest)
|
||||
}
|
||||
}
|
||||
|
44
src/main.rs
44
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<AssetID>,
|
||||
}
|
||||
/// 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<String>,
|
||||
#[arg(long,group="cookie",required=true)]
|
||||
@ -83,8 +83,10 @@ struct DownloadGroupInventoryJsonSubcommand{
|
||||
cookie_file:Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
output_folder:Option<PathBuf>,
|
||||
#[arg(long)]
|
||||
group:u64,
|
||||
#[arg(long,group="owner",required=true)]
|
||||
group_id:Option<u64>,
|
||||
#[arg(long,group="owner",required=true)]
|
||||
user_id:Option<u64>,
|
||||
}
|
||||
/// 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<String>,environment:Option<String>,fil
|
||||
};
|
||||
Ok(ApiKey::new(api_key))
|
||||
}
|
||||
fn owner_from_args(user_id:Option<u64>,group_id:Option<u64>)->AResult<rbx_asset::cookie::Owner>{
|
||||
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<Vec<InventoryItem>>{
|
||||
let mut cursor:Option<String>=None;
|
||||
async fn get_creations_pages(context:&CookieContext,owner:rbx_asset::cookie::Owner)->AResult<Vec<CreationsItem>>{
|
||||
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");
|
||||
|
Loading…
Reference in New Issue
Block a user