diff --git a/nhentai/serializer.py b/nhentai/serializer.py index 5b5675c..17c62b2 100644 --- a/nhentai/serializer.py +++ b/nhentai/serializer.py @@ -1,24 +1,77 @@ # coding: utf-8 +import json +import os - -def serialize(doujinshi): - metadata = {'Title' : doujinshi.name, - 'Subtitle' : doujinshi.info.subtitle} +def serialize(doujinshi, dir): + metadata = {'title' : doujinshi.name, + 'subtitle' : doujinshi.info.subtitle} if doujinshi.info.date: - metadata['Upload_Date'] = doujinshi.info.date + metadata['upload_date'] = doujinshi.info.date if doujinshi.info.parodies: - metadata['Parodies'] = [i.strip() for i in doujinshi.info.parodies.split(',')] + metadata['parody'] = [i.strip() for i in doujinshi.info.parodies.split(',')] if doujinshi.info.characters: - metadata['Characters'] = [i.strip() for i in doujinshi.info.characters.split(',')] + metadata['character'] = [i.strip() for i in doujinshi.info.characters.split(',')] if doujinshi.info.tags: - metadata['Tags'] = [i.strip() for i in doujinshi.info.tags.split(',')] + metadata['tag'] = [i.strip() for i in doujinshi.info.tags.split(',')] if doujinshi.info.artists: - metadata['Artists'] = [i.strip() for i in doujinshi.info.artists.split(',')] + metadata['artist'] = [i.strip() for i in doujinshi.info.artists.split(',')] if doujinshi.info.groups: - metadata['Groups'] = [i.strip() for i in doujinshi.info.groups.split(',')] + metadata['group'] = [i.strip() for i in doujinshi.info.groups.split(',')] if doujinshi.info.languages: - metadata['Languages'] = [i.strip() for i in doujinshi.info.languages.split(',')] - metadata['Categories'] = doujinshi.info.categories + metadata['language'] = [i.strip() for i in doujinshi.info.languages.split(',')] + metadata['category'] = doujinshi.info.categories metadata['URL'] = doujinshi.url metadata['Pages'] = doujinshi.pages - return metadata + with open(os.path.join(dir, 'metadata.json'), 'w') 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: + folder_json = ',"Folder":"' + folder + '"}' + files = os.listdir(folder) + if 'metadata.json' not in files: + continue + data_folder = output_dir + folder + '/' + 'metadata.json' + json_file = open(data_folder, encoding='raw_unicode_escape').read()[:-2]+folder_json + lst.append(json.loads(json_file.encode('raw_unicode_escape').decode())) + return lst + + +def serialize_unique(lst): + dictionary = {} + parody = [] + character = [] + tag = [] + artist = [] + group = [] + for dic in lst: + if dic['parody']: + parody.extend([i for i in dic['parody']]) + if dic['character']: + character.extend([i for i in dic['character']]) + if dic['tag']: + tag.extend([i for i in dic['tag']]) + if dic['artist']: + artist.extend([i for i in dic['artist']]) + if dic['group']: + 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) diff --git a/nhentai/utils.py b/nhentai/utils.py index ce7033c..16f8bdf 100644 --- a/nhentai/utils.py +++ b/nhentai/utils.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals, print_function import sys import re import os -import json import string import zipfile import shutil @@ -12,7 +11,7 @@ import requests from nhentai import constant from nhentai.logger import logger -from nhentai.serializer import serialize +from nhentai.serializer import serialize, set_js_database def request(method, url, **kwargs): @@ -81,22 +80,19 @@ def generate_html(output_dir='.', doujinshi_obj=None): image_html += '\n'\ .format(image) - html = readfile('viewer/index.html') css = readfile('viewer/styles.css') js = readfile('viewer/scripts.js') if doujinshi_obj is not None: - metadata = serialize(doujinshi_obj) + serialize(doujinshi_obj, doujinshi_dir) + name = doujinshi_obj.name if sys.version_info < (3, 0): - metadata['Title'] = doujinshi_obj.name.encode('utf-8') - metadata['Subtitle'] = doujinshi_obj.info.subtitle.encode('utf-8') - with open(os.path.join(doujinshi_dir, 'metadata.json'), 'w') as f: - json.dump(metadata, f, separators=','':') + name = doujinshi_obj.name.encode('utf-8') else: - metadata = {'Title': 'nHentai HTML Viewer'} + name = {'title': 'nHentai HTML Viewer'} - data = html.format(TITLE=metadata['Title'], IMAGES=image_html, SCRIPTS=js, STYLES=css) + data = html.format(TITLE=name, IMAGES=image_html, SCRIPTS=js, STYLES=css) try: if sys.version_info < (3, 0): with open(os.path.join(doujinshi_dir, 'index.html'), 'w') as f: @@ -118,6 +114,7 @@ def generate_main_html(output_dir='./'): """ image_html = '' + main = readfile('viewer/main.html') css = readfile('viewer/main.css') js = readfile('viewer/main.js') @@ -134,11 +131,8 @@ def generate_main_html(output_dir='./'): os.chdir(output_dir) doujinshi_dirs = next(os.walk('.'))[1] - database = open('data.js', 'w') - database.write("var data = JSON.parse('[") for folder in doujinshi_dirs: - folder_json = ',"Folder":"'+folder+'"}' files = os.listdir(folder) files.sort() @@ -147,11 +141,6 @@ def generate_main_html(output_dir='./'): else: continue - database.write(open(output_dir + folder + '/' + files[-1], 'r').read()[:-2]+folder_json) - if folder != doujinshi_dirs[-1]: - database.write(",'+\n'") - else: - database.write("]')") image = files[0] # 001.jpg or 001.png if folder is not None: title = folder.replace('_', ' ') @@ -159,8 +148,6 @@ def generate_main_html(output_dir='./'): title = 'nHentai HTML Viewer' image_html += element.format(FOLDER=folder, IMAGE=image, TITLE=title) - - database.close() if image_html == '': logger.warning('None index.html found, --gen-main paused.') return @@ -172,6 +159,8 @@ def generate_main_html(output_dir='./'): else: with open('./main.html', 'wb') as f: f.write(data.encode('utf-8')) + shutil.copy(os.path.dirname(__file__)+'/viewer/logo.png', './') + set_js_database() logger.log( 15, 'Main Viewer has been write to \'{0}main.html\''.format(output_dir)) except Exception as e: @@ -225,5 +214,3 @@ an invalid filename. def signal_handler(signal, frame): logger.error('Ctrl-C signal received. Stopping...') exit(1) - - diff --git a/nhentai/viewer/main.css b/nhentai/viewer/main.css index dc63203..bf4100c 100644 --- a/nhentai/viewer/main.css +++ b/nhentai/viewer/main.css @@ -1,7 +1,6 @@ /*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.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% @@ -21,10 +20,6 @@ a { -webkit-text-decoration-skip: objects } -a:active,a:hover { - outline-width: 0 -} - abbr[title] { border-bottom: none; text-decoration: underline; @@ -104,11 +99,6 @@ a { color: #34495e } -a:hover { - text-decoration: none; - color: #ed2553 -} - a.count { color: #999 } @@ -130,15 +120,15 @@ blockquote { .container { display: block; clear: both; - margin-left: 200px; - margin-right: auto; - margin-bottom: 10px; - margin-top: 10px; - padding: 10px; + margin-left: 15rem; + margin-right: 0.5rem; + margin-bottom: 5px; + margin-top: 5px; + padding: 4px; border-radius: 9px; background-color: #ecf0f1; - width: 100% - 200px; - max-width: 1200px + width: 100% - 15rem; + max-width: 1500px } .gallery,.gallery-favorite,.thumb-container { @@ -156,7 +146,6 @@ blockquote { .gallery,.gallery-favorite,.thumb-container { width:19%; margin: 3px; - margin-bottom: 8px } } @@ -224,31 +213,202 @@ blockquote { .sidenav { height: 100%; - width: 200px; - position: absolute; + width: 15rem; + position: fixed; z-index: 1; top: 0; left: 0; - background-color: #111; - overflow-x: hidden; + 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 { - padding: 6px 6px 6px 32px; + background-color: #eee; + padding: 5px 0px 5px 15px; text-decoration: none; - font-size: 25px; - color: #818181; + 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: #f1f1f1; + color: white; + background-color: #EC2754; } @media screen and (max-height: 450px) { .sidenav {padding-top: 15px;} - .sidenav a {font-size: 18px;} + .sidenav a {font-size: 15px;} +} + +.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: 10px 0px 5px 8px; + width: 100%; + border: none; + text-align: left; + outline: none; + font-size: 15px; + transition: 0.4s; +} + +.nav-btn.hidden { + display:none +} + +.options { + 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:45px; + white-space: nowrap; + padding-top: 5px +} + +.search input{ + border-top-right-radius:10px; + padding-top:0; + padding-bottom:0; + font-size:1em; + width:100%; + height:38px; + vertical-align:top; +} + +.search .btn.btn-square{ + border-top-left-radius:10px; + border-bottom-left-radius:0px; +} + +.fa{ + font:normal normal normal 14px/1 FontAwesome; + font-size:1.33333333em; + line-height:.75em; +} + +.fa-search:before{ + content:"\f002"; +} + +.btn{ + font-weight:700; + padding-right:12px; + padding-left:12px; + color:#fff; + border:0; + font-size:100%; + height:38px; + line-height:40px; + outline: 0; +} + +.btn.btn-primary{ + background-color:#ed2553; +} + +.btn.btn-primary:active,.btn.btn-primary:focus,.btn.btn-primary:hover{ + color:#fff;background:#f15478; +} + +#tags{ + text-align:left; + display: block; + width:15rem; + display: flex; + flex-flow: row wrap; + justify-content: start; + margin: 2px 2px 2px 0px +} + +.btn-2{ + font-weight:700; + padding-right:10px; + padding-left:10px; + color:#fff; + border:0; + font-size:100%; + height:20px; + outline: 0; + border-radius: 3px; + cursor: pointer; + margin:2px; +} + +.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 { @@ -281,4 +441,4 @@ html.theme-black code { color: #ed2553; border: none; background-color: #292929 -} +} \ No newline at end of file diff --git a/nhentai/viewer/main.html b/nhentai/viewer/main.html index 410f8a2..376dd70 100644 --- a/nhentai/viewer/main.html +++ b/nhentai/viewer/main.html @@ -5,7 +5,7 @@ - nHentai » Viewer + nHentai Viewer