Greasy Fork

Greasy Fork is available in English.

Kdocs batch download 金山文档批量下载

Download a directory in kdocs. 金山文档批量下载。

目前为 2024-02-23 提交的版本,查看 最新版本

// ==UserScript==
// @name         Kdocs batch download 金山文档批量下载
// @namespace    http://tampermonkey.net/
// @version      2024-02-23
// @description  Download a directory in kdocs. 金山文档批量下载。
// @author       yusanshi
// @match        https://www.kdocs.cn/team/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=kdocs.cn
// @grant        none
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js
// @license      MIT
// ==/UserScript==

const teamID = window.location.pathname.split('/')[2];
const zip = new JSZip();

async function dfs(initialState, paths) {
  const files = initialState.file.list.map((e) => ({
    name: e.fname,
    id: e.id,
    type: e.ftype,
  }));

  for (const file of files) {
    await new Promise((r) => setTimeout(() => r(), 500));
    if (['file', 'sharefile'].includes(file.type)) {
      let url;
      try {
        url = (
          await fetch(
            `https://www.kdocs.cn/api/v3/office/file/${file.id}/download`
          ).then((response) => {
            if (!response.ok) {
              throw new Error(response.status);
            }
            return response.json();
          })
        ).url;
      } catch (error) {
        console.error(
          `Failed to download ${file.name} (${error.message}), skipped`
        );
        continue;
      }
      const filepath = [...paths, file.name].join('/');
      console.log(`Download ${filepath} at ${url}`);
      const blob = await fetch(url).then((response) => response.blob());
      zip.file(filepath, blob);
    } else if (['folder', 'linkfolder'].includes(file.type)) {
      await new Promise((r) => setTimeout(() => r(), 1000));
      const dom = await fetch(`https://www.kdocs.cn/team/${teamID}/${file.id}`)
        .then((response) => response.text())
        .then((data) => new DOMParser().parseFromString(data, 'text/html'));
      // TODO how to use the `window` object?
      const scriptContent = dom.body.querySelectorAll('script')[2].innerText;
      const newInitialState = JSON.parse(scriptContent.slice(25, -122)); // TODO
      await dfs(newInitialState, [...paths, file.name]);
    } else {
      console.error(`Unknown file type ${file.type}`);
    }
  }
}

window.downloadDirectory = async function () {
  document.querySelector('#downloadDirectory').innerText =
    'Downloading (see console for details)';
  await dfs(__INITIAL_STATE__, []);
  zip.generateAsync({ type: 'base64' }).then(function (content) {
    window.location.href = 'data:application/zip;base64,' + content;
  });
  document.querySelector('#downloadDirectory').innerText = 'Download finished';
};

(function () {
  'use strict';

  document.body.insertAdjacentHTML(
    'beforeend',
    `<div style="
      position: fixed;
      bottom: 30px;
      right: 30px;
      z-index: 1;
    ">
    <button type="button" style="padding:8px;" id="downloadDirectory" onclick="downloadDirectory()">Download directory</button>
  </div>`
  );
})();