/** * Szurubooru api client */ let axios = require('axios'); let { logger } = require('../../logging'); function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive } class SzurubooruClient { _randomSearchQueryValues = "type:image,animated,video sort:random"; _randomSearchUrlTemplate = "%s/posts/?offset=%s&limit=%d&query=%s"; constructor(url, username, token) { this.url = url; this.baseUrl = url.replace('/api', ''); this.username = username; this.token = token; this.updateRandomScope(); } getRandomSearchUrl(offset, limit, tags = []) { var searchQuery = this._randomSearchQueryValues; if (tags !== null && tags.length > 0) { searchQuery = this._randomSearchQueryValues + tags.join(" "); } return this.url + '/posts/?offset=' + offset + '&limit=' + limit + '&query=' + searchQuery; } /** * Determine a sane range of offset values * * @param {*} limit The content limit of a single page * @param {*} total The number of objects to search through */ getValidOffsetRange(limit, total) { let offsetOverflow = total % limit; var offsetCeiling = (Math.round(total / limit)); if (offsetOverflow === 0) { offsetCeiling -= 1; } return [0, offsetCeiling]; } /** * Determine a random offset based on the potential random search size * * Because Szurubooru doesn't randomize each sort:random search request, we must * manually calculate a random offset for each request to simulate randomness in the * posts returned. * * @param {*} self * @param {*} imageCount */ getRandomSearchParameters(imageCount = null) { let resultLimit = 10; var offsetRange = [0, 1]; if (imageCount === null) { offsetRange = this.getValidOffsetRange(resultLimit, this.randomImageCount); } else { offsetRange = this.getValidOffsetRange(resultLimit, imageCount); } return [resultLimit, getRandomInt(offsetRange[0], offsetRange[1])]; } async updateRandomScope() { let client = this; let target = this.getRandomSearchUrl(0, 1); await this.makeGetRequest(target).then((result) => { client.randomImageCount = result.total; }); } makeGetRequest(url) { logger.debug("Making get request to %s", url); return axios.get(url, { headers: { "Authorization": "Token " + Buffer.from(this.username + ':' + this.token).toString('base64'), "Accept": "application/json" } }).then((response) => { logger.debug("Recieved: %o", response.data); return response.data; }, (err) => { logger.error("Unexpected client error: %o", err); return null; }); return self._handle_response("GET", url, None, response) } /** * Return a random post matching the optionally provided tags. * * @param {*} self * @param {*} tags */ getRandomPost(tags = []) { let client = this; var resultLimit = 0; var randomSearchOffset = 0; if (tags.length === 0) { let randomSearchParameters = this.getRandomSearchParameters(); resultLimit = randomSearchParameters[0]; randomSearchOffset = randomSearchParameters[1]; } let searchUrl = this.getRandomSearchUrl(randomSearchOffset, resultLimit, tags); return this.makeGetRequest(searchUrl) .then((data) => { if (data !== null) { let limitSpace = Math.min(resultLimit, data.results.length - 1); let randomPost = data.results[getRandomInt(0, limitSpace)]; return client.baseUrl + '/' + randomPost.contentUrl; } else { return null } }, (err) => { }) } } exports.Client = SzurubooruClient;