@pieda/video-dl 1.8.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 +9 -3
- 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 +193 -154
- package/package.json +2 -1
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
type TUseInstagram = {
|
|
2
|
+
debug?: boolean;
|
|
3
|
+
ytdlpPath: string;
|
|
2
4
|
videoId: string;
|
|
3
5
|
dest: string;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
tempDir: string;
|
|
7
|
+
ffmpegConfig: {
|
|
8
|
+
ffmpegPath: string;
|
|
9
|
+
ffmpegProbePath: string;
|
|
10
|
+
ffmpegPlayPath: string;
|
|
11
|
+
};
|
|
6
12
|
};
|
|
7
|
-
export declare const useInstagram: ({ 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,205 +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
|
-
}), v = async ({
|
|
26
|
-
ytdlpPath: r,
|
|
27
|
-
videoId: o,
|
|
28
|
-
dest: a,
|
|
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
|
-
},
|
|
99
|
+
}, _ = async ({
|
|
100
|
+
debug: e = !1,
|
|
101
|
+
ytdlpPath: o,
|
|
56
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,
|
|
57
119
|
dest: o,
|
|
58
|
-
debug:
|
|
59
|
-
headless:
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
146
|
+
}, I = async ({
|
|
147
|
+
debug: e = !1,
|
|
148
|
+
ytdlpPath: o,
|
|
149
|
+
videoId: r,
|
|
150
|
+
dest: n,
|
|
151
|
+
tempDir: t,
|
|
152
|
+
ffmpegConfig: a
|
|
89
153
|
}) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
g(h);
|
|
100
|
-
});
|
|
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
|
|
101
163
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (!t)
|
|
106
|
-
throw new Error("無法取得 videoUrl");
|
|
107
|
-
e.log(`取得 videoUrl ${t}`), await f(t, a).catch((i) => {
|
|
108
|
-
throw e.error(`下載失敗: ${i.message}`), i;
|
|
109
|
-
}), e.log(`下載完成 ${a}`), n([null, !0]);
|
|
110
|
-
} catch (t) {
|
|
111
|
-
e.error(`下載失敗: ${t.message}`), n([t, null]);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
}, S = async ({
|
|
164
|
+
}, K = async ({
|
|
165
|
+
debug: e = !1,
|
|
166
|
+
ytdlpPath: o,
|
|
115
167
|
videoId: r,
|
|
116
|
-
dest:
|
|
117
|
-
|
|
118
|
-
|
|
168
|
+
dest: n,
|
|
169
|
+
tempDir: t,
|
|
170
|
+
ffmpegConfig: a
|
|
119
171
|
}) => {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
), e.log("開新分頁"), e.log(`前往 ${w}`), await Promise.race([
|
|
133
|
-
t.goto(w, {
|
|
134
|
-
waitUntil: "networkidle0"
|
|
135
|
-
}),
|
|
136
|
-
t.waitForSelector("video")
|
|
137
|
-
]), e.log("找到 video 元素");
|
|
138
|
-
const i = await t.$eval("video", (m) => m.getAttribute("src"));
|
|
139
|
-
return e.log(`取得 video url: ${i}`), await g.close(), e.log("關閉 puppeteer"), await f(i, o), e.log(`下載完成 ${i}`), [null, !0];
|
|
140
|
-
} catch (e) {
|
|
141
|
-
return [e, null];
|
|
142
|
-
}
|
|
143
|
-
}, b = async ({
|
|
144
|
-
videoLink: r,
|
|
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
|
|
181
|
+
});
|
|
182
|
+
}, C = async ({
|
|
183
|
+
videoLink: e,
|
|
145
184
|
dest: o,
|
|
146
|
-
debug:
|
|
147
|
-
headless:
|
|
185
|
+
debug: r = !1,
|
|
186
|
+
headless: n = !0
|
|
148
187
|
}) => {
|
|
149
188
|
try {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
c.existsSync(
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
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, {
|
|
161
200
|
waitUntil: "networkidle0"
|
|
162
201
|
}),
|
|
163
|
-
|
|
164
|
-
]),
|
|
165
|
-
const
|
|
202
|
+
l.waitForSelector("video")
|
|
203
|
+
]), t.log("找到 video 元素");
|
|
204
|
+
const d = await l.$eval(
|
|
166
205
|
'video source[src^="https://www.tiktok.com/aweme/v1/play/"]',
|
|
167
|
-
(
|
|
206
|
+
(p) => p.getAttribute("src")
|
|
168
207
|
);
|
|
169
|
-
return
|
|
208
|
+
return t.log(`取得 video url: ${d}`), await h.close(), t.log("關閉 puppeteer"), await D(d, o, {
|
|
170
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",
|
|
171
210
|
Referer: "https://www.tiktok.com/"
|
|
172
211
|
// 設定 Referer
|
|
173
|
-
}),
|
|
174
|
-
} catch (
|
|
175
|
-
return [
|
|
212
|
+
}), t.log(`下載完成 ${d}`), [null, !0];
|
|
213
|
+
} catch (t) {
|
|
214
|
+
return [t, null];
|
|
176
215
|
}
|
|
177
|
-
},
|
|
178
|
-
switch (
|
|
216
|
+
}, H = ({ type: e }) => {
|
|
217
|
+
switch (e) {
|
|
179
218
|
case "youtube":
|
|
180
219
|
case "yt-short":
|
|
181
|
-
return
|
|
220
|
+
return _;
|
|
182
221
|
case "facebook":
|
|
183
222
|
case "fb-reel":
|
|
184
|
-
return
|
|
223
|
+
return j;
|
|
185
224
|
case "vimeo":
|
|
186
|
-
return
|
|
225
|
+
return I;
|
|
187
226
|
case "instagram":
|
|
188
227
|
case "ig":
|
|
189
228
|
case "ig-reel":
|
|
190
|
-
return
|
|
229
|
+
return K;
|
|
191
230
|
case "tiktok":
|
|
192
231
|
case "tiktok-reel":
|
|
193
|
-
return
|
|
232
|
+
return C;
|
|
194
233
|
default:
|
|
195
|
-
throw new Error(`Invalid video type: ${
|
|
234
|
+
throw new Error(`Invalid video type: ${e}`);
|
|
196
235
|
}
|
|
197
236
|
};
|
|
198
237
|
export {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
238
|
+
H as useDownloader,
|
|
239
|
+
j as useFacebook,
|
|
240
|
+
K as useInstagram,
|
|
241
|
+
C as useTiktok,
|
|
242
|
+
I as useVimeo,
|
|
243
|
+
_ as useYoutube
|
|
205
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": {
|