您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A simplified gallery for viewing gelbooru images in succession.
// ==UserScript== // @name Gelbooru Paged Gallery // @namespace zixaphir // @description A simplified gallery for viewing gelbooru images in succession. // @match *://*.gelbooru.com/index.php?* // @version 1 // @grant none // ==/UserScript== /* # * $ object largely based on 4chan X's $, which is largely based on jQuery. * non-chainable. # * Copyright (c) 2009-2011 James Campos <[email protected]> * Copyright (c) 2012-2014 Nicolas Stepien <[email protected]> # * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: # * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. # */ (function() { "use strict"; var $, FNLIMIT, LIMIT, PRELOAD, SimpleDict, THRESHOLD, cb, clickThumb, d, err, fer, g, loadGallery, mkImage, mkURL, preload, query, queryImages, setImage, setup, setupImages, updateImages, slice = [].slice; d = document; FNLIMIT = 255; PRELOAD = 1; THRESHOLD = 3; LIMIT = 100; g = { galleryCSS: "#a-gallery {\n position: fixed;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n z-index: 30;\n display: flex;\n flex-direction: row;\n background: rgba(0,0,0,0.7);\n}\n.gal-thumbnails {\n flex-basis: 170px;\n overflow-y: auto;\n overflow-x: hidden;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n text-align: center;\n background: rgba(0,0,0,.5);\n border-left: 1px solid #222;\n order: 3;\n}\n.gal-hide-thumbnails .gal-thumbnails {\n display: none;\n}\n.gal-thumb img {\n max-width: 150px;\n max-height: 150px;\n height: auto;\n width: auto;\n}\n.gal-thumb {\n flex-basis: auto;\n padding: 3px;\n line-height: 0;\n transition: background .2s linear;\n}\n.gal-highlight {\n background: rgba(0, 190, 255, .8);\n}\n.gal-prev {\n order: 0;\n border-right: 1px solid #222;\n}\n.gal-next {\n order: 2;\n border-left: 1px solid #222;\n}\n.gal-prev,\n.gal-next {\n flex-basis: 20px;\n position: relative;\n cursor: pointer;\n opacity: 0.7;\n background-color: rgba(0, 0, 0, 0.3);\n}\n.gal-prev:hover,\n.gal-next:hover {\n opacity: 1;\n}\n.gal-prev::after,\n.gal-next::after {\n position: absolute;\n top: 50%;\n transform: translateY(-50%)\n line-height: 22px;\n display: inline-block;\n border-top: 11px solid transparent;\n border-bottom: 11px solid transparent;\n content: \"\";\n}\n.gal-prev::after {\n border-right: 12px solid #fff;\n right: 5px;\n}\n.gal-next::after {\n border-left: 12px solid #fff;\n right: 3px;\n}\n.gal-image {\n position: relative;\n order: 1;\n display: flex;\n align-items: flex-start;\n justify-content: space-around;\n overflow: hidden;\n flex-grow: 1;\n}\n:root:not(.gal-fit-height):not(.gal-pdf) .gal-image {\n overflow-y: auto !important;\n}\n:root:not(.gal-fit-width):not(.gal-pdf) .gal-image {\n overflow-x: auto !important;\n}\n.gal-image a {\n line-height: 0;\n}\n.gal-image > div {\n margin: auto;\n max-width: 100%;\n}\n:root.gal-pdf .gal-image a {\n width: 100%;\n height: 100%;\n}\n.gal-image video,\n.gal-image img {\n max-width: 100%;\n}\n.gal-fit-height .gal-image video,\n.gal-fit-height .gal-image img {\n max-height: 95vh;\n}\n.gal-image iframe {\n width: 100%;\n height: 100%;\n}\n.gal-buttons .menu-button {\n bottom: 2px;\n color: #ffffff;\n text-shadow: 0px 0px 1px #000000;\n}\n.gal-close {\n font-size: 2em;\n color: #ffffff;\n text-shadow: 0px 0px 1px #000000;\n top: 5px;\n cursor: pointer;\n}\n.gal-close,\n.gal-info {\n position: absolute;\n right: 5px;\n}\n.gal-info {\n bottom: 5px;\n background: rgba(0,0,0,0.6) !important;\n}\n.gal-info,\n.gal-ex-info {\n border-radius: 3px;\n padding: 1px 5px 2px 5px;\n color: #ffffff !important;\n}\n.gal-ex-info {\n display: none;\n position: absolute;\n bottom: 0;\n right: 0;\n font-size: 12px;\n font-family: calibri;\n min-width: 200px;\n padding-left: 15px;\n text-indent: -15px;\n background: rgba(0,0,0,0.8) !important;\n}\n.gal-ex-info p {\n margin: 3px;\n}\n.gal-info:hover .gal-ex-info {\n display: block;\n}\n:root:not(.gal-fit-width):not(.gal-pdf) .gal-name {\n bottom: 23px !important;\n}\n:root:not(.gal-fit-width):not(.gal-pdf) .gal-count {\n bottom: 44px !important;\n}\n:root.gal-fit-height:not(.gal-pdf):not(.gal-hide-thumbnails) .gal-buttons,\n:root.gal-fit-height:not(.gal-pdf):not(.gal-hide-thumbnails) .gal-name,\n:root.gal-fit-height:not(.gal-pdf):not(.gal-hide-thumbnails) .gal-count {\n right: 178px !important;\n}\n:root.gal-hide-thumbnails:.gal-fit-height:not(.gal-pdf) .gal-buttons,\n:root.gal-hide-thumbnails:.gal-fit-height:not(.gal-pdf) .gal-name,\n:root.gal-hide-thumbnails:.gal-fit-height:not(.gal-pdf) .gal-count {\n right: 28px !important;\n}\n.spinner {\n width: 30px;\n height: 30px;\n background-color: #aaa;\n -webkit-animation: rotateplane 1.2s infinite ease-in-out;\n animation: rotateplane 1.2s infinite ease-in-out;\n}\n@-webkit-keyframes rotateplane {\n 0% { -webkit-transform: perspective(120px) }\n 50% { -webkit-transform: perspective(120px) rotateY(180deg) }\n 100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) }\n}\n@keyframes rotateplane {\n 0% {\n transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg)\n } 50% {\n transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg)\n } 100% {\n transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n }\n}", nodes: {} }; (function() { var z; z = 0; return Object.defineProperty(g, "currentImageIndex", { set: function(x) { return z = Math.min(+g.images.length, Math.max(x, 0)); }, get: function() { return z; } }); })(); $ = function(query, root) { if (!root) { root = d.body; } return root.querySelector(query); }; $.$ = function(query, root) { if (!root) { root = d.body; } return slice.call(root.querySelectorAll(query)); }; $.asap = function(test, fn) { var callback; callback = function() { var err; try { return fn(); } catch (_error) { err = _error; console.log(err.message); return console.log(err.stack); } }; if (test()) { return callback(); } else { return setTimeout($.asap, 25, test, callback); } }; $.addStyle = function(css, id) { var style; style = $.el('style', { textContent: css }); if (id) { style.id = id; } $.asap((function() { return d.head; }), function() { return $.add(d.head, style); }); return style; }; $.on = function(target, events, fun, once) { var event, fn, func, j, len1, ref; fn = function() { var err; try { return fun.apply(this, arguments); } catch (_error) { err = _error; console.log(err.message); return console.log(err.stack); } }; func = once ? function() { $.off(target, events, func); return fn.apply(this, arguments); } : fn; ref = events.split(' '); for (j = 0, len1 = ref.length; j < len1; j++) { event = ref[j]; target.addEventListener(event, func, false); } return func; }; $.off = function(target, events, fn) { var event, j, len1, ref; ref = events.split(' '); for (j = 0, len1 = ref.length; j < len1; j++) { event = ref[j]; target.removeEventListener(event, fn, false); } return target; }; $.el = function(type, props) { var el, prop; el = d.createElement(type); for (prop in props) { if (props.hasOwnProperty(prop)) { el[prop] = props[prop]; } } return el; }; $.nodes = function(nodes) { var frag, j, len1, node; if (!(nodes instanceof Array)) { return nodes; } frag = d.createDocumentFragment(); for (j = 0, len1 = nodes.length; j < len1; j++) { node = nodes[j]; frag.appendChild(node); } return frag; }; $.html = function(html) { var el; el = $.el('div', { innerHTML: html }); return $.nodes(slice.call(el.children)); }; $.add = function(root, nodes) { root.appendChild($.nodes(nodes)); return root; }; $.replace = function(root, el) { return root.parentNode.replaceChild($.nodes(el), root); }; SimpleDict = (function() { function SimpleDict() { this.keys = []; } SimpleDict.prototype.push = function(key, data) { key = "" + key; if (!this[key]) { this.keys.push(key); } this[key] = data; return this[key].key = key; }; SimpleDict.prototype.contains = function(obj) { return this.indexOf(obj) !== -1; }; SimpleDict.prototype.indexOf = function(obj) { var key; key = obj.key; if (key) { if (obj !== this[key]) { return -1; } return this.keys.indexOf(key); } else { return this.keys.indexOf(obj); } }; SimpleDict.prototype.rm = function(key) { var i; key = "" + key; i = this.keys.indexOf(key); if (i !== -1) { this.keys.splice(i, 1); return delete this[key]; } }; SimpleDict.prototype.first = function() { return this[this.keys[0]]; }; SimpleDict.prototype.forEach = function(fn) { var j, key, len1, ref; ref = slice.call(this.keys); for (j = 0, len1 = ref.length; j < len1; j++) { key = ref[j]; fn.call(this, this[key]); } }; SimpleDict.prototype.forEachKey = function(fn) { var j, key, len1, ref; ref = slice.call(this.keys); for (j = 0, len1 = ref.length; j < len1; j++) { key = ref[j]; fn.call(this, key); } }; Object.defineProperty(SimpleDict.prototype, 'length', { get: function() { return this.keys.length; } }); return SimpleDict; })(); preload = function(image) { var galLength, i, len, results; galLength = g.images.length; i = g.currentImageIndex; len = Math.min(galLength, i + PRELOAD + 1); results = []; while (++i < len) { results.push($.el('img', { src: g.images[g.images.keys[i]].url })); } return results; }; loadGallery = function() { var close, count, err, gal, next, nodes, prev, thumbs; try { g.gallery = gal = $.el('div', { id: 'a-gallery', innerHTML: "<div class=\"gal-prev\"></div>\n<div class=\"gal-image\">\n <div>\n <div class=\"gal-info\">\n INFO\n <div class=\"gal-ex-info\">\n </div>\n </div>\n <div class=\"gal-close\">✖</div>\n <a class=\"current\"></a>\n </div>\n</div>\n<div class=\"gal-next\"></div>\n<div class=\"gal-thumbnails\"></div>" }); nodes = g.nodes; nodes.prev = prev = $('.gal-prev', gal); nodes.next = next = $('.gal-next', gal); nodes.count = count = $('.gal-count', gal); nodes.thumbs = thumbs = $('.gal-thumbnails', gal); nodes.close = close = $('.gal-close', gal); $.on(close, 'click', cb.hideGallery); $.on(prev, 'click', cb.prev); $.on(next, 'click', cb.next); $.on(d, 'keydown', cb.keybinds); cb.hideGallery(); return d.body.appendChild(gal); } catch (_error) { err = _error; console.log(err.message); return console.log(err.stack); } }; cb = { next: function() { ++g.currentImageIndex; return cb.updateImage(); }, prev: function() { --g.currentImageIndex; return cb.updateImage(); }, updateImage: function() { return setImage(g.images[g.images.keys[g.currentImageIndex]]); }, showGallery: function() { g.gallery.style.display = 'flex'; return d.body.style.overflow = 'hidden'; }, hideGallery: function() { cb.pause(); g.gallery.style.display = 'none'; g.currentImageIndex = 0; return d.body.style.overflow = 'auto'; }, highlight: function(image) { var gal, highlight, thumbs; if (!image) { if (!(image = g.images[g.images.keys[g.currentImageIndex]])) { return; } } gal = g.gallery; $('.gal-image', gal).scrollTop = 0; highlight = $('.gal-highlight', gal); if (highlight != null) { highlight.classList.remove('gal-highlight'); } highlight = $("[data-id='" + image.id + "']", gal); if (highlight != null) { highlight.classList.add('gal-highlight'); } thumbs = g.nodes.thumbs; return thumbs.scrollTop = highlight.offsetTop + highlight.offsetHeight / 2 - thumbs.clientHeight / 2; }, toggleGallery: function() { return cb[g.gallery.style.display === 'block' ? 'hideGallery' : 'showGallery'](); }, keybinds: function(e) { var fn, key; if (!(key = e.keyCode)) { return; } fn = (function() { switch (key) { case 39: return cb.next; case 37: return cb.prev; case 27: return cb.hideGallery; } })(); if (!fn) { return; } e.stopPropagation(); e.preventDefault(); return fn(); }, pause: function() { var current, el; current = $('.gal-image a', g.gallery); if (current) { el = current.firstElementChild; } if (el && el.pause) { return el.pause(); } } }; fer = function(arr, fn) { var item, j, len1; for (j = 0, len1 = arr.length; j < len1; j++) { item = arr[j]; fn(item); } }; clickThumb = function(e) { e.preventDefault(); return $.asap((function() { return g.images.length; }), (function(_this) { return function() { var id, image, queryURL; id = _this.id.slice(1); image = g.images["" + id]; cb.showGallery(); if (!image) { queryURL = g.baseURL + "page=dapi&s=post&q=index&id=" + id; query("get", queryURL, function() { image = mkImage(this.response.childNodes[0].children[0]); return setImage(image); }); return; } return setImage(image); }; })(this)); }; setImage = function(image) { var a, el, err, gal, i, img, info, j, len1, placeHolder, rating, ratingText, ready, ref, source, tag, tags; try { gal = g.gallery; cb.pause(); el = $('.gal-image .current', gal); g.currentImageIndex = i = g.images.indexOf(image); a = $.el('a', { href: image.download, download: image.filename, className: 'current' }); switch (image.type) { case "jpg": case "jpeg": case "gif": case "png": img = $.el('img', { src: image.url, alt: image.tags }); ready = function() { return img.complete; }; break; default: img = $.el('video', { src: image.url, poster: image.thumb, autoplay: true, loop: true, width: image.width, height: image.height }); ready = function() { return img.readyState > 2; }; } if (ready()) { $.add(a, img); preload(); } else { placeHolder = $.el('div', { className: 'spinner' }); $.add(a, placeHolder); $.asap(ready, function() { if (i !== g.currentImageIndex) { return; } $.replace(placeHolder, img); return preload(); }); } $.replace(el, a); a.parentElement.click(); info = $('.gal-ex-info', gal); info.textContent = "ID: " + image.id + "\nScore: " + (image.score || 0) + "\nPosted: " + image.age + "\nWidth: " + image.width + "\nHeight: " + image.height + "\nType: " + (image.type.toUpperCase()); info.innerHTML = "<p>" + (info.textContent.split('\n').join('</p><p>')) + "</p>"; tags = $.el('p', { textContent: "Tags: " }); ref = image.tags.split(' '); for (j = 0, len1 = ref.length; j < len1; j++) { tag = ref[j]; $.add(tags, $.el('a', { href: g.baseURL + "page=post&s=list&tags=" + tag, textContent: tag, target: "_blank" })); $.add(tags, d.createTextNode(' ')); } $.add(info, tags); ratingText = (function() { switch (image.rating) { case 'e': return 'explicit'; case 's': return 'safe'; default: return 'questionable'; } })(); rating = $.el('p', { textContent: "Rating: " }); $.add(rating, $.el('a', { href: g.baseURL + "page=post&s=list&tags=rating:" + ratingText, textContent: ratingText, target: "_blank" })); $.add(info, rating); if (image.source) { source = $.el('p', { textContent: "Source: " }); $.add(source, $.el('a', { href: image.source, textContent: image.source, target: "_blank" })); $.add(info, source); } cb.highlight(image); if (i + THRESHOLD > g.images.length) { return updateImages(); } } catch (_error) { err = _error; console.log(err.message); return console.log(err.stack); } }; updateImages = function() { var queryURL; queryURL = mkURL(g.images.length / LIMIT); return queryImages(queryURL); }; setupImages = function() { var err, j, len1, parser, post, ref, response, results; try { if (this.status !== 200) { g.error = true; return alert(this.status + ": " + this.statusText); } parser = new DOMParser(); response = parser.parseFromString(this.response, 'text/xml'); ref = response.childNodes[0].children; results = []; for (j = 0, len1 = ref.length; j < len1; j++) { post = ref[j]; results.push(mkImage(post)); } return results; } catch (_error) { err = _error; console.log(err.message); return console.log(err.stack); } }; mkImage = function(post) { var a, download, extension, filename, image, item, j, len1, p, ref, ref1, tags, thumb, type; p = {}; ref = post.attributes; for (j = 0, len1 = ref.length; j < len1; j++) { item = ref[j]; p[item.name] = item.value; } a = $.el('a', { href: p.file_url }); a.host = 'gelbooru.com'; download = a.href; type = download.split('.'); type = ("" + type[type.length - 1]).toLowerCase(); extension = "." + type; tags = p.tags.split(' '); while (true) { filename = p.id + " - " + (tags.join(' ').trim()); tags.pop(); if (!(filename.length + extension.length > FNLIMIT)) { break; } } filename += extension; image = { thumb: p.preview_url, url: p.sample_url, rating: p.rating, source: p.source, width: p.width, height: p.height, score: p.score, tags: (ref1 = p.tags) != null ? ref1.trim() : void 0, id: p.id, age: p.created_at, filename: filename, download: download, type: type }; thumb = $.el('a', { href: "javascript:;", className: 'gal-thumb', innerHTML: "<img src='" + image.thumb + "'>" }); thumb.setAttribute('data-id', image.id); $.on(thumb, 'click', function() { g.currentImageIndex = g.images.indexOf(image); return setImage(image); }); $.add(g.nodes.thumbs, thumb); g.images.push(p.id, image); return image; }; query = function(method, URL, callback) { var r; r = new XMLHttpRequest(); r.open("get", URL, true); $.on(r, "load error abort", callback, true); r.send(); return r; }; queryImages = function(URL) { if (g.error) { return; } return query("get", URL, setupImages); }; mkURL = function(pid) { var j, key, len1, queryURL, ref; if (pid) { g.attr.pid = pid; } queryURL = g.baseURL; ref = g.attr.keys; for (j = 0, len1 = ref.length; j < len1; j++) { key = ref[j]; queryURL += key + "=" + g.attr[key] + "&"; } return queryURL = queryURL.slice(0, -1); }; setup = function() { var attr, j, len1, ref; g.images = new SimpleDict(); g.host = d.location; g.attr = new SimpleDict(); ref = g.host.search.slice(1).split('&'); for (j = 0, len1 = ref.length; j < len1; j++) { attr = ref[j]; attr = attr.split('='); g.attr.push(attr[0].toLowerCase(), attr[1].toLowerCase()); } if (g.attr.s === 'view') { return; } g.baseURL = g.host.protocol + "//" + g.host.hostname + "/index.php?"; g.attr.push('page', 'dapi'); g.attr.push('q', 'index'); g.attr.push('s', 'post'); g.attr.push('limit', 100); if (g.attr.tags === 'all') { g.attr.rm('tags'); } if (g.attr.pid) { g.attr.pid = ~~(g.attr.pid / 100); } else { g.attr.push('pid', 0); } g.queryURL = mkURL(); $.addStyle(g.galleryCSS); return $.asap((function() { var ref1; return (ref1 = d.readyState) === 'interactive' || ref1 === 'complete'; }), function() { var k, len2, ref1, thumb; ref1 = $.$('.thumb a'); for (k = 0, len2 = ref1.length; k < len2; k++) { thumb = ref1[k]; $.on(thumb, 'click', clickThumb); } loadGallery(); return queryImages(g.queryURL); }); }; try { setup(); } catch (_error) { err = _error; console.log(err.message); console.log(err.stack); } }).call(this);