Greasy Fork is available in English.
Adds “All”, “Follow”, “My pixiv”, and “Tag Index” tabs to user pages etc. and “All” and “Ugoira” tabs to search r###lt pages.
// ==UserScript==// @name pixiv Tabs Restorer// @name:ja pixiv タブを復活// @description Adds “All”, “Follow”, “My pixiv”, and “Tag Index” tabs to user pages etc. and “All” and “Ugoira” tabs to search r###lt pages.// @description:ja ユーザーページなどに「すべて」「フォロー」「マイピク」「タグ一覧」タブを、検索結果に「すべて」「うごイラ」タブを補完します。// @namespace https://greasyfork.org/users/137// @version 2.8.0// @match https://www.pixiv.net/*// @require https://greasyfork.org/scripts/19616/code/utilities.js?version=895049// @license MPL-2.0// @contributionURL https://www.amazon.co.jp/registry/wishlist/E7PJ5C3K7AM2// @compatible Edge// @compatible Firefox Firefoxを推奨 / Firefox is recommended// @compatible Opera// @compatible Chrome// @grant dummy// @noframes// @run-at document-start// @icon https://s.pximg.net/common/images/apple-touch-icon.png// @author 100の人// @homepageURL https://greasyfork.org/scripts/373026// ==/UserScript==// 当スクリプトはpixivが作成、配布しているアプリケーションではありません。// <https://www.pixiv.net/terms/?page=brand>/*global Gettext, _, waitTarget */'use strict';// L10NGettext.setLocalizedTexts({/*eslint-disable quote-props, max-len */'en': {'すべて': 'All','フォロー': 'Follow','マイピク': 'My pixiv','タグ一覧': 'Tag Index','うごイラ': 'Ugoira',},'ko': {'すべて': '전체','フォロー': '팔로우','マイピク': '마이픽','タグ一覧': '태그 목록','うごイラ': '움직이는 일러스트',},'zh': {'すべて': '全部','フォロー': '关注','マイピク': '好P友','タグ一覧': '标签一览','うごイラ': '动图',},'zh-tw': {'すべて': '全部','フォロー': '關注','マイピク': '好P友','タグ一覧': '標籤一覽','うごイラ': '動圖',},/*eslint-enable quote-props, max-len */});const URLS_AND_LABLES = {search: [{ path: 'artworks', label: _('すべて'), position: 1 },{ path: 'illustrations', type: 'ugoira', label: _('うごイラ'), position: 4 },],user: [{ path: 'artworks', label: _('すべて'), position: 1 },{ path: 'following', label: _('フォロー') },{ path: 'mypixiv', label: _('マイピク') },{ path: '/member_tag_all.php?id=', label: _('タグ一覧') },],};/*** 各タブの共通の親要素。* @var {HTMLElement}*/let list;/*** カレントタブに設定されるクラス。* @var {string[]}*/let currentTabClasses;/*** @returns {HTMLAnchorElement}*/function getCurrentTab(){return list.querySelector('[aria-current][href^="/"]');}function markCurrentTab(){const currentTab = getCurrentTab();const tabs = list.children;for (const tab of tabs) {if (tab.href === location.href) {tab.setAttribute('aria-current', 'page');tab.classList.add(...currentTabClasses);} else {tab.removeAttribute('aria-current');tab.classList.remove(...currentTabClasses);}}if (!list.querySelector('[aria-current]')) {currentTab.setAttribute('aria-current', 'page');currentTab.classList.add(...currentTabClasses);}}/*** タブを補完します。* @returns {void}*/function complete(){list = document.querySelector('#root > :not(header) nav');if (!list) {return;}if (list.querySelector('[href*="type=ugoira"], [href*="/member_tag_all.php"]')) {// すでに補完済みならreturn;}const tabs = list.children;if (!currentTabClasses) {const currentTab = list.querySelector('[aria-current="page"]');const noCurrentTabClassList = Array.from(Array.from(tabs).find(tab => tab !== currentTab).classList);currentTabClasses= Array.from(currentTab.classList).filter(token => !noCurrentTabClassList.includes(token));}const pageType = location.pathname.startsWith('/tags/') ? 'search' : 'user';// 挿入するタブのテンプレートを作成const templateTab = tabs[pageType === 'search' ? 1 : 0].cloneNode(true);templateTab.removeAttribute('aria-current');templateTab.classList.remove(...currentTabClasses);for (const { path, type, label, position } of URLS_AND_LABLES[pageType]) {let tab;if (pageType === 'user' && path === 'artworks') {tab = document.querySelector('a[href$="/artworks"]:not([href$="/bookmarks/artworks"]):not([href$="/requests/artworks"])',);}if (tab) {tab.pathname = tab.pathname.replace('/artworks', '');tab.classList = templateTab.classList;} else {tab = templateTab.cloneNode(true);}switch (pageType) {case 'search':tab.pathname = tab.pathname.replace(/[^/]+$/, path);tab.firstElementChild.textContent = label;if (type) {const param = new URLSearchParams(templateTab.search);param.set('type', type);tab.search = param;}break;case 'user':if (path === '/member_tag_all.php?id=') {tab.href = tab.origin + path + /[0-9]+/.exec(tab.pathname)[0];} else {tab.pathname += '/' + path;}tab.text = label;break;}if (position) {tabs[position].before(tab);} else {list.append(tab);}}}document.addEventListener('DOMContentLoaded', function () {const root = document.getElementById('root');if (!root) {return;}Gettext.setLocale(document.documentElement.lang);addEventListener('click', async event => {const tab = event.target.closest('a');if (!tab || !tab.matches('#root > :not(header) nav > a')) {return;}if (event.defaultPrevented) {// 既存のタブreturn;}if (tab.getAttribute('href').startsWith('/') || !location.pathname.startsWith('/tags/')|| location.pathname.endsWith('/novels')) {// 別サービスへのタブreturn;}// イラスト検索結果ページで「すべて」「うごイラ」タブをクリックした場合event.preventDefault();const allTabClicked = tab.pathname.endsWith('/artworks');if (allTabClicked && /^\/tags\/[^/]+$/u.test(getCurrentTab().pathname)) {// 「すべて」タブを、「トップ」ページでクリックした場合// 「イラスト・マンガ」一覧の下の「すべて見る」ボタンをクリックlist.parentElement.nextElementSibling.querySelector('[href^="/tags/"][href$="/artworks"]').click();return;}// 検索オプションボタンをクリックdocument.querySelector('[d^="M0 1C0 0.447754"]').closest('button').click();await waitTarget(() => document.querySelector('body > [role="presentation"]'), 1);const dialog = document.querySelector('body > [role="presentation"]');dialog.style.opacity = '0';// プルダウンメニューを開くconst select = dialog.querySelector('[tabindex]');select.click();const group = select.closest('[role="group"]');await waitTarget(() => group.querySelector('[role="button"]'), 1);// 項目を選択するconst option = group.querySelectorAll('[role="button"]')[allTabClicked ? /* すべて */0 : /* うごイラ */4];option.click();await waitTarget(() => !dialog.contains(option), 1);// 「適用する」ボタンを押すsetTimeout(() => {dialog.querySelector('[type="submit"]').click();}, 100);});new MutationObserver(mutations => {for (const mutation of mutations) {if (mutation.target.matches('#root > div[class]')) {// 検索結果ページif (!Array.from(mutation.addedNodes).some(node => node.nodeType === Node.ELEMENT_NODE && node.querySelector('nav > a[href^="/tags/"]'),)) {continue;}complete();return;}// ユーザーページlet findChild;if (mutation.target.matches('#root > .charcoal-token > div > div[style] > div[class] > div[class]', // ページのタブ以下全体の親)) {findChild = node => node.localName === 'div' && node.hasAttribute('class'); // ページのタブ以下全体} else if (mutation.target.matches('#root > .charcoal-token > div > div[style] > div[class] > div[class] > div[class]',)) {// フォローページ、マイピクページから戻ったときfindChild = node => node.localName === 'div' && node.getElementsByTagName('nav')[0];}if (!findChild) {continue;}const parent = Array.from(mutation.addedNodes).find(findChild);if (parent) {if (parent.querySelector('[href*="/mypixiv_all.php?"]')) {return;}complete();return;}}if (list) {markCurrentTab();}}).observe(root, {childList: true, subtree: true});}, { passive: true, once: true });