您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Linkifies all images in the tumblr dashboard stream. The script also displays the timestamp of each post in the upper right corner.
当前为
// ==UserScript== // @name Tumblr Dashboard - clickable links to images and post timestamps // @namespace tumblr_dashboard_linkify // @version 1.1.0 // @license GNU AGPLv3 // @description Linkifies all images in the tumblr dashboard stream. The script also displays the timestamp of each post in the upper right corner. // @author marp // @homepageURL http://greasyfork.icu/en/users/204542-marp // @include https://www.tumblr.com/dashboard // @include https://www.tumblr.com/dashboard/* // @include https://www.tumblr.com/likes // @include https://www.tumblr.com/likes/* // @run-at document-end // ==/UserScript== function createImageLinks(myDoc, myContext) { //console.info("createImageLinks: ", myContext); if (myDoc===null) myDoc= myContext; if (myDoc===null) return; if (myContext===null) myContext= myDoc; var matches; var tmpstr; var parentnode; var newnode; matches=myDoc.evaluate("//div[contains(@class,'post_content')]//img[contains(@class,'post_media_photo') and (contains(@src,'.jpg') or contains(@src,'.png') or contains(@src,'.gif'))] | " + "//div[contains(@class,'post_content')]//figure[contains(@class,'tmblr-full')]/img[contains(@src,'.jpg') or contains(@src,'.png') or contains(@src,'.gif')] | " + "//div[contains(@class,'post_content')]//a[contains(@class,'photoset_photo')]/img[contains(@src,'.jpg') or contains(@src,'.png') or contains(@src,'.gif')]", myContext, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for(var i=0, el; (i<matches.snapshotLength); i++) { el=matches.snapshotItem(i); if (el) { try { // console.info("matched-element: ", el); tmpstr=getHighResImageURL(el.getAttribute("src"), false); // console.info("highresurl: ", tmpstr); parentnode=el.parentNode; // console.info("parentnode: ", parentnode); if (parentnode.nodeName.toLowerCase() == "a") { if (parentnode.hasAttribute("class") && (parentnode.getAttribute("class").indexOf("post_media_photo") >= 0 || parentnode.getAttribute("class").indexOf("photoset_photo") >= 0) ) { // console.info("set parentnode href: ", tmpstr); parentnode.setAttribute("href", tmpstr); } // if it is a link type but with other style classes -> do nothing } else { newnode = document.createElement("a"); newnode.setAttribute("href", tmpstr); newnode.setAttribute("target", "_blank"); // console.info("newnode href: ", tmpstr); parentnode.replaceChild(newnode, el); newnode.appendChild(el); // console.info("new child of this parent: ", parentnode); } } catch (e) { console.warn("error: ", e) } } } } function displayDateTime(myDoc, myContext) { if (myDoc===null) myDoc= myContext; if (myDoc===null) return; if (myContext===null) myContext= myDoc; var matches; var tmpstr; var elements; var headernode; var linknode; var pos; var newnode; var newnode2; matches=myDoc.evaluate("//div[contains(@class,'post_wrapper')]", myContext, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for(var i=0, el; (i<matches.snapshotLength); i++) { el=matches.snapshotItem(i); if (el) { try { // console.info("matched-element: ", el); elements = el.getElementsByClassName("post_header"); if (elements.length <= 0) continue; headernode = elements[0]; elements = el.getElementsByClassName("post_permalink"); if (elements.length <= 0) continue; linknode = elements[0]; if (!linknode.hasAttribute("title")) continue; tmpstr = linknode.getAttribute("title"); pos = tmpstr.indexOf(" - "); if (pos >= 0) { tmpstr = tmpstr.substr(pos+3); } newnode = document.createElement("div"); newnode.setAttribute("class", "post_source"); newnode2 = document.createElement("div"); // newnode2.setAttribute("class", "post_source_app"); newnode2.setAttribute("style", "float: right; text-overflow: ellipsis; overflow: hidden;"); newnode2.textContent = tmpstr; newnode.appendChild(newnode2); elements = headernode.getElementsByClassName("post_source"); if (elements.length <= 0) { headernode.appendChild(newnode); } else { headernode.replaceChild(newnode, elements[0]); } } catch (e) { console.warn("error: ", e) } } } } // 2018-08-09 - RAW (original upload) images do not seem to be working anymore function getHighResImageURL(imageurl, isgetraw) { var result = imageurl; var tmplen = imageurl.length; var pos; if ((imageurl.toLowerCase().lastIndexOf(".jpg") == tmplen-4) || (imageurl.toLowerCase().lastIndexOf(".png") == tmplen-4)) { if (isgetraw) { result = "https://s3.amazonaws.com/data" + imageurl.slice(imageurl.indexOf(".tumblr.com/"), imageurl.lastIndexOf("_")) + "_raw" + imageurl.substring(imageurl.lastIndexOf(".")); } else { result = imageurl.replace("_250.","_1280.").replace("_400.","_1280.").replace("_500.","_1280.").replace("_540.","_1280.").replace("_640.","_1280."); } } else if ((imageurl.toLowerCase().lastIndexOf(".gif") == tmplen-4)) { if (isgetraw) { result = "https://s3.amazonaws.com/data" + imageurl.slice(imageurl.indexOf(".tumblr.com/"), imageurl.lastIndexOf("_")) + "_raw" + imageurl.substring(imageurl.lastIndexOf(".")); } else { result = imageurl.replace("_250.","_540.").replace("_400.","_540.").replace("_500.","_540."); } } return result; } // create an observer instance and iterate through each individual new node var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { mutation.addedNodes.forEach(function(addedNode) { createImageLinks(mutation.target.ownerDocument, addedNode); displayDateTime(document, postsnode); }); }); }); // configuration of the observer // NOTE: subtree is false as the wanted nodes are direct children of <ol id="posts"> -> notable performance improvement var config = { attributes: false, childList: true, characterData: false, subtree: false }; // pass in the target node (<ol> element contains all dashboard posts), as well as the observer options var postsmatch = document.evaluate("//ol[@id='posts']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); //console.info("postsmatch: ", postsmatch); var postsnode = postsmatch.singleNodeValue; //console.info("postsnode: ", postsnode); //process already loaded nodes (the initial posts before scrolling down for the first time) createImageLinks(document, postsnode); displayDateTime(document, postsnode); //start the observer for new nodes observer.observe(postsnode, config);