Files
App-Installer-For-Windows-8…/shared/html/js/dboxapi.js
2026-04-04 19:27:45 +08:00

562 lines
23 KiB
JavaScript

/**
* DBox API
* Docs: https://dbox.tools/api/docs
*/
(function(global) {
"use strict";
function joinUrl(url, path) {
if (url.charAt(url.length - 1) === "/") {
url = url.slice(0, -1);
}
if (path.charAt(0) === "/") {
path = path.slice(1);
}
return url + "/" + path;
}
function buildParams(params) {
var queryString = "";
var keys = Object.keys(params);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var value = params[key];
if (value === null || value === void 0) {
continue;
}
queryString += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
}
return queryString.slice(0, -1);
}
var baseUrl = "https://dbox.tools/";
var baseApiUrl = joinUrl(baseUrl, "api");
var dboxApi = {
/**
* @enum {string} DBox.API.System
* @readonly
*/
System: {
/** @type {string} Xbox */
xbox: "XBOX",
/** @type {string} Xbox 360 */
xbox360: "XBOX360",
/** @type {string} Xbox One */
xboxOne: "XBOXONE",
/** @type {string} Xbox Series X */
xboxSeriesX: "XBOXSERIESX",
/** @type {string} PC */
pc: "PC",
/** @type {string} PS3 */
mobile: "MOBILE"
},
Discs: {
/**
* Get and filter discs
* @param {string | null} name query
* @param {DBox.API.System} system query
* @param {integer | number} [limit] query, default: 100
* @param {integer | number} [offset] query, default: 0
* @returns {string} request URL, method: GET
*/
getDiscs: function(name, system, limit, offset) {
var params = {};
if (name) params.name = name;
if (system) params.system = system;
if (limit) params.limit = limit;
if (offset) params.offset = offset;
return joinUrl(baseApiUrl, "discs") +
"?" + buildParams(params);
},
/**
* Get single disc by DBox ID
* @param {integer | number} discId path, required
* @returns {string} request URL, method: GET
*/
getSingleDiscById: function(discId) {
return joinUrl(baseApiUrl, "discs/" + discId);
},
/**
* Get single disc by Redump ID
* @param {integer | number} redumpId path, required
* @returns {string} request URL, method: GET
*/
getSingleDiscByRedumpId: function(redumpId) {
return joinUrl(baseApiUrl, "discs/redump/" + redumpId);
},
/**
* Get single disc by its XMID (OG XBOX only)
* @param {string} xmid path, required
* @returns {string} request URL, method: GET
*/
getSingleDiscByXMId: function(xmid) {
return joinUrl(baseApiUrl, "discs/xmid/" + xmid);
},
/**
* Get single disc by its XeMID (XBOX 360 only)
* @param {string} xeMid path, required
* @returns {string} request URL, method: GET
*/
getSingleDiscByXeMId: function(xeMid) {
return joinUrl(baseApiUrl, "discs/xemid/" + xeMid);
},
/**
* Get single disc by its media ID. Media ID v1 (XBOX & XBOX 360) and Media ID v2 (XBOX One & XBOX Series) are combined in a single query
* @param {string} mediaId path, required
* @returns {string} request URL, method: GET
*/
getSingleDiscByMediaId: function(mediaId) {
return joinUrl(baseApiUrl, "discs/media_id/" + mediaId);
},
/**
* Get the dirs and files (if available) for a disc. Filetype indicates if it is a supported filetype that has further metadata available in the database.
* @param {integer | number} discId path, required
* @returns {string} request URL, method: GET
*/
getDiscFiles: function(discId) {
return joinUrl(baseApiUrl, "discs/" + discId + "/files");
}
},
Releases: {
/**
* Get and filter releases
* @param {string | null} name query
* @param {string | null} edition query
* @param {string | null} barcode query
* @param {DBox.API.System} system query
* @param {integer | number} limit query, default: 100
* @param {integer | number} offset query, default: 0
* @returns {string} request URL, method: GET
*/
getReleases: function(name, edition, barcode, system, limit, offset) {
var params = {};
if (name) params.name = name;
if (edition) params.edition = edition;
if (barcode) params.barcode = barcode;
if (system) params.system = system;
if (limit) params.limit = limit;
if (offset) params.offset = offset;
return joinUrl(baseApiUrl, "releases") +
"?" + buildParams(params);
},
/**
* Get single release by DBox ID
* @param {string} releaseId path, required
* @returns {string} request URL, method: GET
*/
getSingleRelease: function(releaseId) {
return joinUrl(baseApiUrl, "releases/" + releaseId);
}
},
Files: {
/**
* Get all discs that contain a particular file. NOTE: not all discs have been parsed on file-level yet
* @param {string} md5 path, required
* @returns {string} request URL, method: GET
*/
getFiles: function(md5) {
return joinUrl(baseApiUrl, "files/" + md5 + "/discs");
},
/**
* Filter all distinct xbe files. NOTE: not all discs have been parsed on file-level yet
* @param {string | null} titleId query
* @param {integer | null} allowrdMedia query
* @param {integer | null} region query, Available values: 1, 2, 3, 4, 7, 2147483648
* @param {integer | null} gameRating query
* @param {integer | null} discNumber query
* @param {integer | null} version query
* @param {integer | number} limit query, default: 100
* @param {integer | number} offset query, default: 0
* @returns
*/
getXbeFiles: function(titleId, allowrdMedia, region, gameRating, discNumber, version, limit, offset) {
if (region !== null && region !== undefined) {
var valid = [1, 2, 3, 4, 7, 2147483648];
if (!valid.includes(region)) throw new Error('Invalid region');
}
var params = {};
if (titleId) params.title_id = titleId;
if (allowrdMedia) params.allowrd_media = allowrdMedia;
if (region) params.region = region;
if (gameRating) params.game_rating = gameRating;
if (discNumber) params.disc_number = discNumber;
if (version) params.version = version;
if (limit) params.limit = limit;
if (offset) params.offset = offset;
return joinUrl(baseApiUrl, "files/xbe") +
"?" + buildParams(params);
},
/**
* Get xbe file by md5. NOTE: not all discs have been parsed on file-level yet
* @param {string} md5 path, required
* @returns {string} request URL, method: GET
*/
getXbeFileByMd5: function(md5) {
return joinUrl(baseApiUrl, "files/xbe/" + md5);
},
/**
* Get stfs file by md5. NOTE: not all discs have been parsed on file-level yet
* @param {string} md5 path, required
* @returns {string} request URL, method: GET
*/
getStfsFileByMd5: function(md5) {
return joinUrl(baseApiUrl, "files/stfs/" + md5);
},
},
TitleIDs: {
/**
* Get and filter title IDs
* @param {string | (string | null)} name query
* @param {DBox.API.System | null} system query
* @param {string | (string | null)($uuid)} bingId query
* @param {string | (string | null)($uuid)} serviceConfigId query
* @param {integer} limit query, default: 100
* @param {integer} offset query, default: 0
* @returns {string} request URL, method: GET
*/
getTitleIds: function(name, system, bingId, serviceConfigId, limit, offset) {
var params = {};
if (name) params.name = name;
if (system) params.system = system;
if (bingId) params.bing_id = bingId;
if (serviceConfigId) params.service_config_id = serviceConfigId;
if (limit) params.limit = limit;
if (offset) params.offset = offset;
return joinUrl(baseApiUrl, "title_ids") +
"?" + buildParams(params);
},
/**
* Get single title ID by its hexadecimal value
* @param {string} titleId path, required
* @returns {string} request URL, method: GET
*/
getSingleTitleId: function(titleId) {
return joinUrl(baseApiUrl, "title_ids/" + titleId);
}
},
Achievements: {
/**
* Get achievements for a title-id. Xbox 360/GFWL only
* @param {string} titleId path, required
* @returns {string} request URL, method: GET
*/
getAchievementsV1: function(titleId) {
return joinUrl(baseApiUrl, "achievements/v1/" + titleId);
},
/**
* Get achievements for a title-id. Xbox One/Series only
* @param {string} titleId path, required
* @returns {string} request URL, method: GET
*/
getAchievementsV2: function(titleId) {
return joinUrl(baseApiUrl, "achievements/v2/" + titleId);
},
},
Marketplace: {
/**
* Get and filter marketplace products
* @param {integer | (integer | null)} productType query
* @param {integer} limit query, default: 100
* @param {integer} offset query, default: 0
* @returns {string} request URL, method: GET
*/
getProducts: function(productType, limit, offset) {
var params = {};
if (productType) params.product_type = productType;
if (limit) params.limit = limit;
if (offset) params.offset = offset;
return joinUrl(baseApiUrl, "marketplace/products") +
"?" + buildParams(params);
},
/**
* Get single marketplace product by marketplace product ID
* @param {string} productId path, required
* @returns {string} request URL, method: GET
*/
getSingleProduct: function(productId) {
return joinUrl(baseApiUrl, "marketplace/products/" + productId);
},
/**
* Get children of a marketplace product
* @param {string} productId path, required
* @param {integer | (integer | null)} productType query
* @returns {string} request URL, method: GET
*/
getProductChildren: function(productId, productType) {
var params = {};
if (productType) params.product_type = productType;
return joinUrl(baseApiUrl, "marketplace/products/" + productId + "/children") +
"?" + buildParams(params);
},
/**
* Get and filter marketplace product instances
* @param {string | (string | null)($uuid)} productId query
* @param {string | (string | null)} hexOfferId query
* @param {integer | (integer | null)} licenseTypeId query
* @param {integer | (integer | null)} packageType query
* @param {integer | (integer | null)} gameRegion query
* @param {integer} limit query, default: 100
* @param {integer} offset query, default: 0
* @returns {string} request URL, method: GET
*/
getProductInstances: function(productId, hexOfferId, licenseTypeId, packageType, gameRegion, limit, offset) {
var params = {};
if (productId) params.product_id = productId;
if (hexOfferId) params.hex_offer_id = hexOfferId;
if (licenseTypeId) params.license_type_id = licenseTypeId;
if (packageType) params.package_type = packageType;
if (gameRegion) params.game_region = gameRegion;
if (limit) params.limit = limit;
if (offset) params.offset = offset;
return joinUrl(baseApiUrl, "marketplace/product-instances") +
"?" + buildParams(params);
},
/**
* Get single marketplace product instance by marketplace product instance ID
* @param {string} instanceId path, required
* @returns {string} request URL, method: GET
*/
getProductInstanceById: function(instanceId) {
return joinUrl(baseApiUrl, "marketplace/product-instances/" + instanceId);
},
/**
* Get all marketplace product types
* @returns {string} request URL, method: GET
*/
getProductTypes: function() {
return joinUrl(baseApiUrl, "marketplace/product-types");
},
/**
* Get single marketplace category
* @param {integer} productTypeId path, required
* @returns {string} request URL, method: GET
*/
getSingleProductType: function(productTypeId) {
return joinUrl(baseApiUrl, "marketplace/product-types/" + productTypeId);
},
/**
* Get and filter all marketplace categories
* @param {integer | (integer | null)} parent query
* @returns {string} request URL, method: GET
*/
getCategories: function(parent) {
var params = {};
if (parent) params.parent = parent;
return joinUrl(baseApiUrl, "marketplace/categories") +
"?" + buildParams(params);
},
/**
* Get single marketplace category
* @param {integer} categoryId path, required
* @returns {string} request URL, method: GET
*/
getSingleCategory: function(categoryId) {
return joinUrl(baseApiUrl, "marketplace/categories/" + categoryId);
},
/**
* Get all marketplace locales
* @returns {string} request URL, method: GET
*/
getLocales: function() {
return joinUrl(baseApiUrl, "marketplace/locales");
},
/**
* Get single marketplace locale by locale string
* @param {string} localeId path, required
* @returns {string} request URL, method: GET
*/
getSingleLocale: function(localeId) {
return joinUrl(baseApiUrl, "marketplace/locales/" + localeId);
},
},
/**
* Enum for product types, used in store API
* @enum {string} DBox.API.ProductType
*/
ProductType: {
application: "Application",
avatarItem: "AvatarItem",
consumable: "Consumable",
durable: "Durable",
game: "Game",
movie: "Movie",
pass: "PASS",
tvSeries: "TvSeries",
tvSeason: "TvSeason",
tvEpisode: "TVEpisode",
unmanagedConsumable: "UnmanagedConsumable",
},
/**
* Enum for product families, used in store API
* @enum {string} DBox.API.ProductFamily
*/
ProductFamily: {
apps: "Apps",
avatars: "Avatars",
games: "Games",
movies: "Movies",
passes: "Passes",
tv: "TV",
},
/**
* Enum for order by, used in store API
* @enum {string} DBox.API.OrderBy
*/
OrderBy: {
productId: "product_id",
titleId: "title_id",
revisionId: "revision_id",
/** such as "23654onetwoonestudio.cctv_kdpw61jgbrs34" */
packageFamilyName: "package_family_name",
/** such as "23654onetwoonestudio.cctv" */
packageIdentityName: "package_identity_name",
},
/**
* Enum for order direction, used in store API
* @enum {string} DBox.API.OrderDirection
*/
OrderDirection: {
/** @type {string} 升序 */
asc: "asc",
/** @type {string} 降序 */
desc: "desc",
},
Store: {
/**
* Get store products
* @param {string | (string | null)} category query
* @param {string | (string | null)} titleId query
* @param {DBox.API.ProductType | null} productType query
* @param {DBox.API.ProductFamily | null} productFamily query
* @param {DBox.API.OrderBy | null} orderBy query, default: productId
* @param {DBox.API.OrderDirection | null} orderDirection query, default: asc
* @param {integer} limit query, default: 100
* @param {integer} offset query, default: 0
* @returns {string} request URL, method: GET
*/
getProducts: function(category, titleId, productType, productFamily, orderBy, orderDirection, limit, offset) {
var params = {};
if (category) params.category = category;
if (titleId) params.title_id = titleId;
if (productType) params.product_type = productType;
if (productFamily) params.product_family = productFamily;
if (orderBy) params.order_by = orderBy;
if (orderDirection) params.order_direction = orderDirection;
if (limit) params.limit = limit;
if (offset) params.offset = offset;
return joinUrl(baseApiUrl, "store/products") +
"?" + buildParams(params);
},
/**
* Get single store product
* @param {string} productId path, required
* @returns {string} request URL, method: GET
*/
getSingleProduct: function(productId) {
return joinUrl(baseApiUrl, "store/products/" + productId);
},
/**
* Get all related products for a product id. Includes both child and parent relationships. Check the product-ids for relationship direction. The relationship_type is parent -> child direction. Same combinations can appear multiple times with different relationship types.
* @param {string} productId path, required
* @returns {string} request URL, method: GET
*/
getAllReleatedProducts: function(productId) {
return joinUrl(baseApiUrl, "store/products/" + productId + "/related");
},
/**
* Get single sku for store product
* @param {string} productId path, required
* @param {string} skuId path, required
* @returns {string} request URL, method: GET
*/
getSingleSkuFromProduct: function(productId, skuId) {
return joinUrl(baseApiUrl, "store/products/" + productId + "/sku/" + skuId);
}
}
};
function getXhr() {
var xmlhttp;
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
xmlhttp = new XMLHttpRequest();
}
return xmlhttp;
}
/**
* Send an HTTP request to the DBox API and return a Promise that resolves with the response.
* @param {string} api DBox API
* @param {string} method
* @param {[boolean]} isAsync default: true
* @param {[string]} username
* @param {[string]} pwd
* @returns {Promise <XMLHttpRequest>} A Promise that resolves with the response.
*/
var dboxXHR = function(api, method, isAsync, username, pwd) {
method = method || "GET";
if (typeof isAsync === "undefined" || isAsync === null) isAsync = true;
var xhr = getXhr();
if (username && pwd) {
try {
xhr.open(method, api, isAsync, username, pwd);
} catch (e) {
xhr.open(method, api, isAsync);
}
} else {
xhr.open(method, api, isAsync);
}
return new Promise(function(c, e) {
try {
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
if (c) c(xhr);
} else {
if (e) e(xhr.statusText + " (" + xhr.status + ")");
}
}
};
xhr.send("");
} catch (ex) {
if (e) e(ex);
}
});
};
/**
* Send an HTTP request to the DBox API and return a Promise that resolves with the response as JSON.
* @param {string} api DBox API
* @param {string} method
* @param {[boolean]} isAsync default: true
* @param {[string]} username
* @param {[string]} pwd
* @returns {Promise <object>} A Promise that resolves with the response as JSON.
*/
dboxXHR.parseJson = function(api, method, isAsync, username, pwd) {
return dboxXHR(api, method, isAsync, username, pwd).then(function(xhr) {
return JSON.parse(xhr.responseText);
});
}
/**
* DBox namespace
* @namespace {DBox}
*/
global.DBox = {
/**
* DBox API namespace
* @namespace {DBox.API}
*/
API: dboxApi,
/**
* @function {DBox.XHR}
*/
xhr: dboxXHR,
};
})(this);