cldisk Thumb → PDF Helper

自动将 cldisk 缩略图 URL (…/thumb/96.png) 转换为对应 PDF 链接 (…/pdf/{hash}.pdf),支持复制与一键打开。

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

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

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

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

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         cldisk Thumb → PDF Helper
// @namespace    https://greasyfork.org/users/yourname
// @version      1.2
// @description  自动将 cldisk 缩略图 URL (…/thumb/96.png) 转换为对应 PDF 链接 (…/pdf/{hash}.pdf),支持复制与一键打开。
// @author       你(基于 GPT 辅助编写)
// @license      MIT
// @icon         https://s3.cldisk.com/favicon.ico
// @match        https://s3.cldisk.com/*
// @grant        GM_notification
// @grant        GM_setClipboard
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  const HOST_FILTER = 's3.cldisk.com';

  function thumbUrlToPdfUrl(rawUrl) {
    if (!rawUrl) return null;
    try {
      const url = new URL(rawUrl, location.href);
      if (HOST_FILTER && url.host !== HOST_FILTER) return null;
      const idx = url.pathname.indexOf('/thumb/');
      if (idx === -1) return null;
      const beforeThumb = url.pathname.slice(0, idx);
      const segments = beforeThumb.split('/').filter(Boolean);
      if (!segments.length) return null;
      const hash = segments[segments.length - 1];
      const prefix = '/' + segments.join('/');
      const pdfPath = `${prefix}/pdf/${hash}.pdf`;
      return `${url.protocol}//${url.host}${pdfPath}`;
    } catch {
      return null;
    }
  }

  function notify(msg) {
    if (typeof GM_notification === 'function') GM_notification({ text: msg, timeout: 2000 });
    else console.log('[cldisk-helper]', msg);
  }

  function handleThumb(url) {
    const pdfUrl = thumbUrlToPdfUrl(url);
    if (pdfUrl) {
      console.log('[cldisk-helper] thumb =>', pdfUrl);
      notify('检测到缩略图,已解析对应 PDF');
    }
  }

  // Hook fetch
  if (window.fetch) {
    const f = window.fetch;
    window.fetch = function (input, init) {
      if (typeof input === 'string') handleThumb(input);
      return f.apply(this, arguments);
    };
  }

  // Hook XHR
  const o = XMLHttpRequest.prototype.open;
  XMLHttpRequest.prototype.open = function (method, url) {
    handleThumb(url);
    return o.apply(this, arguments);
  };

  // 扫描页面元素并添加按钮
  function attachBtn(el, url) {
    const pdf = thumbUrlToPdfUrl(url);
    if (!pdf || el.dataset.clPdf) return;
    const btn = document.createElement('button');
    btn.textContent = '打开 PDF';
    btn.style.marginLeft = '5px';
    btn.onclick = () => window.open(pdf, '_blank');
    el.insertAdjacentElement('afterend', btn);
    el.dataset.clPdf = 1;
  }

  function scan() {
    document.querySelectorAll('img,a').forEach(el => {
      const url = el.src || el.href;
      if (url) attachBtn(el, url);
    });
  }

  scan();
  new MutationObserver(scan).observe(document.body, { childList: true, subtree: true });

})();