🔥🔥🔥抖音短视频下载🔥🔥🔥

下载抖音短视频

  1. // ==UserScript==
  2. // @name 🔥🔥🔥抖音短视频下载🔥🔥🔥
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.6.2
  5. // @description 下载抖音短视频
  6. // @author 抖音兔不迟到
  7. // @license MIT License
  8. // @run-at document-start
  9. // @grant GM_download
  10. // @include *://*douyin.com
  11. // @include *://*.douyin.com/*
  12. // @require https://greasyfork.org/scripts/440006-mono/code/mono.js?version=1098708
  13. // ==/UserScript==
  14.  
  15. var _META_URL_ = "https://www.douyin.com/web/api/v2/aweme/iteminfo/?item_ids=";
  16.  
  17. (function () {
  18. var mono = window['mono-descargar'];
  19. var useDefaultErr = mono.FAIL_TO_DEFAULT;
  20. var $ = mono.jQuery;
  21. var md5 = mono.md5;
  22. var onRequest = mono.onRequest;
  23.  
  24. var itemCache = {}
  25.  
  26. var parseItem = (item) => {
  27. var key = item.video?.origin_cover?.uri;
  28. if (!key) return;
  29. itemCache[key] = item;
  30. itemCache[key].video_id = itemCache[key].aweme_id;
  31. itemCache[key].title = itemCache[key].desc;
  32. itemCache[key].cover = itemCache[key].video?.origin_cover?.url_list[0];
  33. itemCache[key].url = itemCache[key].video?.play_addr?.url_list[0];
  34. }
  35.  
  36. onRequest(({url, resp}) => {
  37. if (!resp) return;
  38. if (url.includes("general/search/single")) {
  39. var json = JSON.parse(resp);
  40. if (!json?.data?.length) return;
  41. for (var mixItem of json.data) {
  42. if (mixItem.aweme_mix_info?.mix_items?.length) {
  43. for (var item of mixItem.aweme_mix_info?.mix_items) {
  44. parseItem(item);
  45. }
  46. } else if (mixItem.aweme_info) {
  47. parseItem(mixItem.aweme_info);
  48. }
  49. }
  50. }
  51. });
  52.  
  53. var filename = (title) => {
  54. const name = title.replace(' ', '').replace(/[/\\?%*:|"<>]/g, '-');
  55. return `${name}.mp4`;
  56. }
  57.  
  58. var updateItems = async (items) => {
  59. if (items.length <= 0) return;
  60. var resp = await fetch(_META_URL_ + items.map(im => im.meta.video_id).join(','));
  61. try {
  62. var json = await resp.json();
  63. } catch (e) {
  64. return
  65. }
  66.  
  67. metas = {}
  68. for (var i in json.item_list) {
  69. metas[json.item_list[i].aweme_id] = json.item_list[i]
  70. }
  71.  
  72. for (var i in items) {
  73. meta = metas[items[i].meta.video_id]
  74. let url;
  75. if (items[i].video) url = items[i].video.children[0].src;
  76. if (!meta) continue;
  77. meta.title = meta.desc;
  78. meta.cover = meta.video.cover.url_list[0];
  79. meta.name = filename(meta.title);
  80. items[i].url = url || meta.video.play_addr.url_list[0].replace("playwm", "play");
  81. items[i].meta = Object.assign(meta, items[i].meta);
  82. }
  83. return items
  84. }
  85.  
  86. var getItemByDetailUrl = (detail_url) => {
  87. var url = new URL(detail_url);
  88. var video_id = url.pathname.slice("/video/".length);
  89. var id = `dy-${md5(video_id)}`;
  90. if ($(`[mono-dsg-id=${id}]`).length > 0) return null;
  91. var meta = { video_id }
  92. var position = { x: 0, y: 0 };
  93. return { id, url:"", meta, position };
  94. }
  95.  
  96. var getItemsByATag = async () => {
  97. var items = [];
  98. var a = $(`a[href*="/video/"]`);
  99. if (a.length <= 0) return;
  100. for (var i = 0; i < a.length; i++) {
  101. var item = getItemByDetailUrl(a[i].href);
  102. if (!item) continue;
  103. item.container = a[i].parentNode;
  104. item.container.style.position = 'relative';
  105. item.zIndex = 12;
  106. items.push(item);
  107. // 每次返回N个,分多次
  108. if (items.length >= 10) break;
  109. }
  110.  
  111. if (items.length > 0) {
  112. const res = await updateItems(items);
  113. if (!res) return
  114. }
  115. return items;
  116. }
  117.  
  118. var getItemsBySearchRes = () => {
  119. var items = [];
  120. var containers = $(`.player-info`);
  121. if (containers.length <= 0) return;
  122.  
  123. for (var i = 0; i < containers.length; i++) {
  124. let key;
  125. var container = containers[i];
  126. var $ele = $(container);
  127. try {
  128. var img = $ele.find('.imgBackground img')[0];
  129. var url = new URL(img.src.startsWith('//') ? 'https:' + img.src : img.src);
  130. if (url && url.pathname.includes('~')) {
  131. key = url.pathname.substring(1, url.pathname.indexOf('~'));
  132. }
  133. } catch (e) {
  134. console.log('err', e);
  135. continue;
  136. }
  137. // console.log('itemCache', itemCache[key])
  138. if (!key || !itemCache[key]) continue;
  139.  
  140. var meta = itemCache[key];
  141. var id = `dy-${md5(meta.video_id)}`;
  142. var url = meta.url;
  143. meta.name = filename(meta.title);
  144. var position = { x: 10, y: 10 };
  145. var item = { id, url, container, meta, position, zIndex: 12}
  146. items.push(item);
  147. // 每次返回N个,分多次
  148. if (items.length >= 10) break;
  149. }
  150.  
  151. return items;
  152. }
  153.  
  154. var pageParsers = {
  155. detail: async () => {
  156. var item = getItemByDetailUrl(window.location.href);
  157. if (!item) return [];
  158. video = $('video');
  159. if (video.length <= 0) return [];
  160. item.container = video[0].parentNode;
  161. item.zIndex = 12;
  162. item.video = video[0];
  163. const flag = await updateItems([item]);
  164. if (!flag) return
  165. return [item];
  166. },
  167. user: async () => {
  168. return getItemsByATag()
  169. },
  170. list: async () => {
  171. let items = await getItemsByATag();
  172. if (!items) return
  173. items = items.concat(getItemsBySearchRes());
  174. return items.filter(x => x);
  175. }
  176. }
  177.  
  178. var getPageParser = () => {
  179. var url = new URL(window.location.href);
  180. var path = url.pathname.split('/')[1];
  181. if (path === "video") {
  182. return pageParsers.detail;
  183. } else if (path === "user") {
  184. return pageParsers.user;
  185. } else if (["discover", "search", "channel", "hot"].includes(path)) {
  186. return pageParsers.list;
  187. } else {
  188. throw useDefaultErr;
  189. }
  190. }
  191.  
  192. var parser = async function () {
  193. var pr = getPageParser()
  194. const res = await pr();
  195. if (!res || res.length < 1) throw useDefaultErr;
  196. return res
  197. }
  198.  
  199. if (mono?.init) mono.init({
  200. parser,
  201. interval: 100,
  202. });
  203. })()