Greasy Fork

Greasy Fork is available in English.

Pixiv View Util

change the layout of caption. open comments automatically. add popup tool.

当前为 2018-09-07 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name            Pixiv View Util
// @namespace       Pixiv View Util
// @description     change the layout of caption. open comments automatically. add popup tool.
// @author          sotoba
// @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*
// @match           https://www.pixiv.net/search.php*
// @match           https://www.pixiv.net*
// @version         0.0.3.20180908
// @homepageURL     https://github.com/SotobatoNihu/PixivViewUtil
// @license         MIT License
// @require         https://code.jquery.com/jquery-3.2.1.min.js
// @grant           GM.getValue
// @grant           GM.setValue
// ==/UserScript==

/*
this script is based on "Pixiv Arts Preview & Followed Atrists Coloring"(MIT license).
for more details,please visit folows:
http://greasyfork.icu/ja/scripts/39387-pixiv-arts-preview-followed-atrists-coloring
https://github.com/NightLancer/PixivPreview
*/

(() => {
    'use strict';
    /*
    設定画面やsave & load 機能を実装予定
     */
    const init = async () => {
        const default_setting = {
            changeLayout: true,
            openComment: true,
            popup: true
        }
        return await GM.getValue("pixiv_viewutil_setting", JSON.stringify(default_setting));
    }

    const prop = {
        changeLayout: Symbol("changeLayout"),
        popup_typeA: Symbol("popup_typeA"),
        popup_typeB: Symbol("popup_typeB"),
        openComment: Symbol("openComment")
    }


    if (window.top == window.self && window.jQuery) {
        jQuery(($) => {
            class Setting {
                constructor(jsonString) {
                    const jsonData = JSON.parse(jsonString);
                    this.changeLayout = (jsonData.changeLayout == null) ? true : jsonData.changeLayout;
                    this.openComment = (jsonData.openComment == null) ? true : jsonData.openComment;
                    this.popup = (jsonData.popup == null) ? true : jsonData.popup;
                }

                set setData(jsonData) {
                    this.changeLayout = (jsonData.changeLayout == null) ? true : jsonData.changeLayout;
                    this.openComment = (jsonData.openComment == null) ? true : jsonData.openComment;
                    this.popup = (jsonData.popup == null) ? true : jsonData.popup;
                }
            }

            const pagetype = {
                // my top page
                top: Symbol("top"),
                //Works from favourite artists
                bookmark_new_illust: Symbol("bookmark_new_illust"),
                //Discovery page
                discovery: Symbol("discovery"),
                //Artist works page
                member_illust: Symbol("member_illust"),
                //Artist's "top" page
                member: Symbol("member"),
                //Bookmark information
                bookmark_detail: Symbol("bookmark_detail"),
                //Added new bookmarks
                bookmark_add: Symbol("bookmark_add"),
                //Daily rankings
                ranking: Symbol("ranking"),
                //Someone's bookmarks page
                bookmark_id: Symbol("bookmark_id"),
                //Search page
                search: Symbol("search"),
                //Your bookmarks page
                bookmark: Symbol("bookmark"),
                other: Symbol("other"),
            };


            //   function checkPageType(url) {
            const checkPageType = (url) => {
                if (url.match('https://www.pixiv.net/bookmark_new_illust.php?')) return pagetype.bookmark_new_illust;
                if (url.match('https://www.pixiv.net/discovery?')) return pagetype.discovery;
                if (url.match('https://www.pixiv.net/member_illust.php?')) return pagetype.member_illust;
                if (url.match('https://www.pixiv.net/member.php?')) return pagetype.member;
                if (url.match('https://www.pixiv.net/bookmark_detail.php?')) return pagetype.bookmark_detail;
                if (url.match('https://www.pixiv.net/bookmark_add.php?')) return pagetype.bookmark_add;
                if (url.match('https://www.pixiv.net/ranking.php?')) return pagetype.ranking;
                if (url.match(/https:\/\/www\.pixiv\.net\/bookmark\.php\?id/)) return pagetype.bookmark_id;
                if (url.match('https://www.pixiv.net/search.php')) return pagetype.search;
                if (url.match('https://www.pixiv.net/bookmark.php?')) return pagetype.bookmark;
                if (url.match('https://www.pixiv.net/')) return pagetype.top;
                else return pagetype.other;
            };

            const getAllowedFuncList = (type) => {
                switch (type) {
                    case pagetype.top:
                        return [prop.popup_typeB];
                        break;
                    case pagetype.bookmark_new_illust:
                        return [prop.popup_typeA];
                        break;
                    case pagetype.discovery:
                        return [prop.popup_typeA];
                        break;
                    case pagetype.member_illust:
                        return [prop.popup_typeB, prop.changeLayout, prop.openComment];
                        break;
                    case pagetype.member:
                        return [prop.popup_typeB];
                        break;
                    case pagetype.bookmark_detail:
                        return [prop.popup_typeB];
                        break;
                    case pagetype.bookmark_add:
                        return [prop.popup_typeB];
                        break;
                    case pagetype.bookmark_id:
                        return [prop.popup_typeB];
                        break;
                    case pagetype.search:
                        return [prop.popup_typeA];
                        break;
                    case pagetype.ranking:
                        return [prop.popup_typeB];
                        break;
                    case pagetype.bookmark:
                        return [prop.popup_typeB];
                        break;
                        return [];
                }
            }

            class Util {
                changeLayout() {
                    const figure = document.getElementsByTagName("figure");
                    $('figure').before($('figcaption'));
                }

                openComment() {
                    let elem = $("article");
                    elem.find("[aria-expanded='false']").click();
                    var observer = new MutationObserver(function (MutationRecords, MutationObserver) {
                        elem.find("[aria-expanded='false']").click();
                    });
                    observer.observe(document, {
                        childList: true,
                        subtree: true,
                    });
                }
            setPopup(type) {
                let imgContainer = document.createElement('div');
                imgContainer.id = 'imgContainer';
                imgContainer.style = 'position:absolute; display:block; z-index:1000; background:#222; padding:5px; margin:-5px;';

                let popupImg = document.createElement('img');
                popupImg.id = 'popupImg';
                imgContainer.appendChild(popupImg);
                let captionContainer = document.createElement('div');
                captionContainer.id = 'captionContainer';

                let mangaContainer = document.createElement('div');
                mangaContainer.id = 'mangaContainer';
                mangaContainer.style = 'display:block; z-index:1500; background:#111; overflow-x:auto; maxWidth:1200px; white-space:nowrap;';

                let 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);

                let 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,
                    DELTASCALE = ('mozInnerScreenX' in window) ? 70 : 4,
                    PAGETYPE = checkPageType(document.URL);

                mangaWidth = document.body.clientWidth - 80;
                mangaContainer.style.maxWidth = mangaOuterContainer.style.maxWidth = mangaWidth + 'px';
                document.body.appendChild(imgContainer);
                document.body.appendChild(captionContainer);
                document.body.appendChild(mangaOuterContainer);

                function setCaption(imageID, x, y) {
                    if (imageID === undefined || imageID.length === 0) return; //just in case
                    const url = "https://www.pixiv.net/ajax/illust/" + imageID;
                    console.log("url:" + url);

                    fetch(url).then(function (response) {
                        return response.json();
                    }).then(function (json) {
                        //captionContainer.style="position: absolute; display: block; z-index: 1001; background: rgb(255, 255, 255);  top: 0px; left: 0px; color:black "
                        captionContainer.innerHTML = json.body.description;
                        x = x - parseInt($(captionContainer).height());
                        captionContainer.style = "position: absolute; display: block; z-index: 1001; background: rgb(255, 255, 255); padding: 5px; margin: -5px; top: " + x + "px; left: " + y + "px; color:black "
                    });
                }

                function hoverImg(thisObj) {
                    mangaOuterContainer.style.display = 'none';
                    popupImg.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 == pagetype.ranking) ? 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 hoverManga(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)");
                    }
                    imgsArrInit(parseImgUrl(thisObj), +count);
                    //  const imageId = thisObj.getAttribute('data-id');
                    //   setCaption(imageId,parseInt($(mangaOuterContainer).css('top')),parseInt($(mangaOuterContainer).css('left')));
                }

                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)};
                };

                //-----------------------------------------------------------------------------------
                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);
                    //---------------------------------------------------------------------------------
                    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 getImgId(str) {
                    return str.substring(str.lastIndexOf("/") + 1, str.indexOf("_"));
                }


                //-----------------------------------------------------------------------------------
                //**************************************Hide*****************************************
                //-----------------------------------------------------------------------------------
                imgContainer.onmouseleave = function () {

                    // if caption don't have URL, simply erase caption
                    if ($(captionContainer).find('a').length == 0) {
                        captionContainer.style.display = 'none';
                        imgContainer.style.display = 'none';
                        popupImg.src = '';
                    }else {
                        setTimeout(function(){
                            captionContainer.style.display = 'none';
                            imgContainer.style.display = 'none';
                            popupImg.src = '';
                        },1000);
                    }

                };
                //-----------------------------------------------------------------------------------
                mangaOuterContainer.onmouseleave = function () {
                    if ($(captionContainer).find('a').length == 0) {
                        captionContainer.style.display = 'none';
                        mangaOuterContainer.style.display = 'none';
                    }else{
                        setTimeout(function(){
                            captionContainer.style.display = 'none';
                            mangaOuterContainer.style.display = 'none';
                        },500);
                    }
                };
                captionContainer.onmouseleave = function () {
                    captionContainer.style.display = 'none';
                };
                //-----------------------------------------------------------------------------------
                //*************************************Clicks****************************************
                //-----------------------------------------------------------------------------------
                popupImg.onmouseup = function (event) //single arts onclick actions
                {
                    onClickActions(this, event, false);
                };
                //-----------------------------------------------------------------------------------
                $('body').on('mouseup', 'div#mangaContainer > img', function (event) //manga arts onclick actions
                {
                    onClickActions(this, event, true);
                });

                //-----------------------------------------------------------------------------------
               function onClickActions(imgContainerObj, event, isManga) {
                    const strId = getImgId(imgContainerObj.src);
                    const illustPageUrl = 'https://www.pixiv.net/member_illust.php?mode=medium&illust_id=' + strId;
                    window.open(illustPageUrl, '_blank');
                };

                //-----------------------------------------------------------------------------------
                //**************************************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 * DELTASCALE; // TODO - find better value for opera/chrome
                    }
                };
                //-----------------------------------------------------------------------------------
                window.onresize = function () {
                    mangaWidth = document.body.clientWidth - 80;
                    mangaContainer.style.maxWidth = mangaOuterContainer.style.maxWidth = mangaWidth + 'px';
                };

                //-----------------------------------------------------------------------------------
                //**************************************Hover****************************************
                //-----------------------------------------------------------------------------------
                //feed, discovery and search-------------------------------------------------------
                if (type === prop.popup_typeA) {
                    //single art hover
                    siteImgMaxWidth = 200;
                    $('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");
                        var elem = this;
                        $(this).attr('onclick', 'console.log();return false;');
                        $(this).on('click', function () {
                            hoverImg(elem);
                            var x = parseInt($(imgContainer).css('top'));
                            var y = parseInt($(imgContainer).css('left'));
                            const href = $(this).parent().parent().find('a').attr('href');
                            const imageID = href.substring(href.indexOf('illust_id=') + 'illust_id='.length);
                            console.log("id:" + imageID)
                            setCaption(imageID, x, y);
                        });
                    });

                    //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) {
                            $(this).attr('onclick', 'console.log();return false;');
                            var elem1 = this;
                            var elem2 = this.parentNode.firstChild.firstChild.textContent;
                            $(this).on('click', function () {
                                hoverManga(elem1, elem2);
                                var x = parseInt($(mangaOuterContainer).css('top'));
                                var y = parseInt($(mangaOuterContainer).css('left'));
                                const href = $(this).parent().parent().find('a').attr('href');
                                const imageID = href.slice(href.substring('illust_id=') + 'illust_id='.length);
                                console.log("id:" + imageID)
                                setCaption(imageID, x, y);
                            });
                        }
                    });

                    //clearing loaded arts count when switching on tabs
                    if (PAGETYPE === pagetype.discovery) $('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-----------------------------
                if (type === prop.popup_typeB) {
                    {
                        $('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);
                                var elem = this.firstChild.firstChild;
                                var parent = this;
                                $(this).attr('onclick', 'console.log();return false;');
                                $(captionContainer).insertBefore(imgContainer);
                                $(this).on('click', function () {
                                    hoverImg(elem);
                                    var x = parseInt($(imgContainer).css('top'));
                                    var y = parseInt($(imgContainer).css('left'));
                                    const imageId = elem.getAttribute('data-id');
                                    setCaption(imageId, x, y);
                                });
                            }
                            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);
                                var elem1 = this.firstChild.firstChild;
                                var elem2 = this.children[1].children[1].textContent;
                                $(this).attr('onclick', 'console.log();return false;');

                                $(this).on('click', function () {
                                    hoverManga(elem1, elem2);
                                    var x = parseInt($(mangaOuterContainer).css('top'));
                                    var y = parseInt($(mangaOuterContainer).css('left'));
                                    const imageId = elem1.getAttribute('data-id');
                                    setCaption(imageId, x, y);
                                });
                            }
                            ;
                        });
                    }
                }
            }
        }
            class Page {
                constructor(url) {
                    this.URL = url;
                    this.pagetype = checkPageType(url);
                    this.alloedFunclist = getAllowedFuncList(this.pagetype);
                }

                set setURL(url) {
                    this.URL = url;
                    this.pagetype = checkPageType(url);
                }

                get getPagetype() {
                    return this.pagetype;
                }

                get getURL() {
                    return this.URL;
                }

                get getFunclist() {
                    return this.alloedFunclist;
                }

                isEnable(symbol) {
                    return this.alloedFunclist.includes(symbol);
                }
            }

            /*
            * main function
            */
            let page = new Page(document.URL);
            let util = new Util();

            let setting;
            init().then(result => setting = new Setting(result));

            $(document).ready(() => {
                if (setting.popup && page.isEnable(prop.popup_typeA)) {
                    util.setPopup(prop.popup_typeA);
                    console.log("popup  A is enable");
                } else if (setting.popup && page.isEnable(prop.popup_typeB)) {
                    util.setPopup(prop.popup_typeB);
                    console.log("popup  B is enable");
                }


            });

            window.onload = () => {
                if (setting.openComment && page.isEnable(prop.openComment)) {
                    util.openComment();
                    console.log("comment opend");
                }
                console.log("pagetype:" + page.pagetype.toString());
                if (setting.changeLayout && page.isEnable(prop.changeLayout)) {
                    util.changeLayout();
                    console.log("layout chainged");
                }
                $('a').on('click', () => {
                    let page = new Page(document.URL);
                    if (setting.openComment && page.isEnable(prop.openComment)) {
                        util.openComment();
                        console.log("comment opend.");
                    }
                    console.log("pagetype:" + page.pagetype.toString());
                    if (setting.changeLayout && page.isEnable(prop.changeLayout)) {
                        util.changeLayout();
                        console.log("layout chainged.");
                    }
                })

            };
        })
    }
})();