mirror of
				https://github.com/RicterZ/nhentai.git
				synced 2025-11-04 11:00:55 +01:00 
			
		
		
		
	
							
								
								
									
										12
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.rst
									
									
									
									
									
								
							@@ -74,6 +74,12 @@ Download by tag name:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    nhentai --tag lolicon --download --page=2
 | 
					    nhentai --tag lolicon --download --page=2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Download by language:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nhentai --language english --download --page=2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Download by artist name:
 | 
					Download by artist name:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
@@ -84,13 +90,13 @@ Download by character name:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nhentai --character kuro von einsbern --download
 | 
					    nhentai --character "kuro von einsbern" --download
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Download by parody name:
 | 
					Download by parody name:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nhentai --parody the idolmaster --download
 | 
					    nhentai --parody "the idolmaster" --download
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Download by group name:
 | 
					Download by group name:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -102,7 +108,7 @@ Download using multiple tags (--tag, --character, --paordy and --group supported
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nhentai --tag lolicon, teasing --artist tamano kedama, atte nanakusa
 | 
					    nhentai --tag "lolicon, teasing" --artist "tamano kedama, atte nanakusa"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Download your favorites with delay:
 | 
					Download your favorites with delay:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,7 @@ def cmd_parser():
 | 
				
			|||||||
    parser.add_option('--character', type='string', dest='character', action='store', help='download doujinshi by character')
 | 
					    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('--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('--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',
 | 
					    parser.add_option('--favorites', '-F', action='store_true', dest='favorites',
 | 
				
			||||||
                      help='list or download your favorites.')
 | 
					                      help='list or download your favorites.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -115,7 +116,7 @@ def cmd_parser():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if args.main_viewer and not args.id and not args.keyword and \
 | 
					    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.tag and not args.artist and not args.character and \
 | 
				
			||||||
            not args.parody and not args.group and not args.favorites:
 | 
					            not args.parody and not args.group and not args.language and not args.favorites:
 | 
				
			||||||
        generate_main_html()
 | 
					        generate_main_html()
 | 
				
			||||||
        exit(0)
 | 
					        exit(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -176,13 +177,13 @@ def cmd_parser():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (args.is_download or args.is_show) and not args.id and not args.keyword and \
 | 
					    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.tag and not args.artist and not args.character and \
 | 
				
			||||||
            not args.parody and not args.group and not args.favorites:
 | 
					            not args.parody and not args.group and not args.language and not args.favorites:
 | 
				
			||||||
        logger.critical('Doujinshi id(s) are required for downloading')
 | 
					        logger.critical('Doujinshi id(s) are required for downloading')
 | 
				
			||||||
        parser.print_help()
 | 
					        parser.print_help()
 | 
				
			||||||
        exit(1)
 | 
					        exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not args.keyword and not args.id and not args.tag and not args.artist and \
 | 
					    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.favorites:
 | 
					            not args.character and not args.parody and not args.group and not args.language and not args.favorites:
 | 
				
			||||||
        parser.print_help()
 | 
					        parser.print_help()
 | 
				
			||||||
        exit(1)
 | 
					        exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,6 +70,12 @@ def main():
 | 
				
			|||||||
        if options.is_download and doujinshis:
 | 
					        if options.is_download and doujinshis:
 | 
				
			||||||
            doujinshi_ids = [i['id'] for i in doujinshis]
 | 
					            doujinshi_ids = [i['id'] for i in doujinshis]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    elif options.language:
 | 
				
			||||||
 | 
					        doujinshis = tag_parser(options.language, max_page=options.max_page, index=5)
 | 
				
			||||||
 | 
					        print_doujinshi(doujinshis)
 | 
				
			||||||
 | 
					        if options.is_download and doujinshis:
 | 
				
			||||||
 | 
					            doujinshi_ids = [i['id'] for i in doujinshis]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    elif options.keyword:
 | 
					    elif options.keyword:
 | 
				
			||||||
        doujinshis = search_parser(options.keyword, sorting=options.sorting, page=options.page)
 | 
					        doujinshis = search_parser(options.keyword, sorting=options.sorting, page=options.page)
 | 
				
			||||||
        print_doujinshi(doujinshis)
 | 
					        print_doujinshi(doujinshis)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,8 @@ TAG_URL = ['%s/tag' % BASE_URL,
 | 
				
			|||||||
           '%s/artist' % BASE_URL,
 | 
					           '%s/artist' % BASE_URL,
 | 
				
			||||||
           '%s/character' % BASE_URL,
 | 
					           '%s/character' % BASE_URL,
 | 
				
			||||||
           '%s/parody' % BASE_URL,
 | 
					           '%s/parody' % BASE_URL,
 | 
				
			||||||
           '%s/group' % BASE_URL]
 | 
					           '%s/group' % BASE_URL,
 | 
				
			||||||
 | 
					           '%s/language' % BASE_URL]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TAG_API_URL = '%s/api/galleries/tagged' % BASE_URL
 | 
					TAG_API_URL = '%s/api/galleries/tagged' % BASE_URL
 | 
				
			||||||
LOGIN_URL = '%s/login/' % BASE_URL
 | 
					LOGIN_URL = '%s/login/' % BASE_URL
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -163,7 +163,7 @@ def doujinshi_parser(id_):
 | 
				
			|||||||
    doujinshi['subtitle'] = subtitle.text if subtitle else ''
 | 
					    doujinshi['subtitle'] = subtitle.text if subtitle else ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    doujinshi_cover = html.find('div', attrs={'id': 'cover'})
 | 
					    doujinshi_cover = html.find('div', attrs={'id': 'cover'})
 | 
				
			||||||
    img_id = re.search('/galleries/([\d]+)/cover\.(jpg|png)$', doujinshi_cover.a.img.attrs['data-src'])
 | 
					    img_id = re.search('/galleries/([\d]+)/cover\.(jpg|png|gif)$', doujinshi_cover.a.img.attrs['data-src'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ext = []
 | 
					    ext = []
 | 
				
			||||||
    for i in html.find_all('div', attrs={'class': 'thumb-container'}):
 | 
					    for i in html.find_all('div', attrs={'class': 'thumb-container'}):
 | 
				
			||||||
@@ -187,7 +187,7 @@ def doujinshi_parser(id_):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    # gain information of the doujinshi
 | 
					    # gain information of the doujinshi
 | 
				
			||||||
    information_fields = doujinshi_info.find_all('div', attrs={'class': 'field-name'})
 | 
					    information_fields = doujinshi_info.find_all('div', attrs={'class': 'field-name'})
 | 
				
			||||||
    needed_fields = ['Characters', 'Artists', 'Languages', 'Tags']
 | 
					    needed_fields = ['Characters', 'Artists', 'Languages', 'Tags', 'Parodies', 'Groups', 'Categories']
 | 
				
			||||||
    for field in information_fields:
 | 
					    for field in information_fields:
 | 
				
			||||||
        field_name = field.contents[0].strip().strip(':')
 | 
					        field_name = field.contents[0].strip().strip(':')
 | 
				
			||||||
        if field_name in needed_fields:
 | 
					        if field_name in needed_fields:
 | 
				
			||||||
@@ -195,6 +195,9 @@ def doujinshi_parser(id_):
 | 
				
			|||||||
                    field.find_all('a', attrs={'class': 'tag'})]
 | 
					                    field.find_all('a', attrs={'class': 'tag'})]
 | 
				
			||||||
            doujinshi[field_name.lower()] = ', '.join(data)
 | 
					            doujinshi[field_name.lower()] = ', '.join(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    time_field = doujinshi_info.find('time')
 | 
				
			||||||
 | 
					    if time_field.has_attr('datetime'):
 | 
				
			||||||
 | 
					        doujinshi['date'] = time_field['datetime']
 | 
				
			||||||
    return doujinshi
 | 
					    return doujinshi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -224,7 +227,7 @@ def tag_parser(tag_name, sorting='date', max_page=1, index=0):
 | 
				
			|||||||
    if ',' in tag_name:
 | 
					    if ',' in tag_name:
 | 
				
			||||||
        tag_name = [i.strip().replace(' ', '-') for i in tag_name.split(',')]
 | 
					        tag_name = [i.strip().replace(' ', '-') for i in tag_name.split(',')]
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        tag_name = tag_name.replace(' ', '-')
 | 
					        tag_name = tag_name.strip().replace(' ', '-')
 | 
				
			||||||
    if sorting == 'date':
 | 
					    if sorting == 'date':
 | 
				
			||||||
        sorting = ''
 | 
					        sorting = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -331,7 +334,7 @@ def __api_suspended_doujinshi_parser(id_):
 | 
				
			|||||||
    doujinshi['pages'] = len(response['images']['pages'])
 | 
					    doujinshi['pages'] = len(response['images']['pages'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # gain information of the doujinshi
 | 
					    # gain information of the doujinshi
 | 
				
			||||||
    needed_fields = ['character', 'artist', 'language', 'tag']
 | 
					    needed_fields = ['character', 'artist', 'language', 'tag', 'parody', 'group', 'category']
 | 
				
			||||||
    for tag in response['tags']:
 | 
					    for tag in response['tags']:
 | 
				
			||||||
        tag_type = tag['type']
 | 
					        tag_type = tag['type']
 | 
				
			||||||
        if tag_type in needed_fields:
 | 
					        if tag_type in needed_fields:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										79
									
								
								nhentai/serializer.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								nhentai/serializer.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					# coding: utf-8
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def serialize(doujinshi, dir):
 | 
				
			||||||
 | 
					    metadata = {'title'    : doujinshi.name,
 | 
				
			||||||
 | 
					                'subtitle' : doujinshi.info.subtitle}
 | 
				
			||||||
 | 
					    if doujinshi.info.date:
 | 
				
			||||||
 | 
					        metadata['upload_date'] = doujinshi.info.date
 | 
				
			||||||
 | 
					    if doujinshi.info.parodies:
 | 
				
			||||||
 | 
					        metadata['parody']    = [i.strip() for i in doujinshi.info.parodies.split(',')]
 | 
				
			||||||
 | 
					    if doujinshi.info.characters:
 | 
				
			||||||
 | 
					        metadata['character']  = [i.strip() for i in doujinshi.info.characters.split(',')]
 | 
				
			||||||
 | 
					    if doujinshi.info.tags:
 | 
				
			||||||
 | 
					        metadata['tag']        = [i.strip() for i in doujinshi.info.tags.split(',')]
 | 
				
			||||||
 | 
					    if doujinshi.info.artists:
 | 
				
			||||||
 | 
					        metadata['artist']     = [i.strip() for i in doujinshi.info.artists.split(',')]
 | 
				
			||||||
 | 
					    if doujinshi.info.groups:
 | 
				
			||||||
 | 
					        metadata['group']      = [i.strip() for i in doujinshi.info.groups.split(',')]
 | 
				
			||||||
 | 
					    if doujinshi.info.languages:
 | 
				
			||||||
 | 
					        metadata['language']   = [i.strip() for i in doujinshi.info.languages.split(',')]
 | 
				
			||||||
 | 
					    metadata['category']      = doujinshi.info.categories
 | 
				
			||||||
 | 
					    metadata['URL']             = doujinshi.url
 | 
				
			||||||
 | 
					    metadata['Pages']           = doujinshi.pages
 | 
				
			||||||
 | 
					    with open(os.path.join(dir, 'metadata.json'), 'w', encoding="raw_unicode_escape") as f:
 | 
				
			||||||
 | 
					        json.dump(metadata, f, separators=','':')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def merge_json():
 | 
				
			||||||
 | 
					    lst = []
 | 
				
			||||||
 | 
					    output_dir = "./"
 | 
				
			||||||
 | 
					    os.chdir(output_dir)
 | 
				
			||||||
 | 
					    doujinshi_dirs = next(os.walk('.'))[1]
 | 
				
			||||||
 | 
					    for folder in doujinshi_dirs:
 | 
				
			||||||
 | 
					        files = os.listdir(folder)
 | 
				
			||||||
 | 
					        if 'metadata.json' not in files:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        data_folder = output_dir + folder + '/' + 'metadata.json'
 | 
				
			||||||
 | 
					        json_file = open(data_folder, 'r')
 | 
				
			||||||
 | 
					        json_dict = {}
 | 
				
			||||||
 | 
					        json_dict = json.load(json_file)
 | 
				
			||||||
 | 
					        json_dict['Folder'] = folder
 | 
				
			||||||
 | 
					        lst.append(json_dict)
 | 
				
			||||||
 | 
					    return lst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def serialize_unique(lst):
 | 
				
			||||||
 | 
					    dictionary = {}
 | 
				
			||||||
 | 
					    parody = []
 | 
				
			||||||
 | 
					    character = []
 | 
				
			||||||
 | 
					    tag = []
 | 
				
			||||||
 | 
					    artist = []
 | 
				
			||||||
 | 
					    group = []
 | 
				
			||||||
 | 
					    for dic in lst:
 | 
				
			||||||
 | 
					        if 'parody' in dic:
 | 
				
			||||||
 | 
					            parody.extend([i for i in dic['parody']])
 | 
				
			||||||
 | 
					        if 'character' in dic:
 | 
				
			||||||
 | 
					            character.extend([i for i in dic['character']])
 | 
				
			||||||
 | 
					        if 'tag' in dic:
 | 
				
			||||||
 | 
					            tag.extend([i for i in dic['tag']])
 | 
				
			||||||
 | 
					        if 'artist' in dic:
 | 
				
			||||||
 | 
					            artist.extend([i for i in dic['artist']])
 | 
				
			||||||
 | 
					        if 'group' in dic:
 | 
				
			||||||
 | 
					            group.extend([i for i in dic['group']])
 | 
				
			||||||
 | 
					    dictionary['parody'] = list(set(parody))
 | 
				
			||||||
 | 
					    dictionary['character'] = list(set(character))
 | 
				
			||||||
 | 
					    dictionary['tag'] = list(set(tag))
 | 
				
			||||||
 | 
					    dictionary['artist'] = list(set(artist))
 | 
				
			||||||
 | 
					    dictionary['group'] = list(set(group))
 | 
				
			||||||
 | 
					    return dictionary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def set_js_database():
 | 
				
			||||||
 | 
					    with open('data.js', 'w') as f:
 | 
				
			||||||
 | 
					        indexed_json = merge_json()
 | 
				
			||||||
 | 
					        unique_json = json.dumps(serialize_unique(indexed_json), separators=','':')
 | 
				
			||||||
 | 
					        indexed_json = json.dumps(indexed_json, separators=','':')
 | 
				
			||||||
 | 
					        f.write('var data = '+indexed_json)
 | 
				
			||||||
 | 
					        f.write(';\nvar tags = '+unique_json)
 | 
				
			||||||
@@ -11,6 +11,7 @@ import requests
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from nhentai import constant
 | 
					from nhentai import constant
 | 
				
			||||||
from nhentai.logger import logger
 | 
					from nhentai.logger import logger
 | 
				
			||||||
 | 
					from nhentai.serializer import serialize, set_js_database
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def request(method, url, **kwargs):
 | 
					def request(method, url, **kwargs):
 | 
				
			||||||
@@ -79,19 +80,19 @@ def generate_html(output_dir='.', doujinshi_obj=None):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        image_html += '<img src="{0}" class="image-item"/>\n'\
 | 
					        image_html += '<img src="{0}" class="image-item"/>\n'\
 | 
				
			||||||
            .format(image)
 | 
					            .format(image)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    html = readfile('viewer/index.html')
 | 
					    html = readfile('viewer/index.html')
 | 
				
			||||||
    css = readfile('viewer/styles.css')
 | 
					    css = readfile('viewer/styles.css')
 | 
				
			||||||
    js = readfile('viewer/scripts.js')
 | 
					    js = readfile('viewer/scripts.js')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if doujinshi_obj is not None:
 | 
					    if doujinshi_obj is not None:
 | 
				
			||||||
        title = doujinshi_obj.name
 | 
					        serialize(doujinshi_obj, doujinshi_dir)
 | 
				
			||||||
 | 
					        name = doujinshi_obj.name
 | 
				
			||||||
        if sys.version_info < (3, 0):
 | 
					        if sys.version_info < (3, 0):
 | 
				
			||||||
            title = title.encode('utf-8')
 | 
					            name = doujinshi_obj.name.encode('utf-8')
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        title = 'nHentai HTML Viewer'
 | 
					        name = {'title': 'nHentai HTML Viewer'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    data = html.format(TITLE=title, IMAGES=image_html, SCRIPTS=js, STYLES=css)
 | 
					    data = html.format(TITLE=name, IMAGES=image_html, SCRIPTS=js, STYLES=css)
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        if sys.version_info < (3, 0):
 | 
					        if sys.version_info < (3, 0):
 | 
				
			||||||
            with open(os.path.join(doujinshi_dir, 'index.html'), 'w') as f:
 | 
					            with open(os.path.join(doujinshi_dir, 'index.html'), 'w') as f:
 | 
				
			||||||
@@ -112,10 +113,12 @@ def generate_main_html(output_dir='./'):
 | 
				
			|||||||
    Default output folder will be the CLI path.
 | 
					    Default output folder will be the CLI path.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    count = 0
 | 
					 | 
				
			||||||
    image_html = ''
 | 
					    image_html = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    main = readfile('viewer/main.html')
 | 
					    main = readfile('viewer/main.html')
 | 
				
			||||||
    css = readfile('viewer/main.css')
 | 
					    css = readfile('viewer/main.css')
 | 
				
			||||||
 | 
					    js = readfile('viewer/main.js')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    element = '\n\
 | 
					    element = '\n\
 | 
				
			||||||
            <div class="gallery-favorite">\n\
 | 
					            <div class="gallery-favorite">\n\
 | 
				
			||||||
                <div class="gallery">\n\
 | 
					                <div class="gallery">\n\
 | 
				
			||||||
@@ -130,12 +133,10 @@ def generate_main_html(output_dir='./'):
 | 
				
			|||||||
    doujinshi_dirs = next(os.walk('.'))[1]
 | 
					    doujinshi_dirs = next(os.walk('.'))[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for folder in doujinshi_dirs:
 | 
					    for folder in doujinshi_dirs:
 | 
				
			||||||
 | 
					 | 
				
			||||||
        files = os.listdir(folder)
 | 
					        files = os.listdir(folder)
 | 
				
			||||||
        files.sort()
 | 
					        files.sort()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if 'index.html' in files:
 | 
					        if 'index.html' in files:
 | 
				
			||||||
            count += 1
 | 
					 | 
				
			||||||
            logger.info('Add doujinshi \'{}\''.format(folder))
 | 
					            logger.info('Add doujinshi \'{}\''.format(folder))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
@@ -147,18 +148,19 @@ def generate_main_html(output_dir='./'):
 | 
				
			|||||||
            title = 'nHentai HTML Viewer'
 | 
					            title = 'nHentai HTML Viewer'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        image_html += element.format(FOLDER=folder, IMAGE=image, TITLE=title)
 | 
					        image_html += element.format(FOLDER=folder, IMAGE=image, TITLE=title)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if image_html == '':
 | 
					    if image_html == '':
 | 
				
			||||||
        logger.warning('None index.html found, --gen-main paused.')
 | 
					        logger.warning('None index.html found, --gen-main paused.')
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        data = main.format(STYLES=css, COUNT=count, PICTURE=image_html)
 | 
					        data = main.format(STYLES=css, SCRIPTS=js, PICTURE=image_html)
 | 
				
			||||||
        if sys.version_info < (3, 0):
 | 
					        if sys.version_info < (3, 0):
 | 
				
			||||||
            with open('./main.html', 'w') as f:
 | 
					            with open('./main.html', 'w') as f:
 | 
				
			||||||
                f.write(data)
 | 
					                f.write(data)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            with open('./main.html', 'wb') as f:
 | 
					            with open('./main.html', 'wb') as f:
 | 
				
			||||||
                f.write(data.encode('utf-8'))
 | 
					                f.write(data.encode('utf-8'))
 | 
				
			||||||
 | 
					        shutil.copy(os.path.dirname(__file__)+'/viewer/logo.png', './')
 | 
				
			||||||
 | 
					        set_js_database()
 | 
				
			||||||
        logger.log(
 | 
					        logger.log(
 | 
				
			||||||
            15, 'Main Viewer has been write to \'{0}main.html\''.format(output_dir))
 | 
					            15, 'Main Viewer has been write to \'{0}main.html\''.format(output_dir))
 | 
				
			||||||
    except Exception as e:
 | 
					    except Exception as e:
 | 
				
			||||||
@@ -212,5 +214,3 @@ an invalid filename.
 | 
				
			|||||||
def signal_handler(signal, frame):
 | 
					def signal_handler(signal, frame):
 | 
				
			||||||
    logger.error('Ctrl-C signal received. Stopping...')
 | 
					    logger.error('Ctrl-C signal received. Stopping...')
 | 
				
			||||||
    exit(1)
 | 
					    exit(1)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
<html>
 | 
					<html>
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
    <meta charset="UTF-8">
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes, viewport-fit=cover" />
 | 
				
			||||||
    <title>{TITLE}</title>
 | 
					    <title>{TITLE}</title>
 | 
				
			||||||
    <style>
 | 
					    <style>
 | 
				
			||||||
{STYLES}
 | 
					{STYLES}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								nhentai/viewer/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								nhentai/viewer/logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 10 KiB  | 
@@ -1,79 +1,14 @@
 | 
				
			|||||||
/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
 | 
					/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
 | 
				
			||||||
/* Original from https://static.nhentai.net/css/main_style.9bb9b703e601.css */
 | 
					/* Original from https://static.nhentai.net/css/main_style.9bb9b703e601.css */
 | 
				
			||||||
html {
 | 
					 | 
				
			||||||
    font-family: sans-serif;
 | 
					 | 
				
			||||||
    line-height: 1.15;
 | 
					 | 
				
			||||||
    -ms-text-size-adjust: 100%;
 | 
					 | 
				
			||||||
    -webkit-text-size-adjust: 100%
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
body {
 | 
					 | 
				
			||||||
    margin: 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
h1 {
 | 
					 | 
				
			||||||
    font-size: 2em;
 | 
					 | 
				
			||||||
    margin: .67em 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
a {
 | 
					a {
 | 
				
			||||||
    background-color: transparent;
 | 
					    background-color: transparent;
 | 
				
			||||||
    -webkit-text-decoration-skip: objects
 | 
					    -webkit-text-decoration-skip: objects
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
a:active,a:hover {
 | 
					 | 
				
			||||||
    outline-width: 0
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
abbr[title] {
 | 
					 | 
				
			||||||
    border-bottom: none;
 | 
					 | 
				
			||||||
    text-decoration: underline;
 | 
					 | 
				
			||||||
    text-decoration: underline dotted
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
b,strong {
 | 
					 | 
				
			||||||
    font-weight: inherit
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
b,strong {
 | 
					 | 
				
			||||||
    font-weight: bolder
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
code,kbd,samp {
 | 
					 | 
				
			||||||
    font-family: monospace,monospace;
 | 
					 | 
				
			||||||
    font-size: 1em
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
small {
 | 
					 | 
				
			||||||
    font-size: 80%
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub,sup {
 | 
					 | 
				
			||||||
    font-size: 75%;
 | 
					 | 
				
			||||||
    line-height: 0;
 | 
					 | 
				
			||||||
    position: relative;
 | 
					 | 
				
			||||||
    vertical-align: baseline
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sub {
 | 
					 | 
				
			||||||
    bottom: -.25em
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sup {
 | 
					 | 
				
			||||||
    top: -.5em
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
img {
 | 
					img {
 | 
				
			||||||
    border-style: none
 | 
					    border-style: none
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
label {
 | 
					 | 
				
			||||||
    display: block;
 | 
					 | 
				
			||||||
    font-weight: 700;
 | 
					 | 
				
			||||||
    text-align: justify;
 | 
					 | 
				
			||||||
    white-space: nowrap
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
html {
 | 
					html {
 | 
				
			||||||
    box-sizing: border-box
 | 
					    box-sizing: border-box
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -82,10 +17,6 @@ html {
 | 
				
			|||||||
    box-sizing: inherit
 | 
					    box-sizing: inherit
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
h1,h2,h3,h4,h5,h6 {
 | 
					 | 
				
			||||||
    font-weight: 700
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
body,html {
 | 
					body,html {
 | 
				
			||||||
    font-family: 'Noto Sans',sans-serif;
 | 
					    font-family: 'Noto Sans',sans-serif;
 | 
				
			||||||
    font-size: 14px;
 | 
					    font-size: 14px;
 | 
				
			||||||
@@ -104,25 +35,6 @@ a {
 | 
				
			|||||||
    color: #34495e
 | 
					    color: #34495e
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
a:hover {
 | 
					 | 
				
			||||||
    text-decoration: none;
 | 
					 | 
				
			||||||
    color: #ed2553
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
a.count {
 | 
					 | 
				
			||||||
    color: #999
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
a.bold {
 | 
					 | 
				
			||||||
    font-weight: 700
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
code {
 | 
					 | 
				
			||||||
    color: #ed2553;
 | 
					 | 
				
			||||||
    border: 1px solid #fbd3dd;
 | 
					 | 
				
			||||||
    background-color: #fef0f3
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
blockquote {
 | 
					blockquote {
 | 
				
			||||||
    border: 0
 | 
					    border: 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -130,15 +42,15 @@ blockquote {
 | 
				
			|||||||
.container {
 | 
					.container {
 | 
				
			||||||
    display: block;
 | 
					    display: block;
 | 
				
			||||||
    clear: both;
 | 
					    clear: both;
 | 
				
			||||||
    margin-left: auto;
 | 
					    margin-left: 15rem;
 | 
				
			||||||
    margin-right: auto;
 | 
					    margin-right: 0.5rem;
 | 
				
			||||||
    margin-bottom: 10px;
 | 
					    margin-bottom: 5px;
 | 
				
			||||||
    margin-top: 10px;
 | 
					    margin-top: 5px;
 | 
				
			||||||
    padding: 10px;
 | 
					    padding: 4px;
 | 
				
			||||||
    border-radius: 9px;
 | 
					    border-radius: 9px;
 | 
				
			||||||
    background-color: #ecf0f1;
 | 
					    background-color: #ecf0f1;
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100% - 15rem;
 | 
				
			||||||
    max-width: 1200px
 | 
					    max-width: 1500px
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.gallery,.gallery-favorite,.thumb-container {
 | 
					.gallery,.gallery-favorite,.thumb-container {
 | 
				
			||||||
@@ -156,7 +68,6 @@ blockquote {
 | 
				
			|||||||
    .gallery,.gallery-favorite,.thumb-container {
 | 
					    .gallery,.gallery-favorite,.thumb-container {
 | 
				
			||||||
        width:19%;
 | 
					        width:19%;
 | 
				
			||||||
        margin: 3px;
 | 
					        margin: 3px;
 | 
				
			||||||
        margin-bottom: 8px
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -222,6 +133,186 @@ blockquote {
 | 
				
			|||||||
    width: 100%
 | 
					    width: 100%
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.sidenav {
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  width: 15rem;
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  z-index: 1;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  background-color: #0d0d0d;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  padding-top: 20px;
 | 
				
			||||||
 | 
					  -webkit-touch-callout: none; /* iOS Safari */
 | 
				
			||||||
 | 
					  -webkit-user-select: none; /* Safari */
 | 
				
			||||||
 | 
					  -khtml-user-select: none; /* Konqueror HTML */
 | 
				
			||||||
 | 
					  -moz-user-select: none; /* Old versions of Firefox */
 | 
				
			||||||
 | 
					  ms-user-select: none; /* Internet Explorer/Edge */
 | 
				
			||||||
 | 
					  user-select: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.sidenav a {
 | 
				
			||||||
 | 
					  background-color: #eee;
 | 
				
			||||||
 | 
					  padding: 5px 0px 5px 15px;
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					  font-size: 15px;
 | 
				
			||||||
 | 
					  color: #0d0d0d9;
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.sidenav img {
 | 
				
			||||||
 | 
						width:100%;
 | 
				
			||||||
 | 
						padding: 0px 5px 0px 5px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.sidenav h1 {
 | 
				
			||||||
 | 
					    font-size: 1.5em;
 | 
				
			||||||
 | 
						margin: 0px 0px 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.sidenav a:hover {
 | 
				
			||||||
 | 
					  color: white;
 | 
				
			||||||
 | 
					  background-color: #EC2754;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.accordion {
 | 
				
			||||||
 | 
					  font-weight: bold;
 | 
				
			||||||
 | 
					  background-color: #eee;
 | 
				
			||||||
 | 
					  color: #444;
 | 
				
			||||||
 | 
					  padding: 10px 0px 5px 8px;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  font-size: 15px;
 | 
				
			||||||
 | 
					  transition: 0.4s;
 | 
				
			||||||
 | 
					  cursor:pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.accordion:hover {
 | 
				
			||||||
 | 
					  background-color: #ddd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.accordion.active{
 | 
				
			||||||
 | 
					  background-color:#ddd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.nav-btn {
 | 
				
			||||||
 | 
					  font-weight: bold;
 | 
				
			||||||
 | 
					  background-color: #eee;
 | 
				
			||||||
 | 
					  color: #444;
 | 
				
			||||||
 | 
					  padding: 8px 8px 5px 9px;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  font-size: 15px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.hidden {
 | 
				
			||||||
 | 
					  display:none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.nav-btn a{
 | 
				
			||||||
 | 
					  font-weight: normal;
 | 
				
			||||||
 | 
					  padding-right: 10px;
 | 
				
			||||||
 | 
					  border-radius: 15px;
 | 
				
			||||||
 | 
					  cursor: crosshair
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.options {
 | 
				
			||||||
 | 
					  display:block;
 | 
				
			||||||
 | 
					  padding: 0px 0px 0px 0px;
 | 
				
			||||||
 | 
					  background-color: #eee;
 | 
				
			||||||
 | 
					  max-height: 0;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  transition: max-height 0.2s ease-out;
 | 
				
			||||||
 | 
					  cursor:pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search{
 | 
				
			||||||
 | 
					  background-color: #eee;
 | 
				
			||||||
 | 
					  padding-right:40px;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					  padding-top: 5px;
 | 
				
			||||||
 | 
					  height:43px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search input{
 | 
				
			||||||
 | 
					  border-top-right-radius:10px;
 | 
				
			||||||
 | 
					  padding-top:0;
 | 
				
			||||||
 | 
					  padding-bottom:0;
 | 
				
			||||||
 | 
					  font-size:1em;
 | 
				
			||||||
 | 
					  width:100%;
 | 
				
			||||||
 | 
					  height:38px;
 | 
				
			||||||
 | 
					  vertical-align:top;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn{
 | 
				
			||||||
 | 
					  border-top-left-radius:10px;
 | 
				
			||||||
 | 
					  color:#fff;
 | 
				
			||||||
 | 
					  font-size:100%;
 | 
				
			||||||
 | 
					  padding: 8px;
 | 
				
			||||||
 | 
					  width:38px;
 | 
				
			||||||
 | 
					  background-color:#ed2553;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#tags{
 | 
				
			||||||
 | 
					    text-align:left;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
						width:15rem;
 | 
				
			||||||
 | 
					    justify-content: start;
 | 
				
			||||||
 | 
						margin: 2px 2px 2px 0px;
 | 
				
			||||||
 | 
						flex-wrap: wrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-2{
 | 
				
			||||||
 | 
					  font-weight:700;
 | 
				
			||||||
 | 
					  padding-right:0.5rem;
 | 
				
			||||||
 | 
					  padding-left:0.5rem;
 | 
				
			||||||
 | 
					  color:#fff;
 | 
				
			||||||
 | 
					  border:0;
 | 
				
			||||||
 | 
					  font-size:100%;
 | 
				
			||||||
 | 
					  height:1.25rem;
 | 
				
			||||||
 | 
					  outline: 0;
 | 
				
			||||||
 | 
					  border-radius: 0.3rem;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  margin:0.15rem;
 | 
				
			||||||
 | 
					  transition: all 1s linear;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-2#parody{
 | 
				
			||||||
 | 
					  background-color: red;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-2#character{
 | 
				
			||||||
 | 
					  background-color: blue;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-2#tag{
 | 
				
			||||||
 | 
					  background-color: green;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-2#artist{
 | 
				
			||||||
 | 
					  background-color: fuchsia;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-2#group{
 | 
				
			||||||
 | 
					  background-color: teal;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-2.hover{
 | 
				
			||||||
 | 
					  filter: saturate(20%)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					input,input:focus{
 | 
				
			||||||
 | 
					  border:none;
 | 
				
			||||||
 | 
					  outline:0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
html.theme-black,html.theme-black body {
 | 
					html.theme-black,html.theme-black body {
 | 
				
			||||||
    color: #d9d9d9;
 | 
					    color: #d9d9d9;
 | 
				
			||||||
    background-color: #0d0d0d
 | 
					    background-color: #0d0d0d
 | 
				
			||||||
@@ -231,14 +322,6 @@ html.theme-black #thumbnail-container,html.theme-black .container {
 | 
				
			|||||||
    background-color: #1f1f1f
 | 
					    background-color: #1f1f1f
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
html.theme-black #thumbnail-container .lazyload,html.theme-black .lazyload {
 | 
					 | 
				
			||||||
    background-color: #262626
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
html.theme-black #thumbnail-container .lazyload-loading,html.theme-black .lazyload-loading {
 | 
					 | 
				
			||||||
    background-color: #2e2e2e
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
html.theme-black .gallery:hover .caption {
 | 
					html.theme-black .gallery:hover .caption {
 | 
				
			||||||
    box-shadow: 0 10px 20px rgba(0,0,0,.5)
 | 
					    box-shadow: 0 10px 20px rgba(0,0,0,.5)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -247,9 +330,3 @@ html.theme-black .caption {
 | 
				
			|||||||
    background-color: #404040;
 | 
					    background-color: #404040;
 | 
				
			||||||
    color: #d9d9d9
 | 
					    color: #d9d9d9
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
html.theme-black code {
 | 
					 | 
				
			||||||
    color: #ed2553;
 | 
					 | 
				
			||||||
    border: none;
 | 
					 | 
				
			||||||
    background-color: #292929
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -5,7 +5,8 @@
 | 
				
			|||||||
    <meta charset="utf-8" />
 | 
					    <meta charset="utf-8" />
 | 
				
			||||||
    <meta name="theme-color" content="#1f1f1f" />
 | 
					    <meta name="theme-color" content="#1f1f1f" />
 | 
				
			||||||
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes, viewport-fit=cover" />
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes, viewport-fit=cover" />
 | 
				
			||||||
    <title>nHentai » Viewer</title>
 | 
					    <title>nHentai Viewer</title>
 | 
				
			||||||
 | 
					    <script type="text/javascript" src="data.js"></script>
 | 
				
			||||||
        <!-- <link rel="stylesheet" href="./main.css"> -->
 | 
					        <!-- <link rel="stylesheet" href="./main.css"> -->
 | 
				
			||||||
<style>
 | 
					<style>
 | 
				
			||||||
{STYLES}
 | 
					{STYLES}
 | 
				
			||||||
@@ -14,9 +15,27 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
    <div id="content">
 | 
					    <div id="content">
 | 
				
			||||||
 | 
					        <nav class="sidenav">
 | 
				
			||||||
        <h1>Main Folder({COUNT})</h1>
 | 
								<img src="logo.png">
 | 
				
			||||||
 | 
								<h1>nHentai Viewer</h1>
 | 
				
			||||||
 | 
					                        <button class="accordion">Language</button>
 | 
				
			||||||
 | 
					            <div class="options" id="language">
 | 
				
			||||||
 | 
					                    <a>English</a>
 | 
				
			||||||
 | 
					                    <a>Japanese</a>
 | 
				
			||||||
 | 
					                    <a>Chinese</a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
								<button class="accordion">Category</button>
 | 
				
			||||||
 | 
					            <div class="options" id ="category">
 | 
				
			||||||
 | 
					                    <a>Doujinshi</a>
 | 
				
			||||||
 | 
					                    <a>Manga</a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
								<button class="nav-btn hidden">Filters</button>
 | 
				
			||||||
 | 
								<div class="search">
 | 
				
			||||||
 | 
									<input autocomplete="off" type="search" id="tagfilter" name="q" value="" autocapitalize="none" required="">
 | 
				
			||||||
 | 
									<svg class="btn" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="white" d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>
 | 
				
			||||||
 | 
								<div id="tags">
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</nav>
 | 
				
			||||||
        <div class="container" id="favcontainer">
 | 
					        <div class="container" id="favcontainer">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {PICTURE}
 | 
					            {PICTURE}
 | 
				
			||||||
@@ -24,7 +43,9 @@
 | 
				
			|||||||
        </div> <!-- container -->
 | 
					        </div> <!-- container -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					    {SCRIPTS}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										177
									
								
								nhentai/viewer/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								nhentai/viewer/main.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
				
			|||||||
 | 
					    //------------------------------------navbar script------------------------------------
 | 
				
			||||||
 | 
					var menu = document.getElementsByClassName("accordion");
 | 
				
			||||||
 | 
					for (var i = 0; i < menu.length; i++) {
 | 
				
			||||||
 | 
					  menu[i].addEventListener("click", function() {
 | 
				
			||||||
 | 
					    var panel = this.nextElementSibling;
 | 
				
			||||||
 | 
					    if (panel.style.maxHeight) {
 | 
				
			||||||
 | 
						  this.classList.toggle("active");
 | 
				
			||||||
 | 
					      panel.style.maxHeight = null;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      panel.style.maxHeight = panel.scrollHeight + "px";
 | 
				
			||||||
 | 
						  this.classList.toggle("active");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					var language = document.getElementById("language").children;
 | 
				
			||||||
 | 
					for (var i = 0; i < language.length; i++){
 | 
				
			||||||
 | 
						language[i].addEventListener("click", function() {
 | 
				
			||||||
 | 
							toggler = document.getElementById("language")
 | 
				
			||||||
 | 
							toggler.style.maxHeight = null;
 | 
				
			||||||
 | 
							document.getElementsByClassName("accordion")[0].classList.toggle("active");
 | 
				
			||||||
 | 
							filter_maker(this.innerText, "language");
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					var category = document.getElementById("category").children;
 | 
				
			||||||
 | 
					for (var i = 0; i < category.length; i++){
 | 
				
			||||||
 | 
						category[i].addEventListener("click", function() {
 | 
				
			||||||
 | 
							document.getElementById("category").style.maxHeight = null;
 | 
				
			||||||
 | 
							document.getElementsByClassName("accordion")[1].classList.toggle("active");
 | 
				
			||||||
 | 
							filter_maker(this.innerText, "category");
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//-----------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//----------------------------------Tags Script--------------------------------------
 | 
				
			||||||
 | 
					tag_maker(tags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var tag = document.getElementsByClassName("btn-2");
 | 
				
			||||||
 | 
					for (var i = 0; i < tag.length; i++){
 | 
				
			||||||
 | 
						tag[i].addEventListener("click", function() {
 | 
				
			||||||
 | 
						filter_maker(this.innerText, this.id);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var input = document.getElementById("tagfilter");
 | 
				
			||||||
 | 
					input.addEventListener("input", function() {
 | 
				
			||||||
 | 
						var tags = document.querySelectorAll(".btn-2");
 | 
				
			||||||
 | 
						if (this.value.length > 0) {
 | 
				
			||||||
 | 
					        for (var i = 0; i < tags.length; i++) {
 | 
				
			||||||
 | 
					            var tag = tags[i];
 | 
				
			||||||
 | 
					            var nome = tag.innerText;
 | 
				
			||||||
 | 
					            var exp = new RegExp(this.value, "i");;
 | 
				
			||||||
 | 
					            if (exp.test(nome)) {
 | 
				
			||||||
 | 
					                tag.classList.remove("hidden");
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									tag.classList.add("hidden");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        for (var i = 0; i < tags.length; i++) {
 | 
				
			||||||
 | 
					            var tag = tags[i];
 | 
				
			||||||
 | 
									tag.classList.add('hidden');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					input.addEventListener('keypress', function (e) {
 | 
				
			||||||
 | 
						enter_search(e, this.value);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					//-----------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//------------------------------------Functions--------------------------------------
 | 
				
			||||||
 | 
					function enter_search(e, input){
 | 
				
			||||||
 | 
						var count = 0;
 | 
				
			||||||
 | 
						var key = e.which || e.keyCode;
 | 
				
			||||||
 | 
						if (key === 13 && input.length > 0) {
 | 
				
			||||||
 | 
						  var all_tags = document.getElementById("tags").children;
 | 
				
			||||||
 | 
						  for(i = 0; i < all_tags.length; i++){
 | 
				
			||||||
 | 
							if (!all_tags[i].classList.contains("hidden")){
 | 
				
			||||||
 | 
								count++;
 | 
				
			||||||
 | 
								var tag_name = all_tags[i].innerText;
 | 
				
			||||||
 | 
								var tag_id   = all_tags[i].id;
 | 
				
			||||||
 | 
								if (count>1){break}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						  }
 | 
				
			||||||
 | 
						  if (count == 1){
 | 
				
			||||||
 | 
							filter_maker(tag_name, tag_id);
 | 
				
			||||||
 | 
						  }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function filter_maker(text, class_value){
 | 
				
			||||||
 | 
					    var check = filter_checker(text);
 | 
				
			||||||
 | 
						var nav_btn = document.getElementsByClassName("nav-btn")[0];
 | 
				
			||||||
 | 
						if (nav_btn.classList.contains("hidden")){
 | 
				
			||||||
 | 
						  nav_btn.classList.toggle("hidden");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (check == true){
 | 
				
			||||||
 | 
							var node = document.createElement("a");
 | 
				
			||||||
 | 
							var textnode = document.createTextNode(text);
 | 
				
			||||||
 | 
							node.appendChild(textnode);
 | 
				
			||||||
 | 
							node.classList.add(class_value);
 | 
				
			||||||
 | 
							nav_btn.appendChild(node);
 | 
				
			||||||
 | 
							filter_searcher();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function filter_searcher(){
 | 
				
			||||||
 | 
						var verifier = null;
 | 
				
			||||||
 | 
						var tags_filter = [];
 | 
				
			||||||
 | 
						var doujinshi_id = [];
 | 
				
			||||||
 | 
						var filter_tag = document.getElementsByClassName("nav-btn")[0].children;
 | 
				
			||||||
 | 
						filter_tag[filter_tag.length-1].addEventListener("click", function() {
 | 
				
			||||||
 | 
							this.remove();
 | 
				
			||||||
 | 
							try{
 | 
				
			||||||
 | 
								filter_searcher();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							catch{
 | 
				
			||||||
 | 
								var gallery = document.getElementsByClassName("gallery-favorite");
 | 
				
			||||||
 | 
								for (var i = 0; i < gallery.length; i++){
 | 
				
			||||||
 | 
									gallery[i].classList.remove("hidden");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						for (var i=0; i < filter_tag.length; i++){
 | 
				
			||||||
 | 
							var fclass = filter_tag[i].className;
 | 
				
			||||||
 | 
							var fname = filter_tag[i].innerText.toLowerCase();
 | 
				
			||||||
 | 
							tags_filter.push([fclass, fname])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (var i=0; i < data.length; i++){
 | 
				
			||||||
 | 
							for (var j=0; j < tags_filter.length; j++){
 | 
				
			||||||
 | 
								try{
 | 
				
			||||||
 | 
									if(data[i][tags_filter[j][0]].includes(tags_filter[j][1])){
 | 
				
			||||||
 | 
										verifier = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else{
 | 
				
			||||||
 | 
										verifier = false;
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								catch{
 | 
				
			||||||
 | 
									verifier = false;
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (verifier){doujinshi_id.push(data[i].Folder);}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var gallery = document.getElementsByClassName("gallery-favorite");
 | 
				
			||||||
 | 
						for (var i = 0; i < gallery.length; i++){
 | 
				
			||||||
 | 
							gtext = gallery	[i].children[0].children[0].children[1].innerText;
 | 
				
			||||||
 | 
							if(doujinshi_id.includes(gtext)){
 | 
				
			||||||
 | 
								gallery[i].classList.remove("hidden");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else{
 | 
				
			||||||
 | 
							gallery[i].classList.add("hidden");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function filter_checker(text){
 | 
				
			||||||
 | 
					    var filter_tags = document.getElementsByClassName("nav-btn")[0].children;
 | 
				
			||||||
 | 
						if (filter_tags == null){return true;}
 | 
				
			||||||
 | 
						for (var i=0; i < filter_tags.length; i++){
 | 
				
			||||||
 | 
							if (filter_tags[i].innerText == text){return false;}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function tag_maker(data){
 | 
				
			||||||
 | 
						for (i in data){
 | 
				
			||||||
 | 
							for (j in data[i]){
 | 
				
			||||||
 | 
								var node = document.createElement("button");
 | 
				
			||||||
 | 
								var textnode = document.createTextNode(data[i][j]);
 | 
				
			||||||
 | 
								node.appendChild(textnode);
 | 
				
			||||||
 | 
								node.classList.add("btn-2");
 | 
				
			||||||
 | 
								node.setAttribute('id', i);
 | 
				
			||||||
 | 
								node.classList.add("hidden");
 | 
				
			||||||
 | 
								document.getElementById("tags").appendChild(node);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					  
 | 
				
			||||||
*, *::after, *::before {
 | 
					*, *::after, *::before {
 | 
				
			||||||
    box-sizing: border-box;
 | 
					    box-sizing: border-box;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user