Yahoo!ニュース 自動跳轉完整文章(高速版)

在 Yahoo!ニュース pickup 頁自動跳轉至完整文章

// ==UserScript==
// @name         Yahoo!ニュース 自動跳轉完整文章(高速版)
// @namespace    http://tampermonkey.net/
// @author       gpt5
// @version      2.0
// @description  在 Yahoo!ニュース pickup 頁自動跳轉至完整文章
// @match        https://news.yahoo.co.jp/pickup/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  let redirected = false;
  const root = document.querySelector('main, #__next, #content, body') || document.body;

  function findReadMoreLink(container) {
    let a = container.querySelector('a[aria-label*="記事全文"], a[aria-label*="全文"], a[role="button"]');
    if (a && /articles\//.test(a.href)) return a;

    a = container.querySelector('a[class*="read"], a[class*="more"], a[class*="全文"], a[class*="pickup"]');
    if (a && /articles\//.test(a.href)) return a;

    const candidates = container.querySelectorAll('a[href*="/articles/"], a[href*="news.yahoo.co.jp/articles/"]');
    if (candidates.length === 1) return candidates[0];

    for (const link of candidates) {
      const text = (link.innerText || link.textContent || '').trim();
      if (text.includes('記事全文を読む') || text.includes('続きを読む') || text.includes('全文')) {
        return link;
      }
    }
    return null;
  }

  function redirectIfFound() {
    if (redirected) return;
    const link = findReadMoreLink(root);
    if (link && link.href && !redirected) {
      redirected = true;
      location.replace(link.href);
    }
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', redirectIfFound, { once: true, passive: true });
  } else {
    setTimeout(redirectIfFound, 0);
  }

  let timer = null;
  const observer = new MutationObserver(() => {
    if (redirected) {
      observer.disconnect();
      return;
    }
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      redirectIfFound();
    }, 50);
  });

  observer.observe(root, { childList: true, subtree: true });

  setTimeout(redirectIfFound, 1000);
  setTimeout(() => {
    redirectIfFound();
    if (!redirected) observer.disconnect();
  }, 3000);
})();