Shosetsu/VNDB.py
async def get_novel(self, term, hide_nsfw=False):
        """
        If term is an ID will return that specific ID. If it's a string, it will return the details of the first search result for that term.
        Returned Dictionary Has the following structure:
        Please note, if it says list or dict, it means the python types.
        Indentation indicates level. So English is ['Titles']['English']

        'Titles' - Contains all the titles found for the anime
            'English' - English title of the novel
            'Alt' - Alternative title (Usually the Japanese one, but other languages exist)
            'Aliases' - A list of str that define the aliases as given in VNDB.
        'Img' - Link to the Image shown on VNDB for that Visual Novel
        'Length' - Length given by VNDB
        'Developers' - A list containing the Developers of the VN.
        'Publishers' - A list containing the Publishers of the VN.
        'Tags' - Contains 3 lists of different tag categories
            'Content' - List of tags that have to do with the story's content as defined by VNDB. Ex: Edo Era
            'Technology' - List of tags that have to do with the VN's technology. Ex: Protagonist with a Face (Wew Lad, 21st century)
            'Erotic' - List of tags that have to do with the VN's sexual content. Ex: Tentacles
        'Releases' - A list of dictionaries. They have the following format.
            'Date' - Date VNDB lists for release
            'Ages' - Age group appropriate for as determined on VNDB
            'Platform' - Release Platform
            'Name' - The name for this particular Release
            'ID' - The id for this release, also doubles as the link if you append https://vndb.org/ to it
        'Description' - Contains novel description text if there is any.
        'ID' - The id for this novel, also doubles as the link if you append https://vndb.org/ to it

        :param term: id or name to get details of.
        :param hide_nsfw: bool if 'Img' should filter links flagged as NSFW or not. (no reason to be kwargs...yet)
        :return dict: Dictionary with the parsed results of a novel
        """
        if not term.isdigit() and not term.startswith('v'):
            try:
                vnid = await self.search_vndb('v', term)
                vnid = vnid[0]['id']
            except VNDBOneResult as e:
                vnid = e.vnid
        else:
            vnid = str(term)
            if not vnid.startswith('v'):
                vnid = 'v' + vnid
        async with self.session.get(self.base_url + "/{}".format(vnid), headers=self.headers) as response:
            if response.status == 404:
                raise aiohttp.HttpBadRequest("VNDB reported that there is no data for ID {}".format(vnid))
            text = await response.text()
            soup = BeautifulSoup(text, 'lxml')
            data = {'titles': {'english': [], 'alt': [], 'aliases': []}, 'img': None, 'length': None, 'developers': [], 'publishers': [], 'tags': {}, 'releases': {}, 'id': vnid}
            data['titles']['english'] = soup.find_all('div', class_='mainbox')[0].h1.string
            try:
                data['titles']['alt'] = soup.find_all('h2', class_='alttitle')[0].string
            except IndexError:
                data['titles']['alt'] = None
            try:
                imgdiv = soup.find_all('div', class_='vnimg')[0]
                if not (hide_nsfw and 'class' in imgdiv.p.attrs):
                    data['img'] = 'https:' + imgdiv.img.get('src')
            except AttributeError:
                pass
            for item in soup.find_all('tr'):
                if 'class' in item.attrs or len(list(item.children)) == 1:
                    continue
                if item.td.string == 'Aliases':
                    tlist = []
                    for alias in list(item.children)[1:]:
                        tlist.append(alias.string)
                    data['titles']['aliases'] = tlist
                elif item.td.string == 'Length':
                    data['length'] = list(item.children)[1].string
                elif item.td.string == 'Developer':
                    tl = []
                    for item in list(list(item.children)[1].children):
                        if isinstance(item, NavigableString):
                            continue
                        if 'href' in item.attrs:
                            tl.append(item.string)
                    data['developers'] = tl
                    del tl
                elif item.td.string == 'Publishers':
                    tl = []
                    for item in list(list(item.children)[1].children):
                        if isinstance(item, NavigableString):
                            continue
                        if 'href' in item.attrs:
                            tl.append(item.string)
                    data['publishers'] = tl
            conttags = []
            techtags = []
            erotags = []
            test = soup.find('div', attrs={'id': 'vntags'})
            if test:
                for item in list(test.children):
                    if isinstance(item, NavigableString):
                        continue
                    if 'class' not in item.attrs:
                        continue
                    if 'cont' in " ".join(item.get('class')):
                        conttags.append(item.a.string)
                    if 'tech' in " ".join(item.get('class')):
                        techtags.append(item.a.string)
                    if 'ero' in " ".join(item.get('class')):
                        erotags.append(item.a.string)
            data['tags']['content'] = conttags if len(conttags) else None
            data['tags']['technology'] = techtags if len(techtags) else None
            data['tags']['erotic'] = erotags if len(erotags) else None
            del conttags
            del techtags
            del erotags
            releases = []
            cur_lang = None
            for item in list(soup.find('div', class_='mainbox releases').table.children):
                if isinstance(item, NavigableString):
                    continue
                if 'class' in item.attrs:
                    if cur_lang is None:
                        cur_lang = item.td.abbr.get('title')
                    else:
                        data['releases'][cur_lang] = releases
                        releases = []
                        cur_lang = item.td.abbr.get('title')
                else:
                    temp_rel = {'date': 0, 'ages': 0, 'platform': 0, 'name': 0, 'id': 0}
                    children = list(item.children)
                    temp_rel['date'] = children[0].string
                    temp_rel['ages'] = children[1].string
                    temp_rel['platform'] = children[2].abbr.get('title')
                    temp_rel['name'] = children[3].a.string
                    temp_rel['id'] = children[3].a.get('href')[1:]
                    del children
                    releases.append(temp_rel)
                    del temp_rel
            if len(releases) > 0 and cur_lang is not None:
                data['releases'][cur_lang] = releases
            del releases
            del cur_lang
            desc = ""
            for item in list(soup.find_all('td', class_='vndesc')[0].children)[1].contents:
                if not isinstance(item, NavigableString):
                    continue
                if item.startswith('['):
                    continue
                if item.endswith(']'):
                    continue
                desc += item.string + "\n"
            data['description'] = desc
            return data
async def get_novel(self, term, hide_nsfw=False):
        """
        If term is an ID will return that specific ID. If it's a string, it will return the details of the first search result for that term.
        Returned Dictionary Has the following structure:
        Please note, if it says list or dict, it means the python types.
        Indentation indicates level. So English is ['Titles']['English']

        'Titles' - Contains all the titles found for the anime
            'English' - English title of the novel
            'Alt' - Alternative title (Usually the Japanese one, but other languages exist)
            'Aliases' - A list of str that define the aliases as given in VNDB.
        'Img' - Link to the Image shown on VNDB for that Visual Novel
        'Length' - Length given by VNDB
        'Developers' - A list containing the Developers of the VN.
        'Publishers' - A list containing the Publishers of the VN.
        'Tags' - Contains 3 lists of different tag categories
            'Content' - List of tags that have to do with the story's content as defined by VNDB. Ex: Edo Era
            'Technology' - List of tags that have to do with the VN's technology. Ex: Protagonist with a Face (Wew Lad, 21st century)
            'Erotic' - List of tags that have to do with the VN's sexual content. Ex: Tentacles
        'Releases' - A list of dictionaries. They have the following format.
            'Date' - Date VNDB lists for release
            'Ages' - Age group appropriate for as determined on VNDB
            'Platform' - Release Platform
            'Name' - The name for this particular Release
            'ID' - The id for this release, also doubles as the link if you append https://vndb.org/ to it
        'Description' - Contains novel description text if there is any.
        'ID' - The id for this novel, also doubles as the link if you append https://vndb.org/ to it

        :param term: id or name to get details of.
        :param hide_nsfw: bool if 'Img' should filter links flagged as NSFW or not. (no reason to be kwargs...yet)
        :return dict: Dictionary with the parsed results of a novel
        """
        if not term.isdigit() and not term.startswith('v'):
            try:
                vnid = await self.search_vndb('v', term)
                vnid = vnid[0]['id']
            except VNDBOneResult as e:
                vnid = e.vnid
        else:
            vnid = str(term)
            if not vnid.startswith('v'):
                vnid = 'v' + vnid
        async with self.session.get(self.base_url + "/{}".format(vnid), headers=self.headers) as response:
            if response.status == 404:
                raise aiohttp.HttpBadRequest("VNDB reported that there is no data for ID {}".format(vnid))
            text = await response.text()
            soup = BeautifulSoup(text, 'lxml')
            data = {'titles': {'english': [], 'alt': [], 'aliases': []}, 'img': None, 'length': None, 'developers': [], 'publishers': [], 'tags': {}, 'releases': {}, 'id': vnid}
            data['titles']['english'] = soup.find_all('div', class_='mainbox')[0].h1.string
            try:
                data['titles']['alt'] = soup.find_all('h2', class_='alttitle')[0].string
            except IndexError:
                data['titles']['alt'] = None
            try:
                imgdiv = soup.find_all('div', class_='vnimg')[0]
                if not (hide_nsfw and 'class' in imgdiv.p.attrs):
                    data['img'] = 'https:' + imgdiv.img.get('src')
            except AttributeError:
                pass
            for item in soup.find_all('tr'):
                if 'class' in item.attrs or len(list(item.children)) == 1:
                    continue
                if item.td.string == 'Aliases':
                    tlist = []
                    for alias in list(item.children)[1:]:
                        tlist.append(alias.string)
                    data['titles']['aliases'] = tlist
                elif item.td.string == 'Length':
                    data['length'] = list(item.children)[1].string
                elif item.td.string == 'Developer':
                    tl = []
                    for item in list(list(item.children)[1].children):
                        if isinstance(item, NavigableString):
                            continue
                        if 'href' in item.attrs:
                            tl.append(item.string)
                    data['developers'] = tl
                    del tl
                elif item.td.string == 'Publishers':
                    tl = []
                    for item in list(list(item.children)[1].children):
                        if isinstance(item, NavigableString):
                            continue
                        if 'href' in item.attrs:
                            tl.append(item.string)
                    data['publishers'] = tl
            conttags = []
            techtags = []
            erotags = []
            test = soup.find('div', attrs={'id': 'vntags'})
            if test:
                for item in list(test.children):
                    if isinstance(item, NavigableString):
                        continue
                    if 'class' not in item.attrs:
                        continue
                    if 'cont' in " ".join(item.get('class')):
                        conttags.append(item.a.string)
                    if 'tech' in " ".join(item.get('class')):
                        techtags.append(item.a.string)
                    if 'ero' in " ".join(item.get('class')):
                        erotags.append(item.a.string)
            data['tags']['content'] = conttags if len(conttags) else None
            data['tags']['technology'] = techtags if len(techtags) else None
            data['tags']['erotic'] = erotags if len(erotags) else None
            del conttags
            del techtags
            del erotags
            releases = []
            cur_lang = None
            for item in list(soup.find('div', class_='mainbox releases').table.children):
                if isinstance(item, NavigableString):
                    continue
                if 'class' in item.attrs:
                    if cur_lang is None:
                        cur_lang = item.td.abbr.get('title')
                    else:
                        data['releases'][cur_lang] = releases
                        releases = []
                        cur_lang = item.td.abbr.get('title')
                else:
                    temp_rel = {'date': 0, 'ages': 0, 'platform': 0, 'name': 0, 'id': 0}
                    children = list(item.children)
                    temp_rel['date'] = children[0].string
                    temp_rel['ages'] = children[1].string
                    temp_rel['platform'] = children[2].abbr.get('title')
                    temp_rel['name'] = children[3].a.string
                    temp_rel['id'] = children[3].a.get('href')[1:]
                    del children
                    releases.append(temp_rel)
                    del temp_rel
            if len(releases) > 0 and cur_lang is not None:
                data['releases'][cur_lang] = releases
            del releases
            del cur_lang
            desc = ""
            for item in list(soup.find_all('td', class_='vndesc')[0].children)[1].contents:
                if not isinstance(item, NavigableString):
                    continue
                if item.startswith('['):
                    continue
                if item.endswith(']'):
                    continue
                desc += item.string + "\n"
            data['description'] = desc
            return data
async def get_novel ( self , term , hide_nsfw = False ) : if not term . isdigit ( ) and not term . startswith ( 'v' ) : try : vnid = await self . search_vndb ( 'v' , term ) vnid = vnid [ 0 ] [ 'id' ] except VNDBOneResult as e : vnid = e . vnid else : vnid = str ( term ) if not vnid . startswith ( 'v' ) : vnid = 'v' + vnid async with self . session . get ( self . base_url + "/{}" . format ( vnid ) , headers = self . headers ) as response : if response . status == 404 : raise aiohttp . HttpBadRequest ( "VNDB reported that there is no data for ID {}" . format ( vnid ) ) text = await response . text ( ) soup = BeautifulSoup ( text , 'lxml' ) data = { 'titles' : { 'english' : [ ] , 'alt' : [ ] , 'aliases' : [ ] } , 'img' : None , 'length' : None , 'developers' : [ ] , 'publishers' : [ ] , 'tags' : { } , 'releases' : { } , 'id' : vnid } data [ 'titles' ] [ 'english' ] = soup . find_all ( 'div' , class_ = 'mainbox' ) [ 0 ] . h1 . string try : data [ 'titles' ] [ 'alt' ] = soup . find_all ( 'h2' , class_ = 'alttitle' ) [ 0 ] . string except IndexError : data [ 'titles' ] [ 'alt' ] = None try : imgdiv = soup . find_all ( 'div' , class_ = 'vnimg' ) [ 0 ] if not ( hide_nsfw and 'class' in imgdiv . p . attrs ) : data [ 'img' ] = 'https:' + imgdiv . img . get ( 'src' ) except AttributeError : pass for item in soup . find_all ( 'tr' ) : if 'class' in item . attrs or len ( list ( item . children ) ) == 1 : continue if item . td . string == 'Aliases' : tlist = [ ] for alias in list ( item . children ) [ 1 : ] : tlist . append ( alias . string ) data [ 'titles' ] [ 'aliases' ] = tlist elif item . td . string == 'Length' : data [ 'length' ] = list ( item . children ) [ 1 ] . string elif item . td . string == 'Developer' : tl = [ ] for item in list ( list ( item . children ) [ 1 ] . children ) : if isinstance ( item , NavigableString ) : continue if 'href' in item . attrs : tl . append ( item . string ) data [ 'developers' ] = tl del tl elif item . td . string == 'Publishers' : tl = [ ] for item in list ( list ( item . children ) [ 1 ] . children ) : if isinstance ( item , NavigableString ) : continue if 'href' in item . attrs : tl . append ( item . string ) data [ 'publishers' ] = tl conttags = [ ] techtags = [ ] erotags = [ ] test = soup . find ( 'div' , attrs = { 'id' : 'vntags' } ) if test : for item in list ( test . children ) : if isinstance ( item , NavigableString ) : continue if 'class' not in item . attrs : continue if 'cont' in " " . join ( item . get ( 'class' ) ) : conttags . append ( item . a . string ) if 'tech' in " " . join ( item . get ( 'class' ) ) : techtags . append ( item . a . string ) if 'ero' in " " . join ( item . get ( 'class' ) ) : erotags . append ( item . a . string ) data [ 'tags' ] [ 'content' ] = conttags if len ( conttags ) else None data [ 'tags' ] [ 'technology' ] = techtags if len ( techtags ) else None data [ 'tags' ] [ 'erotic' ] = erotags if len ( erotags ) else None del conttags del techtags del erotags releases = [ ] cur_lang = None for item in list ( soup . find ( 'div' , class_ = 'mainbox releases' ) . table . children ) : if isinstance ( item , NavigableString ) : continue if 'class' in item . attrs : if cur_lang is None : cur_lang = item . td . abbr . get ( 'title' ) else : data [ 'releases' ] [ cur_lang ] = releases releases = [ ] cur_lang = item . td . abbr . get ( 'title' ) else : temp_rel = { 'date' : 0 , 'ages' : 0 , 'platform' : 0 , 'name' : 0 , 'id' : 0 } children = list ( item . children ) temp_rel [ 'date' ] = children [ 0 ] . string temp_rel [ 'ages' ] = children [ 1 ] . string temp_rel [ 'platform' ] = children [ 2 ] . abbr . get ( 'title' ) temp_rel [ 'name' ] = children [ 3 ] . a . string temp_rel [ 'id' ] = children [ 3 ] . a . get ( 'href' ) [ 1 : ] del children releases . append ( temp_rel ) del temp_rel if len ( releases ) > 0 and cur_lang is not None : data [ 'releases' ] [ cur_lang ] = releases del releases del cur_lang desc = "" for item in list ( soup . find_all ( 'td' , class_ = 'vndesc' ) [ 0 ] . children ) [ 1 ] . contents : if not isinstance ( item , NavigableString ) : continue if item . startswith ( '[' ) : continue if item . endswith ( ']' ) : continue desc += item . string + "\n" data [ 'description' ] = desc return data
If term is an ID will return that specific ID. If it's a string, it will return the details of the first search result for that term.
        Returned Dictionary Has the following structure:
        Please note, if it says list or dict, it means the python types.
        Indentation indicates level. So English is ['Titles']['English']

        'Titles' - Contains all the titles found for the anime
            'English' - English title of the novel
            'Alt' - Alternative title (Usually the Japanese one, but other languages exist)
            'Aliases' - A list of str that define the aliases as given in VNDB.
        'Img' - Link to the Image shown on VNDB for that Visual Novel
        'Length' - Length given by VNDB
        'Developers' - A list containing the Developers of the VN.
        'Publishers' - A list containing the Publishers of the VN.
        'Tags' - Contains 3 lists of different tag categories
            'Content' - List of tags that have to do with the story's content as defined by VNDB. Ex: Edo Era
            'Technology' - List of tags that have to do with the VN's technology. Ex: Protagonist with a Face (Wew Lad, 21st century)
            'Erotic' - List of tags that have to do with the VN's sexual content. Ex: Tentacles
        'Releases' - A list of dictionaries. They have the following format.
            'Date' - Date VNDB lists for release
            'Ages' - Age group appropriate for as determined on VNDB
            'Platform' - Release Platform
            'Name' - The name for this particular Release
            'ID' - The id for this release, also doubles as the link if you append https://vndb.org/ to it
        'Description' - Contains novel description text if there is any.
        'ID' - The id for this novel, also doubles as the link if you append https://vndb.org/ to it

        :param term: id or name to get details of.
        :param hide_nsfw: bool if 'Img' should filter links flagged as NSFW or not. (no reason to be kwargs...yet)
        :return dict: Dictionary with the parsed results of a novel
If term is an ID will return that specific ID . If it s a string it will return the details of the first search result for that term . Returned Dictionary Has the following structure : Please note if it says list or dict it means the python types . Indentation indicates level . So English is [ Titles ] [ English ]