@pieda/video-dl 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,3 +4,4 @@ export { useFacebook } from './useFacebook';
4
4
  export { useVimeo } from './useVimeo';
5
5
  export { useInstagram } from './useInstagram';
6
6
  export { useTiktok } from './useTiktok';
7
+ export { useYtdlp } from './useYtdlp';
@@ -1,8 +1,14 @@
1
1
  type TUseInstagram = {
2
+ debug?: boolean;
2
3
  ytdlpPath: string;
3
4
  videoId: string;
4
5
  dest: string;
5
- debug?: boolean;
6
+ tempDir: string;
7
+ ffmpegConfig: {
8
+ ffmpegPath: string;
9
+ ffmpegProbePath: string;
10
+ ffmpegPlayPath: string;
11
+ };
6
12
  };
7
- export declare const useInstagram: ({ ytdlpPath, videoId, dest, debug, }: TUseInstagram) => Promise<[Error | null, boolean | null]>;
13
+ export declare const useInstagram: ({ debug, ytdlpPath, videoId, dest, tempDir, ffmpegConfig, }: TUseInstagram) => Promise<[Error | null, boolean | null]>;
8
14
  export {};
@@ -1,9 +1,14 @@
1
1
  type TUseVimeo = {
2
+ debug?: boolean;
2
3
  ytdlpPath: string;
3
4
  videoId: string;
4
5
  dest: string;
5
- downloadBtnSelector?: string;
6
- debug?: boolean;
6
+ tempDir: string;
7
+ ffmpegConfig: {
8
+ ffmpegPath: string;
9
+ ffmpegProbePath: string;
10
+ ffmpegPlayPath: string;
11
+ };
7
12
  };
8
- export declare const useVimeo: ({ ytdlpPath, videoId, dest, debug, }: TUseVimeo) => Promise<[Error | null, boolean | null]>;
13
+ export declare const useVimeo: ({ debug, ytdlpPath, videoId, dest, tempDir, ffmpegConfig, }: TUseVimeo) => Promise<[Error | null, boolean | null]>;
9
14
  export {};
@@ -3,6 +3,12 @@ type TUseYoutube = {
3
3
  videoId: string;
4
4
  dest: string;
5
5
  debug?: boolean;
6
+ tempDir: string;
7
+ ffmpegConfig: {
8
+ ffmpegPath: string;
9
+ ffmpegProbePath: string;
10
+ ffmpegPlayPath: string;
11
+ };
6
12
  };
7
- export declare const useYoutube: ({ ytdlpPath, videoId, dest, debug, }: TUseYoutube) => Promise<[Error | null, boolean | null]>;
13
+ export declare const useYoutube: ({ debug, ytdlpPath, videoId, dest, tempDir, ffmpegConfig, }: TUseYoutube) => Promise<[Error | null, boolean | null]>;
8
14
  export {};
@@ -0,0 +1,14 @@
1
+ type TUseYtdlp = {
2
+ debug?: boolean;
3
+ ytdlpPath: string;
4
+ videoUrl: string;
5
+ dest: string;
6
+ tempDir: string;
7
+ ffmpegConfig: {
8
+ ffmpegPath: string;
9
+ ffmpegProbePath: string;
10
+ ffmpegPlayPath: string;
11
+ };
12
+ };
13
+ export declare const useYtdlp: ({ debug, ytdlpPath, videoUrl, dest, tempDir, ffmpegConfig, }: TUseYtdlp) => Promise<[Error | null, boolean | null]>;
14
+ export {};
package/dist/video-dl.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=i=>new Promise((r,t)=>{import(i).then(g=>r(g.default)).catch(t)}),f=async(i,r,t)=>{const g=await l("fs"),e=await l("axios");return console.log(`Downloading ${i} to ${r}`),new Promise((w,s)=>{e.get(i,{responseType:"stream",headers:t}).then(u=>{const p=u.data,a=g.createWriteStream(r);p.pipe(a),a.on("finish",function(){a.close(()=>{w()})})}).catch(s)})},d=(i=!1)=>({log:(...r)=>{i&&console.log(...r)},error:(...r)=>{i&&console.error(...r)}}),y=async({ytdlpPath:i,videoId:r,dest:t,debug:g=!1})=>{const e=d(g);e.log(`Downloading video: ${r} to: ${t}`);const w=await l("fs"),s=await l("path"),{exec:u}=await l("child_process"),p=(a="")=>new Promise((c,o)=>{const n=`${i} -f b -g https://www.youtube.com/watch?v=${a}`;e.log(`[yt-dlp] 執行命令: ${n}`),u(n,(m,h,$)=>{if(e.log(`[yt-dlp] stdout: ${h}`),!h.includes("https://")){c("");return}c(h)})});return w.existsSync(s.dirname(t))||(w.mkdirSync(s.dirname(t),{recursive:!0},777),e.log(`建立 ${s.dirname(t)}`)),new Promise(async(a,c)=>{try{const o=await p(r);if(!o)throw new Error("無法取得 videoUrl");e.log(`取得 videoUrl ${o}`),await f(o,t).catch(n=>{throw e.error(`下載失敗: ${n.message}`),n}),e.log(`下載完成 ${t}`),a([null,!0])}catch(o){e.error(`下載失敗: ${o.message}`),a([o,null])}})},k=async({videoId:i,dest:r,debug:t=!1,headless:g=!0})=>{try{const e=d(t);e.log(`Downloading video: ${i} to: ${r}`);const w=`https://m.facebook.com/watch/?v=${i}`,s=await l("fs"),u=await l("path"),p=await l("puppeteer");s.existsSync(u.dirname(r))||(s.mkdirSync(u.dirname(r),{recursive:!0},777),e.log(`建立 ${u.dirname(r)}`));const a={};g||(a.headless=!1);const c=await p.launch(a);e.log("啟動 puppeteer");const o=await c.newPage();await o.setUserAgent("'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1'"),e.log("開新分頁"),e.log(`前往 ${w}`),await Promise.race([o.goto(w,{waitUntil:"networkidle0"}),o.waitForSelector("video")]),e.log("找到 video 元素");const n=await o.$eval("video",m=>m.getAttribute("src"));return e.log(`取得 video url: ${n}`),await c.close(),e.log("關閉 puppeteer"),await f(n,r),e.log(`下載完成 ${n}`),[null,!0]}catch(e){return[e,null]}},v=async({ytdlpPath:i,videoId:r,dest:t,debug:g=!1})=>{const e=d(g);e.log(`Downloading video: ${r} to: ${t}`);const w=await l("fs"),s=await l("path"),{exec:u}=await l("child_process"),p=(a="")=>new Promise((c,o)=>{const n=`${i} -f b -g https://vimeo.com/${a}`;console.log(`執行命令: ${n}`),u(n,(m,h,$)=>{if(e.log(`yt-dlp stdout: ${h}`),!h.includes("https://")){c("");return}c(h)})});return w.existsSync(s.dirname(t))||(w.mkdirSync(s.dirname(t),{recursive:!0},777),e.log(`建立 ${s.dirname(t)}`)),new Promise(async(a,c)=>{try{const o=await p(r);if(!o)throw new Error("無法取得 videoUrl");e.log(`取得 videoUrl ${o}`),await f(o,t).catch(n=>{throw e.error(`下載失敗: ${n.message}`),n}),e.log(`下載完成 ${t}`),a([null,!0])}catch(o){e.error(`下載失敗: ${o.message}`),a([o,null])}})},b=async({ytdlpPath:i,videoId:r,dest:t,debug:g=!1})=>{const e=d(g);e.log(`Downloading video: ${r} to: ${t}`);const w=await l("fs"),s=await l("path"),{exec:u}=await l("child_process"),p=(a="")=>new Promise((c,o)=>{const n=`https://www.instagram.com/reel/${a}/`,m=`${i} -f b -g ${n}`;console.log(`執行命令: ${m}`),u(m,(h,$,P)=>{if(e.log(`yt-dlp stdout: ${$}`),!$.includes("https://")){c("");return}c($)})});return w.existsSync(s.dirname(t))||(w.mkdirSync(s.dirname(t),{recursive:!0},777),e.log(`建立 ${s.dirname(t)}`)),new Promise(async(a,c)=>{try{const o=await p(r);if(!o)throw new Error("無法取得 videoUrl");e.log(`取得 videoUrl ${o}`),await f(o,t).catch(n=>{throw e.error(`下載失敗: ${n.message}`),n}),e.log(`下載完成 ${t}`),a([null,!0])}catch(o){e.error(`下載失敗: ${o.message}`),a([o,null])}})},S=async({videoLink:i,dest:r,debug:t=!1,headless:g=!0})=>{try{const e=d(t);e.log(`Downloading video: ${i} to: ${r}`);const w=i,s=await l("fs"),u=await l("path"),p=await l("puppeteer");s.existsSync(u.dirname(r))||(s.mkdirSync(u.dirname(r),{recursive:!0},777),e.log(`建立 ${u.dirname(r)}`));const a={};g||(a.headless=!1);const c=await p.launch(a);e.log("啟動 puppeteer");const o=await c.newPage();e.log("開新分頁"),e.log(`前往 ${w}`),await Promise.race([o.goto(w,{waitUntil:"networkidle0"}),o.waitForSelector("video")]),e.log("找到 video 元素");const n=await o.$eval('video source[src^="https://www.tiktok.com/aweme/v1/play/"]',m=>m.getAttribute("src"));return e.log(`取得 video url: ${n}`),await c.close(),e.log("關閉 puppeteer"),await f(n,r,{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",Referer:"https://www.tiktok.com/"}),e.log(`下載完成 ${n}`),[null,!0]}catch(e){return[e,null]}},U=({type:i})=>{switch(i){case"youtube":case"yt-short":return y;case"facebook":case"fb-reel":return k;case"vimeo":return v;case"instagram":case"ig":case"ig-reel":return b;case"tiktok":case"tiktok-reel":return S;default:throw new Error(`Invalid video type: ${i}`)}};exports.useDownloader=U;exports.useFacebook=k;exports.useInstagram=b;exports.useTiktok=S;exports.useVimeo=v;exports.useYoutube=y;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=(e=!1)=>({log:(...o)=>{e&&console.log(...o)},error:(...o)=>{e&&console.error(...o)}}),s=[];for(let e=0;e<256;++e)s.push((e+256).toString(16).slice(1));function j(e,o=0){return(s[e[o+0]]+s[e[o+1]]+s[e[o+2]]+s[e[o+3]]+"-"+s[e[o+4]]+s[e[o+5]]+"-"+s[e[o+6]]+s[e[o+7]]+"-"+s[e[o+8]]+s[e[o+9]]+"-"+s[e[o+10]]+s[e[o+11]]+s[e[o+12]]+s[e[o+13]]+s[e[o+14]]+s[e[o+15]]).toLowerCase()}let k;const I=new Uint8Array(16);function W(){if(!k){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");k=crypto.getRandomValues.bind(crypto)}return k(I)}const _=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),D={randomUUID:_};function K(e,o,n){var t;e=e||{};const r=e.random??((t=e.rng)==null?void 0:t.call(e))??W();if(r.length<16)throw new Error("Random bytes length must be >= 16");if(r[6]=r[6]&15|64,r[8]=r[8]&63|128,o){if(n=n||0,n<0||n+16>o.length)throw new RangeError(`UUID byte range ${n}:${n+15} is out of buffer bounds`);for(let a=0;a<16;++a)o[n+a]=r[a];return o}return j(r)}function C(e,o,n){return D.randomUUID&&!o&&!e?D.randomUUID():K(e,o,n)}const w=e=>new Promise((o,n)=>{import(e).then(r=>o(r.default)).catch(n)}),x=async(e,o,n)=>{const r=await w("fs"),t=await w("axios");return console.log(`Downloading ${e} to ${o}`),new Promise((a,c)=>{t.get(e,{responseType:"stream",headers:n}).then(i=>{const u=i.data,g=r.createWriteStream(o);u.pipe(g),g.on("finish",function(){g.close(()=>{a()})})}).catch(c)})},U=async({debug:e=!1,ytdlpPath:o,videoUrl:n,dest:r,tempDir:t,ffmpegConfig:a})=>{const c=y(e);c.log(`Downloading video: ${n} to: ${r}`);const i=await w("fs"),u=await w("path"),{exec:g,execSync:h}=await w("child_process"),l=u.join(t,C()),d=()=>new Promise((p,S)=>{const m=`${o} -f mergeall --audio-multistreams --video-multistreams ${n} --downloader ffmpeg -o "${l}/%(id)s.%(ext)s" --merge-output-format mp4`;c.log(`[yt-dlp] 執行命令: ${m}`),g(m,($,v,f)=>{if(c.log(`[yt-dlp] stdout: ${v}`),$){S($);return}p()})});return i.existsSync(u.dirname(r))||(i.mkdirSync(u.dirname(r),{recursive:!0},777),c.log(`建立 ${u.dirname(r)}`)),new Promise(async(p,S)=>{try{await d();let m=!1;const $=i.readdirSync(l);for(const v of $){const f=u.join(l,v),V=`${a.ffmpegProbePath} -v error -show_entries stream=codec_type -of csv=p=0 "${f}"`,b=h(V).toString("utf-8"),R=b.includes("video"),E=b.includes("audio");if(R&&E){m=!0,i.copyFileSync(f,r);break}}if(!m)throw new Error("無法下載影音正常的影片");c.log(`下載完成 ${r}`),p([null,!0])}catch(m){c.error(`下載失敗: ${m.message}`),p([m,null])}})},P=async({debug:e=!1,ytdlpPath:o,videoId:n,dest:r,tempDir:t,ffmpegConfig:a})=>{y(e).log(`Downloading video: ${n} to: ${r}`);const i=`https://www.youtube.com/watch?v=${n}`;return U({debug:e,ytdlpPath:o,videoUrl:i,dest:r,tempDir:t,ffmpegConfig:a})},A=async({videoId:e,dest:o,debug:n=!1,headless:r=!0})=>{try{const t=y(n);t.log(`Downloading video: ${e} to: ${o}`);const a=`https://m.facebook.com/watch/?v=${e}`,c=await w("fs"),i=await w("path"),u=await w("puppeteer");c.existsSync(i.dirname(o))||(c.mkdirSync(i.dirname(o),{recursive:!0},777),t.log(`建立 ${i.dirname(o)}`));const g={};r||(g.headless=!1);const h=await u.launch(g);t.log("啟動 puppeteer");const l=await h.newPage();await l.setUserAgent("'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1'"),t.log("開新分頁"),t.log(`前往 ${a}`),await Promise.race([l.goto(a,{waitUntil:"networkidle0"}),l.waitForSelector("video")]),t.log("找到 video 元素");const d=await l.$eval("video",p=>p.getAttribute("src"));return t.log(`取得 video url: ${d}`),await h.close(),t.log("關閉 puppeteer"),await x(d,o),t.log(`下載完成 ${d}`),[null,!0]}catch(t){return[t,null]}},F=async({debug:e=!1,ytdlpPath:o,videoId:n,dest:r,tempDir:t,ffmpegConfig:a})=>{y(e).log(`Downloading video: ${n} to: ${r}`);const i=`https://vimeo.com/${n}`;return U({debug:e,ytdlpPath:o,videoUrl:i,dest:r,tempDir:t,ffmpegConfig:a})},M=async({debug:e=!1,ytdlpPath:o,videoId:n,dest:r,tempDir:t,ffmpegConfig:a})=>{y(e).log(`Downloading video: ${n} to: ${r}`);const i=`https://www.instagram.com/reel/${n}/`;return U({debug:e,ytdlpPath:o,videoUrl:i,dest:r,tempDir:t,ffmpegConfig:a})},T=async({videoLink:e,dest:o,debug:n=!1,headless:r=!0})=>{try{const t=y(n);t.log(`Downloading video: ${e} to: ${o}`);const a=e,c=await w("fs"),i=await w("path"),u=await w("puppeteer");c.existsSync(i.dirname(o))||(c.mkdirSync(i.dirname(o),{recursive:!0},777),t.log(`建立 ${i.dirname(o)}`));const g={};r||(g.headless=!1);const h=await u.launch(g);t.log("啟動 puppeteer");const l=await h.newPage();t.log("開新分頁"),t.log(`前往 ${a}`),await Promise.race([l.goto(a,{waitUntil:"networkidle0"}),l.waitForSelector("video")]),t.log("找到 video 元素");const d=await l.$eval('video source[src^="https://www.tiktok.com/aweme/v1/play/"]',p=>p.getAttribute("src"));return t.log(`取得 video url: ${d}`),await h.close(),t.log("關閉 puppeteer"),await x(d,o,{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",Referer:"https://www.tiktok.com/"}),t.log(`下載完成 ${d}`),[null,!0]}catch(t){return[t,null]}},H=({type:e})=>{switch(e){case"youtube":case"yt-short":return P;case"facebook":case"fb-reel":return A;case"vimeo":return F;case"instagram":case"ig":case"ig-reel":return M;case"tiktok":case"tiktok-reel":return T;default:throw new Error(`Invalid video type: ${e}`)}};exports.useDownloader=H;exports.useFacebook=A;exports.useInstagram=M;exports.useTiktok=T;exports.useVimeo=F;exports.useYoutube=P;
package/dist/video-dl.js CHANGED
@@ -1,206 +1,244 @@
1
- const l = (i) => new Promise((r, t) => {
2
- import(i).then((u) => r(u.default)).catch(t);
3
- }), f = async (i, r, t) => {
4
- const u = await l("fs"), e = await l("axios");
5
- return console.log(`Downloading ${i} to ${r}`), new Promise((w, c) => {
6
- e.get(i, {
1
+ const y = (e = !1) => ({
2
+ log: (...o) => {
3
+ e && console.log(...o);
4
+ },
5
+ error: (...o) => {
6
+ e && console.error(...o);
7
+ }
8
+ }), s = [];
9
+ for (let e = 0; e < 256; ++e)
10
+ s.push((e + 256).toString(16).slice(1));
11
+ function M(e, o = 0) {
12
+ return (s[e[o + 0]] + s[e[o + 1]] + s[e[o + 2]] + s[e[o + 3]] + "-" + s[e[o + 4]] + s[e[o + 5]] + "-" + s[e[o + 6]] + s[e[o + 7]] + "-" + s[e[o + 8]] + s[e[o + 9]] + "-" + s[e[o + 10]] + s[e[o + 11]] + s[e[o + 12]] + s[e[o + 13]] + s[e[o + 14]] + s[e[o + 15]]).toLowerCase();
13
+ }
14
+ let k;
15
+ const R = new Uint8Array(16);
16
+ function V() {
17
+ if (!k) {
18
+ if (typeof crypto > "u" || !crypto.getRandomValues)
19
+ throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
20
+ k = crypto.getRandomValues.bind(crypto);
21
+ }
22
+ return k(R);
23
+ }
24
+ const E = typeof crypto < "u" && crypto.randomUUID && crypto.randomUUID.bind(crypto), x = { randomUUID: E };
25
+ function T(e, o, r) {
26
+ var t;
27
+ e = e || {};
28
+ const n = e.random ?? ((t = e.rng) == null ? void 0 : t.call(e)) ?? V();
29
+ if (n.length < 16)
30
+ throw new Error("Random bytes length must be >= 16");
31
+ if (n[6] = n[6] & 15 | 64, n[8] = n[8] & 63 | 128, o) {
32
+ if (r = r || 0, r < 0 || r + 16 > o.length)
33
+ throw new RangeError(`UUID byte range ${r}:${r + 15} is out of buffer bounds`);
34
+ for (let a = 0; a < 16; ++a)
35
+ o[r + a] = n[a];
36
+ return o;
37
+ }
38
+ return M(n);
39
+ }
40
+ function W(e, o, r) {
41
+ return x.randomUUID && !o && !e ? x.randomUUID() : T(e, o, r);
42
+ }
43
+ const w = (e) => new Promise((o, r) => {
44
+ import(e).then((n) => o(n.default)).catch(r);
45
+ }), D = async (e, o, r) => {
46
+ const n = await w("fs"), t = await w("axios");
47
+ return console.log(`Downloading ${e} to ${o}`), new Promise((a, c) => {
48
+ t.get(e, {
7
49
  responseType: "stream",
8
- headers: t
9
- }).then((g) => {
10
- const p = g.data, a = u.createWriteStream(r);
11
- p.pipe(a), a.on("finish", function() {
12
- a.close(() => {
13
- w();
50
+ headers: r
51
+ }).then((i) => {
52
+ const u = i.data, g = n.createWriteStream(o);
53
+ u.pipe(g), g.on("finish", function() {
54
+ g.close(() => {
55
+ a();
14
56
  });
15
57
  });
16
58
  }).catch(c);
17
59
  });
18
- }, d = (i = !1) => ({
19
- log: (...r) => {
20
- i && console.log(...r);
21
- },
22
- error: (...r) => {
23
- i && console.error(...r);
24
- }
25
- }), y = async ({
26
- ytdlpPath: i,
27
- videoId: r,
28
- dest: t,
29
- debug: u = !1
60
+ }, U = async ({
61
+ debug: e = !1,
62
+ ytdlpPath: o,
63
+ videoUrl: r,
64
+ dest: n,
65
+ tempDir: t,
66
+ ffmpegConfig: a
30
67
  }) => {
31
- const e = d(u);
32
- e.log(`Downloading video: ${r} to: ${t}`);
33
- const w = await l("fs"), c = await l("path"), { exec: g } = await l("child_process"), p = (a = "") => new Promise((s, o) => {
34
- const n = `${i} -f b -g https://www.youtube.com/watch?v=${a}`;
35
- e.log(`[yt-dlp] 執行命令: ${n}`), g(n, (m, h, $) => {
36
- if (e.log(`[yt-dlp] stdout: ${h}`), !h.includes("https://")) {
37
- s("");
68
+ const c = y(e);
69
+ c.log(`Downloading video: ${r} to: ${n}`);
70
+ const i = await w("fs"), u = await w("path"), { exec: g, execSync: h } = await w("child_process"), l = u.join(t, W()), d = () => new Promise((p, S) => {
71
+ const m = `${o} -f mergeall --audio-multistreams --video-multistreams ${r} --downloader ffmpeg -o "${l}/%(id)s.%(ext)s" --merge-output-format mp4`;
72
+ c.log(`[yt-dlp] 執行命令: ${m}`), g(m, ($, v, f) => {
73
+ if (c.log(`[yt-dlp] stdout: ${v}`), $) {
74
+ S($);
38
75
  return;
39
76
  }
40
- s(h);
77
+ p();
41
78
  });
42
79
  });
43
- return w.existsSync(c.dirname(t)) || (w.mkdirSync(c.dirname(t), { recursive: !0 }, 777), e.log(`建立 ${c.dirname(t)}`)), new Promise(async (a, s) => {
80
+ return i.existsSync(u.dirname(n)) || (i.mkdirSync(u.dirname(n), { recursive: !0 }, 777), c.log(`建立 ${u.dirname(n)}`)), new Promise(async (p, S) => {
44
81
  try {
45
- const o = await p(r);
46
- if (!o)
47
- throw new Error("無法取得 videoUrl");
48
- e.log(`取得 videoUrl ${o}`), await f(o, t).catch((n) => {
49
- throw e.error(`下載失敗: ${n.message}`), n;
50
- }), e.log(`下載完成 ${t}`), a([null, !0]);
51
- } catch (o) {
52
- e.error(`下載失敗: ${o.message}`), a([o, null]);
82
+ await d();
83
+ let m = !1;
84
+ const $ = i.readdirSync(l);
85
+ for (const v of $) {
86
+ const f = u.join(l, v), P = `${a.ffmpegProbePath} -v error -show_entries stream=codec_type -of csv=p=0 "${f}"`, b = h(P).toString("utf-8"), A = b.includes("video"), F = b.includes("audio");
87
+ if (A && F) {
88
+ m = !0, i.copyFileSync(f, n);
89
+ break;
90
+ }
91
+ }
92
+ if (!m)
93
+ throw new Error("無法下載影音正常的影片");
94
+ c.log(`下載完成 ${n}`), p([null, !0]);
95
+ } catch (m) {
96
+ c.error(`下載失敗: ${m.message}`), p([m, null]);
53
97
  }
54
98
  });
55
- }, k = async ({
56
- videoId: i,
57
- dest: r,
58
- debug: t = !1,
59
- headless: u = !0
99
+ }, _ = async ({
100
+ debug: e = !1,
101
+ ytdlpPath: o,
102
+ videoId: r,
103
+ dest: n,
104
+ tempDir: t,
105
+ ffmpegConfig: a
106
+ }) => {
107
+ y(e).log(`Downloading video: ${r} to: ${n}`);
108
+ const i = `https://www.youtube.com/watch?v=${r}`;
109
+ return U({
110
+ debug: e,
111
+ ytdlpPath: o,
112
+ videoUrl: i,
113
+ dest: n,
114
+ tempDir: t,
115
+ ffmpegConfig: a
116
+ });
117
+ }, j = async ({
118
+ videoId: e,
119
+ dest: o,
120
+ debug: r = !1,
121
+ headless: n = !0
60
122
  }) => {
61
123
  try {
62
- const e = d(t);
63
- e.log(`Downloading video: ${i} to: ${r}`);
64
- const w = `https://m.facebook.com/watch/?v=${i}`, c = await l("fs"), g = await l("path"), p = await l("puppeteer");
65
- c.existsSync(g.dirname(r)) || (c.mkdirSync(g.dirname(r), { recursive: !0 }, 777), e.log(`建立 ${g.dirname(r)}`));
66
- const a = {};
67
- u || (a.headless = !1);
68
- const s = await p.launch(a);
69
- e.log("啟動 puppeteer");
70
- const o = await s.newPage();
71
- await o.setUserAgent(
124
+ const t = y(r);
125
+ t.log(`Downloading video: ${e} to: ${o}`);
126
+ const a = `https://m.facebook.com/watch/?v=${e}`, c = await w("fs"), i = await w("path"), u = await w("puppeteer");
127
+ c.existsSync(i.dirname(o)) || (c.mkdirSync(i.dirname(o), { recursive: !0 }, 777), t.log(`建立 ${i.dirname(o)}`));
128
+ const g = {};
129
+ n || (g.headless = !1);
130
+ const h = await u.launch(g);
131
+ t.log("啟動 puppeteer");
132
+ const l = await h.newPage();
133
+ await l.setUserAgent(
72
134
  "'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1'"
73
- ), e.log("開新分頁"), e.log(`前往 ${w}`), await Promise.race([
74
- o.goto(w, {
135
+ ), t.log("開新分頁"), t.log(`前往 ${a}`), await Promise.race([
136
+ l.goto(a, {
75
137
  waitUntil: "networkidle0"
76
138
  }),
77
- o.waitForSelector("video")
78
- ]), e.log("找到 video 元素");
79
- const n = await o.$eval("video", (m) => m.getAttribute("src"));
80
- return e.log(`取得 video url: ${n}`), await s.close(), e.log("關閉 puppeteer"), await f(n, r), e.log(`下載完成 ${n}`), [null, !0];
81
- } catch (e) {
82
- return [e, null];
139
+ l.waitForSelector("video")
140
+ ]), t.log("找到 video 元素");
141
+ const d = await l.$eval("video", (p) => p.getAttribute("src"));
142
+ return t.log(`取得 video url: ${d}`), await h.close(), t.log("關閉 puppeteer"), await D(d, o), t.log(`下載完成 ${d}`), [null, !0];
143
+ } catch (t) {
144
+ return [t, null];
83
145
  }
84
- }, v = async ({
85
- ytdlpPath: i,
146
+ }, I = async ({
147
+ debug: e = !1,
148
+ ytdlpPath: o,
86
149
  videoId: r,
87
- dest: t,
88
- debug: u = !1
150
+ dest: n,
151
+ tempDir: t,
152
+ ffmpegConfig: a
89
153
  }) => {
90
- const e = d(u);
91
- e.log(`Downloading video: ${r} to: ${t}`);
92
- const w = await l("fs"), c = await l("path"), { exec: g } = await l("child_process"), p = (a = "") => new Promise((s, o) => {
93
- const n = `${i} -f b -g https://vimeo.com/${a}`;
94
- console.log(`執行命令: ${n}`), g(n, (m, h, $) => {
95
- if (e.log(`yt-dlp stdout: ${h}`), !h.includes("https://")) {
96
- s("");
97
- return;
98
- }
99
- s(h);
100
- });
101
- });
102
- return w.existsSync(c.dirname(t)) || (w.mkdirSync(c.dirname(t), { recursive: !0 }, 777), e.log(`建立 ${c.dirname(t)}`)), new Promise(async (a, s) => {
103
- try {
104
- const o = await p(r);
105
- if (!o)
106
- throw new Error("無法取得 videoUrl");
107
- e.log(`取得 videoUrl ${o}`), await f(o, t).catch((n) => {
108
- throw e.error(`下載失敗: ${n.message}`), n;
109
- }), e.log(`下載完成 ${t}`), a([null, !0]);
110
- } catch (o) {
111
- e.error(`下載失敗: ${o.message}`), a([o, null]);
112
- }
154
+ y(e).log(`Downloading video: ${r} to: ${n}`);
155
+ const i = `https://vimeo.com/${r}`;
156
+ return U({
157
+ debug: e,
158
+ ytdlpPath: o,
159
+ videoUrl: i,
160
+ dest: n,
161
+ tempDir: t,
162
+ ffmpegConfig: a
113
163
  });
114
- }, S = async ({
115
- ytdlpPath: i,
164
+ }, K = async ({
165
+ debug: e = !1,
166
+ ytdlpPath: o,
116
167
  videoId: r,
117
- dest: t,
118
- debug: u = !1
168
+ dest: n,
169
+ tempDir: t,
170
+ ffmpegConfig: a
119
171
  }) => {
120
- const e = d(u);
121
- e.log(`Downloading video: ${r} to: ${t}`);
122
- const w = await l("fs"), c = await l("path"), { exec: g } = await l("child_process"), p = (a = "") => new Promise((s, o) => {
123
- const n = `https://www.instagram.com/reel/${a}/`, m = `${i} -f b -g ${n}`;
124
- console.log(`執行命令: ${m}`), g(m, (h, $, b) => {
125
- if (e.log(`yt-dlp stdout: ${$}`), !$.includes("https://")) {
126
- s("");
127
- return;
128
- }
129
- s($);
130
- });
131
- });
132
- return w.existsSync(c.dirname(t)) || (w.mkdirSync(c.dirname(t), { recursive: !0 }, 777), e.log(`建立 ${c.dirname(t)}`)), new Promise(async (a, s) => {
133
- try {
134
- const o = await p(r);
135
- if (!o)
136
- throw new Error("無法取得 videoUrl");
137
- e.log(`取得 videoUrl ${o}`), await f(o, t).catch((n) => {
138
- throw e.error(`下載失敗: ${n.message}`), n;
139
- }), e.log(`下載完成 ${t}`), a([null, !0]);
140
- } catch (o) {
141
- e.error(`下載失敗: ${o.message}`), a([o, null]);
142
- }
172
+ y(e).log(`Downloading video: ${r} to: ${n}`);
173
+ const i = `https://www.instagram.com/reel/${r}/`;
174
+ return U({
175
+ debug: e,
176
+ ytdlpPath: o,
177
+ videoUrl: i,
178
+ dest: n,
179
+ tempDir: t,
180
+ ffmpegConfig: a
143
181
  });
144
- }, U = async ({
145
- videoLink: i,
146
- dest: r,
147
- debug: t = !1,
148
- headless: u = !0
182
+ }, C = async ({
183
+ videoLink: e,
184
+ dest: o,
185
+ debug: r = !1,
186
+ headless: n = !0
149
187
  }) => {
150
188
  try {
151
- const e = d(t);
152
- e.log(`Downloading video: ${i} to: ${r}`);
153
- const w = i, c = await l("fs"), g = await l("path"), p = await l("puppeteer");
154
- c.existsSync(g.dirname(r)) || (c.mkdirSync(g.dirname(r), { recursive: !0 }, 777), e.log(`建立 ${g.dirname(r)}`));
155
- const a = {};
156
- u || (a.headless = !1);
157
- const s = await p.launch(a);
158
- e.log("啟動 puppeteer");
159
- const o = await s.newPage();
160
- e.log("開新分頁"), e.log(`前往 ${w}`), await Promise.race([
161
- o.goto(w, {
189
+ const t = y(r);
190
+ t.log(`Downloading video: ${e} to: ${o}`);
191
+ const a = e, c = await w("fs"), i = await w("path"), u = await w("puppeteer");
192
+ c.existsSync(i.dirname(o)) || (c.mkdirSync(i.dirname(o), { recursive: !0 }, 777), t.log(`建立 ${i.dirname(o)}`));
193
+ const g = {};
194
+ n || (g.headless = !1);
195
+ const h = await u.launch(g);
196
+ t.log("啟動 puppeteer");
197
+ const l = await h.newPage();
198
+ t.log("開新分頁"), t.log(`前往 ${a}`), await Promise.race([
199
+ l.goto(a, {
162
200
  waitUntil: "networkidle0"
163
201
  }),
164
- o.waitForSelector("video")
165
- ]), e.log("找到 video 元素");
166
- const n = await o.$eval(
202
+ l.waitForSelector("video")
203
+ ]), t.log("找到 video 元素");
204
+ const d = await l.$eval(
167
205
  'video source[src^="https://www.tiktok.com/aweme/v1/play/"]',
168
- (m) => m.getAttribute("src")
206
+ (p) => p.getAttribute("src")
169
207
  );
170
- return e.log(`取得 video url: ${n}`), await s.close(), e.log("關閉 puppeteer"), await f(n, r, {
208
+ return t.log(`取得 video url: ${d}`), await h.close(), t.log("關閉 puppeteer"), await D(d, o, {
171
209
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
172
210
  Referer: "https://www.tiktok.com/"
173
211
  // 設定 Referer
174
- }), e.log(`下載完成 ${n}`), [null, !0];
175
- } catch (e) {
176
- return [e, null];
212
+ }), t.log(`下載完成 ${d}`), [null, !0];
213
+ } catch (t) {
214
+ return [t, null];
177
215
  }
178
- }, P = ({ type: i }) => {
179
- switch (i) {
216
+ }, H = ({ type: e }) => {
217
+ switch (e) {
180
218
  case "youtube":
181
219
  case "yt-short":
182
- return y;
220
+ return _;
183
221
  case "facebook":
184
222
  case "fb-reel":
185
- return k;
223
+ return j;
186
224
  case "vimeo":
187
- return v;
225
+ return I;
188
226
  case "instagram":
189
227
  case "ig":
190
228
  case "ig-reel":
191
- return S;
229
+ return K;
192
230
  case "tiktok":
193
231
  case "tiktok-reel":
194
- return U;
232
+ return C;
195
233
  default:
196
- throw new Error(`Invalid video type: ${i}`);
234
+ throw new Error(`Invalid video type: ${e}`);
197
235
  }
198
236
  };
199
237
  export {
200
- P as useDownloader,
201
- k as useFacebook,
202
- S as useInstagram,
203
- U as useTiktok,
204
- v as useVimeo,
205
- y as useYoutube
238
+ H as useDownloader,
239
+ j as useFacebook,
240
+ K as useInstagram,
241
+ C as useTiktok,
242
+ I as useVimeo,
243
+ _ as useYoutube
206
244
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pieda/video-dl",
3
3
  "private": false,
4
- "version": "1.9.0",
4
+ "version": "1.10.0",
5
5
  "type": "module",
6
6
  "main": "dist/video-dl.cjs",
7
7
  "module": "dist/video-dl.js",
@@ -39,6 +39,7 @@
39
39
  "dependencies": {
40
40
  "axios": "^1.10.0",
41
41
  "puppeteer": "^22.13.1",
42
+ "uuid": "^13.0.0",
42
43
  "youtubei.js": "^14.0.0"
43
44
  },
44
45
  "devDependencies": {