use std::{io::Read,path::PathBuf}; 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}; type AssetID=u64; type AssetIDFileMap=Vec<(AssetID,PathBuf)>; const CONCURRENT_DECODE:usize=8; const CONCURRENT_REQUESTS:usize=32; #[derive(Parser)] #[command(author,version,about,long_about=None)] #[command(propagate_version = true)] struct Cli{ #[command(subcommand)] command:Commands, } #[derive(Subcommand)] enum Commands{ DownloadHistory(DownloadHistorySubcommand), Download(DownloadSubcommand), DownloadDecompile(DownloadDecompileSubcommand), DownloadGroupInventoryJson(DownloadGroupInventoryJsonSubcommand), CreateAsset(CreateAssetSubcommand), CreateAssetMedia(CreateAssetMediaSubcommand), CreateAssetMedias(CreateAssetMediasSubcommand), UploadAsset(UpdateAssetSubcommand), UploadAssetMedia(UpdateAssetMediaSubcommand), UploadPlace(UpdatePlaceSubcommand), Compile(CompileSubcommand), CompileUploadAsset(CompileUploadAssetSubcommand), CompileUploadPlace(CompileUploadPlaceSubcommand), Decompile(DecompileSubcommand), DecompileHistoryIntoGit(DecompileHistoryIntoGitSubcommand), DownloadAndDecompileHistoryIntoGit(DownloadAndDecompileHistoryIntoGitSubcommand), } #[derive(Args)] struct DownloadHistorySubcommand{ #[arg(long)] asset_id:AssetID, #[arg(long,group="cookie",required=true)] cookie_literal:Option, #[arg(long,group="cookie",required=true)] cookie_envvar:Option, #[arg(long,group="cookie",required=true)] cookie_file:Option, #[arg(long)] output_folder:Option, #[arg(long)] continue_from_versions:Option, #[arg(long)] start_version:Option, #[arg(long)] end_version:Option, } #[derive(Args)] struct DownloadSubcommand{ #[arg(long,group="cookie",required=true)] cookie_literal:Option, #[arg(long,group="cookie",required=true)] cookie_envvar:Option, #[arg(long,group="cookie",required=true)] cookie_file:Option, #[arg(long)] output_folder:Option, #[arg(required=true)] asset_ids:Vec, } #[derive(Args)] struct DownloadGroupInventoryJsonSubcommand{ #[arg(long,group="cookie",required=true)] cookie_literal:Option, #[arg(long,group="cookie",required=true)] cookie_envvar:Option, #[arg(long,group="cookie",required=true)] cookie_file:Option, #[arg(long)] output_folder:Option, #[arg(long)] group:u64, } #[derive(Args)] struct CreateAssetSubcommand{ #[arg(long,group="cookie",required=true)] cookie_literal:Option, #[arg(long,group="cookie",required=true)] cookie_envvar:Option, #[arg(long,group="cookie",required=true)] cookie_file:Option, #[arg(long)] group_id:Option, #[arg(long)] input_file:PathBuf, #[arg(long)] model_name:String, #[arg(long)] description:Option, #[arg(long)] free_model:Option, #[arg(long)] allow_comments:Option, } #[derive(Args)] struct CreateAssetMediaSubcommand{ #[arg(long,group="api_key",required=true)] api_key_literal:Option, #[arg(long,group="api_key",required=true)] api_key_envvar:Option, #[arg(long,group="api_key",required=true)] api_key_file:Option, #[arg(long)] model_name:String, #[arg(long)] description:Option, #[arg(long)] input_file:PathBuf, #[arg(long)] asset_type:AssetType, #[arg(long,group="creator",required=true)] creator_user_id:Option, #[arg(long,group="creator",required=true)] creator_group_id:Option, /// Expected price limits how much robux can be spent to create the asset (defaults to 0) #[arg(long)] expected_price:Option, } #[derive(Args)] /// Automatically detect the media type from file extension and generate asset name and description struct CreateAssetMediasSubcommand{ #[arg(long,group="api_key",required=true)] api_key_literal:Option, #[arg(long,group="api_key",required=true)] api_key_envvar:Option, #[arg(long,group="api_key",required=true)] api_key_file:Option, #[arg(long)] description:Option, #[arg(long,group="creator",required=true)] creator_user_id:Option, #[arg(long,group="creator",required=true)] creator_group_id:Option, /// Expected price limits how much robux can be spent to create the asset (defaults to 0) #[arg(long)] expected_price:Option, input_files:Vec, } #[derive(Args)] struct UpdateAssetSubcommand{ #[arg(long)] asset_id:AssetID, #[arg(long,group="cookie",required=true)] cookie_literal:Option, #[arg(long,group="cookie",required=true)] cookie_envvar:Option, #[arg(long,group="cookie",required=true)] cookie_file:Option, #[arg(long)] group_id:Option, #[arg(long)] input_file:PathBuf, #[arg(long)] change_name:Option, #[arg(long)] change_description:Option, #[arg(long)] change_free_model:Option, #[arg(long)] change_allow_comments:Option, } #[derive(Args)] struct UpdateAssetMediaSubcommand{ #[arg(long)] asset_id:AssetID, #[arg(long,group="api_key",required=true)] api_key_literal:Option, #[arg(long,group="api_key",required=true)] api_key_envvar:Option, #[arg(long,group="api_key",required=true)] api_key_file:Option, #[arg(long)] input_file:PathBuf, } #[derive(Args)] struct UpdatePlaceSubcommand{ #[arg(long)] place_id:u64, #[arg(long)] universe_id:u64, #[arg(long,group="api_key",required=true)] api_key_literal:Option, #[arg(long,group="api_key",required=true)] api_key_envvar:Option, #[arg(long,group="api_key",required=true)] api_key_file:Option, #[arg(long)] input_file:PathBuf, } #[derive(Args)] struct CompileSubcommand{ #[arg(long)] input_folder:Option, #[arg(long)] output_file:PathBuf, #[arg(long)] style:Option