Jump to content

Sketchfab Downloader


Josh
 Share

Recommended Posts

This code can be used to download metadata from Sketchfab files. Each saved JSON file includes all the information associated with that model. An API key is not required at this step.

Most importantly, this code will save your progress as you go, so if the process is interrupted for any reason you can pick it back up later without losing your place. Several settings are supported, and each combination of settings will save a different set of data that can be resumed at any time.

Please only use this code within the bounds of the SketchFab user agreement.

#include "UltraEngine.h"

using namespace UltraEngine;

// API documentation: https://docs.sketchfab.com/data-api/v3/index.html

// Path to save data to
const WString SavePath = GetPath(PATH_DESKTOP) + "/Sketchfab";

// Licenses we want to include
std::set<std::string> Licenses = { "CC0 Public Domain", "Free Standard", "CC Attribution", "CC Attribution-ShareAlike", "CC Attribution-NoDerivs" };

int main(int argc, const char* argv[])
{
    // You could get settings from command line arguments if you want
    //auto settings = ParseCommandLine(argc, argv);

    const int MinLikes = 0;// no minimum
    const int MaxVertices = 0;// zero to disable
    const String Author;// specify a user to get files from
    const String Category;// specify one category
    
    String url = "https://api.sketchfab.com/v3/models?downloadable=true&sort_by=-viewCount";
    if (MinLikes > 0) url += "&liked_by=" + String(MinLikes);
    if (MaxVertices > 0) url += "&max_vertex_count=" + String(MaxVertices);
    if (not Author.empty()) url += "&user=" + Author;
    if (not Category.empty()) url += "&categories=" + Category;// Example: "weapons-military"

    CreateDir(SavePath, true);
    
    // This allows you to pick up where you left off if the process is stopped for any reason
    int page = 0;
    String RequestName = "Request";
    RequestName += "_" + String(MinLikes);
    RequestName += "_" + String(MaxVertices);
    RequestName += "_" + String(Author);
    RequestName += "_" + String(Category);

    CreateDir(SavePath + "/" + RequestName);
    CreateDir(SavePath + "/" + RequestName + "/metadata");
    
    WString pagefile = SavePath + "/" + RequestName + "/pages.txt";
    auto stream = OpenFile(pagefile);
    if (stream)
    {
        stream->Seek(0);
        while (not stream->Eof())
        {
            url = stream->ReadLine();
            ++page;
        }
    }
    else
    {
        stream = WriteFile(pagefile);
    }

    while (true)
    {
        ++page;
        Print("Page " + String(page));

        // Docs: https://docs.sketchfab.com/data-api/v3/index.html#!/models/get_v3_models
        String s = FetchUrl(url);
        auto t = LoadTable(s);

        // Save the JSON data if you want to get a look at it
        //SaveTable(t, SavePath + "/" + String(page) + ".json");

        // Save the metadata for each result
        if (t["results"].is_array())
        {
            std::string uid, license;
            int count = t["results"].size();
            for (int n = 0; n < count; ++n)
            {
                if (int(t["results"][n]["archives"]["glb"]["textureCount"]) == 0) continue;// skip untextured models
                license = t["results"][n]["license"]["label"];
                if (not Licenses.empty() and Licenses.find(license) == Licenses.end()) continue;// skip unsupported licenses
                uid = t["results"][n]["uid"];                
                WString filepath = SavePath + "/" + RequestName + "/metadata/" + uid + ".json";
                if (FileType(filepath) == 0)
                {
                    SaveTable(t["results"][n], filepath);
                }
            }
        }
        else
        {
            if (t["detail"].is_string())
            {
                stream->Close();
                String s = "Error: " + std::string(t["detail"]);
                Print(s);
                Notify(s, "SketchFab API", true);
                return 1;
            }
        }
        if (not t["next"].is_string()) break;
        url = t["next"];
        stream->WriteLine(url);
        stream->Flush();
    }

    return 0;
}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

  • Josh changed the title to Sketchfab Downloader

And then to download an individual file, you can use this function:

bool DownloadSketchFabFile(const String& apikey, const String& uid, const WString& localpath)
{
    String command = "curl -H \"Authorization: Token " + apikey + "\" https://api.sketchfab.com/v3/models/" + uid + "/download";
    auto stream = CreateBufferStream();
    auto err = Command(command, stream);
    if (err != 0)
    {
        Print("Error: " + String(err));
        return false;
    }
    String s = stream->ReadString();
    table t = LoadTable(s);
    if (not t.is_object())
    {
        Print("Error: JSON data not returned");
        return false;
    }
    if (not t["glb"].is_object())
    {
        if (t["detail"].is_string())
        {
            Print("Error: " + std::string(t["detail"]));
            return false;
        }
        Print("Error: glb object not found in response");
        return false;
    }
    std::string url = std::string(t["glb"]["url"]);
    if (not DownloadFile(url, localpath))
    {
        Print("Can't download file " + url);
        return false;
    }
    return true;
}

Example usage:

// Get your API key here : https://sketchfab.com/settings/password
String uid = "f12e67159f75486bb21213e573520612";
WString localpath = GetPath(PATH_DESKTOP) + "/" + uid + ".glb";
DownloadSketchFabFile(APIKey, uid, localpath);
RunFile(localpath);

You can get an API key here:
https://sketchfab.com/settings/password

Please only use this code within the terms of the SketchFab user agreement.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...