diff --git a/README.rst b/README.rst index dc167f2..7dfc26b 100644 --- a/README.rst +++ b/README.rst @@ -79,53 +79,20 @@ Download doujinshi with ids specified in a file (doujinshi ids split by line): nhentai --file=doujinshi.txt +Set search default language + +.. code-block:: bash + + nhentai --language=english + Search a keyword and download the first page: .. code-block:: bash nhentai --search="tomori" --page=1 --download - -Download by tag name: - -.. code-block:: bash - - nhentai --tag lolicon --download --page=2 - -Download by language: - -.. code-block:: bash - - nhentai --language english --download --page=2 - -Download by artist name: - -.. code-block:: bash - - nhentai --artist henreader --download - -Download by character name: - -.. code-block:: bash - - nhentai --character "kuro von einsbern" --download - -Download by parody name: - -.. code-block:: bash - - nhentai --parody "the idolmaster" --download - -Download by group name: - -.. code-block:: bash - - nhentai --group clesta --download - -Download using multiple tags (--tag, --character, --paordy and --group supported): - -.. code-block:: bash - - nhentai --tag "lolicon, teasing" --artist "tamano kedama, atte nanakusa" + # you also can download by tags and multiple keywords + nhentai --search="tag:lolicon, artist:henreader, tag:full color" + nhentai --search="lolicon, henreader, full color" Download your favorites with delay: diff --git a/nhentai/cmdline.py b/nhentai/cmdline.py index 13a8692..8e06bfe 100644 --- a/nhentai/cmdline.py +++ b/nhentai/cmdline.py @@ -38,7 +38,7 @@ def banner(): def cmd_parser(): parser = OptionParser('\n nhentai --search [keyword] --download' '\n NHENTAI=http://h.loli.club nhentai --id [ID ...]' - '\n nhentai --file [filename]' + '\n nhentai --file [filename]' '\n\nEnvironment Variable:\n' ' NHENTAI nhentai mirror url') # operation options @@ -50,14 +50,6 @@ def cmd_parser(): parser.add_option('--id', type='string', dest='id', action='store', help='doujinshi ids set, e.g. 1,2,3') parser.add_option('--search', '-s', type='string', dest='keyword', action='store', help='search doujinshi by keyword') - parser.add_option('--tag', type='string', dest='tag', action='store', help='download doujinshi by tag') - parser.add_option('--artist', type='string', dest='artist', action='store', help='download doujinshi by artist') - parser.add_option('--character', type='string', dest='character', action='store', - help='download doujinshi by character') - parser.add_option('--parody', type='string', dest='parody', action='store', help='download doujinshi by parody') - parser.add_option('--group', type='string', dest='group', action='store', help='download doujinshi by group') - parser.add_option('--language', type='string', dest='language', action='store', - help='download doujinshi by language') parser.add_option('--favorites', '-F', action='store_true', dest='favorites', help='list or download your favorites.') @@ -95,14 +87,14 @@ def cmd_parser(): help='generate a main viewer contain all the doujin in the folder') parser.add_option('--cbz', '-C', dest='is_cbz', action='store_true', help='generate Comic Book CBZ File') - parser.add_option('--comic-info', dest='write_comic_info', action='store_true', - help='when generating Comic Book CBZ File, also write ComicInfo.xml') parser.add_option('--rm-origin-dir', dest='rm_origin_dir', action='store_true', default=False, help='remove downloaded doujinshi dir when generated CBZ file.') # nhentai options parser.add_option('--cookie', type='str', dest='cookie', action='store', help='set cookie of nhentai to bypass Google recaptcha') + parser.add_option('--language', type='str', dest='language', action='store', + help='set default language to parse doujinshis') parser.add_option('--save-download-history', dest='is_save_download_history', action='store_true', default=False, help='save downloaded doujinshis, whose will be skipped if you re-download them') parser.add_option('--clean-download-history', action='store_true', default=False, dest='clean_download_history', @@ -123,8 +115,7 @@ def cmd_parser(): exit(0) if args.main_viewer and not args.id and not args.keyword and \ - not args.tag and not args.artist and not args.character and \ - not args.parody and not args.group and not args.language and not args.favorites: + not args.tag and not args.favorites: generate_main_html() exit(0) @@ -153,6 +144,25 @@ def cmd_parser(): logger.info('Cookie saved.') exit(0) + if os.path.exists(constant.NHENTAI_LANGUAGE) and not args.language: + with open(constant.NHENTAI_LANGUAGE, 'r') as f: + constant.LANGUAGE = f.read() + args.language = f.read() + + if args.language: + try: + if not os.path.exists(constant.NHENTAI_HOME): + os.mkdir(constant.NHENTAI_HOME) + + with open(constant.NHENTAI_LANGUAGE, 'w') as f: + f.write(args.language) + except Exception as e: + logger.error('Cannot create NHENTAI_HOME: {}'.format(str(e))) + exit(1) + + logger.info('Default language now is {}.'.format(args.language)) + exit(0) + if os.path.exists(constant.NHENTAI_PROXY): with open(constant.NHENTAI_PROXY, 'r') as f: link = f.read() @@ -192,14 +202,12 @@ def cmd_parser(): args.id = set(int(i) for i in _ if i.isdigit()) if (args.is_download or args.is_show) and not args.id and not args.keyword and \ - not args.tag and not args.artist and not args.character and \ - not args.parody and not args.group and not args.language and not args.favorites: + not args.tag and not args.favorites: logger.critical('Doujinshi id(s) are required for downloading') parser.print_help() exit(1) - if not args.keyword and not args.id and not args.tag and not args.artist and \ - not args.character and not args.parody and not args.group and not args.language and not args.favorites: + if not args.keyword and not args.id and not args.favorites: parser.print_help() exit(1) diff --git a/nhentai/command.py b/nhentai/command.py index 6f821d3..40e412c 100644 --- a/nhentai/command.py +++ b/nhentai/command.py @@ -6,7 +6,7 @@ import platform import time from nhentai.cmdline import cmd_parser, banner -from nhentai.parser import doujinshi_parser, search_parser, print_doujinshi, favorites_parser, tag_parser +from nhentai.parser import doujinshi_parser, search_parser, print_doujinshi, favorites_parser from nhentai.doujinshi import Doujinshi from nhentai.downloader import Downloader from nhentai.logger import logger @@ -21,14 +21,12 @@ def main(): from nhentai.constant import PROXY # constant.PROXY will be changed after cmd_parser() - if PROXY != {}: + if PROXY: logger.info('Using proxy: {0}'.format(PROXY)) # check your cookie check_cookie() - index = 0 - index_value = None doujinshis = [] doujinshi_ids = [] doujinshi_list = [] @@ -39,38 +37,16 @@ def main(): doujinshis = favorites_parser(options.page_range) - elif options.tag: - doujinshis = tag_parser(options.tag, sorting=options.sorting, max_page=options.max_page) - - elif options.artist: - index = 1 - index_value = options.artist - - elif options.character: - index = 2 - index_value = options.character - - elif options.parody: - index = 3 - index_value = options.parody - - elif options.group: - index = 4 - index_value = options.group - - elif options.language: - index = 5 - index_value = options.language - elif options.keyword: + from nhentai.constant import LANGUAGE + if LANGUAGE: + logger.info('Using deafult language: {0}'.format(LANGUAGE)) + options.keyword += ', language:{}'.format(LANGUAGE) doujinshis = search_parser(options.keyword, sorting=options.sorting, page=options.page) elif not doujinshi_ids: doujinshi_ids = options.id - if index: - doujinshis = tag_parser(index_value, max_page=options.max_page, index=index) - print_doujinshi(doujinshis) if options.is_download and doujinshis: doujinshi_ids = [i['id'] for i in doujinshis] @@ -109,7 +85,7 @@ def main(): if not options.is_nohtml and not options.is_cbz: generate_html(options.output_dir, doujinshi) elif options.is_cbz: - generate_cbz(options.output_dir, doujinshi, options.rm_origin_dir, options.write_comic_info) + generate_cbz(options.output_dir, doujinshi, options.rm_origin_dir) if options.main_viewer: generate_main_html(options.output_dir) @@ -125,6 +101,5 @@ def main(): signal.signal(signal.SIGINT, signal_handler) - if __name__ == '__main__': main() diff --git a/nhentai/constant.py b/nhentai/constant.py index c5c7c53..c6b40c4 100644 --- a/nhentai/constant.py +++ b/nhentai/constant.py @@ -12,17 +12,10 @@ except ImportError: BASE_URL = os.getenv('NHENTAI', 'https://nhentai.net') __api_suspended_DETAIL_URL = '%s/api/gallery' % BASE_URL -__api_suspended_SEARCH_URL = '%s/api/galleries/search' % BASE_URL DETAIL_URL = '%s/g' % BASE_URL -SEARCH_URL = '%s/search/' % BASE_URL +SEARCH_URL = '%s/api/galleries/search' % BASE_URL -TAG_URL = ['%s/tag' % BASE_URL, - '%s/artist' % BASE_URL, - '%s/character' % BASE_URL, - '%s/parody' % BASE_URL, - '%s/group' % BASE_URL, - '%s/language' % BASE_URL] TAG_API_URL = '%s/api/galleries/tagged' % BASE_URL LOGIN_URL = '%s/login/' % BASE_URL @@ -35,8 +28,10 @@ IMAGE_URL = '%s://i.%s/galleries' % (u.scheme, u.hostname) NHENTAI_HOME = os.path.join(os.getenv('HOME', tempfile.gettempdir()), '.nhentai') NHENTAI_PROXY = os.path.join(NHENTAI_HOME, 'proxy') NHENTAI_COOKIE = os.path.join(NHENTAI_HOME, 'cookie') +NHENTAI_LANGUAGE = os.path.join(NHENTAI_HOME, 'language') NHENTAI_HISTORY = os.path.join(NHENTAI_HOME, 'history.sqlite3') PROXY = {} COOKIE = '' +LANGUAGE = '' diff --git a/nhentai/parser.py b/nhentai/parser.py index 97ea354..62224d5 100644 --- a/nhentai/parser.py +++ b/nhentai/parser.py @@ -120,15 +120,15 @@ def page_range_parser(page_range, max_page_num): else: try: left = int(range_str[:idx]) - right = int(range_str[idx+1:]) + right = int(range_str[idx + 1:]) if right > max_page_num: right = max_page_num - for page in range(left, right+1): + for page in range(left, right + 1): pages.add(page) except ValueError: logger.error('page range({0}) is not valid'.format(page_range)) - - return list(pages) + + return list(pages) def doujinshi_parser(id_): @@ -143,7 +143,7 @@ def doujinshi_parser(id_): try: response = request('get', url) - if response.status_code in (200, ): + if response.status_code in (200,): response = response.content else: logger.debug('Slow down and retry ({}) ...'.format(id_)) @@ -202,7 +202,7 @@ def doujinshi_parser(id_): return doujinshi -def search_parser(keyword, sorting='date', page=1): +def old_search_parser(keyword, sorting='date', page=1): logger.debug('Searching doujinshis of keyword {0}'.format(keyword)) response = request('get', url=constant.SEARCH_URL, params={'q': keyword, 'page': page, 'sort': sorting}).content @@ -222,50 +222,15 @@ def print_doujinshi(doujinshi_list): tabulate(tabular_data=doujinshi_list, headers=headers, tablefmt='rst')) -def tag_parser(tag_name, sorting='date', max_page=1, index=0): - result = [] - tag_name = tag_name.lower() - if ',' in tag_name: - tag_name = [i.strip().replace(' ', '-') for i in tag_name.split(',')] - else: - tag_name = tag_name.strip().replace(' ', '-') - if sorting == 'date': - sorting = '' - - for p in range(1, max_page + 1): - if sys.version_info >= (3, 0, 0): - unicode_ = str - else: - unicode_ = unicode - - if isinstance(tag_name, (str, unicode_)): - logger.debug('Fetching page {0} for doujinshi with tag \'{1}\''.format(p, tag_name)) - response = request('get', url='%s/%s/%s?page=%d' % (constant.TAG_URL[index], tag_name, sorting, p)).content - result += _get_title_and_id(response) - else: - for i in tag_name: - logger.debug('Fetching page {0} for doujinshi with tag \'{1}\''.format(p, i)) - response = request('get', - url='%s/%s/%s?page=%d' % (constant.TAG_URL[index], i, sorting, p)).content - result += _get_title_and_id(response) - - if not result: - logger.error('Cannot find doujinshi id of tag \'{0}\''.format(tag_name)) - return - - if not result: - logger.warn('No results for tag \'{}\''.format(tag_name)) - - return result - - -def __api_suspended_search_parser(keyword, sorting, page): +def search_parser(keyword, sorting, page): logger.debug('Searching doujinshis using keywords {0}'.format(keyword)) + keyword = '+'.join([i.strip().replace(' ', '-').lower() for i in keyword.split(',')]) result = [] i = 0 while i < 5: try: - response = request('get', url=constant.SEARCH_URL, params={'query': keyword, 'page': page, 'sort': sorting}).json() + url = request('get', url=constant.SEARCH_URL, params={'query': keyword, 'page': page, 'sort': sorting}).url + response = request('get', url.replace('%2B', '+')).json() except Exception as e: i += 1 if not i < 5: @@ -289,29 +254,6 @@ def __api_suspended_search_parser(keyword, sorting, page): return result -def __api_suspended_tag_parser(tag_id, sorting, max_page=1): - logger.info('Searching for doujinshi with tag id {0}'.format(tag_id)) - result = [] - response = request('get', url=constant.TAG_API_URL, params={'sort': sorting, 'tag_id': tag_id}).json() - page = max_page if max_page <= response['num_pages'] else int(response['num_pages']) - - for i in range(1, page + 1): - logger.info('Getting page {} ...'.format(i)) - - if page != 1: - response = request('get', url=constant.TAG_API_URL, - params={'sort': sorting, 'tag_id': tag_id}).json() - for row in response['result']: - title = row['title']['english'] - title = title[:85] + '..' if len(title) > 85 else title - result.append({'id': row['id'], 'title': title}) - - if not result: - logger.warn('No results for tag id {}'.format(tag_id)) - - return result - - def __api_suspended_doujinshi_parser(id_): if not isinstance(id_, (int,)) and (isinstance(id_, (str,)) and not id_.isdigit()): raise Exception('Doujinshi id({0}) is not valid'.format(id_))