forked from StrafesNET/asset-tool
wip
This commit is contained in:
parent
b1b5602d66
commit
6365a5fad0
@ -79,7 +79,7 @@ impl std::fmt::Display for DownloadError{
|
|||||||
}
|
}
|
||||||
impl std::error::Error for DownloadError{}
|
impl std::error::Error for DownloadError{}
|
||||||
|
|
||||||
pub struct HistoryPageRequest{
|
pub struct AssetVersionsPageRequest{
|
||||||
pub asset_id:u64,
|
pub asset_id:u64,
|
||||||
pub cursor:Option<String>,
|
pub cursor:Option<String>,
|
||||||
}
|
}
|
||||||
@ -97,22 +97,22 @@ pub struct AssetVersion{
|
|||||||
}
|
}
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
#[allow(nonstandard_style,dead_code)]
|
#[allow(nonstandard_style,dead_code)]
|
||||||
pub struct HistoryPageResponse{
|
pub struct AssetVersionsPageResponse{
|
||||||
pub previousPageCursor:Option<String>,
|
pub previousPageCursor:Option<String>,
|
||||||
pub nextPageCursor:Option<String>,
|
pub nextPageCursor:Option<String>,
|
||||||
pub data:Vec<AssetVersion>,
|
pub data:Vec<AssetVersion>,
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum HistoryPageError{
|
pub enum AssetVersionsPageError{
|
||||||
ParseError(url::ParseError),
|
ParseError(url::ParseError),
|
||||||
Reqwest(reqwest::Error),
|
Reqwest(reqwest::Error),
|
||||||
}
|
}
|
||||||
impl std::fmt::Display for HistoryPageError{
|
impl std::fmt::Display for AssetVersionsPageError{
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f,"{self:?}")
|
write!(f,"{self:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl std::error::Error for HistoryPageError{}
|
impl std::error::Error for AssetVersionsPageError{}
|
||||||
|
|
||||||
pub struct InventoryPageRequest{
|
pub struct InventoryPageRequest{
|
||||||
pub group:u64,
|
pub group:u64,
|
||||||
@ -289,8 +289,8 @@ impl CookieContext{
|
|||||||
Err(e)=>Err(e),
|
Err(e)=>Err(e),
|
||||||
}.map_err(DownloadError::IO)
|
}.map_err(DownloadError::IO)
|
||||||
}
|
}
|
||||||
pub async fn history_page(&self,config:HistoryPageRequest)->Result<HistoryPageResponse,HistoryPageError>{
|
pub async fn get_asset_versions_page(&self,config:AssetVersionsPageRequest)->Result<AssetVersionsPageResponse,AssetVersionsPageError>{
|
||||||
let mut url=reqwest::Url::parse(format!("https://develop.roblox.com/v1/assets/{}/saved-versions",config.asset_id).as_str()).map_err(HistoryPageError::ParseError)?;
|
let mut url=reqwest::Url::parse(format!("https://develop.roblox.com/v1/assets/{}/saved-versions",config.asset_id).as_str()).map_err(AssetVersionsPageError::ParseError)?;
|
||||||
//url borrow scope
|
//url borrow scope
|
||||||
{
|
{
|
||||||
let mut query=url.query_pairs_mut();//borrow here
|
let mut query=url.query_pairs_mut();//borrow here
|
||||||
@ -302,8 +302,8 @@ impl CookieContext{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.get(url).await.map_err(HistoryPageError::Reqwest)?
|
Ok(self.get(url).await.map_err(AssetVersionsPageError::Reqwest)?
|
||||||
.json::<HistoryPageResponse>().await.map_err(HistoryPageError::Reqwest)?)
|
.json::<AssetVersionsPageResponse>().await.map_err(AssetVersionsPageError::Reqwest)?)
|
||||||
}
|
}
|
||||||
pub async fn inventory_page(&self,config:InventoryPageRequest)->Result<InventoryPageResponse,InventoryPageError>{
|
pub async fn 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)?;
|
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)?;
|
||||||
|
66
src/main.rs
66
src/main.rs
@ -2,7 +2,8 @@ use std::{io::Read,path::PathBuf};
|
|||||||
use clap::{Args,Parser,Subcommand};
|
use clap::{Args,Parser,Subcommand};
|
||||||
use anyhow::Result as AResult;
|
use anyhow::Result as AResult;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use rbx_asset::cloud::{ApiKey,AssetVersion,CloudContext,InventoryItem};
|
use rbx_asset::cloud::{ApiKey,CloudContext,InventoryItem};
|
||||||
|
use rbx_asset::cookie::{Cookie,CookieContext,AssetVersion};
|
||||||
|
|
||||||
type AssetID=u64;
|
type AssetID=u64;
|
||||||
type AssetIDFileMap=Vec<(AssetID,PathBuf)>;
|
type AssetIDFileMap=Vec<(AssetID,PathBuf)>;
|
||||||
@ -38,12 +39,12 @@ enum Commands{
|
|||||||
struct DownloadHistorySubcommand{
|
struct DownloadHistorySubcommand{
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
asset_id:AssetID,
|
asset_id:AssetID,
|
||||||
#[arg(long,group="api_key",required=true)]
|
#[arg(long,group="cookie",required=true)]
|
||||||
api_key_literal:Option<String>,
|
cookie_literal:Option<String>,
|
||||||
#[arg(long,group="api_key",required=true)]
|
#[arg(long,group="cookie",required=true)]
|
||||||
api_key_envvar:Option<String>,
|
cookie_envvar:Option<String>,
|
||||||
#[arg(long,group="api_key",required=true)]
|
#[arg(long,group="cookie",required=true)]
|
||||||
api_key_file:Option<PathBuf>,
|
cookie_file:Option<PathBuf>,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
output_folder:Option<PathBuf>,
|
output_folder:Option<PathBuf>,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
@ -68,12 +69,12 @@ struct DownloadSubcommand{
|
|||||||
}
|
}
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
struct DownloadGroupInventoryJsonSubcommand{
|
struct DownloadGroupInventoryJsonSubcommand{
|
||||||
#[arg(long,group="api_key",required=true)]
|
#[arg(long,group="cookie",required=true)]
|
||||||
api_key_literal:Option<String>,
|
cookie_literal:Option<String>,
|
||||||
#[arg(long,group="api_key",required=true)]
|
#[arg(long,group="cookie",required=true)]
|
||||||
api_key_envvar:Option<String>,
|
cookie_envvar:Option<String>,
|
||||||
#[arg(long,group="api_key",required=true)]
|
#[arg(long,group="cookie",required=true)]
|
||||||
api_key_file:Option<PathBuf>,
|
cookie_file:Option<PathBuf>,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
output_folder:Option<PathBuf>,
|
output_folder:Option<PathBuf>,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
@ -283,10 +284,10 @@ async fn main()->AResult<()>{
|
|||||||
end_version:subcommand.end_version,
|
end_version:subcommand.end_version,
|
||||||
start_version:subcommand.start_version.unwrap_or(0),
|
start_version:subcommand.start_version.unwrap_or(0),
|
||||||
output_folder:subcommand.output_folder.unwrap_or_else(||std::env::current_dir().unwrap()),
|
output_folder:subcommand.output_folder.unwrap_or_else(||std::env::current_dir().unwrap()),
|
||||||
api_key:api_key_from_args(
|
cookie:cookie_from_args(
|
||||||
subcommand.api_key_literal,
|
subcommand.cookie_literal,
|
||||||
subcommand.api_key_envvar,
|
subcommand.cookie_envvar,
|
||||||
subcommand.api_key_file,
|
subcommand.cookie_file,
|
||||||
).await?,
|
).await?,
|
||||||
asset_id:subcommand.asset_id,
|
asset_id:subcommand.asset_id,
|
||||||
}).await,
|
}).await,
|
||||||
@ -321,10 +322,10 @@ async fn main()->AResult<()>{
|
|||||||
}).await
|
}).await
|
||||||
},
|
},
|
||||||
Commands::DownloadGroupInventoryJson(subcommand)=>download_group_inventory_json(
|
Commands::DownloadGroupInventoryJson(subcommand)=>download_group_inventory_json(
|
||||||
api_key_from_args(
|
cookie_from_args(
|
||||||
subcommand.api_key_literal,
|
subcommand.cookie_literal,
|
||||||
subcommand.api_key_envvar,
|
subcommand.cookie_envvar,
|
||||||
subcommand.api_key_file,
|
subcommand.cookie_file,
|
||||||
).await?,
|
).await?,
|
||||||
subcommand.group,
|
subcommand.group,
|
||||||
subcommand.output_folder.unwrap_or_else(||std::env::current_dir().unwrap()),
|
subcommand.output_folder.unwrap_or_else(||std::env::current_dir().unwrap()),
|
||||||
@ -425,6 +426,15 @@ async fn main()->AResult<()>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn cookie_from_args(literal:Option<String>,environment:Option<String>,file:Option<PathBuf>)->AResult<Cookie>{
|
||||||
|
let cookie=match (literal,environment,file){
|
||||||
|
(Some(cookie_literal),None,None)=>cookie_literal,
|
||||||
|
(None,Some(cookie_environment),None)=>std::env::var(cookie_environment)?,
|
||||||
|
(None,None,Some(cookie_file))=>tokio::fs::read_to_string(cookie_file).await?,
|
||||||
|
_=>Err(anyhow::Error::msg("Illegal api key argument triple"))?,
|
||||||
|
};
|
||||||
|
Ok(Cookie::new(cookie))
|
||||||
|
}
|
||||||
async fn api_key_from_args(literal:Option<String>,environment:Option<String>,file:Option<PathBuf>)->AResult<ApiKey>{
|
async fn api_key_from_args(literal:Option<String>,environment:Option<String>,file:Option<PathBuf>)->AResult<ApiKey>{
|
||||||
let api_key=match (literal,environment,file){
|
let api_key=match (literal,environment,file){
|
||||||
(Some(api_key_literal),None,None)=>api_key_literal,
|
(Some(api_key_literal),None,None)=>api_key_literal,
|
||||||
@ -517,11 +527,11 @@ async fn download_list(api_key:ApiKey,asset_id_file_map:AssetIDFileMap)->AResult
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_inventory_pages(context:&CloudContext,group:u64)->AResult<Vec<InventoryItem>>{
|
async fn get_inventory_pages(context:&CookieContext,group:u64)->AResult<Vec<InventoryItem>>{
|
||||||
let mut cursor:Option<String>=None;
|
let mut cursor:Option<String>=None;
|
||||||
let mut asset_list=Vec::new();
|
let mut asset_list=Vec::new();
|
||||||
loop{
|
loop{
|
||||||
let mut page=context.inventory_page(rbx_asset::cloud::InventoryPageRequest{group,cursor}).await?;
|
let mut page=context.inventory_page(rbx_asset::cookie::InventoryPageRequest{group,cursor}).await?;
|
||||||
asset_list.append(&mut page.data);
|
asset_list.append(&mut page.data);
|
||||||
if page.nextPageCursor.is_none(){
|
if page.nextPageCursor.is_none(){
|
||||||
break;
|
break;
|
||||||
@ -531,8 +541,8 @@ async fn get_inventory_pages(context:&CloudContext,group:u64)->AResult<Vec<Inven
|
|||||||
Ok(asset_list)
|
Ok(asset_list)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn download_group_inventory_json(api_key:ApiKey,group:u64,output_folder:PathBuf)->AResult<()>{
|
async fn download_group_inventory_json(cookie:Cookie,group:u64,output_folder:PathBuf)->AResult<()>{
|
||||||
let context=CloudContext::new(api_key);
|
let context=CookieContext::new(cookie);
|
||||||
let item_list=get_inventory_pages(&context,group).await?;
|
let item_list=get_inventory_pages(&context,group).await?;
|
||||||
|
|
||||||
let mut path=output_folder.clone();
|
let mut path=output_folder.clone();
|
||||||
@ -562,7 +572,7 @@ struct DownloadHistoryConfig{
|
|||||||
end_version:Option<u64>,
|
end_version:Option<u64>,
|
||||||
start_version:u64,
|
start_version:u64,
|
||||||
output_folder:PathBuf,
|
output_folder:PathBuf,
|
||||||
api_key:ApiKey,
|
cookie:Cookie,
|
||||||
asset_id:AssetID,
|
asset_id:AssetID,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,7 +613,7 @@ async fn download_history(mut config:DownloadHistoryConfig)->AResult<()>{
|
|||||||
None=>Err(anyhow::Error::msg("Cannot continue from versions.json - there are no previous versions"))?,
|
None=>Err(anyhow::Error::msg("Cannot continue from versions.json - there are no previous versions"))?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let context=CloudContext::new(config.api_key);
|
let context=CookieContext::new(config.cookie);
|
||||||
|
|
||||||
//limit concurrent downloads
|
//limit concurrent downloads
|
||||||
let mut join_set=tokio::task::JoinSet::new();
|
let mut join_set=tokio::task::JoinSet::new();
|
||||||
@ -611,7 +621,7 @@ async fn download_history(mut config:DownloadHistoryConfig)->AResult<()>{
|
|||||||
//poll paged list of all asset versions
|
//poll paged list of all asset versions
|
||||||
let mut cursor:Option<String>=None;
|
let mut cursor:Option<String>=None;
|
||||||
loop{
|
loop{
|
||||||
let mut page=context.get_asset_versions(rbx_asset::cloud::AssetVersionsRequest{asset_id:config.asset_id,cursor}).await?;
|
let mut page=context.get_asset_versions_page(rbx_asset::cookie::AssetVersionsPageRequest{asset_id:config.asset_id,cursor}).await?;
|
||||||
let context=&context;
|
let context=&context;
|
||||||
let output_folder=config.output_folder.clone();
|
let output_folder=config.output_folder.clone();
|
||||||
let data=&page.data;
|
let data=&page.data;
|
||||||
|
Loading…
Reference in New Issue
Block a user