niconico リンクを修正

Replaces JavaScript links with HTML links in Niconico.

// ==UserScript==
// @name        niconico リンクを修正
// @name:en     niconico Correct Links
// @name:ja     niconico リンクを修正
// @description Replaces JavaScript links with HTML links in Niconico.
// @description:ja JavaScriptのリンクを通常のリンクに置き換えます。
// @namespace   https://userscripts.org/users/347021
// @version     2.2.0
// @match       https://www.nicovideo.jp/*
// @match       https://live.nicovideo.jp/*
// @match       https://live2.nicovideo.jp/watch/*
// @match       https://ch.nicovideo.jp/*
// @match       *://seiga.nicovideo.jp/search/*
// @match       *://app.nicovideo.jp/*
// @match       https://ichiba.nicovideo.jp/*
// @match       *://jk.nicovideo.jp/*
// @match       *://commons.nicovideo.jp/*
// @match       https://com.nicovideo.jp/*
// @match       https://news.nicovideo.jp/*
// @require     https://bowercdn.net/c/css-escape-1.5.1/css.escape.js
// @require     https://greasyfork.org/scripts/17895/code/polyfill.js?version=625392
// @require     https://greasyfork.org/scripts/19616/code/utilities.js?version=752462
// @license     MPL-2.0
// @contributionURL https://www.amazon.co.jp/registry/wishlist/E7PJ5C3K7AM2
// @compatible  Edge 最新安定版 / Latest stable (非推奨 / Deprecated)
// @compatible  Firefox 推奨 / Recommended
// @compatible  Opera
// @compatible  Chrome
// @grant       dummy
// @icon        data:image/vnd.microsoft.icon;base64,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
// @author      100の人
// @homepage    https://greasyfork.org/scripts/260
// ==/UserScript==

'use strict';

/**
 * 通知ボタンのリンク先にするURL。
 * @constant {string}
 */
const NOTIFICATION_BUTTON_LINK = 'https://nicoad.nicovideo.jp/my?from_notification=1#tickets';

switch (location.host) {
	case 'live.nicovideo.jp':
	case 'live2.nicovideo.jp': {
		// 生放送
		// 共通ヘッダの「フォロー中」ボタン
		const notifyboxToggleButton = document.querySelector('#notify_box_count > a');
		if (notifyboxToggleButton) {
			notifyboxToggleButton.href = '/my#Favorite_list';
		}

		if (location.pathname === '/my') {
			// マイページの自分の放送
			for (const anchor of document.querySelectorAll('.nml[onclick^="window.open("]')) {
				anchor.href = /https:\/\/live\.nicovideo\.jp\/[^']+/.exec(anchor.onclick)[0];
				anchor.onclick = null;
			}
		}
		break;
	}
	case 'ch.nicovideo.jp':
		if (/^\/[^/]+\/blomaga\/ar[0-9]+(?:\/.*)?$/.test(location.pathname)) {
			// ブロマガの記事
			// 画像の原寸表示リンク
			for (const image of document.querySelectorAll(`.main_blog_txt img[src*="nicovideo.jp/image/"],
				.main_blog_txt img[data-original*="nicovideo.jp/image/"]`)) {
				if (!image.matches('a img')) {
					const anchor = document.createElement('a');
					anchor.href = image.src || image.dataset.original;
					anchor.target = '_blank';
					image.before(anchor);
					anchor.append(image);
				}
			}

			if (document.getElementsByClassName('attached_image')[0]) {
				// Tampermonkey
				GreasemonkeyUtils.executeOnUnsafeContext(/*globals jQuery */ function () {
					jQuery('.attached_image').unbind('click');
				});
			}
		}
		break;
}

// 共通ヘッダのニコられた数ボタン
const notificationButton = document.getElementsByClassName('siteHeaderNotNotifications')[0];
if (notificationButton) {
	// すでにボタンが挿入されていれば
	observeNicoruButton(notificationButton);
} else {
	const siteHeaderNotificationContainer = document.getElementById('siteHeaderNotificationContainer');
	if (siteHeaderNotificationContainer) {
		// ボタンの挿入を待機
		new MutationObserver(function (mutations, observer) {
			observer.disconnect();
			observeNicoruButton(mutations[0].addedNodes[0]);
		}).observe(siteHeaderNotificationContainer, { childList: true });
	}
}

// 主クリック時のページ遷移防止
const siteHeaderMenuList = document.getElementsByClassName('siteHeaderMenuList')[0];
if (siteHeaderMenuList) {
	siteHeaderMenuList.addEventListener('click', function (event) {
		if (event.button === 0 && event.target.matches(
			`[href="${CSS.escape(NOTIFICATION_BUTTON_LINK)}"], [href="/my#Favorite_list"], [href="/my#Favorite_list"] *`
		)) {
			event.preventDefault();
		}
	});
}

/**
 * ニコられた数ボタンを監視し、ボタンの数字にリンクを張ります。
 * @param {HTMLSpanElement} notificationButton
 */
function observeNicoruButton(notificationButton)
{
	// スタイルシートの設定
	document.head.insertAdjacentHTML('beforeend', `<style>
		#siteHeaderNotification #siteHeaderNotificationContainer .siteHeaderNotNotifications,
		#siteHeaderNotification #siteHeaderNotificationContainer .siteHeaderNotifications {
			border: none;
			padding: 0;
		}
		#siteHeader #siteHeaderInner #siteHeaderNotificationContainer > span a {
			font-size: 1em;
			border-radius: 50%;
			padding: 1px 4px;
			border: solid 2px white !important;
			margin-right: 0;
			background: inherit;
		}
	</style>`);

	fixNicoruLink();

	// ボタンがクリックされるたびに書き換わるので、その都度{@link fixNicoruLink}を実行する
	new MutationObserver(function (mutations, observer) {
		const addedNode = mutations[0].addedNodes[0];
		if (addedNode && addedNode.nodeType === Node.TEXT_NODE) {
			fixNicoruLink();
		}
	}).observe(notificationButton, { childList: true });

	/**
	 * ボタンの数字にリンクを張ります。
	 */
	function fixNicoruLink()
	{
		const anchor = document.createElement('a');
		anchor.href = NOTIFICATION_BUTTON_LINK;
		anchor.append(...notificationButton.childNodes);
		notificationButton.append(anchor);
	}
}