Pixiv Faview

Automatically adds links to your favorite works on a specific artist page(/users/xxxxxxxx).

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name           Pixiv Faview
// @namespace      https://solact.blogspot.com/
// @version        0.2
// @description    Automatically adds links to your favorite works on a specific artist page(/users/xxxxxxxx).
// @description:ja 作者ごとの作品一覧ページ(/users/xxxxxxxx)で、自分がお気に入りに追加した作品へのリンクを自動で追加します。
// @author         Solact
// @include        https://www.pixiv.net/*
// @match          https://www.pixiv.net/*
// @license        GPL-3.0
// @icon           https://www.google.com/s2/favicons?domain=pixiv.net
// @grant          none
// @noframes
// ==/UserScript==

(async () => {
    'use strict';

    // definition
    const i18nLib = {
        'ja': {
            works: '作品',
            illusts_manga: 'イラスト・マンガ',
            favs: 'ブックマーク',
        },
        'en': {
            works: 'Works',
            illusts_manga: 'Illustrations and Manga',
            favs: 'Bookmarks',
        },
        'ko': {
            works: '작품',
            illusts_manga: '일러스트・만화',
            favs: '북마크',
        },
        'zh-cn': {
            works: '作品',
            illusts_manga: '插画·漫画',
            favs: '收藏',
        },
        'zh-tw': {
            works: '作品',
            illusts_manga: '插畫·漫畫',
            favs: '收藏',
        },
    };
    const i18n = key => i18nLib[lang][key];

    const debug = false;
    const debugMsg = (...str) => debug ? console.log(str) : '';

    // main code
    const lang = document.documentElement.getAttribute('lang').toLowerCase();
    if (!lang) {
        throw new Error('pixiv lang not found');
        return;
    }

    // initialize
    let prevHref, prevUrlUserID;
    let bookmarksCount, $bookmarksNode;
    let isOnUserPage, rewriteDone;

    const mainLoop = setInterval(async () => {

        if (location.href != prevHref) {
            // page changed (SPA)
            debugMsg('location.href changed', location.href);
            prevHref = location.href;
            if (!location.href.match(/users\/(\d+)/) || location.href.match(/users\/(\d+)\/bookmarks/)) {
                // not on pixiv.net/users/xxx
                // ignore pixiv.net/users/xxx/bookmarks
                debugMsg("not on an artist's user page");
                isOnUserPage = false;
                return;
            }
            const urlUserID = location.href.match(/users\/(\d+)/)[1];
            if (urlUserID != prevUrlUserID) {
                let profileAllJson, profileIdsJsonBodyWorks = {};

                // user id changed
                debugMsg('urlUserID changed', urlUserID);
                prevUrlUserID = urlUserID;

                // get an artist's all works
                profileAllJson = await fetch(`/ajax/user/${urlUserID}/profile/all?lang=${lang}`).then(res => {
                    if (res.ok) {
                        return res.json();
                    } else {
                        throw new Error('pixiv API [/ajax/user/UID/profile/all] failed');
                    }
                });
                let illustIds = Object.keys({ ...profileAllJson.body.illusts, ...profileAllJson.body.manga });
                while (illustIds.length) {
                    const illustIdsRemaining = illustIds.splice(100); // default 48, maximum approved 100
                    const params = { 'work_category': 'illust', 'is_first_page': 1, 'lang': lang };
                    const qs = new URLSearchParams(params);
                    for (const id of illustIds) {
                        qs.append('ids[]', id);
                    }
                    // get details of an artist's all works
                    const tmpJson = await fetch(`/ajax/user/${urlUserID}/profile/illusts?${qs}`).then(res => {
                        if (res.ok) {
                            return res.json();
                        } else {
                            throw new Error('pixiv API [/ajax/user/UID/profile/illusts] failed');
                        }
                    });
                    profileIdsJsonBodyWorks = { ...profileIdsJsonBodyWorks, ...tmpJson.body.works };

                    illustIds = illustIdsRemaining;
                }
                // bookmarksCount = parseInt(profileAllJson.body.bookmarkCount.public.illust) + parseInt(profileAllJson.body.bookmarkCount.public.novel);
                bookmarksCount = 0;
                $bookmarksNode = document.createElement('ul');
                for (const [id, val] of Object.entries(profileIdsJsonBodyWorks)) {
                    if (val.bookmarkData) {
                        // found a work which you liked
                        const url = `https://www.pixiv.net/artworks/${id}`;
                        const $a = document.createElement('a');
                        $a.setAttribute('href', url);
                        $a.innerHTML = val.title;
                        $a.style.color = 'red';
                        const $li = document.createElement('li');
                        $li.appendChild($a);
                        $bookmarksNode.appendChild($li);
                        bookmarksCount++;
                    }
                }
                debugMsg('bookmarksCount', bookmarksCount);
                debugMsg('$bookmarksNode', $bookmarksNode);

                // we have to set this flag here or we'll get (Bookmarks:undefined)
                // because the next 1000ms timer will start rewriting before $bookmarksNode is prepared
                isOnUserPage = true;
            }
            else {
                debugMsg('urlUserId not changed');
                isOnUserPage = true;
            }
            rewriteDone = false;
        }

        if (!isOnUserPage || rewriteDone) {
            // return if we're not on an artist's user page
            // return if we're on an artist's user page and we've finished rewriting
            return;
        }

        // wait for target and rewrite it
        debugMsg('wait for target');
        for (const $elem of document.querySelectorAll("h2")) {
            if ($elem.innerHTML == i18n('illusts_manga') || $elem.innerHTML == i18n('works')) {
                // add fav count like Illustrations and Manga(Bookmarks: xxx)
                $elem.innerHTML += `(${i18n('favs')}: ${bookmarksCount})`;

                // add fav list after fav count with red title
                const insertAfter = (referenceNode, newNode) => {
                    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
                };
                insertAfter($elem.parentNode.parentNode.parentNode, $bookmarksNode);

                debugMsg('rewriting');
                rewriteDone = true;
            }
        }
    }, 1000);
})();