// ==UserScript== // @name 飞书文档/文件全能下载 // @namespace https://7998888.xyz // @version 1.0 // @description 合二为一:飞书 wiki/doc 导出 Word/PDF/Markdown + 飞书/讯飞文件/文件夹流式下载 PDF // @author 代可行 // @match https://*.feishu.cn/wiki/* // @match https://*.feishu.cn/doc/* // @match https://*.feishu.cn/file/* // @match https://*.feishu.cn/drive/folder/* // @match https://*.feishu.com/file/* // @match https://*.feishu.com/drive/folder/* // @match https://*.larksuite.com/file/* // @match https://*.larksuite.com/drive/folder/* // @match https://*.xfchat.iflytek.com/file/* // @match https://*.xfchat.iflytek.com/drive/folder/* // @icon https://www.feishu.cn/favicon.ico // @grant GM_registerMenuCommand // @grant GM_download // @grant GM_setClipboard // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_notification // @connect internal-api-drive-stream.xfchat.iflytek.com // @connect internal-api-drive-stream.feishu.cn // @connect internal-api-drive-stream.feishu.com // @connect internal-api-drive-stream.larksuite.com // @run-at document-idle // @license MIT // ==/UserScript== // ══════════════════════════════════════════════════════════════════ // 第一部分:wiki/doc 页面 — DOM 提取导出 Word/PDF/Markdown // ══════════════════════════════════════════════════════════════════ (function () { 'use strict'; const isWikiPage = () => location.pathname.match(/^\/(wiki|doc)\//); const isFilePage = () => location.pathname.match(/^\/(file|drive\/folder)\//); if (!isWikiPage() && !isFilePage()) return; // ─── 公用 CSS ───────────────────────────────────────────────── GM_addStyle(` .fp-toast { position:fixed; bottom:40px; left:50%; transform:translateX(-50%); background:rgba(0,0,0,0.82); color:#fff; padding:10px 24px; border-radius:8px; font-size:14px; z-index:999999; font-family:sans-serif; pointer-events:none; transition:opacity .3s; } `); function showToast(msg, dur) { var old = document.querySelector('.fp-toast'); if (old) old.remove(); var el = document.createElement('div'); el.className = 'fp-toast'; el.textContent = msg; el.style.opacity = '1'; document.body.appendChild(el); setTimeout(function() { el.style.opacity = '0'; setTimeout(function() { el.remove(); }, 300); }, dur || 2500); } // ══════════════════════════════════════════════════════════════ // █ 模块 A:wiki/doc → 导出 Word/PDF/Markdown // ══════════════════════════════════════════════════════════════ (function moduleWiki() { if (!isWikiPage()) return; GM_addStyle(` #__fsdl_btn { position:fixed; right:20px; bottom:100px; z-index:99999; font-family:-apple-system,"Helvetica Neue",sans-serif; } #__fsdl_btn .fsdl-main { background:#3370ff; color:#fff; border:none; border-radius:8px; padding:10px 20px; font-size:14px; font-weight:600; cursor:pointer; box-shadow:0 4px 14px rgba(51,112,255,0.45); transition:all .2s; white-space:nowrap; } #__fsdl_btn .fsdl-main:hover { background:#2560e0; transform:translateY(-1px); } #__fsdl_btn .fsdl-menu { display:none; position:absolute; bottom:calc(100% + 8px); right:0; background:#fff; border-radius:10px; box-shadow:0 6px 24px rgba(0,0,0,0.15); min-width:200px; overflow:hidden; border:1px solid #eee; padding:6px 0; } #__fsdl_btn .fsdl-item { padding:10px 18px; cursor:pointer; font-size:13px; color:#333; display:flex; align-items:center; gap:10px; transition:background .15s; white-space:nowrap; } #__fsdl_btn .fsdl-item:hover { background:#f0f4ff; } `); function waitContent(maxWait) { return new Promise(function(resolve) { var check = function() { if (getContentBlocks().length > 0) { resolve(); return; } setTimeout(check, 500); }; check(); setTimeout(resolve, maxWait || 10000); }); } function getTitle() { var cat = document.querySelector('[class*="catalogue"] [class*="list-item"]'); if (cat && cat.textContent.trim().length < 100) return cat.textContent.trim(); var h = document.querySelector('.page-block-content h1, [class*="docTitle"], h1'); if (h && h.textContent.trim()) return h.textContent.trim(); return document.title.replace(/ - 飞书云?文档/, '').trim() || '飞书文档'; } function safeName(s) { return s.replace(/[\\/:*?"<>|]/g, '_'); } function getMeta() { var t = document.querySelector('[class*="metaTime"]'); var a = document.querySelector('.doc-info-wrapper [class*="author"], .doc-info-wrapper [class*="owner"]') || document.querySelector('[class*="owner"], [class*="author"]'); return { author: a ? a.textContent.trim() : '', time: t ? t.textContent.trim() : '' }; } function getContentBlocks() { var blocks = []; var wrapper = document.querySelector('.render-unit-wrapper') || document.querySelector('#docx .editor-container .root-render-unit-container, #docx .page-block-children'); if (!wrapper) return []; for (var i = 0; i < wrapper.children.length; i++) { var child = wrapper.children[i]; var cls = child.className || ''; if (cls.indexOf('render-unit') !== -1 || cls.indexOf('zone-container') !== -1) { var innerBlocks = child.querySelectorAll(':scope > .block, :scope > [class*="block"]'); if (innerBlocks.length > 0) { for (var j = 0; j < innerBlocks.length; j++) { var b = innerBlocks[j]; if ((b.className||'').indexOf('table') !== -1) { var table = b.querySelector('table'); if (table) blocks.push({ type:'table', el: table }); } else { var txt = collectText(b); if (txt) blocks.push({ type:'p', text: txt }); } } continue; } } if (cls.indexOf('docx-table-block') !== -1 || cls.indexOf('table') !== -1) { var tbl = child.querySelector('table'); if (tbl) blocks.push({ type:'table', el: tbl }); } else { var txt = collectText(child); if (txt && txt.length > 2) blocks.push({ type:'p', text: txt }); } } if (blocks.length === 0) { document.querySelectorAll('.editor-container .ace-line, .editor-container .block > span, .editor-container [class*="block"]').forEach(function(el) { var txt = el.textContent.trim(); if (txt && txt.length > 2) blocks.push({ type:'p', text: txt }); }); } return blocks; } function collectText(el) { var textParts = []; function walk(node) { if (node.nodeType === 3) { var t = node.textContent.trim(); if (t) textParts.push(t); } else if (node.nodeType === 1 && node.tagName !== 'TABLE' && node.tagName !== 'IFRAME') { for (var c = node.firstChild; c; c = c.nextSibling) walk(c); } } walk(el); return textParts.join(''); } function extractTable(tableEl) { var rows = []; var trs = tableEl.querySelectorAll('tr'); if (trs.length) { for (var i = 0; i < trs.length; i++) { var cells = []; trs[i].querySelectorAll('td, th').forEach(function(td) { cells.push(td.textContent.trim()); }); rows.push(cells); } } else { tableEl.querySelectorAll('[class*="row"],[class*="tr"]').forEach(function(r) { var cells = []; r.querySelectorAll('[class*="cell"],[class*="td"]').forEach(function(c) { cells.push(c.textContent.trim()); }); if (cells.length) rows.push(cells); }); } return rows; } function esc(s) { return (s||'').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); } function buildHTML() { var title = getTitle(), meta = getMeta(), blocks = getContentBlocks(), body = ''; for (var i = 0; i < blocks.length; i++) { var b = blocks[i]; if (b.type === 'p' && b.text) body += '
' + esc(b.text) + '
\n'; else if (b.type === 'table') { var rows = extractTable(b.el); if (rows.length) { body += '