UNPKG

media-grab

Version:

Grab random media from the internet

134 lines (133 loc) 5.22 kB
// Imports import MagicStrings from './magicStrings.js'; import * as helpers from './helpers.js'; import Reddit from './reddit/index.js'; /** * The possible states of the tool. * @private */ // Export a class called RedditGrabber /** * The super tool class. Holds a state and implements the execute command. */ export class RedditGrabber { /** * The possible states of the tool. * @return {{great: string, cool: string, awesome: string, swag: string}} */ // The constructor should set the username, password, appId, appSecret, and userAgent constructor(options) { // Ensure that options is an object with properties username, password, appId, appSecret else throw an error if (typeof options === 'object' && options?.username && options?.password && options?.appId && options?.appSecret) { this.username = options.username; this.password = options.password; this.appId = options.appId; this.appSecret = options.appSecret; this.userAgent = options.userAgent; } else { throw new Error('Invalid options'); } // Optional this.userAgent = options?.userAgent; this.subreddits = options?.subreddits || ['funny']; this.alwaysTypes = ['hot']; this.randomTypes = ['top']; this.times = ['t=year', 't=month']; this.mediaSources = ['redgifs', 'imgur', 'gfycat', 'v.redd.it', 'i.redd.it']; this.reddit = new Reddit({ username: this.username, password: this.password, appId: this.appId, appSecret: this.appSecret, userAgent: this.userAgent || 'Bot', }); } // Function that gets username /** * Validates a state. To be valid, the value needs to be part of the {tool.states}. * Throws an Error if invalid. Returns void / undefined if passed. * @param value The state candidate to be validated. * @throws if state is not a valid state */ getSubreddits() { return this.subreddits; } // Function that sets username /** * Validates and sets a new state value if given and returns the updated value. If no defined value is given it just returns the * current state value. * @param value {String|undefined} optional state to be set. * @return {String} the current state value */ setSubreddits(subreddits) { // Make sure subreddits is an array of strings if (subreddits.every((e) => typeof e === 'string')) { this.subreddits = subreddits; } else { throw new Error('Subreddits must be an array of strings'); } } // Main grabbit function async grabbit() { let redditSlugs = []; for (const subreddit of this.subreddits) { redditSlugs = redditSlugs.concat(helpers.getRedditSlug(subreddit, this.alwaysTypes[0], this.times[0]) // TODO make types/times configurable in the future ); } // Throw an error if there are no reddit slugs if (redditSlugs.length === 0) { throw new Error('No reddit slugs due to lack of subreddits'); } const allDemUrls = await Promise.all(redditSlugs.map(async (url) => { const res = await this.reddit.get(url); const after = res.data.after; const data = res?.data?.children .map((e) => { if (e?.data?.media?.reddit_video?.fallback_url) { return e?.data?.media?.reddit_video?.fallback_url; } else { return e?.data?.url_overridden_by_dest; } }) .filter((e) => typeof e === 'string') .filter((e) => { return this.mediaSources.some((source) => e.includes(source)); }); return { data, after }; })); // Filter out any string that doesnt contain any value form an array of strings const flattened = allDemUrls.map((e) => e.data).flat(); // Get a random one let theChosenOne = helpers.getRandomIndex(flattened); // Check if the chosen one is a valid url else get another one (5 tries) let start = 0; while (!helpers.isValidURL(theChosenOne) && start < 5) { theChosenOne = helpers.getRandomIndex(flattened); start++; } // Final check and package response data const baseRespData = { url: theChosenOne, subreddits: this.subreddits, }; if (helpers.isValidURL(theChosenOne)) { return helpers.createResponse(true, { ...baseRespData, message: MagicStrings.SUCCESS_MESSAGE, }); } else { return helpers.createResponse(false, { ...baseRespData, message: MagicStrings.ERROR_MESSAGE, }); } } }