danbooru
Version:
danbooru api wrapper
350 lines (286 loc) • 11.7 kB
JavaScript
;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var _require = require('./requires.browser'),
http = _require.http,
https = _require.https,
URL = _require.URL,
btoa = _require.btoa,
fetch = _require.fetch;
var constants = require('./constants');
var util = require('./util');
var defaultUrl = Object.freeze(new URL('https://danbooru.donmai.us/'));
module.exports = function () {
/**
* Create a new Danbooru API wrapper
*
* Optionally specify an alternate url or login details:
* - `login:api_key`
* - `http://safebooru.donmai.us`
* - `https://login:api_key@sonohara.donmai.us`
*
* @param {string} [conn] Connection customization string
*/
function _class() {
var conn = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
_classCallCheck(this, _class);
this.auth(conn);
}
/**
* Look up current username while optionally changing connection details
*
* Note that changing urls does not log out. To log out, pass a falsy value
* and ensure that this function returns undefined.
*
* @param {string | *} conn Connection string, like in constructor
* @returns {string} Current username
*/
_createClass(_class, [{
key: 'auth',
value: function auth(conn) {
var store = storage(this);
if (typeof conn !== 'undefined') {
var username = void 0,
password = void 0;
if (conn && /^https?:\/\//.test(conn)) {
var url = new URL(conn);username = url.username;
password = url.password;
Object.assign(url, {
username: '',
password: '',
hash: '',
search: '',
pathname: (url.pathname || '').replace(/\/*$/, '/')
});
if (url.href !== store.url.href) {
if (url.protocol === 'http:') store.module = http;else store.module = https;
if (url.href !== defaultUrl.href) store.url = url;else store.url = defaultUrl;
}
} else {
var match = /^(.*?):(.*)$/.exec(conn);
if (match) {
;
var _match = _slicedToArray(match, 3);
username = _match[1];
password = _match[2];
}
}
if (username && password) {
// store.authorization = `Basic ${btoa(`${username}:${password}`)}`
store.authParams = { login: username, api_key: password };
store.username = username;
} else if (!conn) {
// delete store.authorization
delete store.authParams;
delete store.username;
}
}
return store.username;
}
/**
* Get base url, or resolve a path
*
* @param {URL | string} [path] Path to resolve
* @returns {URL} Base url or resolved absolute url
*/
}, {
key: 'url',
value: function url() {
var path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
return new URL(path.toString().replace(/^\/*/, ''), storage(this).url);
}
/**
* Perform a web request
*
* May use 'request' or 'fetch', indicated by the first element in array
*
* @param {Object} [options] Request options
* @param {string} [options.method] HTTP request method
* @param {string} [options.path] Path to be appended to base path
* @param {Object} [options.headers] Request headers
* @param {*} [options.body] Request body
* @returns {Array} Function used, followed by return value
*/
}, {
key: 'request',
value: function request() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var _storage = storage(this),
module = _storage.module;
var method = options.method,
path = options.path,
body = options.body;
var url = this.url(path);
var _options$headers = options.headers,
headers = _options$headers === undefined ? {} : _options$headers;
if (module) {
var request = module.request({
protocol: url.protocol,
hostname: url.hostname,
port: url.port,
method: method,
path: url.pathname + url.search,
headers: headers
});
if (body) request.end(body);else request.end();
return ['request', request];
} else {
return ['fetch', fetch(url.href, { method: method, headers: headers, body: body })];
}
}
/**
* Perform a request and receive an object
*
* Only works with `application/json` data, and automatically appends `.json`
* to paths.
*
* Rejects on connection errors and resolves data object or parsing error.
* Returned objects have extra symbol key values:
* * `Danbooru.status` Status code from server
* * `Danbooru.data` Original string data
* * `Danbooru.headers` Response headers
*
* @param {string} path Path to be appended to base path
* @param {Object} [options] Request options
* @param {string} [options.method] HTTP request method
* @param {Object} [options.headers] Request headers
* @param {Object | Array} [options.query] Data to be added to path
* @param {Object | Array} [options.body] Data to be sent as request body
* @returns {Promise} Resolves to a json object or a parsing error
*/
}, {
key: 'json',
value: function json(path) {
var _this = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new Promise(function (resolve, reject) {
var method = options.method;
var query = options.query,
body = options.body;
var _options$headers2 = options.headers,
headers = _options$headers2 === undefined ? {} : _options$headers2;
var _storage2 = storage(_this),
authParams = _storage2.authParams;
if (authParams) {
if (query) {
query = _extends({}, authParams, query);
} else if (!method || method === 'GET') {
query = authParams;
} else if (body) {
body = _extends({}, authParams, body);
} else {
body = authParams;
}
}
var reqBody = body && JSON.stringify(body);
if (reqBody) {
headers = _extends({}, headers, {
'content-type': 'application/json'
});
}
var reqOptions = {
method: method,
headers: headers,
path: path + '.json' + util.queryString(query),
body: reqBody
};
var _request = _this.request(reqOptions),
_request2 = _slicedToArray(_request, 2),
reqType = _request2[0],
reqValue = _request2[1];
switch (reqType) {
case 'request':
reqValue.on('error', reject).on('response', function (response) {
var data = '';
var status = response.statusCode,
headers = response.headers;
response.setEncoding('utf8').on('data', function (chunk) {
return data += chunk;
}).on('end', function () {
return resolve({ data: data, status: status, headers: headers });
});
});
break;
case 'fetch':
reqValue.then(function (response) {
var status = response.status,
headers = response.headers;
return response.text().then(function (data) {
return { data: data, status: status, headers: headers };
});
}).then(resolve, reject);
break;
}
}).then(function (response) {
var _Object$assign;
var data = void 0;
try {
data = JSON.parse(response.data);
} catch (error) {
data = error;
}
Object.assign(data, (_Object$assign = {}, _defineProperty(_Object$assign, constants.status, response.status), _defineProperty(_Object$assign, constants.data, response.data), _defineProperty(_Object$assign, constants.headers, response.headers), _Object$assign));
return data;
});
}
/**
* Perform a json GET request
*
* @param {string} path Resource path
* @param {Object | Array} [query] Query string data
* @returns {Promise} Resolves to server response data
*/
}, {
key: 'get',
value: function get(path, query) {
return this.json(path, { query: query });
}
/**
* Perform a json POST request
*
* @param {string} path Resource path
* @param {Object | Array} [body] Request body data
* @returns {Promise} Resolves to server response data
*/
}, {
key: 'post',
value: function post(path, body) {
return this.json(path, { method: 'POST', body: body });
}
/**
* Perform a json PUT request
*
* @param {string} path Resource path
* @param {Object | Array} [body] Request body data
* @returns {Promise} Resolves to server response data
*/
}, {
key: 'put',
value: function put(path, body) {
return this.json(path, { method: 'PUT', body: body });
}
/**
* Perform a json DELETE request
*
* @param {string} path Resource path
* @param {Object | Array} [body] Request body data
* @returns {Promise} Resolves to server response data
*/
}, {
key: 'delete',
value: function _delete(path, body) {
return this.json(path, { method: 'DELETE', body: body });
}
}]);
return _class;
}();
function storage(key) {
var map = storage.map || (storage.map = new WeakMap());
if (map.has(key)) return map.get(key);
var value = { url: defaultUrl, module: https };
map.set(key, value);
return value;
}