DMM・FANZAで商品(など)のリンクに(だいたいの)フルタイトルをポップアップ
当前为
// ==UserScript==
// @name popupTitleOverAnchorsOnDMM
// @namespace https://greasyfork.org/ja/users/289387-unagionunagi
// @description DMM・FANZAで商品(など)のリンクに(だいたいの)フルタイトルをポップアップ
// @author unagiOnUnagi
// @match *://*.dmm.co.jp/*
// @match *://*.dmm.com/*
// @grant none
// @license GPL-2.0-or-later
// @version 0.11
// ==/UserScript==
function logger(target) {
for (let child of target.childNodes) {
let iText = child.innerText;
if (iText) {
console.log(child);
console.log(iText);
}
logger(child);
}
}
function getTrimText(node) {
return node.textContent.trim().replace(/\s+/g, ' ');
}
function xpathEval(xpath, cxtNode=document.body) {
return document.evaluate(
xpath, cxtNode,
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
}
function getTitle(anchor) {
// タイトルの取得
// alt がなかったら a タグの onclick を見てみる
// onclick もダメだったら a タグ内のタイトル文字列をそのまま
// DMM 動画:
// VR top: altなし、span(title), span(price)
// Idol top: altなし、span(title), span(price)
// IdolCh top: altなし、a直下img><br>title
// 見放題ch top: altなし、a直下
let title = anchor.querySelector('img').alt;
if (title) return title;
let nameNode = anchor.querySelector(
'.mainListLinkWork__txt,.responsive-name,.c-product-card__ttl,' +
'.bx-title,.productCard-title,.title1O8Dg');
if (nameNode) {
if ((title = getTrimText(nameNode))) return title;
}
for (let c of anchor.childNodes) {
if (c.nodeName == '#text') {
if ((title = c.nodeValue.trim())) return title;
}
}
for (let s of anchor.getElementsByTagName('span')) {
let txt = getTrimText(s);
if (txt) {
title = txt;
break;
}
}
if (!title || title == 't') {
if ((title = getTrimText(anchor))) return title;
}
return title;
}
function addTitleAttrAll(nodes) {
// a タグに子要素の img の alt から取ってきたタイトルを title 属性として追加
// ランキングのところは別
let length = nodes.length || nodes.snapshotLength;
let getItem = nodes.item || nodes.snapshotItem;
getItem = getItem.bind(nodes);
for (let i=0; i < length; i++) {
let anchor = getItem(i);
let title = getTitle(anchor);
title && (anchor.title = title);
}
}
function addTitleAttr2Rankings(target) {
// ランキング内商品 anchorに title= 追加
// DMM DVD通販 IdolTop: altがt、タイトルがa直下 (非固定spanのtail)
// FANZA 動画 ビデオtop ranking[1:]: altなし、span(rank) a直下 title br latest
let prefix = '.';
if (!target) {
prefix = './/div[@id="side-rank-tab"]';
target = document.body;
}
const ranking = xpathEval(prefix + '//li[div[a[not(@title) or @title=""]]]',
target);
const rankingLength = ranking.snapshotLength;
for ( let i=0 ; i < rankingLength; i++ ) {
let li = ranking.snapshotItem(i);
let alt = li.getElementsByTagName('img')[0].alt;
if (!alt || alt == 't') alt = getTrimText(li);
if (alt) {
for (let textEl of li.querySelectorAll('div > a')) {
textEl.title = alt;
}
} else {
console.log(`Could not get title on ranking: ${li}`);
}
}
}
function addTitlesOnDMMTV(targetNodes) {
// DMM TV、FANZA TVポップアップ
for (let nodes of targetNodes) {
for (let child of nodes.childNodes) {
let objNode, title;
if (child.nodeType == Node.TEXT_NODE) {
// FANZA TV ページ上のタイトル
objNode = nodes;
title = child.nodeValue;
} else {
// DMM/FANZA TV のポップアップ
objNode = child;
title = child.innerText;
}
// console.log(objNode);
if (!objNode.title) {
objNode.title = title;
}
}
}
}
(function() {
// とりあえず title のない画像つきリンクに一律処理
addTitleAttrAll(xpathEval('.//a[.//img and not(@title)]', document.body));
// カテゴリトップページランキング
// 最初に一発やっとかないとあとで更新されないページがある
addTitleAttr2Rankings();
// ページの動的変更を監視
const observer = new MutationObserver(mutations => {
for (let mutation of mutations) {
let target = mutation.target;
// console.log(target);
// .line-clamp-1 DMM TV ポップアップのタイトル
// .line-clamp-2 DMM TV ポップアップの概要
// .eu14kkw0 FANZA TV ポップアップのタイトル
// .eu14kkw2 FANZA TV ポッポアップの概要
// .text-xs DMM/FANZA TV ページ上のタイトル
// logger(target);
let dmmTV = target.querySelectorAll('.line-clamp-1,.line-clamp-2,.eu14kkw0,.eu14kkw2,.text-xs');
if (dmmTV.length > 0) {
addTitlesOnDMMTV(dmmTV);
continue;
}
addTitleAttrAll(xpathEval('.//a[.//img and not(@title)]', target));
if (target.id.match(/(ranking|s-tb-sect)/)) {
addTitleAttr2Rankings(target);
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
})();