Greasy Fork

Greasy Fork is available in English.

you-get

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

当前为 2023-02-28 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         you-get
// @description  视频下载 bilibili acfun youtube 西瓜 快手 抖音 
// @namespace    http://tampermonkey.net/
// @version      0.0.1
// @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/*
// @license      MIT
// @grant        none
// ==/UserScript==

(function () {
  "use strict";

  // Your code here...
  const CONFIG = "tampermonkey_config";

  const 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);
  };

  const getConfig = (key) => {
    let item = localStorage.getItem(key);
    if (item) {
      try {
        item = JSON.parse(item);
      } catch (error) {
        item = null;
        console.log(error);
      }
    }
    return item;
  };

  const fetchFile = 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"
      );
    }

    // const config = getConfig(CONFIG);
    // if (config?.merge === false) {
    return new Blob(chunks);
    // }

    // let chunksAll = new Uint8Array(receivedLength);
    // let position = 0;
    // for (let chunk of chunks) {
    //   chunksAll.set(chunk, position);
    //   position += chunk.length;
    // }
    // return chunksAll;
  };

  const getUrlsByM3u8 = async (url) => {
    const res = await fetch(url);
    const data = await res.text();
    return data.split("\n").filter((i) => !i.startsWith("#"));
  };

  const getXiGuaVideoInfo = async () => {
    const res = await fetch(window.location.href);
    const str = await res.text();
    const data = JSON.parse(
      str
        .match(/window?._SSR_HYDRATED_DATA=([\d\D]+?)<\/script>/)[1]
        .replaceAll("undefined", "null")
    );
    const videoList = Object.values(
      data?.anyVideo?.gidInformation?.packerData?.video?.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"}`,
      },
    ];
  };

  const 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"}`,
      },
    ];
  };

  const getDouyinVideoInfo = () => {
    const urls = [...document.querySelectorAll("video source")].map(
      (i) => i.src
    );
    return [
      {
        url: urls[0],
        fileName: `download.mp4`,
      },
    ];
  };

  const getKuaishouVideoInfo = () => {
    const urls = [...document.querySelectorAll("video")].map((i) => i.src);
    return [
      {
        url: urls[0],
        fileName: `download.mp4`,
      },
    ];
  };

  const getYoutubeVideoInfo = async () => {
    const res = await fetch(window.location.href);
    const str = await res.text();
    var parser = new DOMParser();
    var doc = parser.parseFromString(str, "text/html");
    const data = JSON.parse(
      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`,
      },
    ];
  };

  const getAcfunVideoInfo = async () => {
    const res = await fetch(window.location.href);
    const str = await res.text();
    const m3u8FileUrl = JSON.parse(window.pageInfo.currentVideoInfo.ksPlayJson)
      .adaptationSet[0].representation[0].url;
    const baseUrl =
      m3u8FileUrl.substring(0, m3u8FileUrl.indexOf("acfun_video")) +
      "acfun_video/";

    const urls = (await getUrlsByM3u8(m3u8FileUrl)).map(
      (i) => `${baseUrl}${i}`
    );

    return urls.map((url) => ({
      url,
      fileName: `download.mp4`,
      merge: true,
    }));
  };

  const platform = {
    ixigua: getXiGuaVideoInfo,
    bilibili: getBilibiliVideoInfo,
    douyin: getDouyinVideoInfo,
    kuaishou: getKuaishouVideoInfo,
    youtube: getYoutubeVideoInfo,
    acfun: getAcfunVideoInfo,
  };

  const youget = async function () {
    const handler = Object.entries(platform).find(([key, fn]) =>
      window.location.host.toLocaleLowerCase().includes(key)
    )?.[1];

    if (handler) {
      const urls = await handler();
      const files = [];
      while (urls?.length) {
        const i = urls.shift();
        if (i.merge) {
          const file = await fetchFile(i.url);
          files.push(file);
          if (!urls.length) {
            download(new Blob(files), i.fileName);
          }
        } else {
          const file = await fetchFile(i.url);
          await download(file, i.fileName);
        }
      }
    }
  };

  youget.toString = () => {
    youget();
    return 1;
  };

  window.you = 1;
  window.get = youget;
  window.youget = youget;
})();