@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.
- package/dist/types/composables/index.d.ts +1 -0
- package/dist/types/composables/useInstagram.d.ts +8 -2
- package/dist/types/composables/useVimeo.d.ts +8 -3
- package/dist/types/composables/useYoutube.d.ts +7 -1
- package/dist/types/composables/useYtdlp.d.ts +14 -0
- package/dist/video-dl.cjs +1 -1
- package/dist/video-dl.js +194 -156
- package/package.json +2 -1
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
type TUseInstagram = {
|
|
2
|
+
debug?: boolean;
|
|
2
3
|
ytdlpPath: string;
|
|
3
4
|
videoId: string;
|
|
4
5
|
dest: string;
|
|
5
|
-
|
|
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,
|
|
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
|
-
|
|
6
|
-
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
e.
|
|
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:
|
|
9
|
-
}).then((
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
},
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
if (
|
|
37
|
-
|
|
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
|
-
|
|
77
|
+
p();
|
|
41
78
|
});
|
|
42
79
|
});
|
|
43
|
-
return
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
c.existsSync(
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
await
|
|
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
|
-
),
|
|
74
|
-
|
|
135
|
+
), t.log("開新分頁"), t.log(`前往 ${a}`), await Promise.race([
|
|
136
|
+
l.goto(a, {
|
|
75
137
|
waitUntil: "networkidle0"
|
|
76
138
|
}),
|
|
77
|
-
|
|
78
|
-
]),
|
|
79
|
-
const
|
|
80
|
-
return
|
|
81
|
-
} catch (
|
|
82
|
-
return [
|
|
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
|
-
},
|
|
85
|
-
|
|
146
|
+
}, I = async ({
|
|
147
|
+
debug: e = !1,
|
|
148
|
+
ytdlpPath: o,
|
|
86
149
|
videoId: r,
|
|
87
|
-
dest:
|
|
88
|
-
|
|
150
|
+
dest: n,
|
|
151
|
+
tempDir: t,
|
|
152
|
+
ffmpegConfig: a
|
|
89
153
|
}) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
},
|
|
115
|
-
|
|
164
|
+
}, K = async ({
|
|
165
|
+
debug: e = !1,
|
|
166
|
+
ytdlpPath: o,
|
|
116
167
|
videoId: r,
|
|
117
|
-
dest:
|
|
118
|
-
|
|
168
|
+
dest: n,
|
|
169
|
+
tempDir: t,
|
|
170
|
+
ffmpegConfig: a
|
|
119
171
|
}) => {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
},
|
|
145
|
-
videoLink:
|
|
146
|
-
dest:
|
|
147
|
-
debug:
|
|
148
|
-
headless:
|
|
182
|
+
}, C = async ({
|
|
183
|
+
videoLink: e,
|
|
184
|
+
dest: o,
|
|
185
|
+
debug: r = !1,
|
|
186
|
+
headless: n = !0
|
|
149
187
|
}) => {
|
|
150
188
|
try {
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
c.existsSync(
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
165
|
-
]),
|
|
166
|
-
const
|
|
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
|
-
(
|
|
206
|
+
(p) => p.getAttribute("src")
|
|
169
207
|
);
|
|
170
|
-
return
|
|
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
|
-
}),
|
|
175
|
-
} catch (
|
|
176
|
-
return [
|
|
212
|
+
}), t.log(`下載完成 ${d}`), [null, !0];
|
|
213
|
+
} catch (t) {
|
|
214
|
+
return [t, null];
|
|
177
215
|
}
|
|
178
|
-
},
|
|
179
|
-
switch (
|
|
216
|
+
}, H = ({ type: e }) => {
|
|
217
|
+
switch (e) {
|
|
180
218
|
case "youtube":
|
|
181
219
|
case "yt-short":
|
|
182
|
-
return
|
|
220
|
+
return _;
|
|
183
221
|
case "facebook":
|
|
184
222
|
case "fb-reel":
|
|
185
|
-
return
|
|
223
|
+
return j;
|
|
186
224
|
case "vimeo":
|
|
187
|
-
return
|
|
225
|
+
return I;
|
|
188
226
|
case "instagram":
|
|
189
227
|
case "ig":
|
|
190
228
|
case "ig-reel":
|
|
191
|
-
return
|
|
229
|
+
return K;
|
|
192
230
|
case "tiktok":
|
|
193
231
|
case "tiktok-reel":
|
|
194
|
-
return
|
|
232
|
+
return C;
|
|
195
233
|
default:
|
|
196
|
-
throw new Error(`Invalid video type: ${
|
|
234
|
+
throw new Error(`Invalid video type: ${e}`);
|
|
197
235
|
}
|
|
198
236
|
};
|
|
199
237
|
export {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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.
|
|
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": {
|