async def reddit_pages(self, ctx, subreddit, limit: int = 5): """Gives you a paginated menu of any subreddit""" posts = [] u = '\u200b' async with self.bot.session.get(f"https://www.reddit.com/r/{subreddit}/hot.json", params={'limit': 100}) as r: res = await r.json() for i in res['data']['children']: if i['data']['over_18'] and not ctx.channel.is_nsfw(): raise commands.NSFWChannelRequired(ctx.channel) posts.append(i['data']) counter = 0 embeds = [] async with ctx.typing(): for s in random.sample(posts, len(posts)): embed = discord.Embed(title=str(s['title']), colour=self.bot.colour, url=f"https://reddit.com/{s['permalink']}") embed.set_author(name=s['author']) embed.set_footer(text=f"{s['upvote_ratio'] * 100:,}% upvote ratio | posted to r/{s['subreddit']}") if s['is_self']: embed.description = f"{s['selftext'].replace('**', f'{u}')}\n{self.up} **{s['score']:,}** :speech_balloon: **{s['num_comments']:,}** {self.share} **{s['num_crossposts']:,}** :medal: **{s['total_awards_received']}**" else: embed.set_image(url=s['url'].split("?")[0]) embed.description = f"{self.up} **{s['score']:,}** :speech_balloon: **{s['num_comments']:,}** {self.share} **{s['num_crossposts']:,}** :medal: **{s['total_awards_received']}**" embeds.append(embed) counter += 1 if counter == limit: break else: continue menu = paginator.CatchAllMenu(paginator.EmbedSource(embeds)) menu.add_info_fields({self.up: "How many upvotes the post has", "💬": "How many comments the post has", self.share: "How many shares/cross-posts the post has", ":medal:": "How many awards the post has"}) await menu.start(ctx)
async def post(self, ctx, subreddit, sort='hot'): posts = [] sorts = ['new', 'hot', 'top', 'rising', 'controversial'] if sort not in sorts: raise commands.BadArgument( f"that isn't a valid sort! Valid sorts include {', '.join(sorts)}." ) async with ctx.typing(): try: s = random.choice(await self.get_post_data(subreddit, sort)) except IndexError: raise commands.BadArgument('subreddit not found!') embed = discord.Embed(title=str(s['title']), colour=self.bot.colour, url=f"https://reddit.com/{s['permalink']}") embed.set_author(name=s['author']) embed.set_footer( text= f"r/{s['subreddit']} • {s['upvote_ratio'] * 100:,}% upvote ratio" ) embed.timestamp = datetime.datetime.utcfromtimestamp(s['created']) if s['is_self']: embed.description = f"{s['selftext']}\n{self.up} **{s['score']:,}** :speech_balloon: **{s['num_comments']:,}** {self.share} **{s['num_crossposts']:,}** :medal: **{s['total_awards_received']}**" else: embed.set_image(url=s['url']) embed.description = f"{self.up} **{s['score']:,}** :speech_balloon: **{s['num_comments']:,}** {self.share} **{s['num_crossposts']:,}** :medal: **{s['total_awards_received']}**" if s['over_18'] and not ctx.channel.is_nsfw(): raise commands.NSFWChannelRequired(ctx.channel) return await ctx.send(embed=embed)
async def _perform_search(self, requester: str, channel: discord.TextChannel, subreddit: str, sort_by: str): """ Performs the search for queries with aiohttp. Returns 10 items. """ async with self.bot.session.get( f"https://reddit.com/r/{subreddit}/about.json", headers=self.headers) as subr_top_resp: subr_deets = await subr_top_resp.json() if "data" not in subr_deets: raise commands.BadArgument("Subreddit not found.") if subr_deets["data"].get("over18", None) and not channel.is_nsfw(): raise commands.NSFWChannelRequired(channel) params = {"t": "all" if sort_by == "top" else ""} async with self.bot.session.get( f"https://reddit.com/r/{subreddit}/{sort_by}.json", headers=self.headers, params=params, ) as subr_resp: subreddit_json = await subr_resp.json() subreddit_pages = [] common_img_exts = (".jpg", ".jpeg", ".png", ".gif") idx = 0 for post_data in subreddit_json["data"]["children"]: image_url = None video_url = None if idx == 20: break _short = post_data["data"] if _short.get("stickied", False) or (_short.get("over_18", False) and not channel.is_nsfw()): idx += 1 continue image_url = (_short["url"] if _short["url"].endswith(common_img_exts) else None) if "v.redd.it" in _short["url"]: image_url = _short["thumbnail"] video_teriary = _short.get("media", None) if video_teriary: video_url = _short["url"] else: continue subreddit_pages.append( SubredditPost(_short, image_link=image_url, video_link=video_url)) idx += 1 return self._gen_embeds(requester, subreddit_pages[:30])
async def thonk(self, ctx): async with ctx.typing(): s = random.choice(await self.get_post_data('showerthoughts', 'top')) embed = discord.Embed(title=str(s['title']), colour=self.bot.colour, url=f"https://reddit.com/{s['permalink']}", description=f"{self.up} **{s['score']:,}** :speech_balloon: **{s['num_comments']:,}** {self.share} **{s['num_crossposts']:,}** :medal: **{s['total_awards_received']}**") embed.timestamp = datetime.datetime.utcfromtimestamp(s['created']) embed.set_author(name=s['author']) embed.set_footer(text=f"r/{s['subreddit']} • {s['upvote_ratio'] * 100:,}% upvote ratio") if s['over_18'] and not ctx.channel.is_nsfw(): raise commands.NSFWChannelRequired(ctx.channel) return await ctx.send(embed=embed)
async def meme(self, ctx): subreddit = random.choice(['memes', 'meme', 'dankmemes', 'okbuddyretard', 'memeeconomy', 'dankexchange', 'pewdiepiesubmissions', 'wholesomememes']) async with ctx.typing(): s = random.choice(await self.get_post_data(subreddit, 'hot')) embed = discord.Embed(title=str(s['title']), colour=self.bot.colour, url=f"https://reddit.com/{s['permalink']}", description=f"{self.up} **{s['score']:,}** :speech_balloon: **{s['num_comments']:,}** {self.share} **{s['num_crossposts']:,}** :medal: **{s['total_awards_received']}**") embed.timestamp = datetime.datetime.utcfromtimestamp(s['created']) embed.set_author(name=s['author']) embed.set_footer(text=f"r/{s['subreddit']} • {s['upvote_ratio'] * 100:,}% upvote ratio") embed.set_image(url=s['url']) if s['over_18'] and not ctx.channel.is_nsfw(): raise commands.NSFWChannelRequired(ctx.channel) return await ctx.send(embed=embed)
async def interaction_response_metacommand(self, ctx:utils.Context, users:commands.Greedy[discord.Member]): """Handles pinging out the responses for a given interaction. Users cannot call this.""" # Get metadata metadata = ctx.response_metadata[0] command_name = metadata['command_name'] # Get command enabled if metadata['enabled'] is False: raise utils.errors.DisabledCustomCommand() # Get command nsfw if metadata['nsfw'] and ctx.channel.is_nsfw is False: raise commands.NSFWChannelRequired() # Check mention count max_mentions = metadata['max_mentions'] min_mentions = metadata['min_mentions'] if len(users) > max_mentions: return await ctx.send("You've mentioned too many users for this command.") # TODO raise custom error if len(users) < min_mentions: return await ctx.send("You've not mentioned enough users for this command.") # TODO raise custom error # Get valid responses async with self.bot.database() as db: response = await db("SELECT response FROM command_responses WHERE command_name=$1 AND guild_id=$2 AND user_mention_count=$3 ORDER BY RANDOM() LIMIT 1", command_name, ctx.guild.id, len(users)) if not response: return await ctx.send(f"There are no responses with {len(users)} user arguments set on the website.") # Build command response def argument_replacer(match): """Replaces the argument of the group with a user mention""" if match.group(2): return users[int(match.group(2)) - 1].mention if match.group(1) == 'user': return users[0].mention return ctx.author.mention # Output text = response[0]['response'] await ctx.send(self.ARGUMENT_REPLACEMENT_REGEX.sub(argument_replacer, text))
async def get_subreddit_embed(self, ctx: MyContext, subreddit: str): min_creation = ctx.message.created_at - datetime.timedelta(hours=3) subinfo = await self.fetch_subreddit_info(subreddit) if subinfo['over18'] and not (ctx.guild and ctx.channel.is_nsfw()): raise commands.NSFWChannelRequired(ctx.channel) def check(post): return (post['approved_at_utc'] or datetime.datetime.fromtimestamp(post['created_utc']) <= min_creation) \ and post['score'] >= 10 \ and (not post['over_18'] or not (ctx.guild and ctx.channel.is_nsfw())) \ and not post['spoiler'] for attempt in range(10): child = await self.fetch_random_reddit_post(subreddit) if not check(child): continue if child.get('url_overridden_by_dest') and not child.get( 'is_video') and not child.get('media'): break else: raise NoPostsFound(subreddit) title: str = child['title'] sub_prefixed: str = child['subreddit_name_prefixed'] author: str = child['author'] permalink: str = child['permalink'] score: int = child['score'] upvote_emoji: discord.Emoji = discord.utils.get(self.bot.emojis, name='upvote') embed = discord.Embed( title=f'/{sub_prefixed}', description=f'[{title}](https://reddit.com{permalink})\n' f'Score: {score}{upvote_emoji}', url=f'https://reddit.com/{sub_prefixed}', colour=discord.Colour.dark_orange(), timestamp=datetime.datetime.fromtimestamp(child['created_utc'])) embed.set_image(url=child['url']) embed.set_author(name=f'/u/{author}', url=f'https://reddit.com/u/{author}') return embed
async def subreddit(self, ctx, subreddit): try: async with ctx.typing(), self.bot.session.get( f"https://reddit.com/r/{subreddit}/about/.json" ) as r, self.bot.session.get( f"https://www.reddit.com/r/{subreddit}/about/moderators.json" ) as r1: res = await r.json() resp = await r1.json() data = res['data'] icon = data['community_icon'].split("?")[0] banner = data['banner_background_image'].split("?")[0] embed = discord.Embed( description= f"{data['public_description']}\n**{data['subscribers']:,}** subscribers | **{data['active_user_count']:,}** active users", colour=self.bot.colour) embed.title = data['display_name_prefixed'] embed.url = f"https://reddit.com/r/{subreddit}" embed.set_thumbnail(url=icon) embed.description += f'\n<:asset:734531316741046283> [Icon URL]({str(icon)}) | [Banner URL]({str(banner)})' daba = resp['data'] mods = [i for i in daba['children']] embed.add_field( name=f"Mods (Total {len(mods)})", value="\n".join([ f"[{mod['name']}](https://reddit.com/user/{mod['name']})" for mod in mods[:10] ])) embed.set_footer( text= f"Subreddit created {humanize.naturaltime(datetime.datetime.utcnow() - datetime.datetime.utcfromtimestamp(data['created_utc']))}" ) if data['over18'] and not ctx.channel.is_nsfw(): raise commands.NSFWChannelRequired(ctx.channel) return await ctx.send(embed=embed) except KeyError: raise commands.BadArgument(f'subreddit {subreddit} not found.')
async def reddit(self, ctx: NewCtx, sub: str = 'memes', sort: str = 'hot'): """Gets the <sub>reddits <amount> of posts sorted by <method>""" if sort.lower() not in ("top", "hot", "best", "controversial", "new", "rising"): return await ctx.send("Not a valid sort-by type.") PostObj = namedtuple('PostObj', [ 'title', 'self_text', 'url', 'author', 'image_link', 'video_link', 'upvotes', 'comment_count', 'subreddit' ]) posts = set() subr_url = f"https://www.reddit.com/r/{sub}/about.json" base_url = f"https://www.reddit.com/r/{sub}/{sort}.json" async with self.bot.session.get( subr_url, headers={"User-Agent": "Yoink discord bot"}) as subr_resp: subr_deets = await subr_resp.json() if 'data' not in subr_deets: raise commands.BadArgument("Subreddit does not exist.") if subr_deets['data'].get('over18', None) and not ctx.channel.is_nsfw(): raise commands.NSFWChannelRequired(ctx.channel) async with self.bot.session.get(base_url) as res: page_json = await res.json() idx = 0 for post_data in page_json['data']['children']: image_url = None video_url = None if idx == 20: break post = post_data['data'] if post['stickied'] or (post['over_18'] and not ctx.channel.is_nsfw()): idx += 1 continue title = shorten(post['title'], width=250) self_text = shorten(post['selftext'], width=1500) url = f"https://www.reddit.com{post['permalink']}" author = post['author'] image_url = post['url'] if post['url'].endswith( (".jpg", ".png", ".jpeg", ".gif", ".webp")) else None if "v.redd.it" in post['url']: image_url = post['thumbnail'] if post.get("media", None): video_url = post['url'] else: continue upvotes = post['score'] comment_count = post['num_comments'] subreddit = post['subreddit'] _post = PostObj(title=title, self_text=self_text, url=url, author=author, image_link=image_url, video_link=video_url, upvotes=upvotes, comment_count=comment_count, subreddit=subreddit) posts.add(_post) embeds = self._gen_embeds(ctx.author, list(posts)) pages = menus.MenuPages(PagedEmbedMenu(embeds)) await pages.start(ctx)
def predicate(ctx): if isinstance(ctx.channel, DMChannel): return True if ctx.channel.is_nsfw(): return True raise commands.NSFWChannelRequired(ctx.channel)