Greasy Fork

Greasy Fork is available in English.

抖音主页视频图文下载

用于抖音主页视频图文下载

当前为 2025-02-08 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         抖音主页视频图文下载
// @namespace    douyin-homepage-download
// @version      0.1.6
// @author       chrngfu
// @description  用于抖音主页视频图文下载
// @license      MIT
// @icon         https://lf1-cdn-tos.bytegoofy.com/goofy/ies/douyin_web/public/favicon.ico
// @match        https://www.douyin.com/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js
// @require      data:application/javascript,%3Bwindow.Vue%3DVue%3B
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/index.full.min.js
// @require      https://cdn.jsdelivr.net/npm/@element-plus/[email protected]/dist/index.iife.min.js
// @resource     element-plus/dist/index.css  https://cdn.jsdelivr.net/npm/[email protected]/dist/index.css
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @grant        GM_registerMenuCommand
// @run-at       document-start
// ==/UserScript==

(t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const e=document.createElement("style");e.textContent=t,document.head.append(e)})(" .my-button[data-v-9f5fc9a8]{z-index:999;position:absolute;right:16px;bottom:64px} ");

(function (vue, ElementPlus, JSZip, iconsVue) {
  'use strict';

  const cssLoader = (e) => {
    const t = GM_getResourceText(e);
    return GM_addStyle(t), t;
  };
  cssLoader("element-plus/dist/index.css");
  const formatNumber = (num) => {
    num = vue.toRaw(num);
    num = num + "";
    return num.replace(new RegExp("\\B(?<!\\.\\d*)(?=(\\d{3})+(?!\\d))", "g"), ",");
  };
  const addZero = (num) => {
    return (num + "").padStart(2, "0");
  };
  const formatData = (timestamp, fmt = "yyyy-MM-dd") => {
    if (timestamp.toString().length === 10) timestamp *= 1e3;
    const date = new Date(timestamp);
    const year = date.getFullYear().toString();
    const month = date.getMonth() + 1;
    const day = date.getDate();
    const hour = date.getHours();
    const minute = date.getMinutes();
    const second = date.getSeconds();
    fmt = fmt.replace("yyyy", year);
    fmt = fmt.replace("MM", addZero(month));
    fmt = fmt.replace("dd", addZero(day));
    fmt = fmt.replace("HH", addZero(hour));
    fmt = fmt.replace("mm", addZero(minute));
    fmt = fmt.replace("ss", addZero(second));
    return fmt;
  };
  function formatSeconds(seconds) {
    const timeUnits = ["小时", "分", "秒"];
    const timeValues = [Math.floor(seconds / 3600), Math.floor(seconds % 3600 / 60), seconds % 60];
    return timeValues.map((value, index) => value > 0 ? value + timeUnits[index] : "").join("");
  }
  function getAwemeName(aweme) {
    let name = aweme.item_title ? aweme.item_title : aweme.caption;
    if (!name) name = aweme.desc ? aweme.desc : aweme.awemeId;
    return (aweme.date ? `【${aweme.date.slice(0, 10)}】` : "") + name.replace(/[\/:*?"<>|\s]+/g, "").slice(0, 27).replace(/\.\d+$/g, "");
  }
  const all_aweme_map = /* @__PURE__ */ new Map();
  function interceptResponse() {
    console.warn("开始拦截响应!");
    const originalSend = XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.send = function() {
      originalSend.apply(this, arguments);
      if (!this._url) return;
      this.url = this._url;
      if (this.url.startsWith("http")) this.url = new URL(this.url).pathname;
      if (!this.url.startsWith("/aweme/v1/web/")) return;
      const self = this;
      let func = this.onreadystatechange;
      this.onreadystatechange = (e) => {
        if (self.readyState === 4) {
          let data = JSON.parse(self.response);
          if (self.url.startsWith("/aweme/v1/web/user/profile/other")) {
            const userInfo = formatUserData(data.user);
            sessionStorage.setItem("userInfo", JSON.stringify(userInfo));
            console.log(
              `%c已拦截到用户主页信息`,
              "background: #009688; color: #fff; padding: 2px 5px; border-radius: 2px"
            );
          }
          if (self.url.startsWith("/aweme/v1/web/aweme/post/")) {
            const dataList = formatAwemeData(data);
            if (dataList) {
              const userInfo = JSON.parse(sessionStorage.getItem("userInfo"));
              if (dataList.some((r) => r.uid !== userInfo.uid)) {
                console.warn("检测到用户已切换,自动刷新捕获数据");
                all_aweme_map.clear();
                sessionStorage.removeItem("all_aweme_list");
              }
              dataList.filter((item) => item.url && item.awemeId).forEach((aweme) => {
                all_aweme_map.set(aweme.awemeId, aweme);
              });
              console.log(
                `%c已捕获到 ${all_aweme_map.size} 条数据`,
                "background: #009688; color: #fff; padding: 2px 5px; border-radius: 2px"
              );
              sessionStorage.setItem("all_aweme_list", JSON.stringify(Array.from(all_aweme_map.values())));
            }
          }
        }
        if (func) func.apply(self, e);
      };
    };
  }
  function formatUserData(userInfo) {
    for (let key in userInfo) {
      if (!userInfo[key]) userInfo[key] = "";
    }
    return {
      uid: userInfo.uid,
      nickname: userInfo.nickname,
      following_count: userInfo.following_count,
      mplatform_followers_count: userInfo.mplatform_followers_count,
      total_favorited: userInfo.total_favorited,
      unique_id: userInfo.unique_id ? userInfo.unique_id : userInfo.short_id,
      ip_location: userInfo.ip_location.replace("IP属地:", ""),
      gender: userInfo.gender ? " 男女".charAt(userInfo.gender).trim() : "",
      city: [userInfo.province, userInfo.city, userInfo.district].filter((x) => x).join("·"),
      signature: userInfo.signature,
      aweme_count: userInfo.aweme_count,
      create_time: Date.now()
    };
  }
  function formatAwemeData(json_data) {
    var _a;
    return (_a = json_data == null ? undefined : json_data.aweme_list) == null ? undefined : _a.map(formatDouyinAwemeData);
  }
  const formatDouyinAwemeData = (item) => Object.assign(
    {
      awemeId: item.aweme_id,
      item_title: item.item_title,
      caption: item.caption,
      desc: item.desc,
      type: item.images ? "图文" : "视频",
      tag: item.text_extra ? item.text_extra.map((tag) => tag.hashtag_name).filter((tag) => tag).join("#") : "",
      video_tag: item.video_tag ? item.video_tag.map((tag) => tag.tag_name).filter((tag) => tag).join("->") : "",
      date: formatData(item.create_time, "yyyy-MM-dd HH:mm:ss"),
      create_time: item.create_time
    },
    item.statistics ? {
      diggCount: item.statistics.digg_count,
      commentCount: item.statistics.comment_count,
      collectCount: item.statistics.collect_count,
      shareCount: item.statistics.share_count
    } : {},
    item.video ? {
      duration: formatSeconds(Math.round(item.video.duration / 1e3)),
      url: item.video.play_addr.url_list[0],
      cover: item.video.cover.url_list[0],
      images: item.images ? item.images.map((row) => row.url_list.pop()) : null
    } : {},
    item.author ? {
      uid: item.author.uid,
      nickname: item.author.nickname
    } : {}
  );
  interceptResponse();
  var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : undefined)();
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const _sfc_main$2 = {
    __name: "view-data-button",
    emits: ["click"],
    setup(__props, { emit: __emit }) {
      const emit = __emit;
      const handleClick = () => {
        emit("click");
      };
      return (_ctx, _cache) => {
        const _component_el_button = vue.resolveComponent("el-button");
        return vue.openBlock(), vue.createBlock(_component_el_button, {
          class: "my-button",
          size: "default",
          icon: vue.unref(iconsVue.Histogram),
          circle: "",
          onClick: handleClick
        }, null, 8, ["icon"]);
      };
    }
  };
  const ViewDataButton = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-9f5fc9a8"]]);
  const _hoisted_1 = { style: { "margin": "10px 0" } };
  const _hoisted_2 = { class: "dialog-footer" };
  const _sfc_main$1 = {
    __name: "aweme-data-dialog",
    setup(__props) {
      const dialogVisible = vue.ref(false);
      const userInfo = vue.ref({});
      const videoCount = vue.ref(0);
      const imageCount = vue.ref(0);
      const allAwemeList = vue.ref([]);
      const handleDataDialogOpen = () => {
        const _userInfo = JSON.parse(sessionStorage.getItem("userInfo"));
        const _allAwemeList = JSON.parse(sessionStorage.getItem("all_aweme_list"));
        if (!(_userInfo == null ? undefined : _userInfo.uid) || !(_allAwemeList == null ? undefined : _allAwemeList.length)) {
          ElementPlus.ElMessage.warning("未捕获到用户信息或作品列表,请刷新页面后重试");
          return;
        }
        userInfo.value = _userInfo;
        allAwemeList.value = _allAwemeList.sort((a, b) => b.create_time - a.create_time);
        videoCount.value = _allAwemeList.filter((item) => !(item == null ? undefined : item.images)).length;
        imageCount.value = _allAwemeList.filter((item) => item == null ? undefined : item.images).length;
        dialogVisible.value = true;
      };
      vue.onMounted(() => {
        _GM_registerMenuCommand("查看全部已加载数据", handleDataDialogOpen);
      });
      const downloadFile = async (url, filename, ext = "mp4") => {
        try {
          const response = await fetch(url);
          if (!response.ok) {
            throw new Error(`网络请求失败,状态码: ${response.status}`);
          }
          const blob = await response.blob();
          return blob;
        } catch (error) {
          console.error(`${ext === "mp4" ? "视频" : "图片"}下载失败:`, error);
          return null;
        }
      };
      const createDownloadLink = (blob, filename, ext, prefix = "") => {
        var _a;
        if (!blob) return;
        filename = filename || ((_a = userInfo.value) == null ? undefined : _a.nickname) || document.title;
        const url = URL.createObjectURL(blob);
        const link = document.createElement("a");
        link.href = url;
        link.download = `${prefix}${filename.replace(/[\/:*?"<>|\s]/g, "").slice(0, 40)}.${ext}`;
        link.click();
        URL.revokeObjectURL(url);
      };
      const handleDownloadAllVideos = async () => {
        if (videoCount.value === 0) {
          ElementPlus.ElMessage.warning("暂未发现视频,请继续滚动加载或刷新页面后重试");
          return;
        }
        const batchSize = 5;
        const totalVideos = videoCount.value;
        const loading = ElementPlus.ElLoading.service({
          lock: true,
          text: `视频正在下载中,请稍后...`,
          background: "rgba(0, 0, 0, 0.7)"
        });
        const zip = new JSZip();
        let start = 0;
        let currentBatch = [];
        const downloadBatch = async (batchIndex) => {
          const batchStart = batchIndex * batchSize;
          const batchEnd = Math.min(batchStart + batchSize, allAwemeList.value.length);
          if (batchStart >= batchEnd) return;
          const currentBatchPromises = [];
          for (let index = batchStart; index < batchEnd; index++) {
            const item = allAwemeList.value[index];
            if (!item.images && item.url) {
              currentBatch.push(item);
              const downloadPromise = downloadFile(item.url, getAwemeName(item), "mp4").then((blob) => {
                const filename = `${getAwemeName(item)}.mp4`;
                zip.file(filename, blob);
              }).catch((error) => {
                console.error(`下载视频失败: ${error}`);
              });
              currentBatchPromises.push(downloadPromise);
            }
          }
          Promise.all(currentBatchPromises).then(() => {
            start = currentBatch.length;
            loading.setText(`视频正在下载中(${start}/${totalVideos}),请稍后...`);
            if (batchEnd < allAwemeList.value.length) {
              downloadBatch(batchIndex + 1);
            } else {
              loading.setText("视频下载完成,正在打包中...");
              zip.generateAsync({ type: "blob" }).then((blob) => {
                createDownloadLink(blob, `【视频】${userInfo.value.nickname}`, "zip");
                loading.close();
              }).catch((error) => {
                loading.close();
                console.error("打包视频失败:", error);
              });
            }
          }).catch((error) => {
            console.error("视频下载失败:", error);
          });
        };
        downloadBatch(0);
      };
      const handleDownloadAllImages = async () => {
        if (imageCount.value === 0) {
          ElementPlus.ElMessage.warning("暂未发现图文,请继续滚动加载或刷新页面后重试");
          return;
        }
        const loading = ElementPlus.ElLoading.service({ lock: true, text: "图文正在下载中,请稍后..." });
        const zip = new JSZip();
        let start = 0;
        for (let index = 0; index < allAwemeList.value.length; index++) {
          const item = allAwemeList.value[index];
          if (item.images) {
            start++;
            loading.setText(`图文正在下载中(${start}/${imageCount.value}),请稍后...`);
            const folder = zip.folder(getAwemeName(item));
            await Promise.all(
              item.images.map(async (link, index2) => {
                const blob = await downloadFile(link, `image_${index2 + 1}`, "jpg");
                if (blob) {
                  folder.file(`image_${index2 + 1}.jpg`, blob);
                }
              })
            );
          }
        }
        zip.generateAsync({ type: "blob" }).then((content) => {
          createDownloadLink(content, `【图文】${userInfo.value.nickname}`, "zip");
          loading.close();
        }).catch((error) => {
          loading.close();
          console.error("打包图片失败:", error);
        });
      };
      const handleDownload = (row) => {
        const _row = vue.toRaw(row);
        if (_row == null ? undefined : _row.images) {
          downloadImages(getAwemeName(_row), _row.images);
        } else {
          downloadVideo(getAwemeName(_row), row.url);
        }
      };
      const downloadImages = async (filename, urls) => {
        const loading = ElementPlus.ElLoading.service({ lock: true, text: "图片正在下载中,请稍后..." });
        const zip = new JSZip();
        for (let i = 0; i < urls.length; i++) {
          const url = urls[i];
          const blob = await downloadFile(url, `image_${i + 1}`, "jpg");
          if (blob) {
            zip.file(`image_${i + 1}.jpg`, blob);
          }
        }
        zip.generateAsync({ type: "blob" }).then((blob) => {
          createDownloadLink(blob, filename, "zip", "【图文】");
          loading.close();
        }).catch((error) => {
          loading.close();
          console.error("下载图片失败:", error);
        });
      };
      const downloadVideo = async (filename, url) => {
        const blob = await downloadFile(url, filename, "mp4");
        createDownloadLink(blob, filename, "mp4");
      };
      const handleExport = () => {
        if (allAwemeList.value.length === 0) {
          ElementPlus.ElMessage.warning("暂未发现视频和图文数据,请继续滚动加载或刷新页面后重试");
          return;
        }
        const loading = ElementPlus.ElLoading.service({ lock: true, text: "数据正在导出中,请稍后..." });
        try {
          let text = "作者昵称,封面,类型,标题,Tag,点赞数,收藏数,评论数,分享数,发布时间,描述,时长,分类,作品链接,下载链接\n";
          allAwemeList.value.forEach((aweme) => {
            text += [
              aweme.nickname,
              aweme.cover,
              aweme.type,
              aweme.caption,
              aweme.tag,
              aweme.diggCount,
              aweme.collectCount,
              aweme.commentCount,
              aweme.shareCount,
              aweme.date,
              '"' + aweme.desc.replace(/,/g, ",").replace(/"/g, '""') + '"',
              aweme.duration,
              aweme.video_tag,
              "https://www.douyin.com/video/" + aweme.awemeId,
              aweme.url
            ].join(",") + "\n";
          });
          const filename = `【${userInfo.value.nickname}】数据导出 - ${formatData(Date.now(), "yyyy-MM-dd HH:mm:ss")}`;
          createDownloadLink(new Blob([text], { type: "text/plain" }), filename, "csv");
        } finally {
          loading.close();
        }
      };
      return (_ctx, _cache) => {
        const _component_el_descriptions_item = vue.resolveComponent("el-descriptions-item");
        const _component_el_descriptions = vue.resolveComponent("el-descriptions");
        const _component_el_button = vue.resolveComponent("el-button");
        const _component_el_image = vue.resolveComponent("el-image");
        const _component_el_table_column = vue.resolveComponent("el-table-column");
        const _component_el_table = vue.resolveComponent("el-table");
        const _component_el_dialog = vue.resolveComponent("el-dialog");
        return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
          vue.createVNode(ViewDataButton, { onClick: handleDataDialogOpen }),
          vue.createVNode(_component_el_dialog, {
            title: "",
            "append-to-body": "",
            modelValue: dialogVisible.value,
            "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => dialogVisible.value = $event),
            top: "5vh",
            width: "80%"
          }, {
            footer: vue.withCtx(() => [
              vue.createElementVNode("div", _hoisted_2, [
                vue.createVNode(_component_el_button, {
                  onClick: _cache[0] || (_cache[0] = ($event) => dialogVisible.value = false)
                }, {
                  default: vue.withCtx(() => _cache[7] || (_cache[7] = [
                    vue.createTextVNode("取 消")
                  ])),
                  _: 1
                }),
                vue.createVNode(_component_el_button, {
                  type: "primary",
                  onClick: _cache[1] || (_cache[1] = ($event) => dialogVisible.value = false)
                }, {
                  default: vue.withCtx(() => _cache[8] || (_cache[8] = [
                    vue.createTextVNode("确 定")
                  ])),
                  _: 1
                })
              ])
            ]),
            default: vue.withCtx(() => [
              vue.createVNode(_component_el_descriptions, {
                title: "该主页用户信息",
                direction: "vertical",
                border: "",
                column: 8
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_descriptions_item, { label: "用户名" }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(userInfo.value.nickname || "--"), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_descriptions_item, { label: "抖音号" }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(userInfo.value.unique_id || "--"), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_descriptions_item, { label: "IP归属地" }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(userInfo.value.ip_location || "--"), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_descriptions_item, { label: "粉丝量" }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(vue.unref(formatNumber)(userInfo.value.mplatform_followers_count) || "--"), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_descriptions_item, { label: "获赞量" }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(vue.unref(formatNumber)(userInfo.value.total_favorited) || "--"), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_descriptions_item, { label: "作品数" }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(vue.unref(formatNumber)(userInfo.value.aweme_count) || "--"), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_descriptions_item, { label: "已加载视频数" }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(vue.unref(formatNumber)(videoCount.value)), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_descriptions_item, { label: "已加载图文数" }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(vue.unref(formatNumber)(imageCount.value)), 1)
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_descriptions_item, {
                    label: "简介",
                    span: 8
                  }, {
                    default: vue.withCtx(() => [
                      vue.createTextVNode(vue.toDisplayString(userInfo.value.signature || "--"), 1)
                    ]),
                    _: 1
                  })
                ]),
                _: 1
              }),
              vue.createElementVNode("div", _hoisted_1, [
                vue.createVNode(_component_el_button, {
                  type: "primary",
                  onClick: handleDownloadAllVideos
                }, {
                  default: vue.withCtx(() => _cache[3] || (_cache[3] = [
                    vue.createTextVNode("下载全部视频")
                  ])),
                  _: 1
                }),
                vue.createVNode(_component_el_button, {
                  type: "primary",
                  onClick: handleDownloadAllImages
                }, {
                  default: vue.withCtx(() => _cache[4] || (_cache[4] = [
                    vue.createTextVNode("下载全部图文")
                  ])),
                  _: 1
                }),
                vue.createVNode(_component_el_button, {
                  type: "primary",
                  onClick: handleExport
                }, {
                  default: vue.withCtx(() => _cache[5] || (_cache[5] = [
                    vue.createTextVNode("导出全部数据")
                  ])),
                  _: 1
                })
              ]),
              vue.createVNode(_component_el_table, {
                data: allAwemeList.value,
                border: "",
                style: { "width": "100%" },
                height: "480"
              }, {
                default: vue.withCtx(() => [
                  vue.createVNode(_component_el_table_column, {
                    prop: "cover",
                    label: "封面",
                    width: "100",
                    align: "center"
                  }, {
                    default: vue.withCtx((scope) => [
                      vue.createVNode(_component_el_image, {
                        style: { "width": "60px" },
                        src: scope.row.cover,
                        "preview-src-list": [scope.row.cover]
                      }, null, 8, ["src", "preview-src-list"])
                    ]),
                    _: 1
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "awemeId",
                    label: "awemeId",
                    "show-overflow-tooltip": "",
                    width: "180",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "caption",
                    label: "标题",
                    "show-overflow-tooltip": "",
                    "min-width": "180",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "tag",
                    label: "Tag",
                    "show-overflow-tooltip": "",
                    "min-width": "120",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "diggCount",
                    label: "点赞数",
                    width: "120",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "collectCount",
                    label: "收藏数",
                    width: "120",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "commentCount",
                    label: "评论数",
                    width: "120",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "shareCount",
                    label: "分享数",
                    width: "120",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "date",
                    label: "发布时间",
                    width: "160",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    prop: "desc",
                    label: "描述",
                    "show-overflow-tooltip": "",
                    width: "180",
                    align: "center"
                  }),
                  vue.createVNode(_component_el_table_column, {
                    label: "操作",
                    width: "100",
                    align: "center"
                  }, {
                    default: vue.withCtx((scope) => [
                      vue.createVNode(_component_el_button, {
                        type: "primary",
                        onClick: ($event) => handleDownload(scope.row)
                      }, {
                        default: vue.withCtx(() => _cache[6] || (_cache[6] = [
                          vue.createTextVNode("下载")
                        ])),
                        _: 2
                      }, 1032, ["onClick"])
                    ]),
                    _: 1
                  })
                ]),
                _: 1
              }, 8, ["data"])
            ]),
            _: 1
          }, 8, ["modelValue"])
        ], 64);
      };
    }
  };
  const _sfc_main = {
    __name: "App",
    setup(__props) {
      console.log("%c插件加载成功", "color:red;padding:2px 4px;");
      const size = vue.ref("small");
      return (_ctx, _cache) => {
        const _component_el_config_provider = vue.resolveComponent("el-config-provider");
        return vue.openBlock(), vue.createBlock(_component_el_config_provider, { size: size.value }, {
          default: vue.withCtx(() => [
            vue.createVNode(_sfc_main$1)
          ]),
          _: 1
        }, 8, ["size"]);
      };
    }
  };
  vue.createApp(_sfc_main).use(ElementPlus).mount(
    (() => {
      const app = document.createElement("div");
      app.id = "app";
      window.onload = () => {
        document.body.append(app);
      };
      return app;
    })()
  );

})(Vue, ElementPlus, JSZip, ElementPlusIconsVue);