async def nhentai(self, ctx: commands.Context, djid=None, *, extra: str = ''): '''finds doujins on nhentai by id''' if ctx.invoked_subcommand is not None: return if djid is None: await ctx.send_help(ctx.command) return if not Hentai.exists(djid): return await self.search(ctx, tags=f'{djid} {extra}') result = Hentai(djid) tags = [_.name for _ in result.tag] e = discord.Embed(title=result.title(Format.Pretty), description=f'#{result.id}', url=result.url, color=int(djid)) e.set_image(url=result.cover) e.set_footer(text=result.upload_date) e.add_field(name="Tags", value=', '.join(tags)) artists = ', '.join([_.name for _ in result.artist ]) if result.artist != [] else 'None' e.add_field(name="Artist(s)", value=artists) await ctx.send(embed=e)
def make_embed(hnt: Hentai): def convert(tag: list) -> str: lst = list(map(lambda x: x.name, tag)) return ", ".join(lst) def convert_list(tag: list) -> list: return list(map(lambda x: x.name, tag)) embed = discord.Embed( colour = discord.Colour.random(), title = hnt.title(Format.Pretty), url = f"https://nhentai.net/g/{hnt.id}" ) embed.set_thumbnail( url=hnt.thumbnail ) embed.set_image(url=hnt.cover) description = \ f"`id` : {hnt.id}\n" + \ f"`pages` : {hnt.num_pages}\n" + \ f"`tags` : {convert(hnt.tag)}\n" if hnt.artist: description += f"`artist` : {convert(hnt.artist)}" embed.description = description embed.set_footer(text="Speedwagon Foundation got ur back") for e in convert_list(hnt.tag): if e == "lolicon": embed.set_footer(text="Speedwagon Foundation can't cover u from FBI") embed.timestamp = datetime.datetime.utcnow() return embed
async def read(self, ctx, code): async with ctx.typing(): try: doujin = Hentai(code) except HTTPError: return UI.error_embed(f'Doujin dengan code {code} tidak ada') pages = [image for image in doujin.image_urls] curr_index = 1 max_index = len(pages) title = doujin.title(Format.Pretty) embed, components = self.helpers.generate_read_hentai_embed(title, pages[curr_index-1], curr_index, max_index) nhentai = await ctx.send(embed=embed, components=components) try: while True: btn = await nhentai.wait_for('button', self.bot, timeout=60) await btn.respond(ninja_mode=True) if btn.custom_id == 'hentai_first': curr_index = 1 if btn.custom_id == 'hentai_prev': curr_index -= 1 if btn.custom_id == 'hentai_next': curr_index += 1 if btn.custom_id == 'hentai_last': curr_index = max_index embed, components = self.helpers.generate_read_hentai_embed(title, pages[curr_index-1], curr_index, max_index) await nhentai.edit(embed=embed, components=components) except TimeoutError: embed, components = self.helpers.generate_read_hentai_embed(title, pages[curr_index-1], curr_index, max_index, disable_components=True) await nhentai.edit(components=components) except NotFound: pass
def make_page_embed(ctx: Context, hnt: Hentai, page: int): """ This function converts a `getpage` query to a suitable Embed. :raises: ValueError if the page number provided is invalid :param ctx: context :param hnt: the hentai :param page: the desired page number :return: an Embed or Raises an Error """ if page < 1 or page > hnt.num_pages: raise ValueError(f"[Invalid page **{page}**") embed = discord.Embed( title=hnt.title(Format.Pretty) + f" || page {page}", url=NHentaiCommands.hentai_url(hnt)+f"{page}", colour=NHentaiCommands.get_random_color() ) embed.set_image(url=hnt.pages[page - 1].url) embed.set_footer( text=f"requested by || {ctx.author.name}({ctx.author.display_name})", icon_url=ctx.author.avatar_url ) return embed
def make_embed(hnt: Hentai) -> discord.Embed: """ This class method takes a NHentai manga element and turns it into a discord Embed and returns it """ def convert(tag: list) -> str: lst = list(map(lambda x: x.name, tag)) return ", ".join(lst) embed = discord.Embed( colour=NHentaiCommands.get_random_color(), title=hnt.title(Format.Pretty), url=f"https://nhentai.net/g/{hnt.id}" ) embed.set_thumbnail( url=hnt.thumbnail ) embed.set_image(url=hnt.cover) description = \ f"`id` : {hnt.id}\n" + \ f"`pages` : {hnt.num_pages}\n" + \ f"`tags` : {convert(hnt.tag)}\n" if hnt.artist: description += f"artist : {convert(hnt.artist)}" embed.description = description return embed
async def rnd(self, ctx: commands.Context): """Random one""" doujin = Hentai(Utils.get_random_id()) embed_list = [] for i in doujin.image_urls: embed = Embed.default(ctx) embed.title = doujin.title(Format.Pretty) embed.set_image(url=i) embed_list.append(embed) await menus.MenuPages( source=EmbedListMenu(embed_list), clear_reactions_after=True, ).start(ctx=ctx, wait=False)
def nuke_codes(): if request.method == 'POST': data = request.get_json() code = data['code'] print(data) if (Hentai.exists(code)): doujin = Hentai(code) print(f"\n#{code} : success") print(f"title : {doujin.title()}") print(f"tags : {[tag.name for tag in doujin.tag]}") print(f"poster url : {doujin.image_urls[0]}\n") return { 'id': doujin.id, 'title_release': doujin.title(), 'title_pretty': doujin.title(Format.Pretty), 'tags': [tag.name for tag in doujin.tag], 'poster_link': doujin.image_urls[0], # 'poster_blob' : poster_blob, 'artist': [{ 'name': artist.name, 'url': artist.url, 'count': artist.count } for artist in doujin.artist], 'languages': [lang.name for lang in doujin.language], 'categories': [cat.name for cat in doujin.category], 'pages': doujin.num_pages, 'uploaded': doujin.upload_date } else: return None return None
async def sauce(self, ctx, nuke_code): """ What's behind that nuke code? """ message = await ctx.send("Extracting sauce from nuke code... 👨💻") if Hentai.exists(nuke_code): doujin = Hentai(nuke_code) english = doujin.title() japanese = doujin.title(Format.Japanese) pages = str(doujin.num_pages) hentai_id = str(doujin.id) link = "||" + doujin.url + "||" tag = (getattr(i, 'name') for i in doujin.tag) content_list = ( f'**Hentai ID**: {hentai_id}', f'**Thumbnail**: {doujin.thumbnail}', f'** English Title**: {english if english else "none"}', f'**Japanese Title**: {japanese if japanese else "none"}', f'**Pages**: {pages}', f'**Tags**: {", ".join(tag)}', f'**Link**: {link}' ) await message.edit(content="\n".join(content_list)) else: await message.edit(content="The sauce you are looking for does not exist. 🤷♂️")
async def read(self, ctx: commands.Context, digits): """Read doujins.""" if not digits.isdigit(): return await ctx.send("Only digits allowed.") if not Hentai.exists(digits): return await ctx.send("Doesn't exist.") doujin = Hentai(digits) embed_list = [] for i in doujin.image_urls: embed = Embed.default(ctx) embed.title = doujin.title(Format.Pretty) embed.set_image(url=i) embed_list.append(embed) await menus.MenuPages( source=EmbedListMenu(embed_list), clear_reactions_after=True, ).start(ctx=ctx, wait=False)
async def lookup(self, ctx: commands.Context, doujin): """ Info about a doujin.""" if not doujin.isdigit(): return await ctx.send("Only digits allowed.") if not Hentai.exists(doujin): return await ctx.send("Doesn't exist.") doujin = Hentai(doujin) embed = Embed.default(ctx) embed.title = doujin.title(Format.Pretty) embed.add_field(name="Holy Digits", value=doujin.id, inline=True) embed.add_field(name="Languages", value=Tag.get(doujin.language, "name"), inline=True) embed.add_field(name="Uploaded", value=doujin.upload_date, inline=True) embed.add_field(name="Number of times liked", value=doujin.num_favorites, inline=True) embed.add_field(name="Tags", value=Tag.get(doujin.tag, "name")) embed.add_field(name="Number of pages", value=doujin.num_pages) embed.set_thumbnail(url=doujin.thumbnail) await ctx.send(embed=embed)
async def lookup_id(self, ctx, id: int): if not Hentai.exists(id): await ctx.send("Error: Invalid ID.") else: doujin = Hentai(id) embed = discord.Embed( title=doujin.title(Format.Pretty), description=f"🌍 {', '.join(Tag.get_names(doujin.language))}", url=doujin.url, color=discord.Color.red()) embed.add_field(name="Author", value=Tag.get_names(doujin.artist)) embed.add_field(name="Favorites", value=f"❤ {doujin.num_favorites}") embed.add_field(name="Pages", value=f"📕 {doujin.num_pages}") embed.set_thumbnail(url=doujin.thumbnail) embed.set_footer( text=f"Tags: {', '.join(Tag.get_names(doujin.tag))}") await self.client.change_presence( status=discord.Status.online, activity=discord.Game( f"Now reading {doujin.title(Format.Pretty)}🥰")) await ctx.send(embed=embed)
async def nhentai(self, ctx: commands.Context, djid: int = None): '''finds doujins on nhentai by id''' if ctx.invoked_subcommand is not None: return if djid is None: await ctx.send_help(ctx.command) return if not Hentai.exists(djid): await ctx.send(content="Doujin does not exist!") return result = Hentai(djid) tags = [_.name for _ in result.tag] e = discord.Embed(title=result.title(Format.Pretty), description=f'#{result.id}', url=result.url, color=0x177013) e.set_image(url=result.cover) e.set_footer(text=result.upload_date) e.add_field(name="Tags", value=', '.join(tags)) e.add_field(name="Artist(s)", value=', '.join([_.name for _ in result.artist])) await ctx.send(embed=e)
async def read_id(self, ctx, id: int): if not Hentai.exists(id): await ctx.send("Error: Invalid ID.") else: doujin = Hentai(id) reactions = { 'prev': Emoji[':arrow_left:'], 'next': Emoji[':arrow_right:'] } embed = discord.Embed(title=doujin.title(Format.Pretty), description=f"Page 1 of {doujin.num_pages}", color=discord.Color.red()) embed.set_image(url=doujin.cover) # TODO: implement emoji reaction event handler for pagination message = await ctx.send(embed=embed) self.reader_id = message.id print(type(message)) print(self.reader_id) for emoji in reactions.values(): await message.add_reaction(emoji)
async def _(event): if event.fwd_from: return input_str = event.pattern_match.group(1) code = input_str if "nhentai" in input_str: link_regex = r"(https?://)?(www\.)?nhentai\.net/g/(\d+)" match = re.match(link_regex, input_str) code = match.group(3) await event.edit("☙ `Searching for doujin...` ❧") try: doujin = Hentai(code) except BaseException as n_e: if "404" in str(n_e): return await event.edit(f"`{code}` is not found!") return await event.edit(f"**Error: **`{n_e}`") msg = "" imgs = "" for url in doujin.image_urls: imgs += f"<img src='{url}'/>" imgs = f"‍ {imgs}" title = doujin.title() graph_link = post_to_telegraph(title, imgs) msg += f"[{title}]({graph_link})" msg += f"\n**Source :**\n[{code}]({doujin.url})" if doujin.parody: msg += "\n**Parodies :**" parodies = [] for parody in doujin.parody: parodies.append("#" + parody.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(parodies)) if doujin.character: msg += "\n**Characters :**" charas = [] for chara in doujin.character: charas.append("#" + chara.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(charas)) if doujin.tag: msg += "\n**Tags :**" tags = [] for tag in doujin.tag: tags.append("#" + tag.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(tags)) if doujin.artist: msg += "\n**Artists :**" artists = [] for artist in doujin.artist: artists.append("#" + artist.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(artists)) if doujin.language: msg += "\n**Languages :**" languages = [] for language in doujin.language: languages.append("#" + language.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(languages)) if doujin.category: msg += "\n**Categories :**" categories = [] for category in doujin.category: categories.append("#" + category.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(categories)) msg += f"\n**Pages :**\n{doujin.num_pages}" await event.edit(msg, link_preview=True)
class CatalogueEntry: markdown_map = { "WhatsApp": { "bold": ["*", "*"], "italic": ["_", "_"], "scode": ["```", "```"], "mcode": ["```", "```"], }, "Telegram": { "bold": ["**", "**"], "italic": ["__", "__"], "scode": ["`", "`"], "mcode": ["```\n", "\n```"], }, } def __init__( self, eid: int, hid: int, desc: str = "", markdown: str = "Telegram", ) -> None: self.config = data.Config() self.submission = "Official Submission" self.rating = "" if not Path(self.config["Repository"]["path"]).is_dir(): print( f'categen: {self.config["Repository"]["path"]} is non-existant, ' "attempting to download Format.") try: data.Format.retrieve_online( url=self.config["Repository"]["link"], path=self.config["Repository"]["path"], ) except Exception as e: print( "categen: Error encountered while attempting to download format. " f"({e}) categen will use the local Format shipped with the package." ) data.Format.retrieve_local( format_dir=self.config["Repository"]["path"]) self.format = data.Format(repo_config=self.config["Repository"]) self.doujin = Hentai(hid) self.markdown = self.markdown_map[markdown] self.id = "0" * (3 - len(str(eid))) + str(eid) self.description = str(desc) assert self.config["Settings"]["divide"] in [ "both", "left", "right" ], (f'config:General:divide - "{self.config["Settings"]["divide"]}"' "is not a valid divide value!") self.divide = self.config["Settings"]["divide"] placements_path = Path( self.config["Repository"]["path"]).joinpath("placements.json") assert placements_path.exists(), f"{placements_path}: Non-existant" with open(placements_path, "r", encoding="utf-8") as pf: self.placements = load(pf) entry_path = Path( self.config["Repository"]["path"]).joinpath("entry.txt") assert entry_path.exists(), f"{entry_path}: Non-existant" with open(entry_path, "r", encoding="utf-8") as ef: self.entry_text = ef.read() tagsofinterest_path = Path( self.config["Repository"]["path"]).joinpath("tagsofinterest.json") assert tagsofinterest_path.exists( ), f"{tagsofinterest_path}: Non-existant" with open(tagsofinterest_path, "r", encoding="utf-8") as toif: self.tagsofinterest = load(toif) formatting_map_path = Path( self.config["Repository"]["path"]).joinpath("formatting.json") if formatting_map_path.is_file(): with open(formatting_map_path, "r", encoding="utf-8") as fmf: self.formatting_map = load(fmf) else: self.formatting_map = {} template_path = Path(self.config["Repository"]["path"]).joinpath( "thumbnail/template.png") assert template_path.is_file(), f"{template_path}: Non-existant" self.template = Image.open(str(template_path)) self._thumbnail = None self._entry = None def _divide(self, text: str) -> str: if "|" in text and self.divide != "both": if self.divide == "left": divided = text.split("|")[0].lstrip().rstrip() else: divided = text.split("|")[1].lstrip().rstrip() return divided else: return text def _strf(self, text: str, markdown_type: str = None, disable_override: bool = False) -> str: def fword(keyword: str) -> str: override = self.formatting_map.get(keyword, None) return (f"{keyword}:-sep-:{override}" if not any( [override is None, override == "", disable_override]) else keyword) if markdown_type is None: markdown_type = self.config["Settings"]["markdown_type"] # Title Generation title_p_en = self._divide(self.doujin.title(Format.Pretty)) title_p_jp = self._divide( Utils.sanitize(self.doujin.title(Format.Japanese))) markdown = self.markdown_map[markdown_type] bold = markdown["bold"][0] _bold = markdown["bold"][1] if title_p_en != "" and title_p_jp != "": title = f"{bold}{title_p_en}{_bold} - {bold}{title_p_jp}{_bold}" elif title_p_en != "" and title_p_jp == "": title = f"{bold}{title_p_en}{_bold}" elif title_p_en == "" and title_p_jp != "": title = f"{bold}{title_p_jp}{_bold}" else: title = "Unnamed" # Creator Text Generation artist_names = [tag.name for tag in self.doujin.artist] artist_names_str = ", ".join(artist_names) group_names = [tag.name for tag in self.doujin.group] group_names_str = ", ".join(group_names) if len(artist_names) > 0 and len(group_names) > 0: creator = f"({artist_names_str} / {group_names_str})" elif len(artist_names) > 0 and len(group_names) == 0: creator = f"({artist_names_str})" elif len(artist_names) == 0 and len(group_names) > 0: creator = f"({group_names_str})" else: creator = "(No Creator Info)" # Tags tags = [self._divide(tag.name) for tag in self.doujin.tag] tags_interest = [tag for tag in tags if tag in self.tagsofinterest] tags_remainder = [tag for tag in tags if tag not in tags_interest] format_map = { "bold": markdown["bold"][0], "-bold": markdown["bold"][1], "italic": markdown["italic"][0], "-italic": markdown["italic"][1], "scode": markdown["scode"][0], "-scode": markdown["scode"][1], "mcode": markdown["mcode"][0], "-mcode": markdown["mcode"][1], fword("entry_id"): self.id, fword("description"): self.description, fword("title.english"): self._divide(self.doujin.title()), fword("title.english.pretty"): title_p_en, fword("title.japanese:"): self._divide(self.doujin.title(Format.Japanese)), fword("title.japanese.pretty"): title_p_jp, fword("title"): title, fword("tags.interest"): ", ".join(tags_interest), fword("tags.remainder"): ", ".join(tags_remainder), fword("tags"): ", ".join(tags), fword("creator.scanlator"): self.doujin.scanlator, fword("creator.artist"): ", ".join([t.name for t in self.doujin.artist]), fword("creator.group"): ", ".join([t.name for t in self.doujin.group]), fword("creator"): creator, fword("doujin_id"): self.doujin.id, fword("pages"): self.doujin.num_pages, fword("favourites"): self.doujin.num_favorites, fword("link"): self.doujin.url, fword("time"): datetime.fromtimestamp( self.doujin.epos).strftime("%B %d %Y, %H:%M:%S"), fword("parody"): ", ".join([t.name for t in self.doujin.parody]), fword("characters"): ", ".join([t.name for t in self.doujin.character]), fword("slink"): f"nh.{self.doujin.id}", fword("submission"): self.submission, fword("rating"): self.rating, } for keyword, replacement in format_map.items(): conditions = [ "parody" in keyword and replacement == "original", "parody" in keyword and replacement == "", "favourites" in keyword and replacement == "0", "characters" in keyword and replacement == "", "creator.group" in keyword and replacement == "", "description" in keyword and replacement == "", "tags.remainder" in keyword and replacement == "", "rating" in keyword and replacement == "", ] if not any(conditions): if ":-sep-:" in keyword: # keyword:-sep-:\nkeyword\n _keyword = keyword keyword = keyword.split(":-sep-:")[0] override = _keyword.lstrip(keyword + ":-sep-:") replacement = self._strf( text=override, markdown_type=markdown_type, disable_override=True, ) text = text.replace(f"<[{keyword}]>", str(replacement)) else: if ":-sep-:" in keyword: keyword = keyword.split(":-sep-:")[0] text = text.replace(f"<[{keyword}]>", "") return text def thumbnail(self, preview: Image.Image, suppress: bool = False) -> Image.Image: placements = deepcopy(self.placements) if ".meta" in placements: placements.pop(".meta") for area in [ area for area in placements if placements[area].get("type") == "text" ]: placements[area]["text"] = self._strf(placements[area]["text"]) for area in [ area for area in placements if placements[area]["path"] != "" ]: placements[area]["path"] = str( Path(self.config["Repository"]["path"]).joinpath( placements[area]["path"])) placements["viewfinder"]["path"] = preview self._thumbnail = operate( image=self.template, placements=Placements.parse(placements), suppress=suppress, ) return self._thumbnail def entry(self, markdown_type: str = None) -> str: self._entry = self._strf(self.entry_text, markdown_type=markdown_type) return self._entry def export(self, level: int = 4) -> bytes: from bz2 import compress from dill import dumps return compress(dumps(self), compresslevel=level) def pure_export(self) -> bytes: from dill import dumps return dumps(self)
async def _(event): if event.fwd_from: return await event.edit("`Mencari doujin...`") input_str = event.pattern_match.group(1) code = input_str if "nhentai" in input_str: link_regex = r"(?:https?://)?(?:www\.)?nhentai\.net/g/(\d+)" match = re.match(link_regex, input_str) code = match.group(1) if input_str == "random": code = Utils.get_random_id() try: doujin = Hentai(code) except BaseException as n_e: if "404" in str(n_e): return await event.edit(f"Doujin tidak ditemukan untuk `{code}`") return await event.edit(f"**Kesalahan :** `{n_e}`") msg = "" imgs = "" for url in doujin.image_urls: imgs += f"<img src='{url}'/>" imgs = f"‍ {imgs}" title = doujin.title() graph_link = post_to_telegraph(title, imgs) msg += f"[{title}]({graph_link})" msg += f"\n**Sumber :**\n[{code}]({doujin.url})" if doujin.parody: msg += "\n**Parodi :**" parodies = [] for parody in doujin.parody: parodies.append("#" + parody.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(parodies)) if doujin.character: msg += "\n**Karakter :**" charas = [] for chara in doujin.character: charas.append("#" + chara.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(charas)) if doujin.tag: msg += "\n**Tag :**" tags = [] for tag in doujin.tag: tags.append("#" + tag.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(tags)) if doujin.artist: msg += "\n**Artis :**" artists = [] for artist in doujin.artist: artists.append("#" + artist.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(artists)) if doujin.language: msg += "\n**Bahasa :**" languages = [] for language in doujin.language: languages.append("#" + language.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(languages)) if doujin.category: msg += "\n**Kategori :**" categories = [] for category in doujin.category: categories.append( "#" + category.name.replace(" ", "_").replace("-", "_")) msg += "\n" + " ".join(natsorted(categories)) msg += f"\n**Halaman :**\n{doujin.num_pages}" await event.edit(msg, link_preview=True)