// ==UserScript== // @name pixivイラストページ改善 // @description pixivイラストページのタグに作者マーカーと百科事典アイコン、ユーザー名の列に作品タグを復活させます // @namespace Aime // @match https://www.pixiv.net/member_illust.php* // @version 1.0.1 // @grant none // @run-at document-end // @noframes // @note 2018/06/22 1.0.1 作者アイコンを大サイズに差し替え // @downloadURL none // ==/UserScript== (() => { "use strict"; const pixivService = { enablePixpediaIcon : true, // 百科事典アイコンを付けるか? enableTagCloud : true, // 作品タグを表示するか? enableReplaceAuthorIcon : true, // 作者アイコンを大サイズに差し替える? _existPixpedia : {}, _illustTags : {}, _currenAuthorId : -1, _delayTimer : null, run: function() { const root = document.getElementById("root"); if (!root) return; const head = document.querySelector("head"); const style = document.createElement("style"); style.textContent = this._style; head.appendChild(style); new MutationObserver(records => { records.forEach(record => { if (record.type === "attributes") { const target = record.target; if (target.classList.contains("_2lyPnMP") && target.parentElement.classList.contains("_2kZnEk0")) this.replaceAuthorIcon(); } else { record.addedNodes.forEach(node => { if (!node.querySelectorAll) return; // 増えたタグに百科事典アイコンを付ける const tags = node.querySelectorAll("a.gtm-new-work-tag-event-click:not([pixpedia]"); if (tags.length) { if (this.enablePixpediaIcon) tags.forEach(node => this.insertPixpedia(node)); this.authorTags(); return; } // タグが減ったか変わらない場合は画像が変わったかで判断 // イラスト:img._2r_DywD, うごイラ:div._3QPzwxP, 閲覧注意:div._27qPnrS if (node.classList.contains("_2r_DywD") || node.classList.contains("_3QPzwxP") || node.classList.contains("_27qPnrS")) { this.stopDelayTimer(); this._delayTimer = setTimeout(this.illustChanged.bind(this), 1000); } }); } }); }).observe(root, { childList : true, subtree : true, attributes : true, attributeFilter : [ "style" ] }); }, stopDelayTimer: function() { if (this._delayTimer) { clearTimeout(this._delayTimer); this._delayTimer = null; } }, illustChanged: function() { this.stopDelayTimer(); this.authorTags(); }, insertPixpedia: async function(node) { if (node.hasAttribute("pixpedia")) return; node.setAttribute("pixpedia", "true"); node.addEventListener("mouseover", this, true); try { const eTag = encodeURIComponent(node.textContent.trim()); if (!(eTag in this._existPixpedia)) this._existPixpedia[eTag] = !!await this.fetchJSON("https://www.pixiv.net/ajax/tag/" + eTag + "/info"); const a = document.createElement("a"); a.className = "pixpedia-icon" + (this._existPixpedia[eTag]? "": " pixpedia-icon-no-item"); a.href = "https://dic.pixiv.net/a/" + eTag; node.parentElement.appendChild(a); } catch (e) { console.error(e); } }, handleEvent: function(event) { event.stopPropagation(); }, authorTags: async function() { this.replaceAuthorIcon(); const match = /illust_id=(\d+)/.exec(location.href); if (!match) return; const illustId = match[1]; let authorId; try { if (!(illustId in this._illustTags)) this._illustTags[illustId] = await this.fetchJSON("https://www.pixiv.net/ajax/tags/illust/" + illustId); const tagData = this._illustTags[illustId]; if (!tagData) return; authorId = tagData.authorId; document.querySelectorAll("li._1tTPwGC").forEach(elem => { let isOwn = false; const a = elem.querySelector("a.gtm-new-work-tag-event-click"); if (a) { const tag = a.textContent.trim(); const find = tagData.tags.find(t => t.tag == tag); isOwn = find && find.userId === authorId; } if (isOwn) elem.classList.add("author-tag-marker"); else elem.classList.remove("author-tag-marker"); }); } catch (e) { console.error(e); } if (this.enableTagCloud && authorId && this._currenAuthorId !== authorId) { this._currenAuthorId = authorId; this.authorTagCloud(authorId); } }, authorTagCloud: async function(authorId) { const aside = document.querySelector("aside._2e0p8Qb"); if (!aside) return; let ok = false; try { // タグ一覧ページから引っ張ってきて差し込む const tagAllUrl = "https://www.pixiv.net/member_tag_all.php?id=" + authorId; const response = await this.fetchSameOrigin(tagAllUrl); const text = await response.text(); const parser = new DOMParser(); const html = parser.parseFromString(text, "text/html"); const tagCloud = html.querySelector("ul.tagCloud"); if (tagCloud) { let container = document.getElementById("author-tags"); if (!container) { container = document.createElement("div"); container.id = "author-tags"; container.className = "_3mXmB-F"; aside.insertBefore(container, document.querySelector("._3M6FtEB")); } container.innerHTML = `

作品タグ

`; container.appendChild(tagCloud); ok = true; } } catch (e) { console.error(e); } if (!ok) { const container = document.getElementById("author-tags"); if (container) container.parentElement.removeChild(container); } }, replaceAuthorIcon: function() { if (!this.enableReplaceAuthorIcon) return; const icon = document.querySelector("section.tYcZrl1 a._2lyPnMP"); if (icon) { const img = icon.style.backgroundImage.replace("_50.", "_170.").replace("_s.", "."); if (icon.style.backgroundImage !== img ) { icon.style.backgroundImage = img; icon.parentElement.classList.add("icon170"); } } }, fetchSameOrigin: function (url) { return fetch(url, { mode: "same-origin", credentials: "same-origin" }); }, fetchJSON: async function(url) { const response = await this.fetchSameOrigin(url); const data = await response.json(); if (data.error) throw new Error(data.message); return data.body; }, _style: ` /* 百科事典 */ .pixpedia-icon { display: inline-block; margin-left: 2px; width: 15px; height: 14px; vertical-align: -2px; text-decoration: none; background: url(https://s.pximg.net/www/images/inline/pixpedia.png) no-repeat; } .pixpedia-icon-no-item { background: url(https://s.pximg.net/www/images/inline/pixpedia-no-item.png) no-repeat; } .pixpedia-icon::before { display: none; } /* 作者タグ */ .author-tag-marker::before { content: "*" !important; color: #E66; } /* "#"を消す */ .qE_sxIX::before { display: none !important; } /* tag cloud */ #author-tags._3mXmB-F { padding: 8px; background-color: #FFF; } #author-tags h2 { color: #333; font-size: 14px; margin: 0 0 8px; } #author-tags h2 a { color: inherit; text-decoration: none; } .tagCloud { font-size: 12px; line-height: 1.6; padding: 0; margin: 0; word-break: break-all; } .tagCloud li { display: inline; font-size: 12px; padding: 0px 2px; margin: 0px; } .tagCloud li a { color: inherit; text-decoration: none; } .tagCloud li.level1 { font-size: 20px; font-weight: bold; } .tagCloud li.level1 a { color: #3E5B71; } .tagCloud li.level2 { font-size: 18px; font-weight: bold; } .tagCloud li.level2 a { color: #3E5B71; } .tagCloud li.level3 { font-size: 17px; font-weight: bold; } .tagCloud li.level3 a { color: #587C97; } .tagCloud li.level4 { font-size: 16px; font-weight: bold; } .tagCloud li.level4 a { color: #587C97; } .tagCloud li.level5 { font-size: 14px; font-weight: bold; } .tagCloud li.level5 a { color: #587C97; } .tagCloud li.level6 a { color: #5E9ECE; } .tagCloud li a:hover { background-color: #3E5B71; color: #FFF; } .tagCloud li .cnt { font-size: 11px; font-weight: normal; color: #999999; } /* 作者アイコンを大きく */ section.tYcZrl1._3mXmB-F { margin-top: 0; } .icon170._2kZnEk0 { display: block !important; text-align: center !important; } .icon170 a._2lyPnMP { width: 170px !important; height: 170px !important; margin: 0 auto 4px !important; border-radius: 4px !important; background-position: center !important; background-repeat: no-repeat !important; background-size: contain !important; } ` }; pixivService.run(); })();