Scribd Bypass (domain switch only)

Adds a toolbar button that rewrites Scribd URL to scribd.vdownloaders.com and navigates there.

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Scribd Bypass (domain switch only)
// @description  Adds a toolbar button that rewrites Scribd URL to scribd.vdownloaders.com and navigates there.
// @author       573dave
// @version      2.7
// @license      MIT
// @match        *://*.scribd.com/*
// @grant        GM_addStyle
// @run-at       document-idle
// @noframes
// @namespace https://greasyfork.org/users/1294930
// ==/UserScript==

(function () {
  'use strict';

  // ----- Styles -----
  GM_addStyle(`
    .sb-bar{position:fixed;top:0;left:50%;transform:translateX(-50%);
      display:flex;gap:6px;z-index:2147483646;background:rgba(255,255,255,.92);
      padding:6px 10px;border-radius:0 0 6px 6px;box-shadow:0 2px 6px rgba(0,0,0,.2);
      backdrop-filter:saturate(120%) blur(4px)}
    .sb-btn{font:12px/1.2 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
      padding:6px 10px;background:#FFC017;color:#111;border:none;border-radius:6px;
      cursor:pointer;transition:filter .2s}
    .sb-btn:hover{filter:brightness(.95)}
  `);

  // ----- Helpers -----
  const byId = (id) => document.getElementById(id);
  const create = (tag, props = {}, kids = []) => {
    const el = document.createElement(tag);
    for (const [k, v] of Object.entries(props)) {
      if (k === 'class') el.className = v;
      else if (k === 'text') el.textContent = v;
      else if (k.startsWith('on') && typeof v === 'function') el.addEventListener(k.slice(2), v);
      else el.setAttribute(k, v);
    }
    for (const kid of kids) el.appendChild(kid);
    return el;
  };
  const waitDOM = () =>
    new Promise((r) => (document.readyState === 'loading'
      ? document.addEventListener('DOMContentLoaded', r, { once: true })
      : r()));

  // Build the toolbar if on a document-like page
  function mountBar() {
    if (byId('sb-bar')) return;

    // Only show on typical doc-like routes to avoid cluttering account/home pages
    const path = location.pathname;
    const looksDoc = /(\/(doc|document|presentation|book|read)\/\d+\/?)|(^\/read\/\d+)/i.test(path);
    if (!looksDoc) return;

    const bar = create('div', { id: 'sb-bar', class: 'sb-bar' });
    const dlBtn = create('button', {
      class: 'sb-btn',
      text: 'Download (switch domain)',
      onclick: () => {
        // Rewrite: https://www.scribd.com/<path>  ->  https://scribd.vdownloaders.com/<path>
        // Leave path & query intact; the downloader usually accepts the same structure.
        const u = new URL(location.href);
        u.protocol = 'https:'; // normalize
        u.hostname = 'scribd.vdownloaders.com';
        // Optional: remove marketing params if any (kept minimal)
        // u.searchParams.delete('utm_source'); u.searchParams.delete('utm_medium'); u.searchParams.delete('utm_campaign');

        location.assign(u.toString());
      },
    });

    bar.append(dlBtn);
    document.documentElement.appendChild(bar);
  }

  // Re-run when SPA navigation occurs
  function onURLChange(cb) {
    let last = location.href;
    const fire = () => {
      const now = location.href;
      if (now !== last) { last = now; cb(); }
    };
    const wrap = (prop) => {
      const orig = history[prop];
      return function () {
        const ret = orig.apply(this, arguments);
        fire();
        return ret;
      };
    };
    history.pushState = wrap('pushState');
    history.replaceState = wrap('replaceState');
    window.addEventListener('popstate', fire);
    // Lightweight observer as a fallback for dynamic DOM/router changes
    const mo = new MutationObserver(() => fire());
    mo.observe(document, { subtree: true, childList: true });
  }

  // Init
  (async () => {
    await waitDOM();
    mountBar();
    onURLChange(() => {
      // Remove prior bar if we left a doc page, then (re)mount if needed
      const old = byId('sb-bar'); if (old) old.remove();
      mountBar();
    });
  })();
})();