Greasy Fork

Greasy Fork is available in English.

pixivイラストページ改善

pixivイラストページのタグに作者マーカーと百科事典アイコン、ユーザー名の列に作品タグを復活させます

当前为 2018-06-24 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==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 作者アイコンを大サイズに差し替え
// ==/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 = `<h2><a href="${tagAllUrl}">作品タグ</a></h2>`;
				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();
})();