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)
 | 
			
		||||
 | 
			
		||||
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):
 | 
			
		||||
    image_html = ''
 | 
			
		||||
    previous = ''
 | 
			
		||||
 | 
			
		||||
    if doujinshi_obj is not None:
 | 
			
		||||
        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.sort()
 | 
			
		||||
 | 
			
		||||
    for index, image in enumerate(file_list):
 | 
			
		||||
    for image in file_list:
 | 
			
		||||
        if not os.path.splitext(image)[1] in ('.jpg', '.png'):
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            next_ = file_list[file_list.index(image) + 1]
 | 
			
		||||
        except IndexError:
 | 
			
		||||
            next_ = ''
 | 
			
		||||
        image_html += '<img src="{0}" class="image-item"/>\n'\
 | 
			
		||||
            .format(image)
 | 
			
		||||
 | 
			
		||||
        image_html += '<img src="{0}" class="image-item {1}" attr-prev="{2}" attr-next="{3}">\n'\
 | 
			
		||||
            .format(image, 'current' if index == 0 else '', previous, next_)
 | 
			
		||||
        previous = image
 | 
			
		||||
 | 
			
		||||
    with open(os.path.join(os.path.dirname(__file__), 'doujinshi.html'), 'r') as template:
 | 
			
		||||
        html = template.read()
 | 
			
		||||
    html = readfile('viewer/index.html')
 | 
			
		||||
    css = readfile('viewer/styles.css')
 | 
			
		||||
    js = readfile('viewer/scripts.js')
 | 
			
		||||
 | 
			
		||||
    if doujinshi_obj is not None:
 | 
			
		||||
        title = doujinshi_obj.name
 | 
			
		||||
    else:
 | 
			
		||||
        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:
 | 
			
		||||
        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