PTT Sites Redirection

Redirects PTT URLs to other sites

目前為 2023-06-27 提交的版本,檢視 最新版本

// ==UserScript==
// @name        PTT Sites Redirection
// @namespace   Userscript
// @version     0.1.0
// @license     MIT
// @author      CY Fung
// @run-at      document-start
// @grant       GM_registerMenuCommand
//
// @match       https://www.ptt.cc/bbs/*
// @match       https://www.pttweb.cc/*
// @match       https://disp.cc/ptt/*
// @match       https://hotptt.com/*
// @match       https://moptt.tw/p/*
// @match       https://ptthito.com/*
// @match       https://webptt.com/*
// @match       https://pttweb.tw/*
// @match       http://www.ucptt.com/*
// @match       https://www.ucptt.com/*
//
// @match       https://pttent.com/*
// @match       https://pttgame.com/*
// @match       https://pttdigit.com/*
// @match       https://pttlocal.com/*
//
// @description Redirects PTT URLs to other sites
//
// ==/UserScript==

(() => {

  /**
   * To obtain the full list of boards.

https://webptt.com/Hot.html

window.m33t = 'td:first-child a[href*="bbs/"]';
window.ss3 = new Set();

window.n33g = (a)=>a.map(e=>e.textContent).filter(x=>/^[\x20-\xFF]+$/.test(x)).filter(x=>!/[\s\,\|]/.test(x))

setInterval(()=>{
for(const t of window.n33g([...document.querySelectorAll(window.m33t)])) window.ss3.add(t);
},1);

[...ss3.keys()]

[...ss3.keys()].join(',').replace(/(\b.{100,120}\b,)/g,'$1\n')

   *
   * */

  const NO_BUTTON_FOR_CACHER = true;

  const lowerCaseMatcher = (() => {

    const fullBoards = `

ALLPOST,AC_Sale,Accounting,Actuary,ai-photo,AllTogether,AnimalGoods,Anti-ramp,AntiVirus,Aquarium,aqua-shop,Aromatherapy,
Ask,Babymother,bag,Bank_Service,barterbooks,Baseball,beauty,BeautyBody,BeautyMarket,BeautySalon,bicycle,biker,BikerShop,
Boy-Girl,Brand,Browsers,BuyTogether,C_Chat,Cad_Cae,car,cat,CATCH,Chat82gether,chatskill,China-Drama,Clothes,CMWang,
ComicHouse,CompBook,cookclub,creditcard,consumer,CVS,DC,dog,DPP,drama-ticket,DSLR,DV,EatToDie,Education,egg-exchange,
equal_change,e-shopping,Examination,EZsoft,facelift,FamilyCircle,fastfood,feminine_sex,Finance,first-wife,Fitness,Food,
forsale,Free_box,Fund,Gamesale,gardener,gay,GEPT,Getmarry,give,GoodShop,Gossiping,graduate,guitar,hairdo,handmade,
HardwareSale,hate,HelpBuy,HK-drama,homemaker,home-sale,hypermall,IELTS,Insurance,Japan_Travel,japanavgirls,Japandrama,
jeans,joke,joyinDIY,Key_Mou_Pad,Kids,KMT,KoreaDrama,KR_Entertain,L_BeautyCare,License,LicenseShop,Lifeismoney,LightNovel,
Little-Games,LivingGoods,LoL,Lomo,Lottery,MacShop,MakeUp,Mancare,marriage,marvel,memento,MenTalk,Mind,Mix_Match,MJ,
MobileComm,mobilesales,model,movie,multi-lovers,MuscleBeach,NailSalon,NBA,NBA_Film,nb-shopping,nightlife,TOEFL_iBT,
Office,Old-Games,Option,P2PSoftWare,Palmar_Drama,pay_home,PC_Shopping,perfume,Perfume_Shop,pet,photo-buy,PhotoCritic,
PhotoLink,Plant,PttEarnMoney,pttlifelaw,PuzzleDragon,Q_ary,rabbit,Railway,rent-exp,RIPE_gender,sex,share,Loan,sp_teacher,
SportLottery,SportsShop,Stock,Storage_Zone,studyteacher,StupidClown,Rent_apart,Rent_tao,Rent_ya,TaiwanDrama,talk,tax,
Teacher,teaching,Tech_Job,teeth_salon,Test,textbook,third-person,TOEIC,ToS,underwear,Wanted,WomenTalk,WoodworkDIY,
jawawa

  `.replace(/\s/g, '').split(',');

    let lowerCaseMatcher = new Map();
    for (const board of fullBoards) lowerCaseMatcher.set(board.toLowerCase(), board);

    return lowerCaseMatcher;


  })();


  const cacheKey = 'nJ0wg';

  // let m = sessionStorage.setItem(cacheKey


  function onReady() {


    // Extract the current hostname
    let currentHostname = window.location.hostname;

    // Function to handle menu command redirection
    function redirectToPTT(url) {
      sessionStorage.setItem(cacheKey, new URL(url).hostname);
      window.location.href = url;
    }
    function extraction(uObject) {

      // Extract parameters


      /*
       *
  
  supported:
  
      https://www.pttweb.cc/bbs/C_Chat/M.1684501378.A.9F2
  https://moptt.tw/p/C_Chat.M.1684501378.A.9F2
  https://www.ptt.cc/bbs/C_Chat/M.1684501378.A.9F2.html
  https://disp.cc/ptt/C_Chat/1acPSKqZ
  https://ptthito.com/c_chat/m-1684501378-a-9f2/
  https://webptt.com/m.aspx?n=bbs/C_Chat/M.1684501378.A.9F2.html
  https://pttweb.tw/C_Chat/M.1684501378.A.9F2
  http://www.ucptt.com/article/C_Chat/1684501378/9F2
  https://hotptt.com/j3pu5u01ag
  
  supported (no menu option):
  
  https://pttent.com/movie/M.1548573736.A.DD4.html
  https://pttgame.com/lol/M.1476373373.A.239.html
  https://pttdigit.com/macshop/M.1551692551.A.8EA.html
  https://pttlocal.com/tainan/M.1551683492.A.63D.html
  
  not supported:
  
  https://ptt.reviews/HatePolitics/E.w1rS970orKqI
  https://www.ptt666.com/M.1551680529.A.759.html
  
  
  */

      const f = (board) => {
        // lowerCased-board
        if (!board) return board;
        if (board !== board.toLowerCase()) return board;
        return lowerCaseMatcher.get(board) || board.replace(/_/g, '-').replace(/\b([a-z])([a-z0-9]*)\b/g, (_, a, b) => a.toUpperCase() + (b || '')).replace(/-/g, '_');
      }

      const { pathname, hostname } = uObject

      if (pathname.startsWith('/bbs/')) {
        let s = pathname.split('/');

        return {
          board: s[2],
          article: s[3].replace('.html', '')
        }
      } else if (pathname.startsWith('/p/')) {
        let d = pathname.substring(3);
        let i = d.indexOf('.');
        if (i > 0) {
          return {
            board: d.substring(0, i),
            article: d.substring(i + 1)
          }
        }
      } else if (hostname === 'ptthito.com') { // just in case

        let s = pathname.split('/');

        return {
          board: f(s[1]),
          article: s[2].replace(/-/g, '.').toUpperCase()
        }
      } else if (hostname === 'webptt.com') {

        let s = location.search.split('/');

        return {
          board: s[1],
          article: s[2].replace('.html', '')
        }

      } else if (hostname === 'pttweb.tw') {

        let s = pathname.split('/');

        return {
          board: s[1],
          article: s[2].replace('.html', '')
        }
      } else if (hostname === 'www.ucptt.com') {

        let s = pathname.split('/');
        if (s[1] === 'article' && s.length === 5) {

          return {
            board: s[2],
            article: `M.${s[3]}.A.${s[4]}`
          }
        }
      } else if (hostname === 'pttent.com' || hostname === 'pttgame.com' || hostname === 'pttdigit.com') {

        let s = pathname.split('/');

        return {
          board: f(s[1]),
          article: s[2].replace('.html', '')
        }
      }

      return null;
    }


    let objectVariables = null;
    // Handle disp.cc URL conversion
    if (currentHostname === "disp.cc" /*|| currentHostname === "ptthito.com"*/ || currentHostname === 'hotptt.com') {
      let pttLink = document.evaluate("//span[contains(text(),'※ 文章網址: ')]/a", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
      if (pttLink && !pttLink.href.startsWith("https://www.ptt.cc/bbs/")) pttLink = null;
      if (!pttLink) {
        pttLink = document.querySelector('a[href^="https://www.ptt.cc/bbs/"]');
      }
      if (pttLink) {
        let pttURL = pttLink.href;
        if (pttURL && pttURL.startsWith("https://www.ptt.cc/bbs/")) {
          objectVariables = extraction(new URL(pttURL));
        }
      }

    } else {
      objectVariables = extraction(window.location)
    }

    console.log(objectVariables)
    if (!objectVariables || !objectVariables.board || !objectVariables.article) return;
    lowerCaseMatcher.set(objectVariables.board.toLowerCase(), objectVariables.board);


    if (currentHostname !== "www.ptt.cc") {
      GM_registerMenuCommand("Redirect to www.ptt.cc", function () {
        redirectToPTT("https://www.ptt.cc/bbs/" + (objectVariables.board + "/" + objectVariables.article) + ".html");
      });
    }
    if (currentHostname !== "www.pttweb.cc") {
      GM_registerMenuCommand("Redirect to www.pttweb.cc", function () {
        redirectToPTT("https://www.pttweb.cc/bbs/" + objectVariables.board + "/" + objectVariables.article);
      });
    }


    /*
    if (currentHostname !== "disp.cc") {
      GM_registerMenuCommand("Redirect to disp.cc", function () {
        redirectToPTT("https://disp.cc/ptt/" + (objectVariables.board + "/" + objectVariables.article));
      });
    }
    */


    if (currentHostname !== "moptt.tw") {
      GM_registerMenuCommand("Redirect to moptt.tw", function () {
        redirectToPTT("https://moptt.tw/p/" + objectVariables.board + "." + objectVariables.article);
      });
    }

    if (currentHostname !== "ptthito.com") {
      GM_registerMenuCommand("Redirect to ptthito.tw", function () {
        redirectToPTT("https://ptthito.com/" + (objectVariables.board + "/" + objectVariables.article.replace(/\./g, '-') + "/").toLowerCase());
      });

    }

    if (currentHostname !== "webptt.com") {


      GM_registerMenuCommand("Redirect to webptt.com", function () {
        redirectToPTT(`https://webptt.com/m.aspx?n=bbs/${objectVariables.board}/${objectVariables.article}.html`);
      });



    }


    if (currentHostname !== "pttweb.tw") {


      GM_registerMenuCommand("Redirect to pttweb.tw", function () {
        redirectToPTT(`https://pttweb.tw/${objectVariables.board}/${objectVariables.article}`);
      });



    }

    if (currentHostname !== 'www.ucptt.com') {




      GM_registerMenuCommand("Redirect to www.ucptt.com", function () {
        let p = /M\.([^\s.,|\/\\]+)\.A\.([^\s.,|\/\\]+)/.exec(objectVariables.article);
        if (p) {

          redirectToPTT(`http://www.ucptt.com/article/${objectVariables.board}/${p[1]}/${p[2]}`);
        }
      });


    }

    if (currentHostname !== 'pttent.com' && !NO_BUTTON_FOR_CACHER) {


      // not all posts can read
      // https://www.ptt.cc/bbs/Lifeismoney/M.1687762841.A.5E8.html

      GM_registerMenuCommand("Redirect to pttent.com", function () {
        redirectToPTT(`https://pttent.com/${objectVariables.board.toLowerCase()}/${objectVariables.article}.html`);
      });



    }



    if (currentHostname !== 'pttgame.com' && !NO_BUTTON_FOR_CACHER) {

      // not all posts can read
      // https://www.ptt.cc/bbs/Lifeismoney/M.1687762841.A.5E8.html

      GM_registerMenuCommand("Redirect to pttgame.com", function () {
        redirectToPTT(`https://pttgame.com/${objectVariables.board.toLowerCase()}/${objectVariables.article}.html`);
      });



    }


    if (currentHostname !== 'pttdigit.com' && !NO_BUTTON_FOR_CACHER) {

      // not all posts can read
      // https://www.ptt.cc/bbs/Lifeismoney/M.1687762841.A.5E8.html

      GM_registerMenuCommand("Redirect to pttdigit.com", function () {
        redirectToPTT(`https://pttdigit.com/${objectVariables.board.toLowerCase()}/${objectVariables.article}.html`);
      });



    }

    if (currentHostname !== 'pttlocal.com' && !NO_BUTTON_FOR_CACHER) {

      // not all posts can read
      // https://www.ptt.cc/bbs/Lifeismoney/M.1687762841.A.5E8.html

      GM_registerMenuCommand("Redirect to pttlocal.com", function () {
        redirectToPTT(`https://pttlocal.com/${objectVariables.board.toLowerCase()}/${objectVariables.article}.html`);
      });



    }



  }



  if (document.readyState != 'loading') {
    onReady();
  } else {
    window.addEventListener("DOMContentLoaded", onReady, false);
  }



})();