Skip to content

Instantly share code, notes, and snippets.

@Syfaro
Last active May 14, 2025 03:09
Show Gist options
  • Select an option

  • Save Syfaro/583e6e1a949e0156fd022db0f05625eb to your computer and use it in GitHub Desktop.

Select an option

Save Syfaro/583e6e1a949e0156fd022db0f05625eb to your computer and use it in GitHub Desktop.
Download OBJ previews of products from Bad Dragon
from typing import List, Iterator
import os
import urllib.request
import json
from dataclasses import dataclass
import argparse
PRODUCT_URL = "https://bad-dragon.com/api/products"
SAVE_DIR = "models"
@dataclass
class DownloadableProduct:
name: str
preview_object_url: str
preview_texture_map_url: str
preview_normal_map_url: str
def load_products() -> List[dict]:
with urllib.request.urlopen(PRODUCT_URL) as f:
return json.load(f)
def process_products(products: List[dict]) -> Iterator[DownloadableProduct]:
for product in products:
name = product.get("sku")
preview_object_url = product.get("previewObjModel", {}).get("url")
preview_texture_map_url = product.get("previewTextureMap", {}).get("url")
preview_normal_map_url = product.get("previewNormalMap", {}).get("url")
if (
not name
or not preview_object_url
or not preview_texture_map_url
or not preview_normal_map_url
):
continue
yield DownloadableProduct(
name, preview_object_url, preview_texture_map_url, preview_normal_map_url
)
def download_file(url: str, path: str) -> None:
if os.path.exists(path):
print("Already downloaded {path}".format(path=path))
return
print("Downloading {path}".format(path=path))
urllib.request.urlretrieve(url, path)
def download_product(
product: DownloadableProduct, save_dir: str, include_maps: bool = False
) -> None:
download_file(
product.preview_object_url,
os.path.join(save_dir, "{name}.obj".format(name=product.name)),
)
if include_maps:
download_file(
product.preview_texture_map_url,
os.path.join(save_dir, "{name}_texture_map.png".format(name=product.name)),
)
download_file(
product.preview_normal_map_url,
os.path.join(save_dir, "{name}_normal_map.png".format(name=product.name)),
)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Download Bad Dragon preview objects.")
parser.add_argument(
"--maps", help="include texture and normal maps", action="store_true"
)
parser.add_argument("dir", help="Path to save models", nargs="?", default=SAVE_DIR)
args = parser.parse_args()
if not os.path.exists(args.dir):
os.mkdir(args.dir)
print("Saving objects to {dir}".format(dir=args.dir))
products = load_products()
for product in process_products(products):
download_product(product, args.dir, args.maps)
@sirThomasMoore
Copy link

sirThomasMoore commented Feb 25, 2022

@TommyBoyio Just tested, it still works. It has to be ran in Python 3.x I believe. I didn't do anything special to make it work.

Python version: 3.9.10

I ran python3 dragon_download.py

It downloaded all the models for me.

@devynF0401
Copy link

hey uhm it isnt working for me could someone just send me like a folder full of all the models sorry

@PhazerRazer
Copy link

Works great, but is there any way to get the internal designs of the penetrables?

@human-beep
Copy link

how do i get the textures for the different colors?

@Zrksie
Copy link

Zrksie commented Apr 18, 2023

So I’m having a really hard time using this, I’m trying to get them into blender but it keeps coming up with an error and it doesn’t say what that error is but I think it has something to do with line 85. (I’m a complete noob when it comes to python scripts and blender)

@foxwearingbox
Copy link

foxwearingbox commented Apr 18, 2023 via email

@Zrksie
Copy link

Zrksie commented Apr 18, 2023

The script wont run in blender, get the newest version of python and run the downloaded script on your desktop. It'll create a folder with the models.

So I did that now I don’t know how to get the models into blender it’s saying it’s the wrong file type (the file type is .obj)

@foxwearingbox
Copy link

foxwearingbox commented Apr 18, 2023 via email

@Zrksie
Copy link

Zrksie commented Apr 19, 2023

you have to tell it to import .obj files, its one of the options in the "files" tab i think

Thank you it worked

@foxwearingbox
Copy link

foxwearingbox commented Apr 19, 2023 via email

@WellGoblin
Copy link

is there a way to construct the model with the texture maps to give it the high res look like the preveiw?

@PixelVengeur
Copy link

PixelVengeur commented May 2, 2025

I was getting 403 Forbidden errors when downloading the maps, which I assumed were related to the User Agent, since I could open the URLs and download the maps in my normal browser.

I changed two lines in the download_file function, so that I could add my own user agent to the request:

def download_file(url: str, path: str) -> None:
    if os.path.exists(path):
        print("Already downloaded {path}".format(path=path))
        return

    print(f"Downloading {path}")
    opener = urllib.request.URLopener()
    opener.addheader('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/20100101 Firefox/138.0')

    opener.retrieve(url, path)

Now everything works as expected when using --maps :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment