you-get

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

  1. // ==UserScript==
  2. // @name you-get
  3. // @description 视频下载 bilibili acfun youtube 西瓜 快手 抖音
  4. // @namespace http://tampermonkey.net/
  5. // @version 0.0.2
  6. // @description try to take over the world!
  7. // @author You
  8. // @match https://www.ixigua.com/*
  9. // @match https://www.bilibili.com/video/*
  10. // @match https://www.douyin.com/*
  11. // @match https://www.kuaishou.com/*
  12. // @match https://www.acfun.cn/v/*
  13. // @match https://www.youtube.com/watch/*
  14. // @match https://v.qq.com/*
  15. // @match https://v.cctv.com/*
  16. // @match https://v.youku.com/*
  17. // @license MIT
  18. // @grant none
  19. // ==/UserScript==
  20. (() => {
  21. // src/util/index.js
  22. var download = async (blob, fileName) => {
  23. let link = window.URL.createObjectURL(blob);
  24. const a = document.createElement("a");
  25. a.download = `${fileName}`;
  26. a.href = link;
  27. document.body.appendChild(a);
  28. a.click();
  29. document.body.removeChild(a);
  30. window.URL.revokeObjectURL(link);
  31. };
  32. var safetyParse = (str) => {
  33. try {
  34. return JSON.parse(str);
  35. } catch (error) {
  36. return null;
  37. }
  38. };
  39. var getFile = async (url) => {
  40. const res = await fetch(url);
  41. const reader = res.body.getReader();
  42. const contentLength = +res.headers.get("Content-Length");
  43. if (!contentLength) {
  44. const data = await res.arrayBuffer();
  45. return new Uint8Array(data);
  46. }
  47. let receivedLength = 0;
  48. let chunks = [];
  49. while (true) {
  50. const { done, value } = await reader.read();
  51. if (done) {
  52. break;
  53. }
  54. chunks.push(value);
  55. receivedLength += value.length;
  56. console.log(
  57. `fileSize: ${contentLength} %c downloaded ${receivedLength}`,
  58. "background: #222; color: #bada55"
  59. );
  60. }
  61. return new Blob(chunks);
  62. };
  63. var getUrlsByM3u8 = async (url, parser) => {
  64. const urlObj = new URL(url);
  65. urlObj.pathname = urlObj.pathname.split("/").slice(0, -1).join("/");
  66. urlObj.search = "";
  67. const base = urlObj.toString();
  68. const res = await fetch(url);
  69. const data = await res.text();
  70. return data.split("\n").filter((i) => !!i && !i.startsWith("#")).map((i) => {
  71. if (parser) {
  72. return parser(i);
  73. }
  74. return i.startsWith("/") ? `${base}${i}` : `${base}/${i}`;
  75. });
  76. };
  77. var getFiles = (urls, max = 8) => {
  78. let connections = 0;
  79. let files = [];
  80. urls = urls.map((i, index) => ({
  81. ...i,
  82. index
  83. }));
  84. return new Promise((resolve, reject) => {
  85. const getSingleFile = async ({ url, index, ...rest }) => {
  86. if (connections < max) {
  87. try {
  88. connections = connections + 1;
  89. const data = await getFile(url);
  90. connections = connections - 1;
  91. files[index] = data;
  92. if (urls?.length) {
  93. getSingleFile(urls.shift());
  94. } else {
  95. connections === 0 && resolve(files);
  96. }
  97. } catch (error) {
  98. console.log(error);
  99. urls.push({
  100. url,
  101. index,
  102. ...rest
  103. });
  104. }
  105. }
  106. };
  107. new Array(max).fill(0).forEach((i) => {
  108. getSingleFile(urls.shift());
  109. });
  110. });
  111. };
  112.  
  113. // src/module/acfun.js
  114. var getVideoInfo = async () => {
  115. const m3u8FileUrl = safetyParse(window.pageInfo.currentVideoInfo.ksPlayJson)?.adaptationSet?.[0]?.representation?.[0]?.url;
  116. const urls = await getUrlsByM3u8(m3u8FileUrl);
  117. return urls.map((url) => ({ url }));
  118. };
  119. var acfun_default = async () => {
  120. const urls = await getVideoInfo();
  121. const files = await getFiles(urls);
  122. download(new Blob(files), "download.mp4");
  123. };
  124.  
  125. // src/module/xigua.js
  126. var getXiGuaVideoInfo = async () => {
  127. const res = await fetch(window.location.href);
  128. const str = await res.text();
  129. const data = safetyParse(
  130. str.match(/window?._SSR_HYDRATED_DATA=([\d\D]+?)<\/script>/)[1].replaceAll("undefined", "null")
  131. );
  132. const videoResource = data?.anyVideo?.gidInformation?.packerData?.video?.videoResource || data?.anyVideo?.gidInformation?.packerData?.videoResource;
  133. const videoList = Object.values(videoResource?.normal?.video_list ?? {}).sort(
  134. (a, b) => b?.vheight - a?.vheight
  135. );
  136. const video = videoList?.[0];
  137. return {
  138. url: atob(video.main_url, "base64"),
  139. fileName: `download.${video.vtype || "mp4"}`
  140. };
  141. };
  142. var xigua_default = async () => {
  143. const url = await getXiGuaVideoInfo();
  144. const file = await getFile(url.url);
  145. download(file, "download.mp4");
  146. };
  147.  
  148. // src/module/bilibili.js
  149. var getBilibiliVideoInfo = async () => {
  150. const res = await fetch(window.location.href);
  151. const str = await res.text();
  152. const data = JSON.parse(
  153. str.match(/window.__playinfo__=([\d\D]+?)<\/script>/)[1]
  154. );
  155. const dash = data.data.dash;
  156. const video = dash.video.sort((a, b) => b?.width - a?.width)?.[0];
  157. const audio = dash.audio[0];
  158. return [
  159. {
  160. url: video.baseUrl,
  161. fileName: `download.${video?.mimeType?.split("/")?.[1] || "mp4"}`
  162. },
  163. {
  164. url: audio.baseUrl,
  165. fileName: `download.${video?.mimeType?.split("/")?.[1] || "mp4"}`
  166. }
  167. ];
  168. };
  169. var bilibili_default = async () => {
  170. const urls = await getBilibiliVideoInfo();
  171. while (urls?.length) {
  172. const { url, fileName } = urls.shift();
  173. const file = await getFile(url);
  174. download(file, fileName);
  175. }
  176. };
  177.  
  178. // src/module/douyin.js
  179. var getDouyinVideoInfo = () => {
  180. const urls = [...document.querySelectorAll("video source")].map((i) => i.src);
  181. return {
  182. url: urls[0],
  183. fileName: `download.mp4`
  184. };
  185. };
  186. var douyin_default = async () => {
  187. const url = await getDouyinVideoInfo();
  188. const file = await getFile(url.url);
  189. download(file, url.fileName);
  190. };
  191.  
  192. // src/module/kuaishou.js
  193. var getKuaishouVideoInfo = () => {
  194. const urls = [...document.querySelectorAll("video")].map((i) => i.src);
  195. return {
  196. url: urls[0],
  197. fileName: `download.mp4`
  198. };
  199. };
  200. var kuaishou_default = async () => {
  201. const url = await getKuaishouVideoInfo();
  202. const file = await getFile(url.url);
  203. download(file, url.fileName);
  204. };
  205.  
  206. // src/module/youtube.js
  207. var getYoutubeVideoInfo = async () => {
  208. const res = await fetch(window.location.href);
  209. const str = await res.text();
  210. const parser = new DOMParser();
  211. const doc = parser.parseFromString(str, "text/html");
  212. const data = safetyParse(
  213. doc.body.innerHTML.match(/("formats":)([\d\D]+?}]+?)/)[2]
  214. );
  215. const video = data.sort((a, b) => b?.width - a?.width)?.[0];
  216. return {
  217. url: video.url,
  218. fileName: `download.mp4`
  219. };
  220. };
  221. var youtube_default = async () => {
  222. const url = await getYoutubeVideoInfo();
  223. const file = await getFile(url.url);
  224. download(file, url.fileName);
  225. };
  226.  
  227. // src/module/qq.js
  228. var proxyhttpBody = null;
  229. var monitor = async () => {
  230. try {
  231. window.__PLAYER__.pluginMsg.emit = new Proxy(
  232. window.__PLAYER__.pluginMsg.emit,
  233. {
  234. apply: (...args) => {
  235. if (args?.[2]?.[0] === "PROXY_HTTP_START" && args?.[2]?.[1]?.vinfoparam) {
  236. console.log(args?.[2]?.[1]);
  237. proxyhttpBody = JSON.stringify(args?.[2]?.[1]);
  238. }
  239. return Reflect.apply(...args);
  240. }
  241. }
  242. );
  243. } catch (error) {
  244. console.log("monitor error");
  245. }
  246. };
  247. var getVideoInfo2 = async () => {
  248. let m3u8FileUrl = null;
  249. if (!m3u8FileUrl) {
  250. let res = await fetch("https://vd6.l.qq.com/proxyhttp", {
  251. method: "post",
  252. body: proxyhttpBody
  253. });
  254. res = await res.json();
  255. if (res?.errCode === 0 && res?.vinfo) {
  256. const data = safetyParse(res?.vinfo);
  257. const m3u8 = data?.vl?.vi?.sort((a, b) => b.vw - a.vw)?.[0]?.ul;
  258. if (m3u8) {
  259. m3u8FileUrl = m3u8.ui[0].url;
  260. }
  261. }
  262. }
  263. const urls = await getUrlsByM3u8(m3u8FileUrl);
  264. return urls.map((url) => ({
  265. url,
  266. fileName: `download.mp4`
  267. }));
  268. };
  269. if (window.location.host === "v.qq.com") {
  270. monitor();
  271. }
  272. var qq_default = async () => {
  273. const urls = await getVideoInfo2();
  274. const files = await getFiles(urls);
  275. download(new Blob(files), "download.mp4");
  276. };
  277.  
  278. // src/module/cctv.js
  279. var getVideoInfo3 = async () => {
  280. let data = await fetch(
  281. `https://vdn.apps.cntv.cn/api/getHttpVideoInfo.do?pid=${window.guid}`
  282. );
  283. data = await data.json();
  284. const urls = data?.video?.[`chapters${data?.video?.validChapterNum}`];
  285. return { urls, fileName: `${data?.title}.mp4` };
  286. };
  287. var cctv_default = async () => {
  288. const { urls, fileName } = await getVideoInfo3();
  289. while (urls.length) {
  290. const file = await getFile(urls.shift().url);
  291. download(file, fileName);
  292. }
  293. };
  294.  
  295. // src/module/youku.js
  296. var youku_default = async () => {
  297. if (!document.querySelector("meta#you-get-youku")) {
  298. const meta = document.createElement("meta");
  299. meta.httpEquiv = "Content-Security-Policy";
  300. meta.content = "upgrade-insecure-requests";
  301. meta.id = "you-get-youku";
  302. document.querySelector("head").appendChild(meta);
  303. }
  304. const data = window?.videoPlayer?.context?.mediaData?.mediaResource?._model;
  305. if (data) {
  306. const m3u8FileUrl = data.streamList.sort((a, b) => b.width - a.width)[0].uri.HLS;
  307. const urls = await getUrlsByM3u8(m3u8FileUrl, (i) => i);
  308. const files = await getFiles(urls.map((url) => ({ url })));
  309. download(new Blob(files), `${data.video.title}.ts`);
  310. }
  311. };
  312.  
  313. // src/module/index.js
  314. var module_default = {
  315. ixigua: xigua_default,
  316. bilibili: bilibili_default,
  317. douyin: douyin_default,
  318. kuaishou: kuaishou_default,
  319. youtube: youtube_default,
  320. acfun: acfun_default,
  321. qq: qq_default,
  322. cctv: cctv_default,
  323. youku: youku_default
  324. };
  325.  
  326. // src/index.js
  327. var fetch2 = window.fetch;
  328. var youget = () => {
  329. const handler = Object.entries(module_default).find(
  330. ([key, fn]) => window.location.host.toLocaleLowerCase().includes(key)
  331. )?.[1];
  332. if (handler) {
  333. handler();
  334. } else {
  335. console.log("not support");
  336. }
  337. };
  338. youget.toString = () => {
  339. youget();
  340. return 1;
  341. };
  342. window.you = 1;
  343. window.get = youget;
  344. window.youget = youget;
  345. })();