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 @@
-