AH/QQ/SB/SV direct links to Reader Mode

Append "/reader/" to forum links if they have a wordcount.

// ==UserScript==
// @name        AH/QQ/SB/SV direct links to Reader Mode
// @description Append "/reader/" to forum links if they have a wordcount.
// @author      C89sd
// @version     1.7
// @match       https://forums.spacebattles.com/forums/*
// @match       https://forums.spacebattles.com/search/*
// @match       https://forums.spacebattles.com/tags/*
// @match       https://forums.sufficientvelocity.com/forums/*
// @match       https://forums.sufficientvelocity.com/search/*
// @match       https://forums.sufficientvelocity.com/tags/*
// @match       https://forum.questionablequesting.com/forums/*
// @match       https://forum.questionablequesting.com/search/*
// @match       https://forum.questionablequesting.com/tags/*
// @match       https://www.alternatehistory.com/forum/forums/*
// @match       https://www.alternatehistory.com/forum/search/*
// @match       https://www.alternatehistory.com/forum/tags/*
// @namespace   https://gf.qytechs.cn/users/1376767
// ==/UserScript==

// Note: https://forums.spacebattles.com/account/*
// cannot be implemented because there's no wordcount to detect if /reader/ is valid or not.

// Note: AlternateHistory is .com/forum/search instead of .com/search
const IS_SEARCH = /^(https:\/\/[^\/]+\/(search|forum\/search)\/)/.test(window.location.href);

// Note: post links from Search page cannot be converted to reader mode.
// e.g "site.com/threads/foo.123/post-456"
//   resolves to "site.com/threads/foo.123/page-11#post-456"
//   not         "site.com/threads/foo.123/reader/page-2#post-456"
let regex = /^(https:\/\/[^\/]+\/(?:threads|forum\/threads)\/[^\/]+\/)(post-\d+)?/;

function isPost(match) {
  return match[2] !== undefined;
}

let small = true;
let spanReader;
let spanPostLink;
let spanZeroWords;
if (IS_SEARCH) {
  spanReader = document.createElement('span');
  spanReader.style.fontWeight = 'normal';
  if(small) spanReader.style.fontSize = 'small';
  spanReader.textContent = '⌸ ';

  spanPostLink = document.createElement('span');
  spanPostLink.style.fontWeight = 'normal';
  if(small) spanPostLink.style.fontSize = 'small';
  spanPostLink.textContent = '☍ ';

  spanZeroWords = document.createElement('span');
  spanZeroWords.style.fontWeight = 'normal';
  if(small) spanZeroWords.style.fontSize = 'small';
  spanZeroWords.textContent = '⎕ ';
}

function prependTitleIcon(title, icon) {
  title.insertBefore(icon.cloneNode(true), title.firstChild);
}

const threads = document.querySelectorAll('div.structItem, li.block-row'); // forum, search
for (const thread of threads) {

   // old, view as threads
  var foundCount = false;

  let wordcountOld = thread.querySelector('li>a[data-xf-click="overlay"]')?.textContent?.trim();
  let wordcountNew;
  let wordcountSearch;
  if (wordcountOld && wordcountOld.startsWith('Word')) { // (wordcountOld.startsWith('Words: ') || wordcountOld.startsWith('Word Count: '))) {
    foundCount = true;
  }
  else {
    wordcountNew = thread.querySelector('dl:has(>dd>a[data-xf-click="overlay"])')?.textContent?.trim();
    if (wordcountNew && wordcountNew.startsWith('Word')) {
      foundCount = true;
    }
    else {
      wordcountSearch = thread.querySelector('li>a.wordcount');
      if (wordcountSearch) {
        foundCount = true;
      }
    }
  }

  // Note:
  // If the code breaks it will probably due to this, as there can be multiple links,
  // and I may not have :not() excluded all the cases.
  let title = thread.querySelector('div.structItem-title > a:not(.unreadLink):not(.labelLink), h3.contentRow-title > a');
  if (title) {
    const match = title.href.match(regex);
    if (match) {

      if (isPost(match)) {
        if (IS_SEARCH) prependTitleIcon(title, spanPostLink);
      } else {
        if (foundCount) {
          title.href = match[1] + 'reader/';

          if (IS_SEARCH) prependTitleIcon(title, spanReader);
        } else {
          if (IS_SEARCH) prependTitleIcon(title, spanZeroWords);
        }
      }
    }
  }

  // console.log(thread, wordcountOld, wordcountNew, wordcountSearch, foundCount, title)
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址