mirror of
				https://github.com/RicterZ/nhentai.git
				synced 2025-11-04 02:50:55 +01:00 
			
		
		
		
	Rework the HTML Viewer
* More modern and efficient code, particularily for the JS * Also the layout is better, with flexboxes and all * The CSS and JS have their own files * The sidebar has proper margins around the images * You can use A + D and the arrow keys to navigate images, like on nhentai * Images with a lot of width are properly sized * There is a page counter on the bottom left
This commit is contained in:
		@@ -1,126 +0,0 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					 | 
				
			||||||
<html lang="en">
 | 
					 | 
				
			||||||
<head>
 | 
					 | 
				
			||||||
    <meta charset="UTF-8">
 | 
					 | 
				
			||||||
    <title>{TITLE}</title>
 | 
					 | 
				
			||||||
    <style>
 | 
					 | 
				
			||||||
        html, body {{
 | 
					 | 
				
			||||||
            background-color: #e8e6e6;
 | 
					 | 
				
			||||||
            height: 100%;
 | 
					 | 
				
			||||||
            padding: 0;
 | 
					 | 
				
			||||||
            margin: 0;
 | 
					 | 
				
			||||||
            overflow: hidden;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .container img {{
 | 
					 | 
				
			||||||
            display: block;
 | 
					 | 
				
			||||||
            width: 100%;
 | 
					 | 
				
			||||||
            margin: 30px 0;
 | 
					 | 
				
			||||||
            padding:  10px;
 | 
					 | 
				
			||||||
            cursor: pointer;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .container {{
 | 
					 | 
				
			||||||
            height: 100%;
 | 
					 | 
				
			||||||
            overflow: scroll;
 | 
					 | 
				
			||||||
            background: #e8e6e6;
 | 
					 | 
				
			||||||
            width: 200px;
 | 
					 | 
				
			||||||
            padding: 30px;
 | 
					 | 
				
			||||||
            float: left;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .image {{
 | 
					 | 
				
			||||||
            margin-left: 260px;
 | 
					 | 
				
			||||||
            height: 100%;
 | 
					 | 
				
			||||||
            background: #222;
 | 
					 | 
				
			||||||
            text-align: center;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .image img {{
 | 
					 | 
				
			||||||
            height: 100%;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .i a {{
 | 
					 | 
				
			||||||
            display: block;
 | 
					 | 
				
			||||||
            position: absolute;
 | 
					 | 
				
			||||||
            top: 0;
 | 
					 | 
				
			||||||
            width: 50%;
 | 
					 | 
				
			||||||
            height: 100%;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .i {{
 | 
					 | 
				
			||||||
            position: relative;
 | 
					 | 
				
			||||||
            height: 100%;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .current {{
 | 
					 | 
				
			||||||
            background: #BBB;
 | 
					 | 
				
			||||||
            border-radius: 10px;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
    </style>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <script>
 | 
					 | 
				
			||||||
        function cursorfocus(elem) {{
 | 
					 | 
				
			||||||
            var container = document.getElementsByClassName('container')[0];
 | 
					 | 
				
			||||||
            container.scrollTop = elem.offsetTop - 500;
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function getImage(type) {{
 | 
					 | 
				
			||||||
            var current = document.getElementsByClassName("current")[0];
 | 
					 | 
				
			||||||
            current.className = "image-item";
 | 
					 | 
				
			||||||
            var img_src = type == 1 ? current.getAttribute('attr-next') : current.getAttribute('attr-prev');
 | 
					 | 
				
			||||||
            if (img_src === "") {{
 | 
					 | 
				
			||||||
                img_src = current.src;
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            var img_list = document.getElementsByClassName("image-item");
 | 
					 | 
				
			||||||
            for (i=0; i<img_list.length; i++) {{
 | 
					 | 
				
			||||||
                if (img_list[i].src.endsWith(img_src)) {{
 | 
					 | 
				
			||||||
                    img_list[i].className = "image-item current";
 | 
					 | 
				
			||||||
                    cursorfocus(img_list[i]);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }}
 | 
					 | 
				
			||||||
            }}
 | 
					 | 
				
			||||||
            var display = document.getElementById("dest");
 | 
					 | 
				
			||||||
            display.src = img_src;
 | 
					 | 
				
			||||||
            display.focus();
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
    </script>
 | 
					 | 
				
			||||||
</head>
 | 
					 | 
				
			||||||
<body>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div class="container">
 | 
					 | 
				
			||||||
{IMAGES}</div>
 | 
					 | 
				
			||||||
<div class="image">
 | 
					 | 
				
			||||||
    <div class="i">
 | 
					 | 
				
			||||||
        <img src="" id="dest">
 | 
					 | 
				
			||||||
        <a href="javascript:getImage(-1)" style="left: 0;"></a>
 | 
					 | 
				
			||||||
        <a href="javascript:getImage(1)" style="left: 50%;"></a>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
</body>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script>
 | 
					 | 
				
			||||||
    var img_list = document.getElementsByClassName("image-item");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var display = document.getElementById("dest");
 | 
					 | 
				
			||||||
    display.src = img_list[0].src;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (var i = 0; i < img_list.length; i++) {{
 | 
					 | 
				
			||||||
        img_list[i].addEventListener('click', function() {{
 | 
					 | 
				
			||||||
            var current = document.getElementsByClassName("current")[0];
 | 
					 | 
				
			||||||
            current.className = "image-item";
 | 
					 | 
				
			||||||
            this.className = "image-item current";
 | 
					 | 
				
			||||||
            var display = document.getElementById("dest");
 | 
					 | 
				
			||||||
            display.src = this.src;
 | 
					 | 
				
			||||||
            display.focus();
 | 
					 | 
				
			||||||
        }}, false);
 | 
					 | 
				
			||||||
    }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    document.onkeypress = function(e) {{
 | 
					 | 
				
			||||||
        if (e.keyCode == 32) {{
 | 
					 | 
				
			||||||
            getImage(1);
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
    }}
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
</html>
 | 
					 | 
				
			||||||
@@ -30,10 +30,14 @@ def urlparse(url):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return urlparse(url)
 | 
					    return urlparse(url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def readfile(path):
 | 
				
			||||||
 | 
					    loc = os.path.dirname(__file__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with open(os.path.join(loc, path), 'r') as file:
 | 
				
			||||||
 | 
					        return file.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def generate_html(output_dir='.', doujinshi_obj=None):
 | 
					def generate_html(output_dir='.', doujinshi_obj=None):
 | 
				
			||||||
    image_html = ''
 | 
					    image_html = ''
 | 
				
			||||||
    previous = ''
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if doujinshi_obj is not None:
 | 
					    if doujinshi_obj is not None:
 | 
				
			||||||
        doujinshi_dir = os.path.join(output_dir, format_filename('%s-%s' % (doujinshi_obj.id,
 | 
					        doujinshi_dir = os.path.join(output_dir, format_filename('%s-%s' % (doujinshi_obj.id,
 | 
				
			||||||
@@ -44,28 +48,23 @@ def generate_html(output_dir='.', doujinshi_obj=None):
 | 
				
			|||||||
    file_list = os.listdir(doujinshi_dir)
 | 
					    file_list = os.listdir(doujinshi_dir)
 | 
				
			||||||
    file_list.sort()
 | 
					    file_list.sort()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for index, image in enumerate(file_list):
 | 
					    for image in file_list:
 | 
				
			||||||
        if not os.path.splitext(image)[1] in ('.jpg', '.png'):
 | 
					        if not os.path.splitext(image)[1] in ('.jpg', '.png'):
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        image_html += '<img src="{0}" class="image-item"/>\n'\
 | 
				
			||||||
            next_ = file_list[file_list.index(image) + 1]
 | 
					            .format(image)
 | 
				
			||||||
        except IndexError:
 | 
					 | 
				
			||||||
            next_ = ''
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        image_html += '<img src="{0}" class="image-item {1}" attr-prev="{2}" attr-next="{3}">\n'\
 | 
					    html = readfile('viewer/index.html')
 | 
				
			||||||
            .format(image, 'current' if index == 0 else '', previous, next_)
 | 
					    css = readfile('viewer/styles.css')
 | 
				
			||||||
        previous = image
 | 
					    js = readfile('viewer/scripts.js')
 | 
				
			||||||
 | 
					 | 
				
			||||||
    with open(os.path.join(os.path.dirname(__file__), 'doujinshi.html'), 'r') as template:
 | 
					 | 
				
			||||||
        html = template.read()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if doujinshi_obj is not None:
 | 
					    if doujinshi_obj is not None:
 | 
				
			||||||
        title = doujinshi_obj.name
 | 
					        title = doujinshi_obj.name
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        title = 'nHentai HTML Viewer'
 | 
					        title = 'nHentai HTML Viewer'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    data = html.format(TITLE=title, IMAGES=image_html)
 | 
					    data = html.format(TITLE=title, IMAGES=image_html, SCRIPTS=js, STYLES=css)
 | 
				
			||||||
    with open(os.path.join(doujinshi_dir, 'index.html'), 'w') as f:
 | 
					    with open(os.path.join(doujinshi_dir, 'index.html'), 'w') as f:
 | 
				
			||||||
        f.write(data)
 | 
					        f.write(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								nhentai/viewer/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								nhentai/viewer/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8">
 | 
				
			||||||
 | 
					    <title>{TITLE}</title>
 | 
				
			||||||
 | 
					    <style>
 | 
				
			||||||
 | 
					{STYLES}
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<nav id="list">
 | 
				
			||||||
 | 
					{IMAGES}</nav>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div id="image-container">
 | 
				
			||||||
 | 
					    <span id="page-num"></span>
 | 
				
			||||||
 | 
					    <div id="dest"></div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					{SCRIPTS}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										62
									
								
								nhentai/viewer/scripts.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								nhentai/viewer/scripts.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					const pages = Array.from(document.querySelectorAll('img.image-item'));
 | 
				
			||||||
 | 
					let currentPage = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function changePage(pageNum) {
 | 
				
			||||||
 | 
					    const previous = pages[currentPage];
 | 
				
			||||||
 | 
					    const current = pages[pageNum];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (current == null) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    previous.classList.remove('current');
 | 
				
			||||||
 | 
					    current.classList.add('current');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    currentPage = pageNum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const display = document.getElementById('dest');
 | 
				
			||||||
 | 
					    display.style.backgroundImage = `url("${current.src}")`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    document.getElementById('page-num')
 | 
				
			||||||
 | 
					        .innerText = [
 | 
				
			||||||
 | 
					                (pageNum + 1).toLocaleString(),
 | 
				
			||||||
 | 
					                pages.length.toLocaleString()
 | 
				
			||||||
 | 
					            ].join('\u200a/\u200a');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					changePage(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.getElementById('list').onclick = event => {
 | 
				
			||||||
 | 
					    if (pages.includes(event.target)) {
 | 
				
			||||||
 | 
					        changePage(pages.indexOf(event.target));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.getElementById('image-container').onclick = event => {
 | 
				
			||||||
 | 
					    const width = document.getElementById('image-container').clientWidth;
 | 
				
			||||||
 | 
					    const clickPos = event.clientX / width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (clickPos < 0.5) {
 | 
				
			||||||
 | 
					        changePage(currentPage - 1);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        changePage(currentPage + 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.onkeypress = event => {
 | 
				
			||||||
 | 
					    switch (event.key.toLowerCase()) {
 | 
				
			||||||
 | 
					        // Previous Image
 | 
				
			||||||
 | 
					        case 'arrowleft':
 | 
				
			||||||
 | 
					        case 'a':
 | 
				
			||||||
 | 
					            changePage(currentPage - 1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Next Image
 | 
				
			||||||
 | 
					        case ' ':
 | 
				
			||||||
 | 
					        case 'enter':
 | 
				
			||||||
 | 
					        case 'arrowright':
 | 
				
			||||||
 | 
					        case 'd':
 | 
				
			||||||
 | 
					            changePage(currentPage + 1);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										69
									
								
								nhentai/viewer/styles.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								nhentai/viewer/styles.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					*, *::after, *::before {
 | 
				
			||||||
 | 
					    box-sizing: border-box;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					img {
 | 
				
			||||||
 | 
					    vertical-align: middle;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					html, body {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    background-color: #e8e6e6;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    font-family: sans-serif;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#list {
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    overflow: auto;
 | 
				
			||||||
 | 
					    width: 260px;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#list img {
 | 
				
			||||||
 | 
					    width: 200px;
 | 
				
			||||||
 | 
					    padding: 10px;
 | 
				
			||||||
 | 
					    border-radius: 10px;
 | 
				
			||||||
 | 
					    margin: 15px 0;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#list img.current {
 | 
				
			||||||
 | 
					    background: #0003;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#image-container {
 | 
				
			||||||
 | 
					    flex: auto;
 | 
				
			||||||
 | 
					    height: 100vh;
 | 
				
			||||||
 | 
					    background: #222;
 | 
				
			||||||
 | 
					    color: #fff;
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    -webkit-user-select: none;
 | 
				
			||||||
 | 
					    user-select: none;
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#image-container #dest {
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    background-size: contain;
 | 
				
			||||||
 | 
					    background-repeat: no-repeat;
 | 
				
			||||||
 | 
					    background-position: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#image-container #page-num {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    font-size: 18pt;
 | 
				
			||||||
 | 
					    left: 10px;
 | 
				
			||||||
 | 
					    bottom: 5px;
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					    opacity: 0.75;
 | 
				
			||||||
 | 
					    text-shadow: /* Duplicate the same shadow to make it very strong */
 | 
				
			||||||
 | 
					        0 0 2px #222,
 | 
				
			||||||
 | 
					        0 0 2px #222,
 | 
				
			||||||
 | 
					        0 0 2px #222;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user