Reddit → LiveContainer (iOS)

Redirect Reddit links to LiveContainer so they open in the containerized Reddit app.

// ==UserScript==
// @name         Reddit → LiveContainer (iOS)
// @namespace    sharmanhall
// @version      0.5
// @description  Redirect Reddit links to LiveContainer so they open in the containerized Reddit app.
// @author       sharmanhall
// @match        https://www.reddit.com/*
// @match        https://old.reddit.com/*
// @match        https://np.reddit.com/*
// @match        https://reddit.com/*
// @match        https://redd.it/*
// @match        *://*/*
// @grant        none
// @license      MIT
// @run-at       document-start
// @noframes
// ==/UserScript==

(function () {
  'use strict';

  // ---- prefs ----
  const VERBOSE = true; // set false to quiet logs
  const AUTO_REDIRECT_ON_REDDIT_PAGES = true;  // when you're *on* a Reddit page
  const REWRITE_LINKS_ON_ALL_PAGES = true;     // intercept <a> to Reddit anywhere
  const ADD_LC_FLAG = true;                    // append lc=1 to avoid bounce loops

  const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);

  // Cover reddit root + all subdomains; include redd.it shortener.
  const redditHosts = new Set([
    'reddit.com',       // matches www/old/np/amp/etc via endsWith
    'redd.it'           // shortlinks (posts, comments, media pages)
  ]);

  function log(...args){ if (VERBOSE) console.log('[LC-Reddit]', ...args); }

  function isRedditURL(u) {
    try {
      const url = (u instanceof URL) ? u : new URL(u, location.href);
      return [...redditHosts].some(h => url.hostname === h || url.hostname.endsWith('.' + h));
    } catch { return false; }
  }

  // Encode for LiveContainer's open-web-page scheme (expects Base64)
  function toBase64(str) {
    try {
      return btoa(String.fromCharCode(...new TextEncoder().encode(str)));
    } catch {
      // Fallback for older Safari
      return btoa(unescape(encodeURIComponent(str)));
    }
  }

  function buildLcUrl(originalUrl) {
    const url = new URL(originalUrl, location.href);
    if (ADD_LC_FLAG && !url.searchParams.has('lc')) url.searchParams.set('lc', '1');
    return `livecontainer://open-web-page?url=${toBase64(url.toString())}`;
  }

  function redirectToLC(u) {
    const lc = buildLcUrl(u);
    log('Redirecting to LiveContainer:', lc);
    location.replace(lc); // avoid extra history entries
  }

  // 1) If we're on a Reddit page already, bounce to LiveContainer (iOS only)
  if (isIOS && AUTO_REDIRECT_ON_REDDIT_PAGES && isRedditURL(location.href)) {
    const cur = new URL(location.href);
    if (!cur.searchParams.get('lc')) {
      redirectToLC(location.href);
      return; // stop executing further on this page
    } else {
      log('lc=1 present; skipping auto-redirect to avoid loop.');
    }
  }

  if (!isIOS) return; // iOS-only behavior below

  // Some pages expose expanded URLs (e.g., via data-* attributes). Prefer those when they point to Reddit.
  function resolveTargetHref(a) {
    const expanded =
      a?.dataset?.expandedUrl ||
      a?.getAttribute?.('data-expanded-url') ||
      a?.dataset?.fullUrl ||
      a?.getAttribute?.('data-full-url');
    if (expanded && isRedditURL(expanded)) return expanded;
    return a?.href || '';
  }

  // 2) Global capture fallback for delegated clicks (robust vs dynamic UIs)
  if (REWRITE_LINKS_ON_ALL_PAGES) {
    document.addEventListener('click', (e) => {
      const a = e.target?.closest?.('a[href]');
      if (!a) return;
      const targetHref = resolveTargetHref(a);
      if (!isRedditURL(targetHref)) return;
      try {
        e.preventDefault();
        e.stopPropagation();
        redirectToLC(targetHref);
      } catch (err) {
        log('Error redirecting (global):', err);
      }
    }, { capture: true, passive: false });
  }

  // 3) Per-anchor hook + dynamic observer (in case sites block global handlers)
  if (REWRITE_LINKS_ON_ALL_PAGES) {
    const processAnchor = (a) => {
      if (!a || !a.href) return;
      if (a.dataset.lcReddit === '1') return; // double-hook guard
      const targetHref = resolveTargetHref(a);
      if (!isRedditURL(targetHref)) return;

      const handler = (e) => {
        try {
          e.preventDefault();
          e.stopPropagation();
          redirectToLC(targetHref);
        } catch (err) {
          log('Error redirecting (anchor):', err);
        }
      };
      a.addEventListener('click', handler, { capture: true, passive: false });
      a.dataset.lcReddit = '1';
      log('Hooked Reddit link:', targetHref);
    };

    // Initial pass
    document.querySelectorAll('a[href]:not([data-lc-reddit])').forEach(processAnchor);

    // Observe dynamically-added links (SPAs, infinite scroll, etc.)
    const mo = new MutationObserver((muts) => {
      for (const m of muts) {
        for (const node of m.addedNodes) {
          if (node.nodeType !== 1) continue;
          if (node.tagName === 'A' && node.href) processAnchor(node);
          else node.querySelectorAll?.('a[href]:not([data-lc-reddit])').forEach(processAnchor);
        }
      }
    });
    mo.observe(document.documentElement, { childList: true, subtree: true });
  }
})();

QingJ © 2025

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