抖音短视频下载

下载抖音短视频

目前為 2022-02-08 提交的版本,檢視 最新版本

// ==UserScript==
// @name         抖音短视频下载
// @namespace    http://tampermonkey.net/
// @version      0.3.0
// @description  下载抖音短视频
// @author       抖音兔不迟到
// @license      MIT License
// @run-at       document-start
// @grant        GM_download
// @include      *://*.douyin.com/*
// @require      https://gf.qytechs.cn/scripts/439696-mono-js/code/monojs.js?version=1016361
// ==/UserScript==

var _META_URL_ = "https://www.douyin.com/web/api/v2/aweme/iteminfo/?item_ids=";
var _TAG_CLASS = {
  user: 'd517474cdaa572104bddc8637c4eeb3c-scss',
  list: 'b388acfeaeef33f0122af9c4f71a93c9-scss',
}
var itemCache = {}

//hook xhr
var origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
  if (url.includes("mssdk.snssdk.com/web/report")) return;
  this.addEventListener('load', function() {
    if (url.includes("general/search/single")) {
      var json = JSON.parse(this.responseText);
      if (!json?.data?.length) return;
      for (let i in json.data) {
        var key = json.data[i].aweme_info?.video?.origin_cover?.uri;
        if (!key) continue;
        itemCache[key] = json.data[i].aweme_info;
        itemCache[key].video_id = itemCache[key].aweme_id;
        itemCache[key].title = itemCache[key].desc;
        itemCache[key].cover = itemCache[key].video?.origin_cover?.url_list[0];
        itemCache[key].url = itemCache[key].video?.play_addr?.url_list[0];
      }
      console.log({itemCache});
    }
  });
  origOpen.call(this, method, url, ...rest);
};

(function () {
  var mono = window['mono-descargar'];
  var useDefaultErr = mono.FAIL_TO_DEFAULT;
  var $             = mono.jQuery;
  var md5           = mono.md5;

  var updateItems = async (items) => {
    if (items.length <= 0) return;
    var resp = await fetch(_META_URL_ + items.map(im => im.meta.video_id).join(','))
    var json = await resp.json()

    metas = {}
    for (var i in json.item_list) {
      metas[json.item_list[i].aweme_id] = json.item_list[i]
    }

    for (var i in items) {
      meta = metas[items[i].meta.video_id]
      if (!meta) continue;
      meta.title = meta.desc;
      meta.cover = meta.video.cover.url_list[0];
      items[i].url = meta.video.play_addr.url_list[0].replace("playwm", "play");
      items[i].meta = Object.assign(meta, items[i].meta);
    }
  }

  var getItemByDetailUrl = (detail_url) => {
    var url = new URL(detail_url);
    var video_id = url.pathname.slice("/video/".length);
    var id = `mona-${md5(video_id)}`
    if ($(`#${id}`).length > 0) return null;
    var dom = $(`<div id='${id}'></div>`);
    var filename = `${video_id}.mp4`;
    var meta = { video_id, filename }
    return { id, url:"", dom, meta }
  }

  var getItemsByATag = async (className) => {
    var items = [];
    var a = $(`.${className}`);
    if (a.length <= 0) return;

    for (var i = 0; i < a.length; i++) {
      var item = getItemByDetailUrl(a[i].href);
      if (!item) continue;
      item.pdom = $(a[i]);
      items.push(item);
      // 每次返回N个,分多次
      if (items.length >= 10) break;
    }

    if (items.length > 0) {
      await updateItems(items);
    }
    return items;
  }

  var getItemsBySearchRes = async () => {
    var items = [];
    var pdoms = $(`.playerContainer`);
    if (pdoms.length <= 0) return;

    for (var i = 0; i < pdoms.length; i++) {
      let key;
      var pdom = $(pdoms[i]);
      try {
        var img = pdom.find('.imgBackground img')[0];
        var url = new URL(img.src.startsWith('//') ? 'https:' + img.src : img.src);
        if (url && url.pathname.includes('~')) {
          key = url.pathname.substring(1, url.pathname.indexOf('~'));
        }
      } catch (e) { 
        console.log('err', e);
        continue; 
      }
      if (!key || !itemCache[key]) continue;

      var meta = itemCache[key];
      var id = `mona-${md5(meta.video_id)}`
      if ($(`#${id}`).length > 0) return null;
      var dom = $(`<div id='${id}'></div>`);
      var url = meta.url;
      meta.filename = `${meta.video_id}.mp4`;
      var item = { id, url, dom, pdom, meta }
      items.push(item);
      // 每次返回N个,分多次
      if (items.length >= 10) break;
    }

    return items;
  }

  var pageParsers = {
    detail: async () => {
      var item = getItemByDetailUrl(window.location.href);
      if (!item) return [];
      video = $('video')
      if (video.length <= 0) return [];
      item.pdom = $(video[0]).parent();
      await updateItems([item]);
      return [item];
    },
    user: async () => {
      return getItemsByATag(_TAG_CLASS.user)
    },
    list: async () => {
      let items = await getItemsByATag(_TAG_CLASS.list);
      return items || getItemsBySearchRes()
    }
  }

  var getPageParser = () => {
    var url = new URL(window.location.href);
    var path = url.pathname.split('/')[1];
    if (path === "video") {
      return pageParsers.detail;
    } else if (path === "user") {
      return pageParsers.user;
    } else if (["discover", "search", "channel", "hot"].includes(path)) {
      return pageParsers.list;
    } else {
      throw useDefaultErr;
    }
  }

  var parser = async function () {
    var pr = getPageParser()
    if (!pr) return []
    return pr()
  }

  if (mono?.init) mono.init({ 
    parser,
    interval: 100,
  });
})()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址