async def on_message(self, msg: Message): if str(self.bot.user.id) in msg.content: ts = tz.localize(datetime.now()).strftime("%b. %d, %Y %I:%M %p") author = msg.author display_name = f' ({author.display_name})' if author.display_name != author.name else '' em = Embed(title=f"{msg.guild}: #{msg.channel} at {ts}", description=msg.content, color=author.colour) em.set_author( name=f"{author.name}#{author.discriminator}{display_name}", icon_url=author.avatar_url_as(format="png")) await self.notifchannel.send(msg.jump_url, embed=em)
def em_base(self, user: Union[Member, User], log_title: str, color: int) -> Embed: """Do basic formatting on the embed""" em = Embed(description=f"*{log_title}*", color=color) user_repr = f"{user.name}#{user.discriminator} (ID: {user.id})" em.set_author(name=user_repr, icon_url=user.avatar_url) em.set_footer(text=self._get_timestamp()) return em
async def user(self, ctx: Context, *, user: str = None): """User Selects a GitHub user account and shows a brief of the profile. `[p]gh user <username>` will select a user account `[p]gh user self` will select your user account `[p]gh user` will display the currently selected user""" try: if user == "self": self.user = user = self.gh_client.get_user() elif user: self.user = user = self.gh_client.get_user(user) else: if self.user: user = self.user else: return await self.bot.send_help_for( ctx.command, "No account is currently selected." ) if self.repo.owner.name != self.user.name: self.repo = None repos = len(list(user.get_repos())) gists = len(list(user.get_gists())) stars = len(list(user.get_gists())) em = Embed( title=f"{user.login}'s Public GitHub Profile", description=f"*\"{user.bio}\"*\n\n" f"{Emoji.repo} [Repositories]({user.html_url}?tab=repositories): {repos}\n" f"{Emoji.gist} [Gists](https://gist.github.com/{user.login}): {gists}\n" f"{Emoji.star} [Starred Repositories]({user.html_url}?tab=stars): {stars}", color=Colour.green() ) em.set_author(name=user.name, url=user.html_url, icon_url=user.avatar_url) except: em = Embed( title="GitHub: Error", description="Unable to load user or user not found", color=Colour.red() ) await ctx.send(embed=em)
class SearchResultsBrowser: def __init__(self, bot: Bot, ctx: Context, results: List[Doujin], **kwargs): """Class to create and run a browser from NHentai-API `results` - obtained from nhentai_api.search(query) `msg` - optional message that the bot owns to edit, otherwise created """ self.bot = bot self.ctx = ctx self.doujins = results self.index = 0 self.lolicon_allowed = kwargs.pop("lolicon_allowed", False) self.minimal_details = kwargs.pop("minimal_details", True) self.name = kwargs.pop("name", "Search Results") self.active_message: Message = kwargs.pop("msg", None) self.am_embed: Embed = Embed() self.is_zoomed = False self.language = kwargs.pop("user_language", "eng") async def update_browser(self, ctx): message_part = [] for ind, dj in enumerate(self.doujins): try: if ind == self.index and int(dj.id) in self.bot.user_data['UserData'][str(ctx.author.id)]['Lists']['Built-in']["Favorites|*n*|fav"]: symbol = '🟩' elif ind == self.index: symbol='🟥' elif int(dj.id) in self.bot.user_data['UserData'][str(ctx.author.id)]['Lists']['Built-in']["Favorites|*n*|fav"]: symbol = '🟦' else: symbol='⬛' except KeyError: symbol='⬛' tags = [tag.name for tag in dj.tags if tag.type == "tag"] if any([tag in restricted_tags for tag in tags]) and ctx.guild and not self.lolicon_allowed: message_part.append( f"{'**' if ind == self.index else ''}" f"`{symbol} {str(ind+1).ljust(2)}` | {localization[self.language]['search_doujins']['contains_restricted_tags']}" f"{'**' if ind == self.index else ''}") else: message_part.append( f"{'**' if ind == self.index else ''}" f"`{symbol} {str(ind+1).ljust(2)}` | " f"__`{str(dj.id).ljust(7)}`__ | " f"{language_to_flag(dj.languages)} | " f"{shorten(dj.title.pretty, width=40, placeholder='...')}" f"{'**' if ind == self.index else ''}") doujin = self.doujins[self.index] previous_emb = deepcopy(self.am_embed) #self.active_message.embeds[0] = self.am_embed self.am_embed = Embed( title=self.name, description=f"\n"+('\n'.join(message_part))+"\n\n▌█████████████████▓▓▒▒░░") nhentai = NHentai() tags = [tag.name for tag in doujin.tags if tag.type == "tag"] if any([tag in restricted_tags for tag in tags]) and ctx.guild and not self.lolicon_allowed: self.am_embed.add_field( name=localization[self.language]['results_browser']['forbidden']['title'], inline=False, value=localization[self.language]['results_browser']['forbidden']['description'] ).set_footer( text=f"⭐ N/A" ) doujin.cover.src = str(self.bot.user.avatar.url) else: if self.minimal_details: self.am_embed.add_field( name=localization[self.language]['results_browser']['minimal_details'], inline=False, value= f"ID: `{doujin.id}`\n" f"{localization[self.language]['doujin_info']['fields']['title']}: {language_to_flag(doujin.languages)} `{shorten(doujin.title.pretty, width=256, placeholder='...')}`\n" f"{localization[self.language]['doujin_info']['fields']['artists']}: `{', '.join([tag.name for tag in doujin.artists]) if doujin.artists else localization[self.language]['doujin_info']['fields']['not_provided']}`\n" f"{localization[self.language]['doujin_info']['fields']['characters']}: `{', '.join([tag.name for tag in doujin.characters]) if doujin.characters else localization[self.language]['doujin_info']['fields']['original']}`\n" f"{localization[self.language]['doujin_info']['fields']['parodies']}: `{', '.join([tag.name for tag in doujin.parodies]) if doujin.parodies else localization[self.language]['doujin_info']['fields']['original']}`\n" f"{localization[self.language]['doujin_info']['fields']['tags']}:\n||`{shorten(str(', '.join([tag.name for tag in doujin.tags if tag.type == 'tag']) if [tag.name for tag in doujin.tags if tag.type == 'tag'] else localization[self.language]['doujin_info']['fields']['not_provided']), width=950, placeholder='...')}`||" ).set_footer( text=f"{localization[self.language]['doujin_info']['sfw']}") self.am_embed.set_author( name=f"NHentai", icon_url="https://cdn.discordapp.com/emojis/845298862184726538.png?v=1") self.am_embed.set_thumbnail(url=Embed.Empty) self.am_embed.set_image(url=Embed.Empty) else: self.am_embed.add_field( name=localization[self.language]['doujin_info']['fields']['title'], inline=False, value=f"`{shorten(doujin.title.pretty, width=256, placeholder='...')}`" ).add_field( inline=False, name=localization[self.language]['doujin_info']['fields']['id/pages'], value=f"`{doujin.id}` - `{doujin.total_pages}`" ).add_field( inline=False, name=localization[self.language]['doujin_info']['fields']['date_uploaded'], value=f"<t:{int(doujin.upload_at.timestamp())}>" ).add_field( inline=False, name=localization[self.language]['doujin_info']['fields']['languages'], value=f"{language_to_flag(doujin.languages)} `{', '.join([localization[self.language]['doujin_info']['fields']['language_names'][tag.name] for tag in doujin.languages]) if doujin.languages else localization[self.language]['doujin_info']['fields']['not_provided']}`" ).add_field( inline=False, name=localization[self.language]['doujin_info']['fields']['artists'], value=f"`{', '.join([tag.name for tag in doujin.artists]) if doujin.artists else localization[self.language]['doujin_info']['fields']['not_provided']}`" ).add_field( inline=False, name=localization[self.language]['doujin_info']['fields']['characters'], value=f"`{', '.join([tag.name for tag in doujin.characters]) if doujin.characters else localization[self.language]['doujin_info']['fields']['original']}`" ).add_field( inline=False, name=localization[self.language]['doujin_info']['fields']['parodies'], value=f"`{', '.join([tag.name for tag in doujin.parodies]) if doujin.parodies else localization[self.language]['doujin_info']['fields']['original']}`" ).set_footer( text=f"⭐ {doujin.total_favorites}" ) # Doujin count for tags tags_list = [] for tag in [tag for tag in doujin.tags if tag.type == "tag"]: count = tag.count parse_count = list(str(count)) if len(parse_count) < 4: tags_list.append(f"{localization[self.language]['fields']['tag_names'][tag.name] if tag.name in localization[self.language]['doujin_info']['fields']['tag_names'] else tag.name}[{count}]") elif len(parse_count) >= 4 and len(parse_count) <= 6: count = count/1000 tags_list.append(f"{localization[self.language]['fields']['tag_names'][tag.name] if tag.name in localization[self.language]['doujin_info']['fields']['tag_names'] else tag.name}[{round(count, 1)}k]") elif len(parse_count) > 7: count = count/1000000 tags_list.append(f"{localization[self.language]['fields']['tag_names'][tag.name] if tag.name in localization[self.language]['doujin_info']['fields']['tag_names'] else tag.name}[{round(count, 2)}m]") self.am_embed.add_field( inline=False, name=localization[self.language]["doujin_info"]["fields"]["tags"], value=f"```{shorten(str(', '.join(tags_list) if tags_list else localization[self.language]['doujin_info']['fields']['not_provided']), width=1018, placeholder='...')}```" ) self.am_embed.set_author( name=f"NHentai", url=f"https://nhentai.net/g/{doujin.id}/", icon_url="https://cdn.discordapp.com/emojis/845298862184726538.png?v=1") if self.is_zoomed: self.am_embed.set_image(url=doujin.cover.src) self.am_embed.set_thumbnail(url=Embed.Empty) elif not self.is_zoomed: self.am_embed.set_thumbnail(url=doujin.cover.src) self.am_embed.set_image(url=Embed.Empty) if not self.active_message: self.active_message = await ctx.send("...") class SRBControls(ui.View): def __init__(self, bot, ctx, parent): super().__init__(timeout=60) self.value = 0 self.bot = bot self.ctx = ctx self.parent = parent @ui.button(emoji=self.bot.get_emoji(853800909108936754), style=ButtonStyle.secondary, custom_id="up") async def up_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() if self.parent.index > 0: self.parent.index -= 1 elif self.parent.index == 0: self.parent.index = len(self.parent.doujins)-1 self.stop() @ui.button(emoji=self.bot.get_emoji(853800909276315678), style=ButtonStyle.secondary, custom_id="down") async def down_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() if self.parent.index < len(self.parent.doujins)-1: self.parent.index += 1 elif self.parent.index == len(self.parent.doujins)-1: self.parent.index = 0 self.stop() @ui.button(emoji=self.bot.get_emoji(853668227212902410), style=ButtonStyle.secondary, custom_id="select") async def select_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() conf = await self.ctx.send(embed=Embed( description=localization[self.parent.language]['results_browser']['buttons']['select'])) while True: try: m = await self.bot.wait_for("message", timeout=15, bypass_cooldown=True, check=lambda m: m.author.id == self.ctx.author.id and m.channel.id == self.ctx.channel.id) except TimeoutError: await conf.delete() self.stop() return else: with suppress(Forbidden): await m.delete() if m.content == "n-cancel": await conf.delete() self.stop() return if is_int(m.content) and (int(m.content)-1) in range(0, len(self.parent.doujins)): await conf.delete() self.parent.index = int(m.content)-1 self.stop() return else: continue self.stop() # unreachable, but just to be consistant with design @ui.button(emoji=self.bot.get_emoji(853668227175546952), style=ButtonStyle.secondary, custom_id="stop") async def stop_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() message_part = [] for ind, dj in enumerate(self.parent.doujins): tags = [tag.name for tag in dj.tags if tag.type == "tag"] if any([tag in restricted_tags for tag in tags]) and self.ctx.guild and not self.parent.lolicon_allowed: message_part.append(localization[self.parent.language]['search_doujins']['contains_restricted_tags']) else: message_part.append( f"__`{str(dj.id).ljust(7)}`__ | " f"{language_to_flag(dj.languages)} | " f"{shorten(dj.title.pretty, width=50, placeholder='...')}") self.parent.am_embed = Embed( title=self.parent.name, description=f"\n"+('\n'.join(message_part))) self.parent.am_embed.set_author( name="NHentai", url=f"https://nhentai.net/", icon_url="https://cdn.discordapp.com/emojis/845298862184726538.png?v=1") self.parent.am_embed.set_thumbnail(url=Embed.Empty) self.parent.am_embed.set_image(url=Embed.Empty) await self.parent.active_message.edit(embed=self.parent.am_embed, view=None) self.value = 1 self.stop() if not self.ctx.guild or (self.ctx.guild and not all([ self.ctx.guild.me.guild_permissions.manage_channels, self.ctx.guild.me.guild_permissions.manage_roles, self.ctx.guild.me.guild_permissions.manage_messages])): @ui.button(emoji=self.bot.get_emoji(853684136379416616), style=ButtonStyle.secondary, custom_id="read", disabled=True) async def read_button(self, button, interaction): return else: @ui.button(emoji=self.bot.get_emoji(853684136379416616), style=ButtonStyle.secondary, custom_id="read", disabled=self.minimal_details) async def read_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() tags = [tag.name for tag in self.parent.doujins[self.parent.index].tags if tag.type == "tag"] if any([tag in restricted_tags for tag in tags]) and self.ctx.guild and not self.parent.lolicon_allowed: self.stop() return message_part = [] for ind, dj in enumerate(self.parent.doujins): tags = [tag.name for tag in dj.tags if tag.type == "tag"] if any([tag in restricted_tags for tag in tags]) and self.ctx.guild and not self.parent.lolicon_allowed: message_part.append(localization[self.parent.language]['search_doujins']['contains_restricted_tags']) else: message_part.append( f"{'**' if ind == self.parent.index else ''}" f"__`{str(dj.id).ljust(7)}`__ | " f"{language_to_flag(dj.languages)} | " f"{shorten(dj.title.pretty, width=50, placeholder='...')}" f"{'**' if ind == self.parent.index else ''}") self.parent.am_embed = Embed( title=self.parent.name, description=f"\n"+('\n'.join(message_part))) self.parent.am_embed.set_author( name="NHentai", url=f"https://nhentai.net/", icon_url="https://cdn.discordapp.com/emojis/845298862184726538.png?v=1") self.parent.am_embed.set_thumbnail(url=Embed.Empty) self.parent.am_embed.set_image(url=Embed.Empty) await self.parent.active_message.edit(embed=self.parent.am_embed, view=None) self.value = 1 self.stop() doujin = self.parent.doujins[self.parent.index] if str(doujin.id) in self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']["Bookmarks|*n*|bm"]: page = self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']["Bookmarks|*n*|bm"][str(doujin.id)] else: page = 0 session = ImagePageReader(self.bot, self.ctx, doujin.images, doujin.title.pretty, str(doujin.id), starting_page=page) response = await session.setup() if response: await session.start() else: await self.parent.active_message.edit(embed=self.parent.am_embed) @ui.button(emoji=self.bot.get_emoji(853684136433942560), style=ButtonStyle.secondary, custom_id="zoom", disabled=self.minimal_details) async def zoom_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() self.parent.is_zoomed = not self.parent.is_zoomed self.stop() @ui.button(emoji=self.bot.get_emoji(853668227205038090), style=ButtonStyle.secondary, custom_id="readlater") async def readlater_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() if len(self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["Read Later|*n*|rl"]) >= 25: await self.ctx.send( embed=Embed( color=0xff0000, description=localization[self.parent.language]['results_browser']['buttons']['read_later_full'] ), delete_after=5) self.stop() return if str(self.parent.doujins[self.parent.index].id) not in self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["Read Later|*n*|rl"]: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["Read Later|*n*|rl"].append(str(self.parent.doujins[self.parent.index].id)) await self.ctx.send( embed=Embed( description=localization[self.parent.language]['results_browser']['buttons']['add_to_read_later'].format(code=self.parent.doujins[self.parent.index].id) ), delete_after=5) else: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["Read Later|*n*|rl"].remove(str(self.parent.doujins[self.parent.index].id)) await self.ctx.send( embed=Embed( description=localization[self.parent.language]['results_browser']['buttons']['remove_from_read_later'].format(code=self.parent.doujins[self.parent.index].id) ), delete_after=5) self.stop() async def on_timeout(self): message_part = [] for ind, dj in enumerate(self.parent.doujins): tags = [tag.name for tag in dj.tags if tag.type == "tag"] if any([tag in restricted_tags for tag in tags]) and self.ctx.guild and not self.parent.lolicon_allowed: message_part.append(localization[self.parent.language]['search_doujins']['contains_restricted_tags']) else: message_part.append( f"__`{str(dj.id).ljust(7)}`__ | " f"{language_to_flag(dj.languages)} | " f"{shorten(dj.title.pretty, width=50, placeholder='...')}") self.parent.am_embed = Embed( title=self.parent.name, description=f"\n"+('\n'.join(message_part))) self.parent.am_embed.set_author( name="NHentai", url=f"https://nhentai.net/", icon_url="https://cdn.discordapp.com/emojis/845298862184726538.png?v=1") self.parent.am_embed.set_thumbnail(url=Embed.Empty) self.parent.am_embed.set_image(url=Embed.Empty) await self.parent.active_message.edit(embed=self.parent.am_embed, view=None) self.value = 1 self.stop() view = SRBControls(self.bot, self.ctx, self) view.add_item(ui.Button(label=localization[self.language]['results_browser']['buttons']['support_server'], style=ButtonStyle.link, url="https://discord.gg/DJ4wdsRYy2")) await self.active_message.edit(embed=self.am_embed, view=view) await view.wait() return view.value async def start(self, ctx): """Initial start of the result browser.""" view_exit_code = 0 while view_exit_code == 0: view_exit_code = await self.update_browser(self.ctx)
class ImagePageReader: def __init__(self, bot: Bot, ctx: Context, images:list, name:str, code:str, **kwargs): """Create and run a reader based on pages from a Doujin. To work for any purpose, this class needs a few changes. `bot` - The Bot class created on initialization `ctx` - Context used `images` The list of image urls to use `name` - Title of the reader `code` - Book/Item ID `**kwargs` - Further keyword arguments if need be -- `current_page` - The starting page as an integer. Defaults to `0` """ self.bot = bot self.ctx: Context = ctx self.images: list = images self.name: str = name self.code: str = code self.current_page: int = kwargs.pop("starting_page", 0) self.active_message: Message = None self.am_embed: Embed = None self.am_channel: TextChannel = None self.is_paused: bool = False self.on_bookmarked_page: bool = False self.language = kwargs.pop("user_language", "eng") async def update(self, ctx): if self.code in self.bot.user_data['UserData'][str(ctx.author.id)]['Lists']['Built-in']['Bookmarks|*n*|bm'] and \ self.current_page == self.bot.user_data['UserData'][str(ctx.author.id)]['Lists']['Built-in']['Bookmarks|*n*|bm'][self.code]: self.on_bookmarked_page = True else: self.on_bookmarked_page = False self.am_embed.description = f"<:nprev:853668227124953159>{'<:nfini:853670159310913576>' if self.current_page == (len(self.images)-1) else '<:nnext:853668227207790602>'} {localization[self.language]['page_reader']['description']['previous']} | {localization[self.language]['page_reader']['description']['finish'] if self.current_page == (len(self.images)-1) else localization[self.language]['page_reader']['description']['next']}\n" \ f"<:nsele:853668227212902410><:nstop:853668227175546952> {localization[self.language]['page_reader']['description']['select']} | {localization[self.language]['page_reader']['description']['stop']}\n" \ f"<:npaus:853668227234529300><:nbook:853668227205038090> {localization[self.language]['page_reader']['description']['pause']} | {localization[self.language]['page_reader']['description']['bookmark'] if not self.on_bookmarked_page else localization[self.language]['page_reader']['description']['unbookmark']}\n" self.am_embed.set_image(url=self.images[self.current_page].src) self.am_embed.set_footer(text=localization[self.language]['page_reader']['footer'].format(current=self.current_page+1, total=len(self.images), bookmark='🔖' if self.on_bookmarked_page else '')) if self.bot.user_data["UserData"][str(ctx.author.id)]["Settings"]["ThumbnailPreference"] == 0: self.am_embed.set_thumbnail(url=self.images[self.current_page+1].src if (self.current_page+1) in range(0, len(self.images)) else Embed.Empty) if self.bot.user_data["UserData"][str(ctx.author.id)]["Settings"]["ThumbnailPreference"] == 1: self.am_embed.set_thumbnail(url=self.images[self.current_page-1].src if (self.current_page-1) in range(0, len(self.images)) else Embed.Empty) if self.bot.user_data["UserData"][str(ctx.author.id)]["Settings"]["ThumbnailPreference"] == 2: self.am_embed.set_thumbnail(url=Embed.Empty) thumbnail_buttons = { 0: self.bot.get_emoji(903121521571168276), 1: self.bot.get_emoji(903122915619373106), 2: self.bot.get_emoji(903121521621491732) } class IPRControls(ui.View): def __init__(self, bot, ctx, parent): super().__init__(timeout=300) self.value = 0 self.bot = bot self.ctx = ctx self.parent = parent @ui.button(emoji=self.bot.get_emoji(853668227124953159), style=ButtonStyle.secondary, custom_id="previous", disabled=self.current_page==0) async def previous_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() if self.parent.current_page == 0: # Not allowed to go behind zero return self.stop() else: self.parent.current_page = self.parent.current_page - 1 self.stop() @ui.button(emoji=self.bot.get_emoji(853670159310913576) if self.current_page+1==len(self.images) else self.bot.get_emoji(853668227207790602), style=ButtonStyle.secondary, custom_id="next") async def next_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() self.parent.current_page = self.parent.current_page + 1 if self.parent.current_page > (len(self.parent.images)-1): # Finish the doujin if at last page self.parent.am_embed.set_image(url=Embed.Empty) self.parent.am_embed.set_thumbnail(url=Embed.Empty) self.parent.am_embed.description=localization[self.parent.language]['page_reader']['finished'] await self.parent.active_message.edit(embed=self.parent.am_embed, view=None) if self.parent.code in self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Read Later|*n*|rl']: self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Read Later|*n*|rl'].remove(self.parent.code) await sleep(2) await self.parent.active_message.edit(content=f"{self.parent.bot.get_emoji(810936543401213953)} {localization[self.parent.language]['page_reader']['closing']}", embed=None) await sleep(1) await self.parent.am_channel.delete() self.value = 1 self.stop() else: self.stop() @ui.button(emoji=self.bot.get_emoji(853668227212902410), style=ButtonStyle.secondary, custom_id="select") async def select_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() bm_page = None if self.parent.code in self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Bookmarks|*n*|bm']: bm_page = self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Bookmarks|*n*|bm'][self.parent.code] conf = await self.parent.am_channel.send(embed=Embed( description=localization[self.parent.language]['page_reader']['select_inquiry']['description'] ).set_footer( text=localization[self.parent.language]['page_reader']['select_inquiry']['footer'].format(bookmarked_page=str(bm_page+1) if bm_page else 'N/A'))) while True: try: m = await self.bot.wait_for("message", timeout=15, bypass_cooldown=True, check=lambda m: m.author.id == self.ctx.author.id and m.channel.id == self.parent.am_channel.id) except TimeoutError: await conf.delete() break else: with suppress(Forbidden): await m.delete() if m.content == "n-cancel": await conf.delete() break if is_int(m.content) and (int(m.content)-1) in range(0, len(self.parent.images)): await conf.delete() self.parent.current_page = int(m.content)-1 return self.stop() else: with suppress(Forbidden): await m.delete() continue @ui.button(emoji=self.bot.get_emoji(853668227175546952), style=ButtonStyle.secondary, custom_id="stop") async def stop_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() self.parent.am_embed.set_image(url=Embed.Empty) self.parent.am_embed.set_thumbnail(url=Embed.Empty) self.parent.am_embed.description=localization[self.parent.language]['page_reader']['stopped'] await self.parent.active_message.edit(embed=self.parent.am_embed, view=None) await sleep(2) await self.parent.active_message.edit(content=f"{self.bot.get_emoji(810936543401213953)} {localization[self.parent.language]['page_reader']['closing']}", embed=None) await sleep(1) await self.parent.am_channel.delete() self.value = 1 self.stop() @ui.button(emoji=self.bot.get_emoji(853668227234529300), style=ButtonStyle.secondary, custom_id="pause") async def pause_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() self.parent.am_embed.set_image(url=Embed.Empty) self.parent.am_embed.set_thumbnail(url=Embed.Empty) self.parent.am_embed.description=localization[self.parent.language]['page_reader']['paused'] await self.parent.active_message.edit(embed=self.parent.am_embed, view=None) await sleep(2) await self.parent.active_message.edit(content=f"{self.bot.get_emoji(810936543401213953)} {localization[self.parent.language]['page_reader']['closing']}", embed=None) await sleep(1) await self.parent.am_channel.delete() await sleep(1) self.bot.user_data["UserData"][str(self.ctx.author.id)]["Recall"] = f"{self.parent.code}*n*{self.parent.current_page}" await self.ctx.author.send(embed=Embed( title=localization[self.parent.language]['page_reader']['recall_saved']['title'], description=localization[self.parent.language]['page_reader']['recall_saved']['description'].format(code=self.parent.code, current=self.parent.current_page+1, total=len(self.parent.images)))) self.value = 1 self.stop() @ui.button(emoji=self.bot.get_emoji(853668227205038090), style=ButtonStyle.secondary, custom_id="bookmark") async def bookmark_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() if not self.parent.on_bookmarked_page: if self.parent.current_page == 0: await self.parent.am_channel.send( embed=Embed( color=0xFF0000, description=localization[self.parent.language]['page_reader']['cannot_bookmark_first_page'] ), delete_after=5) return self.stop() if len(self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["Bookmarks|*n*|bm"]) >= 25: await self.parent.am_channel.send( color=0xff0000, embed=Embed( description=localization[self.parent.language]['page_reader']['bookmarks_full'] ), delete_after=5) return self.stop() self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Bookmarks|*n*|bm'][self.parent.code] = self.parent.current_page self.parent.on_bookmarked_page = True else: if self.parent.code in self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Bookmarks|*n*|bm']: self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Bookmarks|*n*|bm'].pop(self.parent.code) self.parent.on_bookmarked_page = False self.stop() @ui.button(emoji="⭐", style=ButtonStyle.secondary, custom_id="favorite") async def favorite_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() if self.parent.code not in self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Favorites|*n*|fav']: if len(self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["Favorites|*n*|fav"]) >= 25: await self.parent.am_channel.send( embed=Embed( color=0xff0000, description=localization[self.parent.language]['page_reader']['favorites_full'] ), delete_after=5) return self.stop() self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Favorites|*n*|fav'].append(self.parent.code) await self.parent.am_channel.send( embed=Embed( description=localization[self.parent.language]['page_reader']['added_to_favorites'].format(code=self.parent.code) ), delete_after=5) else: self.bot.user_data['UserData'][str(self.ctx.author.id)]['Lists']['Built-in']['Favorites|*n*|fav'].remove(self.parent.code) await self.parent.am_channel.send( embed=Embed( description=localization[self.parent.language]['page_reader']['removed_from_favorites'].format(code=self.parent.code) ), delete_after=5) self.stop() @ui.button(emoji=thumbnail_buttons[self.bot.user_data["UserData"][str(self.ctx.author.id)]["Settings"]["ThumbnailPreference"]], style=ButtonStyle.secondary, custom_id="thumbnail") async def thumbnail_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() if self.bot.user_data["UserData"][str(self.ctx.author.id)]["Settings"]["ThumbnailPreference"] == 2: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Settings"]["ThumbnailPreference"] = 0 else: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Settings"]["ThumbnailPreference"] += 1 self.stop() async def on_timeout(self): with suppress(NotFound): self.parent.am_embed.set_image(url=Embed.Empty) self.parent.am_embed.set_thumbnail(url=Embed.Empty) self.parent.am_embed.description=localization[self.parent.language]['page_reader']['timeout'].format(current=self.parent.current_page+1, total=len(self.parent.images)) await self.parent.active_message.edit(embed=self.parent.am_embed, view=None) temp = await self.parent.am_channel.send(content=localization[self.parent.language]['page_reader']['timeout_notification'].format(mention=self.ctx.author.mention), delete_after=1) await sleep(10) with suppress(NotFound): await self.parent.active_message.edit(content=f"{self.bot.get_emoji(810936543401213953)} {localization[self.parent.language]['page_reader']['closing']}", embed=None) await sleep(1) await self.parent.am_channel.delete() self.value = 1 self.stop() self.view = IPRControls(self.bot, self.ctx, self) self.view.add_item(ui.Button(label=localization[self.language]['page_reader']['redirect_button'], style=ButtonStyle.link, url="https://discord.gg/DJ4wdsRYy2")) with suppress(NotFound): await self.active_message.edit(embed=self.am_embed, view=self.view) await self.view.wait() return self.view.value async def setup(self): edit = await self.ctx.send(embed=Embed( description=f"{self.bot.get_emoji(810936543401213953)}")) # Fetch existing category for readers, otherwise create new cat = get(self.ctx.guild.categories, name="📖NReader") if not cat: cat = await self.ctx.guild.create_category_channel(name="📖NReader") elif not cat.permissions_for(self.ctx.guild.me).manage_roles: with suppress(Forbidden): await cat.delete() cat = await self.ctx.guild.create_category_channel(name="📖NReader") # Create reader channel under category channel = await cat.create_text_channel(name=f"📖nreader-{self.ctx.message.id}", nsfw=True) # Set channel permissions await channel.set_permissions(self.ctx.guild.me, read_messages=True) await channel.set_permissions(self.ctx.guild.default_role, read_messages=False) await channel.set_permissions(self.ctx.author, read_messages=True) self.am_embed = Embed( description=localization[self.language]['page_reader']['init']['description']) self.am_embed.set_author( name=f"{self.code} [*n*] {self.name}", icon_url="https://cdn.discordapp.com/emojis/845298862184726538.png?v=1") self.am_embed.set_footer( text=localization[self.language]['page_reader']['init']['footer'].format(total=len(self.images))) class Start(ui.View): def __init__(self, bot, ctx, parent): super().__init__(timeout=30) self.value = None self.bot = bot self.ctx = ctx self.parent = parent @ui.button(label=localization[self.language]["page_reader"]["init"]["button"], style=ButtonStyle.primary, emoji=self.bot.get_emoji(853674277416206387), custom_id="button1") async def start_button(self, button, interaction): if interaction.user.id == self.ctx.author.id: await interaction.response.defer() self.active_message = view.message self.value = True self.stop() async def on_timeout(self): with suppress(NotFound): await view.message.edit(content=f"{self.bot.get_emoji(810936543401213953)} {localization[self.parent.language]['page_reader']['closing']}", embed=None) await sleep(1) with suppress(NotFound): await view.message.channel.delete() self.value = 1 self.stop() # Reader message view = Start(self.bot, self.ctx, self) self.am_channel = channel self.active_message = view.message = await self.am_channel.send(embed=self.am_embed, view=view) # Portal await edit.edit( content=self.am_channel.mention, embed=Embed( description=localization[self.language]['page_reader']['portal'].format(code=self.code, name=self.name) ).set_author( name=self.bot.user.name, icon_url=self.bot.user.avatar.url), delete_after=10) await view.wait() if view.value: print(f"[HRB] {self.ctx.author} ({self.ctx.author.id}) started reading `{self.code}`.") await self.update(self.ctx) return view.value async def start(self): if self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["enabled"]: while self.code in self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"]: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"].remove(self.code) self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"].insert(0, self.code) if "0" in self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"]: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"].remove("0") if len(self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"]) >= 2 and \ self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"][1] == self.code: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"].pop(0) while len(self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"]) > 25: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"].pop() if "0" not in self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"]: self.bot.user_data["UserData"][str(self.ctx.author.id)]["Lists"]["Built-in"]["History|*n*|his"]["list"].append("0") view_exit_code = 0 while view_exit_code == 0: view_exit_code = await self.update(self.ctx)
async def doujin_info(self, ctx, code="random", interface="new"): lolicon_allowed = False try: if ctx.guild.id in self.bot.user_data["UserData"][str( ctx.guild.owner_id)]["Settings"]["UnrestrictedServers"]: lolicon_allowed = True except KeyError: pass if not ctx.channel.is_nsfw(): await ctx.send(embed=Embed( description= ":x: This command cannot be used in a non-NSFW channel.")) return try: if code.lower() not in ["random", "r"]: code = int(code) code = str(code) except ValueError: await ctx.send(embed=Embed( description= ":x: You didn't type a proper ID. Hint: It has to be a number!" )) return nhentai_api = NHentai() edit = await ctx.send(embed=Embed( description="<a:nreader_loading:810936543401213953>")) if code.lower() not in ["random", "r"]: if code not in self.bot.doujin_cache: doujin = await nhentai_api.get_doujin(code) else: doujin = self.bot.doujin_cache[code] if not doujin: await edit.edit(embed=Embed( description= ":mag_right::x: I did not find a doujin with that ID.")) return else: self.bot.doujin_cache[code] = doujin if ("lolicon" in doujin.tags or "shotacon" in doujin.tags) and ctx.guild and not lolicon_allowed: await edit.edit(embed=Embed( description= ":warning::no_entry_sign: This doujin contains lolicon/shotacon content and cannot be displayed publically." )) if not self.bot.user_data["UserData"][str( ctx.author.id )]["Settings"]["NotificationsDue"]["LoliconViewingTip"]: with suppress(Forbidden): await ctx.author.send( localization["eng"]["notifications_due"] ["lolicon_viewing_tip"]) self.bot.user_data["UserData"][str( ctx.author.id)]["Settings"]["NotificationsDue"][ "LoliconViewingTip"] = True return else: while True: doujin = await nhentai_api.get_random() self.bot.doujin_cache[doujin.id] = doujin if ("lolicon" in doujin.tags or "shotacon" in doujin.tags) and ctx.guild and not lolicon_allowed: await sleep(0.5) continue else: break # Doujin count for tags tags_list = [] for tag in [tag for tag in doujin.tags if tag.type == "tag"]: count = tag.count parse_count = list(str(count)) if len(parse_count) < 4: tags_list.append(f"{tag.name}[{count}]") elif len(parse_count) >= 4 and len(parse_count) <= 6: count = count / 1000 tags_list.append(f"{tag.name}[{round(count, 1)}k]") elif len(parse_count) > 7: count = count / 1000000 tags_list.append(f"{tag.name}[{round(count, 2)}m]") if interface == "old": emb = Embed( description=f"Doujin ID: __`{doujin.id}`__\n" f"Languages: {language_to_flag(doujin.languages)} `{', '.join([tag.name for tag in doujin.languages]) if doujin.languages else 'Not provided'}`\n" f"Pages: `{len(doujin.images)}`\n" f"Artist(s): `{', '.join([tag.name for tag in doujin.artists]) if doujin.artists else 'Not provided'}`\n" f"Character(s): `{', '.join([tag.name for tag in doujin.characters]) if doujin.characters else 'Original'}`\n" f"Parody of: `{', '.join([tag.name for tag in doujin.parodies]) if doujin.parodies else 'Original'}`\n" f"Tags: ```{', '.join(tags_list) if doujin.tags else 'None provided'}```" ) else: emb = Embed() emb.add_field( inline=False, name="Title", value= f"`{shorten(doujin.title.pretty, width=256, placeholder='...') if doujin.title.pretty else 'Not provided'}`" ).add_field( inline=False, name="ID ー Pages", value=f"`{doujin.id} ー {len(doujin.images)}`" ).add_field( inline=False, name="Language(s)", value= f"{language_to_flag(doujin.languages)} `{', '.join([tag.name for tag in doujin.languages]) if doujin.languages else 'Not provided'}`" ).add_field( inline=False, name="Artist(s)", value= f"`{', '.join([tag.name for tag in doujin.artists]) if doujin.artists else 'Not provided'}`" ).add_field( inline=False, name="Character(s)", value= f"`{', '.join([tag.name for tag in doujin.characters]) if doujin.characters else 'Original'}`" ).add_field( inline=False, name="Parody Of", value= f"`{', '.join([tag.name for tag in doujin.parodies]) if doujin.parodies else 'Original'}`" ).add_field( inline=False, name="Tags", value= f"```{', '.join(tags_list) if doujin.tags else 'None provided'}```" ) emb.set_author( name= f"{shorten(doujin.title.pretty, width=120, placeholder='...') if doujin.title.pretty else 'Not provided'}", url=f"https://nhentai.net/g/{doujin.id}/", icon_url= "https://cdn.discordapp.com/emojis/845298862184726538.png?v=1") emb.set_thumbnail(url=doujin.images[0].src) print(f"[HRB] {ctx.author} ({ctx.author.id}) looked up `{doujin.id}`.") await edit.edit(content="", embed=emb) await edit.add_reaction("📖") await edit.add_reaction("🔍") while True: try: reaction, user = await self.bot.wait_for("reaction_add", timeout=60, check=lambda r,u: r.message.id==edit.id and \ u.id==ctx.author.id and \ str(r.emoji) in ["📖", "🔍"]) except TimeoutError: emb.set_footer(text="Provided by NHentai-API") emb.set_thumbnail(url=doujin.images[0].src) emb.set_image(url=Embed.Empty) await edit.edit(embed=emb) with suppress(Forbidden): await edit.clear_reactions() return except BotInteractionCooldown: continue else: if str(reaction.emoji) == "📖": with suppress(Forbidden): await edit.clear_reactions() emb.set_footer(text="Provided by NHentai-API") emb.set_thumbnail(url=doujin.images[0].src) emb.set_image(url=Embed.Empty) await edit.edit(embed=emb) session = ImagePageReader( self.bot, ctx, doujin.images, f"{doujin.id} [*n*] {doujin.title.pretty if doujin.title.pretty else 'Not provided'}" ) response = await session.setup() if response: print( f"[HRB] {ctx.author} ({ctx.author.id}) started reading `{doujin.id}`." ) await session.start() else: emb.set_footer(text=Embed.Empty) await edit.edit(embed=emb) return elif str(reaction.emoji) == "🔍": if not emb.image: emb.set_image(url=emb.thumbnail.url) emb.set_thumbnail(url=Embed.Empty) # word = "Hide" elif not emb.thumbnail: emb.set_thumbnail(url=emb.image.url) emb.set_image(url=Embed.Empty) # word = "Minimize" await edit.remove_reaction("🔍", ctx.author) await edit.edit(content="", embed=emb) continue
async def download_doujin(self, ctx, code): return await ctx.send( "Due to recent shutdowns, this command has been disabled prematurely. It will be removed in the future." ) lolicon_allowed = False try: if not ctx.guild or ctx.guild.id in self.bot.user_data["UserData"][ str(ctx.guild.owner_id )]["Settings"]["UnrestrictedServers"]: lolicon_allowed = True except KeyError: pass if ctx.guild and not ctx.channel.is_nsfw(): await ctx.send( ":x: This command cannot be used in a non-NSFW channel.") return try: code = int(code) except ValueError: await ctx.send( ":x: You didn't type a proper ID. Hint: It has to be a number!" ) return nhentai_api = NHentai() conf = await ctx.send("<a:nreader_loading:810936543401213953>") if code not in self.bot.doujin_cache: doujin = await nhentai_api.get_doujin(code) else: doujin = self.bot.doujin_cache[code] if not doujin: await conf.edit(content="🔎❌ I did not find a doujin with that ID.") return self.bot.doujin_cache[code] = doujin if ("lolicon" in doujin.tags or "shotacon" in doujin.tags) and ctx.guild: try: if ctx.guild.id in self.bot.user_data["UserData"][str( ctx.guild.owner_id )]["Settings"]["UnrestrictedServers"]: lolicon_allowed = True except KeyError: pass if ("lolicon" in doujin.tags or "shotacon" in doujin.tags) and ctx.guild and not lolicon_allowed: await conf.edit( content= ":warning::no_entry_sign: This doujin contains lolicon/shotacon content and cannot be shown publically." ) return emb = Embed( description= "You are attempting to download a doujin. Press the arrow to continue." ) emb.set_author( name=f"{language_to_flag(doujin.languages)} {doujin.title}", url=f"https://nhentai.net/g/{doujin.id}/", icon_url= "https://cdn.discordapp.com/emojis/845298862184726538.png?v=1") emb.set_thumbnail(url=doujin.images[0]) await conf.edit(content='', embed=emb) await conf.add_reaction("⬇") try: await self.bot.wait_for("reaction_add", timeout=30, bypass_cooldown=True, check=lambda r,u: r.message.id==conf.id and \ u.id==ctx.message.author.id and \ str(r.emoji)=="⬇") except TimeoutError: await conf.remove_reaction("⬇", self.bot.user) emb.description = "You timed out." await conf.edit(embed=emb) return else: emb.description = "Downloading...\nYou will be notified when completed." emb.set_author( name=f"[{language_to_flag(doujin.languages)}] {doujin.title}", url=f"https://nhentai.net/g/{doujin.id}/", icon_url= "https://cdn.discordapp.com/emojis/810936543401213953.gif?v=1") emb.set_footer(text=f"[{' '*len(doujin.images)}]") await conf.edit(embed=emb) print( f"[HRB] {ctx.author} ({ctx.author.id}) started downloading {doujin.id} ({len(doujin.images)} pages)." ) files = list() for ind, page_url in enumerate(doujin.images, 1): udownload(page_url, f"Workspace/{ctx.message.id}_{doujin.id}_page{ind}.png") files.append( f"Workspace/{ctx.message.id}_{doujin.id}_page{ind}.png") if ind % 5 == 0: emb.set_footer( text=f"[{'|'*ind}{' '*(len(doujin.images)-ind)}]") await conf.edit(embed=emb) await sleep(0.5) emb.set_footer( text=f"Processing zip file... [{'|'*len(doujin.images)}]") await conf.edit(embed=emb) with ZipFile(f"Workspace/{ctx.message.id}.zip", "w") as send_zip: for ind, file_p in enumerate(files, 1): send_zip.write(file_p, f"page_{ind}.png", compress_type=ZIP_DEFLATED) os.remove(file_p) os.rename(f"Workspace/{ctx.message.id}.zip", f"Storage/{ctx.message.id}") new_filelink = f"https://nreader.supermechm500.repl.co/download?" \ f"id={ctx.message.id}" await conf.delete() await ctx.send( content=f"{ctx.author.mention}, your download has completed. ⬇", embed=Embed( color=0x32d17f, description= f"Here is a zipped file of your downloaded doujin. [Download]({new_filelink})\n" f'Remember to rename the file from "download" to "**something.zip**".\n' f"Expires in **5 minutes** or until bot is forced to reboot."). set_author( name=f"{language_to_flag(doujin.languages)} {doujin.title}", url=f"https://nhentai.net/g/{doujin.id}/", icon_url= "https://cdn.discordapp.com/emojis/845298862184726538.png?v=1" ).set_footer(text=f"[{'|'*len(doujin.images)}]")) await sleep(5 * 60) with suppress(FileNotFoundError): os.remove(f"Storage/{ctx.message.id}")