-
-
Save Pldare/ebf704c752a8d77ff9603d4adfe54083 to your computer and use it in GitHub Desktop.
| using System; | |
| using System.Security.Cryptography; | |
| using System.IO; | |
| using System.IO.Compression; | |
| namespace Vroid | |
| { | |
| class Vroiddec | |
| { | |
| static void Main(string[] args) | |
| { | |
| using (FileStream fs = new FileStream(args[0],FileMode.Open)) { | |
| using (BinaryReader bs = new BinaryReader(fs)) { | |
| int buff_size=(int)(fs.Length)-48; | |
| RijndaelManaged rDel=new RijndaelManaged(); | |
| rDel.IV=bs.ReadBytes(16); | |
| rDel.Key=bs.ReadBytes(32); | |
| rDel.Mode=CipherMode.CBC; | |
| byte[] resultarray=rDel.CreateDecryptor().TransformFinalBlock(bs.ReadBytes(buff_size),0,buff_size); | |
| using(MemoryStream ms =new MemoryStream(resultarray)){ | |
| using(GZipStream gzs=new GZipStream(ms,CompressionMode.Decompress)){ | |
| using(FileStream df=new FileStream(args[0]+".dec",FileMode.OpenOrCreate,FileAccess.Write)) | |
| { | |
| int data; | |
| while((data=gzs.ReadByte())!=-1) | |
| { | |
| df.WriteByte((byte)data); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| log_msg("Done!"); | |
| } | |
| static void log_msg(string msg) | |
| { | |
| Console.WriteLine(msg); | |
| } | |
| } | |
| } |
| import requests | |
| import os | |
| import json | |
| import argparse | |
| USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/114.0" | |
| HOST = "https://hub.vroid.com" | |
| API_VERSION = "11" | |
| def download_model_from_vroid(model_id, subdir=None): | |
| #model_path_base = os.path.join( | |
| # subdir if subdir else args.directory, model_id) | |
| model_api_url = f"{HOST}/api/character_models/{model_id}" | |
| #print(model_api_url) | |
| return model_api_url | |
| def get_user_model_ids(user_id): | |
| model_ids = [] | |
| api_url = f"{HOST}/api/users/{user_id}/character_models?antisocial_or_hate_usage=&characterization_allowed_user=&corporate_commercial_use=&credit=&modification=&personal_commercial_use=&political_or_religious_usage=&redistribution=&sexual_expression=&violent_expression=" | |
| page_num = 1 | |
| while api_url: | |
| user_r = requests.get( | |
| api_url, headers={"User-Agent": USER_AGENT, "X-Api-Version": API_VERSION}) | |
| if not user_r.ok: | |
| print( | |
| f"[user:{user_id}:page:{page_num}] got bad response from vroid hub, {user_r.status_code}") | |
| break | |
| user_j = user_r.json() | |
| if "next" in user_j["_links"]: | |
| api_url = HOST + user_j["_links"]["next"]["href"] | |
| else: | |
| api_url = None | |
| for model in user_j["data"]: | |
| model_ids.append(model["id"]) | |
| print(f"[user:{user_id}] found {len(model_ids)} models") | |
| return model_ids | |
| def download_user_from_vroid(user_id): | |
| user_api_url = f"{HOST}/api/users/{user_id}" | |
| user_api_r = requests.get(user_api_url, headers={ | |
| "User-Agent": USER_AGENT, "X-Api-Version": API_VERSION}) | |
| if not user_api_r.ok: | |
| print( | |
| f"[user:{user_id}:api] got bad response from vroid hub, user might not exist, {user_api_r.status_code}") | |
| return | |
| user_api_j = user_api_r.json() | |
| username = user_api_j["data"]["user"]["name"] | |
| #user_base_path = os.path.join(args.directory, f"{username} ({user_id})") | |
| #if not os.path.isdir(user_base_path): | |
| # os.makedirs(user_base_path) | |
| #json_path = f"{user_base_path}.info.json" | |
| #if args.write_info_json: | |
| # with open(json_path, "w") as json_file: | |
| # json_file.write(json.dumps(user_api_j["data"])) | |
| # print(f"[user:{user_id}:api] wrote '{os.path.basename(json_path)}'") | |
| model_ids = get_user_model_ids(user_id) | |
| all_url=[] | |
| for model_id in model_ids: | |
| url=download_model_from_vroid(model_id)#, user_base_path) | |
| all_url.append(url) | |
| return all_url | |
| if __name__ == "__main__": | |
| #parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) | |
| #parser.add_argument("-d", "--directory", type=str, | |
| # help="save directory (defaults to current)", default=os.getcwd()) | |
| #args = parser.parse_args() | |
| #print(args.directory) | |
| #https://hub.vroid.com/en/users/36667771 | |
| download_user_from_vroid(36667771) |
| #use project https://github.com/Pldare/vrh-deobfuscator/tree/MatchAndBatch | |
| #use example | |
| #python dlhelp.py users_id or vroid_model_view_url | |
| import os,sys | |
| import re | |
| import checkusersmodel | |
| import time | |
| def dl_glb(url,sdir): | |
| print(url) | |
| os.system("node src/index2.js {}".format(url)) | |
| url=sys.argv[1] | |
| if "http" in url: | |
| dl_glb(url,"model") | |
| else: | |
| all_url=checkusersmodel.download_user_from_vroid(url) | |
| cou=len(all_url) | |
| idd=1 | |
| for gurl in all_url: | |
| print("{}/{}".format(idd,cou)) | |
| dl_glb(gurl,str(url)) | |
| #time.sleep(0) | |
| idd+=1 |
VRoid is now using ZSTD in place of GZIP. I wrote a Python script which handles the new decompression along with the decryption https://github.com/CetaceanNation/misc-scripts/blob/main/vroid-hub-downloader/vroid-hub-downloader.py#L52. If @Pldare completes their extraction code it would be nice to incorporate or at least add to my workflow.
Hi excuse me to reply to you too, but i wanted to know if there's a way to import the glb models downloaded with your script to Blender, or any program at all... With blender i keep getting that PIXIV texture error
hihihi Everyone I’m glad that everyone pays attention to this code of mine I share some json parsing methods of gltf models for everyone to facilitate extraction and error correction. get block info
import json import sys with open(sys.argv[1],encoding='utf-8') as f: data = json.load(f) for i in data.keys(): a=data[i] #print(type(a)) accessors = data["accessors"] buffer_views = data["bufferViews"] type_num_dict = {"SCALAR": 1, "VEC2": 2, "VEC3": 3, "VEC4": 4, "MAT4": 16} type_dict={ 5120: "BYTE", 5121: "UNSIGNED_BYTE", 5122: "SHORT", 5123: "UNSIGNED_SHORT", 5124: "INT", 5125: "UNSIGNED_INT", 5126: "FLOAT" } for accessor_index, accessor in enumerate(accessors): type_count = type_num_dict[accessor["type"]] #ct=accessor["componentType"] pos=buffer_views[accessor["bufferView"]]["byteOffset"] count=accessor["count"] ac=accessor["componentType"] print(accessor_index,count,type_dict[ac],type_count==1,pos)get mesh info
print("mesh") for n, mesh in enumerate(data["meshes"]): #print(n,mesh.keys()) for j,primive in enumerate(mesh["primitives"]): #print(primive) if primive["mode"] != 4: raise "1" dbb=primive["indices"] print(dbb) va=primive["attributes"] print(va)The id in meshinfo corresponds to the id in blockinfo I will provide the complete model extraction code later
Hi, is there any update about the complete model extraction code?
I checked the differences between the downloaded VRM and the VRM in the browser, and found that the vertex coordinate data had undergone some transformations
VRoid Hub obfuscates the mesh of the preview models. You can read more on this here: https://toon.link/blog/1740863435/borrowing-intellectual-property.
Nice post!
I checked the differences between the downloaded VRM and the VRM in the browser, and found that the vertex coordinate data had undergone some transformations
true dude, I hope this will shows how it works:
https://toon.link/blog/1740863435/borrowing-intellectual-property
Hello everyone, you can finally use this project https://github.com/Pldare/vrh-deobfuscator/tree/MatchAndBatch to download all or a single model from your user's collection (this was mostly made for research purposes). If you like vroid model, please support model author.
Have you ever found a way to use these models?