您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enlarged preview of arts and manga on mouse hovering on most pages. Click on image preview to open original art in new tab, or MMB-click to open art illustration page, Ctrl+LMB-click to add art to bookmarks. Install "NewTabImageOpen.user.js"(placed in same folder) for propper new tab image originals opening. The names of the authors you are already subscribed to are highlighted with green.
当前为
// ==UserScript== // @name Pixiv Arts Preview & Followed Atrists Coloring // @name:ru Pixiv Arts Preview & Followed Atrists Coloring // @namespace Pixiv // @description Enlarged preview of arts and manga on mouse hovering on most pages. Click on image preview to open original art in new tab, or MMB-click to open art illustration page, Ctrl+LMB-click to add art to bookmarks. Install "NewTabImageOpen.user.js"(placed in same folder) for propper new tab image originals opening. The names of the authors you are already subscribed to are highlighted with green. // @description:ru Увеличённый предпросмотр артов и манги по наведению мышки на большинстве страниц. Клик ЛКМ по превью арта для открытия исходника в новой вкладке, СКМ для открытия страницы с артом, Ctrl + клик ЛКМ для добавления в закладки. Для правильного открытия оригиналов артов в новом окне нужна также установка "NewTabImageOpen.user.js". Имена авторов, на которых вы уже подписаны, подсвечиваются зелёным цветом. // @author NightLancerX // @match https://www.pixiv.net/bookmark_new_illust.php* // @match https://www.pixiv.net/discovery* // @match https://www.pixiv.net/bookmark_detail.php?illust_id=* // @match https://www.pixiv.net/bookmark_add.php?id=* // @match https://www.pixiv.net/member_illust.php* // @match https://www.pixiv.net/ranking.php?mode=* // @match https://www.pixiv.net/member.php?id=* // @match https://www.pixiv.net/bookmark.php?id=* // @match https://www.pixiv.net/search.php* // @version 0.38 // @homepageURL https://github.com/NightLancer/PixivPreview // @license MIT License // @grant none // ==/UserScript== //--------------------------------------------------------------------------------------- (function () { 'use strict'; console.log('MyPixivJS'); if (!window.jQuery) { console.error("jQuery lib doesn't found"); } jQuery(function($) { var hoverImg = document.createElement('img'); var imgContainer = document.createElement('div'); imgContainer.style = 'position:absolute; display:block; z-index:1000; background:#222; padding:5px; margin:-5px;'; imgContainer.appendChild(hoverImg); var mangaContainer = document.createElement('div'); mangaContainer.id = 'mangaContainer'; mangaContainer.style = 'display:block; z-index:1500; background:#111; overflow-x:auto; maxWidth:1200px; white-space:nowrap;'; var mangaOuterContainer = document.createElement('div'); mangaOuterContainer.style = 'position:absolute; display:block; z-index:1000; padding:5px; background:#111; maxWidth:1200px; marginY:-5px; marginX: auto;'; mangaOuterContainer.appendChild(mangaContainer); var imgsArr = [], //for manga-style image packs... followedUsersId = [], //storing followed users pixiv ID BOOKMARK_URL = 'https://www.pixiv.net/bookmark.php', CheckedPublic = false, Checked = false, artsContainers, artsLoaded = 0, hits = 0, isRunning = false, lastImgId = " ", siteImgMaxWidth = 150, //for now it is used for pagetype==7 mangaWidth = 1200, bookmarkObj, PAGETYPE = checkPageType(); //----------------------------------------------------------------------------------- //************************************PageType*************************************** //----------------------------------------------------------------------------------- function checkPageType() { if (document.URL.match('https://www.pixiv.net/bookmark_new_illust.php?')) return 0; //Works from favourite artists if (document.URL.match('https://www.pixiv.net/discovery?')) return 1; //Discovery page if (document.URL.match('https://www.pixiv.net/member_illust.php?')) return 2; //Artist works page if (document.URL.match('https://www.pixiv.net/member.php?')) return 3; //Artist "top" page if (document.URL.match('https://www.pixiv.net/bookmark_detail.php?')) return 4; //Bookmark information if (document.URL.match('https://www.pixiv.net/bookmark_add.php?')) return 5; //Added new bookmarks if (document.URL.match('https://www.pixiv.net/ranking.php?')) return 6; //Daily rankings if (document.URL.match(/https:\/\/www\.pixiv\.net\/bookmark\.php\?/)) return 7; //Someone's bookmarks page if (document.URL.match('https://www.pixiv.net/search.php')) return 8; //Search page return -1; } console.log('PAGETYPE: '+ PAGETYPE); //----------------------------------------------------------------------------------- //**********************************ColorFollowed************************************ //----------------------------------------------------------------------------------- if (PAGETYPE==1 || PAGETYPE>=4) { checkFollowedArtists(BOOKMARK_URL+'?type=user'); $.ajaxSetup( { success: function(data) { let condition = !!((PAGETYPE===6 && typeof(data)=="object" && data.contents && data.contents.length>1 && data.contents[0].illust_id)||(PAGETYPE!=6 && Array.isArray(data) && data.length && data[0].illust_id)); console.log(condition); if (condition) colorFollowed(); } }); } //----------------------------------------------------------------------------------- async function checkFollowedArtists(url) { if (url === undefined || url.length === 0) return; //just in case let xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.timeout = 15000; xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { console.log("XHR done"); let doc = document.implementation.createHTMLDocument("Followed"); doc.documentElement.innerHTML = xhr.responseText; let followedProfiles = doc.querySelectorAll('div>a.ui-profile-popup'); for(let i = 0; i < followedProfiles.length; i++) { followedUsersId.push(followedProfiles[i].getAttribute("data-user_id")); } console.log(followedUsersId.length); let urlTail = $(doc).find('a[rel="next"]').attr('href'); if (urlTail !== undefined && urlTail.length && !CheckedPublic) //todo: rewrite condition when multiple private followed pages supported { console.log(urlTail); checkFollowedArtists(BOOKMARK_URL+urlTail); } else { if (!CheckedPublic) checkFollowedArtists('https://www.pixiv.net/bookmark.php?type=user&rest=hide'); //works for 1 page only (yet) else { Checked = true; console.log('XHR querying ended.'); colorFollowed(); //extra call for heavy load case skipping ajaxSucess } CheckedPublic = true; } doc = followedProfiles = null; //I don't trust anything } }; xhr.onerror = function() { console.log('ERROR WHILE GETTING SUBSCRIPTIONS LIST!'); Checked = CheckedPublic = true; //to stop while loop; (make diff flag or smth if needed) }; xhr.send(); } //----------------------------------------------------------------------------------- async function colorFollowed() { if (isRunning) return; isRunning = true; while (!Checked) //wait until last XHR completed if it is not { console.log("waiting for followed users..."); await sleep(2000); } checkArtists(); let c = 0; while (!artsContainers||artsContainers.length<=artsLoaded) { console.log('waiting for arts...'); await sleep(1000); checkArtists(); ++c; if (c>5) break; //we may wait until next update if smth goes wrong } console.log('arts loaded: '+artsContainers.length + ' (new: '+(artsContainers.length - artsLoaded)+')'); let h = 0; for(let i = 0; i < artsContainers.length; i++) //from 0 - 'cause "More like this" insert objects inside array { if (followedUsersId.indexOf(artsContainers[i].getAttribute('data-user_id'))>=0) { ++h; artsContainers[i].setAttribute("style", "background-color: green;"); }; } artsLoaded = artsContainers.length; console.log('hits: '+h + ' (new: '+(h-hits)+')'); hits = h; c = h = null; isRunning = false; } //----------------------------------------------------------------------------------- function checkArtists() { artsContainers = $('.ui-profile-popup'); } //----------------------------------------------------------------------------------- function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } //----------------------------------------------------------------------------------- //**************************************Hover**************************************** //----------------------------------------------------------------------------------- if (PAGETYPE==0 || PAGETYPE==1 || PAGETYPE==8) siteImgMaxWidth = 200; else if (PAGETYPE>=2 && PAGETYPE<=5) siteImgMaxWidth = 150; else if (PAGETYPE==6) siteImgMaxWidth = 240; //----------------------------------------------------------------------------------- $(document).ready(function () { console.log('$(document).ready'); mangaWidth = document.body.clientWidth - 80; mangaContainer.style.maxWidth = mangaOuterContainer.style.maxWidth = mangaWidth+'px'; document.body.appendChild(imgContainer); document.body.appendChild(mangaOuterContainer); //feed, discovery and search--------------------------------------------------------------- if ((PAGETYPE === 0)||(PAGETYPE === 1) || (PAGETYPE===8)) { //single art hover $('body').on('mouseenter', 'a[href*="member_illust.php?mode=medium&illust_id="] > div:only-child', function() { bookmarkObj = $(this).parent().parent().children(".thumbnail-menu").children("._one-click-bookmark"); setHover(this); }); //manga-style arts hover $('body').on('mouseenter', 'a[href*="member_illust.php?mode=medium&illust_id="] > div:nth-child(2) ', function() { bookmarkObj = $(this).parent().parent().children(".thumbnail-menu").children("._one-click-bookmark"); if (this.parentNode.firstChild.childNodes.length) setMangaHover(this, this.parentNode.firstChild.firstChild.textContent); }); //clearing loaded arts count when switching on tabs if (PAGETYPE === 1) $('body').on('mouseup','a[href="/discovery/users"]', function() //todo:make into single event handler { console.log('leaving works page...'); artsLoaded = hits = 0; }); } //artist works page and daily rankings & rest of pages----------------------------- else if ((PAGETYPE >= 2)&&(PAGETYPE <= 7)) { $('body').on('mouseenter', 'a[href*="member_illust.php?mode=medium&illust_id="]', function() //direct div selector works badly with "::before" { if (this.childNodes.length == 1 && this.childNodes[0].nodeName=="DIV") //single art { bookmarkObj = $(this.firstChild.firstChild).parent().children("._one-click-bookmark"); setHover(this.firstChild.firstChild); } else if (this.children[1] && this.children[1].className == 'page-count') //manga { bookmarkObj = $(this.firstChild.firstChild).parent().children("._one-click-bookmark"); setMangaHover(this.firstChild.firstChild, this.children[1].children[1].textContent); }; }); } //getNextPage(); //global todo task... no need: Endless Pixiv Pages has been fixed }); //----------------------------------------------------------------------------------- function setHover(thisObj) { mangaOuterContainer.style.display='none'; hoverImg.src = parseImgUrl(thisObj); imgContainer.style.top = getOffsetRect(thisObj.parentNode.parentNode).top+'px'; //adjusting preview position considering expected image width let l = getOffsetRect(thisObj.parentNode.parentNode).left; let w = 600*(((PAGETYPE==6)?thisObj.clientWidth:thisObj.parentNode.parentNode.clientWidth)/siteImgMaxWidth)+5; imgContainer.style.left = (document.body.clientWidth-l < w)? document.body.clientWidth-w +'px': l +'px'; if($(bookmarkObj).hasClass("on")) { $(imgContainer).css("background", "rgb(255, 64, 96)"); } else { $(imgContainer).css("background", "rgb(34, 34, 34)"); } imgContainer.style.display='block'; } //----------------------------------------------------------------------------------- function setMangaHover(thisObj, count) { imgContainer.style.display='none'; //just in case mangaOuterContainer.style.top = getOffsetRect(thisObj.parentNode.parentNode).top+'px'; mangaOuterContainer.style.left = '30px'; if($(bookmarkObj).hasClass("on")) { $(mangaOuterContainer).css("background", "rgb(255, 64, 96)"); } else { $(mangaOuterContainer).css("background", "rgb(34, 34, 34)"); $(mangaContainer).css("background", "rgb(34, 34, 34)"); } imgsArrInit(parseImgUrl(thisObj), +count); } //----------------------------------------------------------------------------------- function imgsArrInit(primaryLink, l) { let margins = document.body.clientWidth - l*600; //some blind frame adjusting if (margins > 0) mangaOuterContainer.style.left = margins/2-10+'px'; let currentImgId = getImgId(primaryLink); console.log('lastImgId: ' + lastImgId); console.log('currentImgId: ' + currentImgId); //--------------------------------------------------------------------------------- if (currentImgId != lastImgId) { for(let j=0; j<imgsArr.length; j++) { imgsArr[j].src = ''; } mangaOuterContainer.style.display='block'; lastImgId = currentImgId; for(let i=0; i<l; i++) { if (!(!!imgsArr[i])) //if [i] img element doesn't exist { imgsArr[i] = document.createElement('img'); mangaContainer.appendChild(imgsArr[i]); }; imgsArr[i].src = primaryLink.replace('p0','p'+i); } } //--------------------------------------------------------------------------------- else mangaOuterContainer.style.display='block'; }; //----------------------------------------------------------------------------------- function parseImgUrl(thisObj) { let url = (thisObj.src)? thisObj.src: thisObj.style.backgroundImage.slice(5,-2); //pixiv changes layout randomly url = url.replace(/\/...x...\//, '/600x600/'); //both feed and artist works case | TODO: '1200x1200' variant return url; }; //----------------------------------------------------------------------------------- function getOffsetRect(elem) { // (1) let box = elem.getBoundingClientRect(); // (2) let body = document.body; let docElem = document.documentElement; // (3) let scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop; let scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft; // (4) let clientTop = docElem.clientTop || body.clientTop || 0; let clientLeft = docElem.clientLeft || body.clientLeft || 0; // (5) let top = box.top + scrollTop - clientTop; let left = box.left + scrollLeft - clientLeft; return { top: Math.round(top), left: Math.round(left) }; }; //----------------------------------------------------------------------------------- //**************************************Hide***************************************** //----------------------------------------------------------------------------------- imgContainer.onmouseleave = function() { imgContainer.style.display='none'; hoverImg.src=''; }; //----------------------------------------------------------------------------------- mangaOuterContainer.onmouseleave = function () { mangaOuterContainer.style.display='none'; $(mangaOuterContainer).css("background", "rgb(34, 34, 34)"); }; //----------------------------------------------------------------------------------- //*************************************Clicks**************************************** //----------------------------------------------------------------------------------- hoverImg.onmouseup = function (event) //single arts onclick actions { onClickActions(this, event); }; //----------------------------------------------------------------------------------- $('body').on('mouseup', 'div#mangaContainer > img', function(event) //manga arts onclick actions { onClickActions(this, event); }); //----------------------------------------------------------------------------------- function onClickActions(imgContainerObj, event) { event.preventDefault(); let sourceUrl = imgContainerObj.src.replace(/c\/...x...\/img-master/, 'img-original').replace('_master1200', ''); //"blind" link to source image if (event.button == 1) //Middle Mouse Button click { let strId = getImgId(sourceUrl); let illustPageUrl = document.querySelectorAll('a[href*="member_illust.php?mode=medium&illust_id=' + strId + '"]')[0].href; window.open(illustPageUrl,'_blank'); //open illust page in new tab(in background — with FF pref "browser.tabs.loadDivertedInBackground" set to "true") } else if (event.button == 0) //Left Mouse Button click { if(event.ctrlKey) //Ctrl + LMB-click { $(bookmarkObj).click(); $(imgContainerObj).parent().css("background", "rgb(255, 64, 96)"); } else //single click { window.open(sourceUrl, '_blank'); //open source of image in new tab window.open(sourceUrl.replace('jpg','png'),'_blank'); } } }; //----------------------------------------------------------------------------------- function getImgId(str) { return str.substring(str.lastIndexOf("/")+1,str.indexOf("_")); } //----------------------------------------------------------------------------------- //**************************************Other**************************************** //----------------------------------------------------------------------------------- mangaContainer.onwheel = function(e) { if (e.deltaY<0 && (mangaOuterContainer.getBoundingClientRect().top < 0)) { mangaOuterContainer.scrollIntoView({block: "start", behavior: "smooth"}); //aligning to top screen side on scrollUp if needed } else if (e.deltaY>0 && (mangaOuterContainer.getBoundingClientRect().bottom > document.documentElement.clientHeight)) { mangaOuterContainer.scrollIntoView({block: "end", behavior: "smooth"}); //aligning to bottom screen side on scrollDown if needed } let scrlLft = mangaContainer.scrollLeft; if ((scrlLft>0 && e.deltaY<0) || ((scrlLft<(mangaContainer.scrollWidth-mangaContainer.clientWidth)) && e.deltaY>0)) { e.preventDefault(); mangaContainer.scrollLeft += e.deltaY*70; } } //----------------------------------------------------------------------------------- window.onresize = function() { mangaWidth = document.body.clientWidth - 80; mangaContainer.style.maxWidth = mangaOuterContainer.style.maxWidth = mangaWidth+'px'; }; //----------------------------------------------------------------------------------- //*********************************************************************************** //----------------------------------------------------------------------------------- }); }) (); //function