you-get

视频下载 bilibili acfun youtube 西瓜 快手 抖音

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         you-get
// @description  视频下载 bilibili acfun youtube 西瓜 快手 抖音 
// @namespace    http://tampermonkey.net/
// @version      0.0.2
// @description  try to take over the world!
// @author       You
// @match               https://www.ixigua.com/*
// @match               https://www.bilibili.com/video/*
// @match               https://www.douyin.com/*
// @match               https://www.kuaishou.com/*
// @match               https://www.acfun.cn/v/*
// @match               https://www.youtube.com/watch/*
// @match               https://v.qq.com/*
// @match               https://v.cctv.com/*
// @match               https://v.youku.com/*
// @license      MIT
// @grant        none
// ==/UserScript==
(() => {
  // src/util/index.js
  var download = async (blob, fileName) => {
    let link = window.URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.download = `${fileName}`;
    a.href = link;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    window.URL.revokeObjectURL(link);
  };
  var safetyParse = (str) => {
    try {
      return JSON.parse(str);
    } catch (error) {
      return null;
    }
  };
  var getFile = async (url) => {
    const res = await fetch(url);
    const reader = res.body.getReader();
    const contentLength = +res.headers.get("Content-Length");
    if (!contentLength) {
      const data = await res.arrayBuffer();
      return new Uint8Array(data);
    }
    let receivedLength = 0;
    let chunks = [];
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        break;
      }
      chunks.push(value);
      receivedLength += value.length;
      console.log(
        `fileSize: ${contentLength} %c downloaded ${receivedLength}`,
        "background: #222; color: #bada55"
      );
    }
    return new Blob(chunks);
  };
  var getUrlsByM3u8 = async (url, parser) => {
    const urlObj = new URL(url);
    urlObj.pathname = urlObj.pathname.split("/").slice(0, -1).join("/");
    urlObj.search = "";
    const base = urlObj.toString();
    const res = await fetch(url);
    const data = await res.text();
    return data.split("\n").filter((i) => !!i && !i.startsWith("#")).map((i) => {
      if (parser) {
        return parser(i);
      }
      return i.startsWith("/") ? `${base}${i}` : `${base}/${i}`;
    });
  };
  var getFiles = (urls, max = 8) => {
    let connections = 0;
    let files = [];
    urls = urls.map((i, index) => ({
      ...i,
      index
    }));
    return new Promise((resolve, reject) => {
      const getSingleFile = async ({ url, index, ...rest }) => {
        if (connections < max) {
          try {
            connections = connections + 1;
            const data = await getFile(url);
            connections = connections - 1;
            files[index] = data;
            if (urls?.length) {
              getSingleFile(urls.shift());
            } else {
              connections === 0 && resolve(files);
            }
          } catch (error) {
            console.log(error);
            urls.push({
              url,
              index,
              ...rest
            });
          }
        }
      };
      new Array(max).fill(0).forEach((i) => {
        getSingleFile(urls.shift());
      });
    });
  };

  // src/module/acfun.js
  var getVideoInfo = async () => {
    const m3u8FileUrl = safetyParse(window.pageInfo.currentVideoInfo.ksPlayJson)?.adaptationSet?.[0]?.representation?.[0]?.url;
    const urls = await getUrlsByM3u8(m3u8FileUrl);
    return urls.map((url) => ({ url }));
  };
  var acfun_default = async () => {
    const urls = await getVideoInfo();
    const files = await getFiles(urls);
    download(new Blob(files), "download.mp4");
  };

  // src/module/xigua.js
  var getXiGuaVideoInfo = async () => {
    const res = await fetch(window.location.href);
    const str = await res.text();
    const data = safetyParse(
      str.match(/window?._SSR_HYDRATED_DATA=([\d\D]+?)<\/script>/)[1].replaceAll("undefined", "null")
    );
    const videoResource = data?.anyVideo?.gidInformation?.packerData?.video?.videoResource || data?.anyVideo?.gidInformation?.packerData?.videoResource;
    const videoList = Object.values(videoResource?.normal?.video_list ?? {}).sort(
      (a, b) => b?.vheight - a?.vheight
    );
    const video = videoList?.[0];
    return {
      url: atob(video.main_url, "base64"),
      fileName: `download.${video.vtype || "mp4"}`
    };
  };
  var xigua_default = async () => {
    const url = await getXiGuaVideoInfo();
    const file = await getFile(url.url);
    download(file, "download.mp4");
  };

  // src/module/bilibili.js
  var getBilibiliVideoInfo = async () => {
    const res = await fetch(window.location.href);
    const str = await res.text();
    const data = JSON.parse(
      str.match(/window.__playinfo__=([\d\D]+?)<\/script>/)[1]
    );
    const dash = data.data.dash;
    const video = dash.video.sort((a, b) => b?.width - a?.width)?.[0];
    const audio = dash.audio[0];
    return [
      {
        url: video.baseUrl,
        fileName: `download.${video?.mimeType?.split("/")?.[1] || "mp4"}`
      },
      {
        url: audio.baseUrl,
        fileName: `download.${video?.mimeType?.split("/")?.[1] || "mp4"}`
      }
    ];
  };
  var bilibili_default = async () => {
    const urls = await getBilibiliVideoInfo();
    while (urls?.length) {
      const { url, fileName } = urls.shift();
      const file = await getFile(url);
      download(file, fileName);
    }
  };

  // src/module/douyin.js
  var getDouyinVideoInfo = () => {
    const urls = [...document.querySelectorAll("video source")].map((i) => i.src);
    return {
      url: urls[0],
      fileName: `download.mp4`
    };
  };
  var douyin_default = async () => {
    const url = await getDouyinVideoInfo();
    const file = await getFile(url.url);
    download(file, url.fileName);
  };

  // src/module/kuaishou.js
  var getKuaishouVideoInfo = () => {
    const urls = [...document.querySelectorAll("video")].map((i) => i.src);
    return {
      url: urls[0],
      fileName: `download.mp4`
    };
  };
  var kuaishou_default = async () => {
    const url = await getKuaishouVideoInfo();
    const file = await getFile(url.url);
    download(file, url.fileName);
  };

  // src/module/youtube.js
  var getYoutubeVideoInfo = async () => {
    const res = await fetch(window.location.href);
    const str = await res.text();
    const parser = new DOMParser();
    const doc = parser.parseFromString(str, "text/html");
    const data = safetyParse(
      doc.body.innerHTML.match(/("formats":)([\d\D]+?}]+?)/)[2]
    );
    const video = data.sort((a, b) => b?.width - a?.width)?.[0];
    return {
      url: video.url,
      fileName: `download.mp4`
    };
  };
  var youtube_default = async () => {
    const url = await getYoutubeVideoInfo();
    const file = await getFile(url.url);
    download(file, url.fileName);
  };

  // src/module/qq.js
  var proxyhttpBody = null;
  var monitor = async () => {
    try {
      window.__PLAYER__.pluginMsg.emit = new Proxy(
        window.__PLAYER__.pluginMsg.emit,
        {
          apply: (...args) => {
            if (args?.[2]?.[0] === "PROXY_HTTP_START" && args?.[2]?.[1]?.vinfoparam) {
              console.log(args?.[2]?.[1]);
              proxyhttpBody = JSON.stringify(args?.[2]?.[1]);
            }
            return Reflect.apply(...args);
          }
        }
      );
    } catch (error) {
      console.log("monitor error");
    }
  };
  var getVideoInfo2 = async () => {
    let m3u8FileUrl = null;
    if (!m3u8FileUrl) {
      let res = await fetch("https://vd6.l.qq.com/proxyhttp", {
        method: "post",
        body: proxyhttpBody
      });
      res = await res.json();
      if (res?.errCode === 0 && res?.vinfo) {
        const data = safetyParse(res?.vinfo);
        const m3u8 = data?.vl?.vi?.sort((a, b) => b.vw - a.vw)?.[0]?.ul;
        if (m3u8) {
          m3u8FileUrl = m3u8.ui[0].url;
        }
      }
    }
    const urls = await getUrlsByM3u8(m3u8FileUrl);
    return urls.map((url) => ({
      url,
      fileName: `download.mp4`
    }));
  };
  if (window.location.host === "v.qq.com") {
    monitor();
  }
  var qq_default = async () => {
    const urls = await getVideoInfo2();
    const files = await getFiles(urls);
    download(new Blob(files), "download.mp4");
  };

  // src/module/cctv.js
  var getVideoInfo3 = async () => {
    let data = await fetch(
      `https://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid=${window.guid}`
    );
    data = await data.json();
    const urls = data?.video?.[`chapters${data?.video?.validChapterNum}`];
    return { urls, fileName: `${data?.title}.mp4` };
  };
  var cctv_default = async () => {
    const { urls, fileName } = await getVideoInfo3();
    while (urls.length) {
      const file = await getFile(urls.shift().url);
      download(file, fileName);
    }
  };

  // src/module/youku.js
  var youku_default = async () => {
    if (!document.querySelector("meta#you-get-youku")) {
      const meta = document.createElement("meta");
      meta.httpEquiv = "Content-Security-Policy";
      meta.content = "upgrade-insecure-requests";
      meta.id = "you-get-youku";
      document.querySelector("head").appendChild(meta);
    }
    const data = window?.videoPlayer?.context?.mediaData?.mediaResource?._model;
    if (data) {
      const m3u8FileUrl = data.streamList.sort((a, b) => b.width - a.width)[0].uri.HLS;
      const urls = await getUrlsByM3u8(m3u8FileUrl, (i) => i);
      const files = await getFiles(urls.map((url) => ({ url })));
      download(new Blob(files), `${data.video.title}.ts`);
    }
  };

  // src/module/index.js
  var module_default = {
    ixigua: xigua_default,
    bilibili: bilibili_default,
    douyin: douyin_default,
    kuaishou: kuaishou_default,
    youtube: youtube_default,
    acfun: acfun_default,
    qq: qq_default,
    cctv: cctv_default,
    youku: youku_default
  };

  // src/index.js
  var fetch2 = window.fetch;
  var youget = () => {
    const handler = Object.entries(module_default).find(
      ([key, fn]) => window.location.host.toLocaleLowerCase().includes(key)
    )?.[1];
    if (handler) {
      handler();
    } else {
      console.log("not support");
    }
  };
  youget.toString = () => {
    youget();
    return 1;
  };
  window.you = 1;
  window.get = youget;
  window.youget = youget;
})();