// ==UserScript== // @name 资料宝库·文档下载器 // @namespace http://tampermonkey.net/ // @version 3.3 // @description 替换网页预览区为完整全文渲染(支持文字文档和PPT图片文档),解除试读限制,支持直接选择/复制/下载 // @author you // @match *://web.cpsad.cn/* // @icon https://web.cpsad.cn/favicon.ico // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_log // @connect gyy.kuduoke.net // @connect web.cpsad.cn // @run-at document-start // @license MIT // ==/UserScript== (function () { 'use strict'; const TAG = '[cpsad_dl]'; const log = (...a) => { const msg = a.map(x => (typeof x === 'string' ? x : JSON.stringify(x))).join(' '); try { GM_log(TAG + ' ' + msg); } catch (e) {} try { console.log(TAG, ...a); } catch (e) {} }; log('脚本启动 v3.3, URL =', location.href); // ===== 样式 ===== GM_addStyle(` /* 全文渲染容器 — 替换原 iframe 预览区 */ .cpsad-fullview { width: 100% !important; min-height: 60vh !important; padding: 32px 48px !important; box-sizing: border-box !important; background: #fff !important; position: relative !important; font-family: "仿宋_GB2312","仿宋",FangSong,STFangsong,serif !important; font-size: 16pt !important; line-height: 1.9 !important; color: #333 !important; overflow: visible !important; -webkit-user-select: text !important; user-select: text !important; -webkit-touch-callout: default !important; } .cpsad-fullview * { box-sizing: border-box !important; -webkit-user-select: text !important; user-select: text !important; } .cpsad-fullview p { margin: 0 0 4pt 0 !important; text-indent: 2em !important; text-align: justify !important; } .cpsad-fullview h1 { font-family: SimHei,"黑体" !important; font-size: 16pt !important; font-weight: normal !important; text-indent: 2em !important; margin: 12pt 0 4pt 0 !important; } .cpsad-fullview h2 { font-family: KaiTi,"楷体" !important; font-size: 16pt !important; font-weight: normal !important; text-indent: 2em !important; margin: 12pt 0 4pt 0 !important; } .cpsad-fullview h3 { font-size: 16pt !important; font-weight: bold !important; text-indent: 2em !important; margin: 12pt 0 4pt 0 !important; } .cpsad-fullview h4 { font-size: 16pt !important; font-weight: normal !important; text-indent: 2em !important; margin: 8pt 0 4pt 0 !important; } .cpsad-fullview table { border-collapse: collapse !important; width: 100% !important; margin: 8pt 0 !important; } .cpsad-fullview table td, .cpsad-fullview table th { border: 1px solid #999 !important; padding: 6px 10px !important; font-size: 14pt !important; } .cpsad-fullview img { max-width: 100% !important; height: auto !important; } .cpsad-fullview .gw-title { font-family: "方正小标宋简体","小标宋体","华文中宋",SimSun,serif !important; font-size: 22pt !important; text-align: center !important; text-indent: 0 !important; font-weight: normal !important; margin: 0 0 28pt 0 !important; line-height: 1.5 !important; } /* PPT 图片容器 */ .cpsad-pptview { width: 100% !important; display: flex !important; flex-direction: column !important; align-items: center !important; gap: 16px !important; padding: 24px 0 !important; } .cpsad-pptview .ppt-slide { width: 100% !important; max-width: 888px !important; position: relative !important; border-radius: 8px !important; overflow: hidden !important; box-shadow: 0 2px 12px rgba(0,0,0,0.12) !important; background: #f8f9fa !important; } .cpsad-pptview .ppt-slide img { display: block !important; width: 100% !important; height: auto !important; object-fit: contain !important; } .cpsad-pptview .ppt-page-num { position: absolute !important; top: 8px !important; right: 12px !important; background: rgba(0,0,0,0.5) !important; color: #fff !important; padding: 2px 10px !important; border-radius: 12px !important; font-size: 12px !important; font-family: -apple-system, BlinkMacSystemFont, sans-serif !important; z-index: 1 !important; } @media (min-width: 768px) { .cpsad-pptview.ppt-multiple { flex-direction: row !important; flex-wrap: wrap !important; justify-content: center !important; } .cpsad-pptview.ppt-multiple .ppt-slide { width: calc(50% - 8px) !important; max-width: 444px !important; } } /* 顶部工具条 */ .cpsad-actionbar { display: flex !important; align-items: center !important; gap: 10px !important; padding: 12px 24px !important; background: #f8f8f8 !important; border-bottom: 1px solid #e8e8e8 !important; border-radius: 8px 8px 0 0 !important; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important; position: sticky !important; top: 0 !important; z-index: 100 !important; } .cpsad-actionbar .cpsad-title-display { flex: 1 !important; font-size: 15px !important; font-weight: 600 !important; color: #333 !important; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; } .cpsad-actionbar button { border: none !important; border-radius: 6px !important; padding: 8px 16px !important; font-size: 13px !important; cursor: pointer !important; font-weight: 500 !important; transition: all .15s !important; white-space: nowrap !important; } .cpsad-actionbar .btn-copy { background: #8e44ad !important; color: #fff !important; } .cpsad-actionbar .btn-copy:hover { background: #7d3c9d !important; } .cpsad-actionbar .btn-copy:disabled { background: #bbb !important; cursor: not-allowed !important; } .cpsad-actionbar .btn-download { background: #07c160 !important; color: #fff !important; } .cpsad-actionbar .btn-download:hover { background: #06ad56 !important; } .cpsad-actionbar .btn-download:disabled { background: #bbb !important; cursor: not-allowed !important; } .cpsad-actionbar .btn-restore { background: #f0f0f0 !important; color: #666 !important; } .cpsad-actionbar .btn-restore:hover { background: #e0e0e0 !important; } /* 占位 */ .cpsad-placeholder { padding: 60px 24px !important; text-align: center !important; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important; font-size: 15px !important; color: #999 !important; } .cpsad-placeholder.error { color: #e64340 !important; } /* Toast */ .cpsad-toast { position: fixed !important; top: 50% !important; left: 50% !important; transform: translate(-50%, -50%) !important; z-index: 2147483647 !important; background: rgba(0,0,0,.8) !important; color: #fff !important; padding: 12px 28px !important; border-radius: 8px !important; font-size: 15px !important; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important; animation: cpsad-toast-in .2s ease !important; } @keyframes cpsad-toast-in { from { opacity: 0; transform: translate(-50%, -45%); } to { opacity: 1; transform: translate(-50%, -50%); } } `); // ===== 全局拦截:阻止原网页 JS 禁用复制/选择/右键 ===== const rawAddEventListener = EventTarget.prototype.addEventListener; const blockedEvents = ['contextmenu', 'selectstart', 'dragstart', 'copy']; EventTarget.prototype.addEventListener = function (type, listener, options) { if (blockedEvents.includes(type)) { return; } return rawAddEventListener.call(this, type, listener, options); }; ['oncontextmenu', 'onselectstart', 'oncopy', 'ondragstart'].forEach(prop => { try { Object.defineProperty(document, prop, { get: () => null, set: () => {}, configurable: true }); } catch (e) {} }); ['contextmenu', 'selectstart', 'copy', 'dragstart'].forEach(evtName => { document.addEventListener(evtName, e => { e.stopImmediatePropagation(); if (e.cancelable) e.returnValue = true; }, true); }); const styleUnlock = document.createElement('style'); styleUnlock.textContent = ` body, * { -webkit-user-select: text !important; user-select: text !important; -webkit-touch-callout: default !important; } `; (document.head || document.documentElement).appendChild(styleUnlock); // ===== 查找预览 iframe 及 URL ===== function findPreviewIframe() { const ifr = document.querySelector('iframe[src*="gyy.kuduoke.net"], iframe[src*="kuduoke"]'); if (ifr) return { iframe: ifr, url: ifr.src }; const html = document.documentElement.outerHTML; const m = html.match(/https?:\/\/gyy\.kuduoke\.net[^\s"'<>\\]+/i) || html.match(/https?:\/\/[\w.-]*kuduoke\.net[^\s"'<>\\]+/i); if (m) { const anyIfr = document.querySelector('iframe'); return { iframe: anyIfr, url: m[0] }; } return null; } // ===== 缓存 ===== let cachedDoc = null; // ===== 抓取预览页完整正文 ===== function fetchPreviewContent(previewUrl, callback) { GM_xmlhttpRequest({ method: 'GET', url: previewUrl, headers: { 'Referer': location.href }, timeout: 15000, onload: function (resp) { const html = resp.responseText || ''; log('预览返回 状态:', resp.status, '长度:', html.length); const bodyMatch = html.match(/
]*>([\s\S]*?)<\/body>/i); if (!bodyMatch) { callback({ error: 'parse', msg: '未匹配到 ' }); return; } const rawBody = bodyMatch[1]; const previewOrigin = previewUrl.match(/^(https?:\/\/[^/]+)/i)[1]; const docIdMatch = previewUrl.match(/\/html\/([\w]+)\.html/i); const docId = docIdMatch ? docIdMatch[1] : ''; // ===== 检测 PPT/图片类型 ===== const hasGallery = rawBody.includes('galleryContainer') || rawBody.includes('img-container'); if (hasGallery) { log('检测到 PPT/图片类型文档'); const images = []; const imgRegex = /data-src=["']([^"']+)["']/gi; let m; while ((m = imgRegex.exec(rawBody)) !== null) { let src = m[1]; if (src.startsWith('/')) src = previewOrigin + src; else if (!src.startsWith('http')) src = previewOrigin + '/html/' + docId + '/' + src; images.push(src); } if (images.length === 0) { const srcRegex = /