you-get-fork

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

当前为 2023-05-19 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name              you-get-fork
// @description         视频下载 bilibili acfun youtube 西瓜 快手 抖音
// @description:en-US     fork from [460910]
// @namespace             https://greasyfork.org/users/135090
// @version             1.0.8
// @author             You
// @match              https://www.ixigua.com/1*
// @match              https://www.ixigua.com/2*
// @match              https://www.ixigua.com/3*
// @match              https://www.ixigua.com/4*
// @match              https://www.ixigua.com/5*
// @match              https://www.ixigua.com/6*
// @match              https://www.ixigua.com/7*
// @match              https://www.ixigua.com/8*
// @match              https://www.ixigua.com/9*
// @match              https://www.bilibili.com/video/BV*
// @match              https://www.douyin.com/video/*
// @match              https://www.kuaishou.com/short-video/*
// @match              https://www.acfun.cn/v/ac*
// @match              https://www.youtube.com/watch/*
// @match              https://v.qq.com/x/*
// @match              https://v.cctv.com/*/V*.shtml*
// @match              https://v.cctv.cn/*/V*.shtml*
// @match              https://tv.cctv.cn/*/V*.shtml*
// @match              https://tv.cctv.com/*/V*.shtml*
// @match              https://v.youku.com/v_*
// @license            MIT
// @icon               data:image/png;base64,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
// @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);
        var tname = document.title;
        download(new Blob(files), tname+".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 xtit = data?.anyVideo?.gidInformation?.packerData?.video?.title || data?.anyVideo?.gidInformation?.packerData?.albumInfo?.title;
        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: `${xtit || "download"}.${video.vtype || "mp4"}`
    };
    };
    var xigua_default = async () => {
        const url = await getXiGuaVideoInfo();
        const file = await getFile(url.url);
        var tname = document.title;
        download(file, tname+".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];
        const btit = document.title.substring(0,document.title.length-14);
        return [
            {
                url: video.baseUrl,
                fileName: btit+".m4v"
            },
            {
                url: audio.baseUrl,
                fileName: btit+".m4a"
            }
        ];
    };
    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);
        var dyvt=document.title.concat(".mp4");
        return {
            url: urls[0],
            fileName: dyvt
        };
    };
    var douyin_default = async () => {
        const url = await getDouyinVideoInfo();
        const file = await getFile(url.url);
        download(file, url.fileName);
    };

    // src/module/kuaishou.js
    var getKuaishouVideoInfo = () => {
        var ktname = document.title;
        const urls = [...document.querySelectorAll("video")].map((i) => i.src);
        return {
            url: urls[0],
            fileName: ktname+".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: `youtube.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: `qqvideo.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), "qqvideo.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}.mpeg`);
        }
    };

    // 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;
})();