UNPKG

danbooru

Version:
350 lines (286 loc) 11.7 kB
'use strict'; 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; }