- // ==UserScript==
- // @name A Gelbooru Viewer
- // @namespace http://tampermonkey.net/
- // @version 1.0.1
- // @description Adds a download button and makes thumbnails a little bigger. Make shure to add (.png, .jpeg, .jpg, etc) to the tampermonkey download whitelist
- // @author Anonymous
- // @match https://gelbooru.com/*page=post*s=list*
- // @grant GM_download
- // @grant GM_xmlhttpRequest
- // ==/UserScript==
-
- (function() {
- 'use strict';
- // Your code here...
-
- function setCustomStyles(){
- const customStyles = document.createElement("style");
- customStyles.innerHTML = "" +
- ".thumbnail-preview {" +
- "max-width: unset;"+
- "width: 30%;" +
- "min-height: 200px;" +
- "max-height: unset;" +
- "height: 500px;"+
- "}" +
- ".thumbnail-preview span {display: contents;}"+
- ".thumbnail-preview a {display: contents;}"+
- ".thumbnail-preview button {width: 100%; height: 25px; background-color: blue; color: white; text-decoration:none;border:none;}"+
- ".thumbnail-preview button[disabled] {background-color: gray; color: black;}"+
- ".thumbnail-preview button[data-done] {background-color: green;}"+
- ".thumbnail-preview button.secondary {background-color: gray;}"+
- ".thumbnail-preview img {"+
- "object-fit: contain;" +
- "width: 100%;" +
- "height: calc(100% - 50px);" +
- "} "+
- ".next-page-message-container {display:flex;align-items:center;width:100%;height:100px;margin:0;background-color:darkgray;} "+
- ".next-page-message-container p {width:fit-content;margin:auto;font-size:3em;}";
-
- document.head.appendChild(customStyles);
- }
-
- function parsePaginationInfo(doc){
- let currentPage,
- nextPage, nextPageUrl,
- previousPage,previousPageUrl;
-
- const currentPageEl = doc.querySelector(".pagination b");
- if (currentPageEl){
- currentPage = currentPageEl.innerText;
- } else {
- console.debug("cant parse current page");
- }
-
- const aList = Array.from(doc.querySelectorAll(".pagination a"));
-
- for (let i=0; i < aList.length; i++){
- const a = aList[i];
- const altText = a.getAttribute("alt");
- if (!altText) { continue }
-
- switch(altText){
- case "next": {
- nextPage = altText;
- nextPageUrl = a.href;
- break;
- }
- case "back": {
- previousPage = altText;
- previousPageUrl = a.href;
- break;
- }
- }
- }
-
- const alertIfNotFound = (name, value) => {
- if (!value) { console.debug( name + " was not found"); }
- }
- alertIfNotFound("nextPage", nextPage);
- alertIfNotFound("previousPage", previousPage);
-
- return {currentPage,
- nextPage, nextPageUrl,
- previousPage,previousPageUrl}
- }
-
- function parseThumbPreview(el){
- const a = el.querySelector("a");
- const img = el.querySelector("img");
-
- if (!a || !img){
- throw new Error("parse error " + el.outerHTML);
- }
-
- const thumbUrl = img.src;
- const pageUrl = a.href;
-
- if (!thumbUrl || !pageUrl) {
- throw new Error("parse error " + el.outerHTML);
- }
-
- return {thumbUrl, pageUrl}
- }
-
- function parseDetailPage(doc){
- let originalImageUrl = undefined;
- doc.querySelectorAll("#tag-list a").forEach(a=>{
- if (a.innerText === "Original image"){
- originalImageUrl = a.href;
- }
- });
-
- if (!originalImageUrl) {
- throw new Error("parse error");
- }
-
- return {originalImageUrl}
- }
-
- async function getDetailPageDoc(url){
- const response = await fetch(url, {method:"GET"});
- if (!response.ok){ throw new Error("request error", response) }
- const text = await response.text();
- return new DOMParser().parseFromString(text,"text/html");
- }
-
- async function downloadImage(url, saveAs=false){
- const name = url.substring(url.lastIndexOf("/")+1);
-
- return new Promise((resolve, reject)=>{
- GM_download({
- url,
- name,
- saveAs,
- onload: (data)=>{
- console.debug("GM_download.onload", data);
- resolve();
- },
- onerror: (e)=>{
- console.debug("GM_download.onerror", e);
- reject(e);
- }
- });
- });
- }
-
- async function downloadOriginalFromDetailPage(url){
- const doc = await getDetailPageDoc(url);
- console.debug("page fetched");
- const data = parseDetailPage(doc);
- console.debug("page parsed", data);
-
- await downloadImage(data.originalImageUrl);
- console.debug("image downloaded");
- return;
-
- }
-
- // https://stackoverflow.com/questions/1038727/how-to-get-browser-width-using-javascript-code
- function getWidth() {
- return Math.max(
- document.body.scrollWidth,
- document.documentElement.scrollWidth,
- document.body.offsetWidth,
- document.documentElement.offsetWidth,
- document.documentElement.clientWidth
- );
- }
-
- function getHeight() {
- return Math.max(
- document.body.scrollHeight,
- document.documentElement.scrollHeight,
- document.body.offsetHeight,
- document.documentElement.offsetHeight,
- document.documentElement.clientHeight
- );
- }
-
- function openChildWindow(url,name="page",w=null,h=null) {
- // http://www.nigraphic.com/blog/java-script/how-open-new-window-popup-center-screen
-
- if (!w) { w = getWidth() * 0.8; }
- if (!h) { h = getHeight() * 0.8; }
-
- const dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : screen.left;
- const dualScreenTop = window.screenTop != undefined ? window.screenTop : screen.top;
-
- const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
- const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
-
- const left = ((width / 2) - (w / 2)) + dualScreenLeft;
- const top = ((height / 2) - (h / 2)) + dualScreenTop;
- const windowref = window.open(url, name, `width=${w},height=${h},top=${top},left=${left},resizable,location=no,toolbar=no,menubar=no,status=no,titlebar=0`);
- }
-
-
- function setOnScrollBottomHandler(handler){
- window.onscroll = function(e) {
- let pageHeight=document.documentElement.offsetHeight,
- windowHeight=window.innerHeight,
- scrollPosition=window.scrollY || window.pageYOffset || document.body.scrollTop + (document.documentElement && document.documentElement.scrollTop || 0);
-
- if (pageHeight*0.98 <= (windowHeight+scrollPosition)) {
- console.debug('bottom reached');
- handler(e);
- }
- };
- }
-
- function addButtons(){
- document.querySelectorAll(".thumbnail-preview").forEach(el=>{
- const item = parseThumbPreview(el);
-
- const button = document.createElement("button");
- button.innerText = "download";
- button.addEventListener("click", async e=> {
- try{
- button.setAttribute("disabled","disabled");
- button.innerText = "downloading..."
- await downloadOriginalFromDetailPage(item.pageUrl);
- button.removeAttribute("disabled");
- button.dataset.done=true;
- button.innerText = "done";
- }
- catch(e) {
- button.innerText = "error";
- console.error(e);
- }
-
- });
-
- const openPageButton = document.createElement("button");
- openPageButton.classList.add("secondary");
- openPageButton.innerText = "open details";
- openPageButton.onclick = (e) => {
- e.preventDefault();
- openChildWindow(item.pageUrl, "Detail");
- }
-
- el.appendChild(button);
- el.appendChild(openPageButton);
- });
- }
-
- function addLoadOnScrollBottom(){
- const pagination = parsePaginationInfo(document);
-
- if (pagination.nextPage) {
- const nextPageMessageContainer = document.createElement("footer");
- const nextPageMessageEl = document.createElement("p");
- nextPageMessageEl.innerText = "loading next page";
- nextPageMessageContainer.classList.add("next-page-message-container");
- nextPageMessageContainer.appendChild(nextPageMessageEl);
- document.body.appendChild(nextPageMessageContainer);
-
- // Hide lasts br to show next page message sooner
- const containerPushBr = Array.from(document.querySelectorAll(".contain-push br"));
- let count = 0, limit=6;
- for (let i=containerPushBr.length - 1;i >= 0 && count < limit ;i--){
- containerPushBr[i].style.display = "none";
- count++;
- }
-
- setOnScrollBottomHandler(e=>{window.location.replace(pagination.nextPageUrl)})
- }
- }
-
- function init(){
- setCustomStyles();
- addButtons();
- addLoadOnScrollBottom();
- }
-
- init();
-
- })();