@pieda/video-dl 1.10.2 → 1.11.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/useInstagram.d.ts +1 -0
- package/dist/types/composables/useVimeo.d.ts +1 -0
- package/dist/types/composables/useYoutube.d.ts +1 -0
- package/dist/types/composables/useYtdlp.d.ts +3 -3
- package/dist/video-dl.cjs +5 -1
- package/dist/video-dl.js +193 -171
- package/package.json +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
type TUseYtdlp = {
|
|
2
2
|
debug?: boolean;
|
|
3
|
-
|
|
4
|
-
videoUrl: string;
|
|
3
|
+
command: string;
|
|
5
4
|
dest: string;
|
|
6
5
|
tempDir: string;
|
|
7
6
|
ffmpegConfig: {
|
|
7
|
+
ffmpegDir: string;
|
|
8
8
|
ffmpegPath: string;
|
|
9
9
|
ffmpegProbePath: string;
|
|
10
10
|
ffmpegPlayPath: string;
|
|
11
11
|
};
|
|
12
12
|
};
|
|
13
|
-
export declare const useYtdlp: ({ debug,
|
|
13
|
+
export declare const useYtdlp: ({ debug, command, dest, tempDir, ffmpegConfig, }: TUseYtdlp) => Promise<[Error | null, boolean | null]>;
|
|
14
14
|
export {};
|
package/dist/video-dl.cjs
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=(t=!1)=>({log:(...o)=>{t&&console.log(...o)},error:(...o)=>{t&&console.error(...o)}}),u=t=>new Promise((o,a)=>{import(t).then(i=>o(i.default)).catch(a)}),P=async(t,o,a)=>{const i=await u("fs"),e=await u("axios");return console.log(`Downloading ${t} to ${o}`),new Promise((n,c)=>{e.get(t,{responseType:"stream",headers:a}).then(s=>{const l=s.data,g=i.createWriteStream(o);l.pipe(g),g.on("finish",function(){g.close(()=>{n()})})}).catch(c)})},x=async({debug:t=!1,command:o,dest:a,tempDir:i,ffmpegConfig:e})=>{const n=v(t),c=await u("fs"),s=await u("path"),{exec:l,execSync:g}=await u("child_process"),d=()=>new Promise((r,p)=>{n.log(`[yt-dlp] 執行命令: ${o}`),l(o,(w,b,f)=>{if(n.log(`[yt-dlp] stdout: ${b}`),w){p(w);return}r()})});return c.existsSync(s.dirname(a))||(c.mkdirSync(s.dirname(a),{recursive:!0},777),n.log(`建立 ${s.dirname(a)}`)),new Promise(async(r,p)=>{try{await d();let w=!1;const b=c.readdirSync(i);for(const f of b){const h=s.join(i,f),y=`${e.ffmpegProbePath} -v error -show_entries stream=codec_type -of csv=p=0 "${h}"`,m=g(y).toString("utf-8"),$=m.includes("video"),S=m.includes("audio");if($&&S){w=!0,c.copyFileSync(h,a);break}}if(!w)throw new Error("無法下載影音正常的影片");n.log(`下載完成 ${a}`),r([null,!0])}catch(w){n.error(`下載失敗: ${w.message}`),r([w,null])}})},T=async({debug:t=!1,ytdlpPath:o,videoId:a,dest:i,tempDir:e,ffmpegConfig:n})=>{const c=v(t);c.log(`Downloading video: ${a} to: ${i}`);const s=await u("fs"),l=await u("path"),g=await u("puppeteer"),d=`https://www.youtube.com/watch?v=${a}`,r=l.join(l.dirname(o),"cookies.txt"),p=(f=[])=>{const h=["# Netscape HTTP Cookie File","# https://curl.se/docs/http-cookies.html","# This file was generated by Puppeteer",""].join(`
|
|
2
|
+
`),y=f.map(m=>{const $=m.domain.startsWith(".")?m.domain:`.${m.domain}`,S="TRUE",k=m.path||"/",A=m.secure?"TRUE":"FALSE",M=m.expires?Math.floor(m.expires):Math.floor(Date.now()/1e3)+3600*24*365,E=m.name,_=m.value;return[$,S,k,A,M,E,_].join(" ")});return h+`
|
|
3
|
+
`+y.join(`
|
|
4
|
+
`)+`
|
|
5
|
+
`};await(async()=>{const f=l.join(l.dirname(o),"chrome-profile");if(s.existsSync(f)||s.mkdirSync(f,{recursive:!0},777),s.existsSync(r)&&s.statSync(r).mtimeMs+6e5>Date.now()){c.log("Using existing cookies.txt");return}console.log("Launching Chrome…");const h=await g.launch({headless:!1,userDataDir:f,defaultViewport:null,args:["--disable-blink-features=AutomationControlled"]}),y=await h.newPage();await y.goto("https://www.youtube.com",{waitUntil:"networkidle2"}),console.log("If not logged in, please log in manually."),console.log("Waiting 30 seconds…"),await new Promise(k=>setTimeout(k,3e4));const $=(await y.cookies()).filter(k=>k.domain.includes("youtube.com")||k.domain.includes("google.com"));$.length===0&&(console.error("No YouTube cookies found. Are you logged in?"),process.exit(1));const S=p($);s.writeFileSync(r,S,{encoding:"utf8"}),console.log(`cookies.txt written to ${r}`),console.log(`Cookies count: ${$.length}`),await h.close()})();const b=[`${o}`,'-f "bv*[vcodec^=avc1][acodec^=mp4a][height<=1080]/ba/b"',"--js-runtimes node",`${d}`,`-o "${e}/%(id)s.%(ext)s"`,`--cookies ${r}`,n.ffmpegDir?`--ffmpeg-location "${n.ffmpegDir}"`:""];return x({debug:t,command:b.join(" "),dest:i,tempDir:e,ffmpegConfig:n})},U=async({videoId:t,dest:o,debug:a=!1,headless:i=!0})=>{try{const e=v(a);e.log(`Downloading video: ${t} to: ${o}`);const n=`https://m.facebook.com/watch/?v=${t}`,c=await u("fs"),s=await u("path"),l=await u("puppeteer");c.existsSync(s.dirname(o))||(c.mkdirSync(s.dirname(o),{recursive:!0},777),e.log(`建立 ${s.dirname(o)}`));const g={};i||(g.headless=!1);const d=await l.launch(g);e.log("啟動 puppeteer");const r=await d.newPage();await r.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(`前往 ${n}`),await r.goto(n,{waitUntil:"networkidle2"}),await r.waitForSelector("video"),e.log("找到 video 元素");const p=await r.$eval("video",w=>w.getAttribute("src"));return e.log(`取得 video url: ${p}`),await d.close(),e.log("關閉 puppeteer"),await P(p,o),e.log(`下載完成 ${p}`),[null,!0]}catch(e){return[e,null]}},j=async({debug:t=!1,ytdlpPath:o,videoId:a,dest:i,tempDir:e,ffmpegConfig:n})=>{v(t).log(`Downloading video: ${a} to: ${i}`);const s=`https://vimeo.com/${a}`,l=[`${o}`,'-f "bv*[vcodec^=avc1][acodec^=mp4a][height<=1080]/ba/b"',"--js-runtimes node",`${s}`,`-o "${e}/%(id)s.%(ext)s"`];return x({debug:t,command:l.join(" "),dest:i,tempDir:e,ffmpegConfig:n})},D=async({debug:t=!1,ytdlpPath:o,videoId:a,dest:i,tempDir:e,ffmpegConfig:n})=>{v(t).log(`Downloading video: ${a} to: ${i}`);const s=`https://www.instagram.com/reel/${a}/`,l=[`${o}`,"-f mergeall","--audio-multistreams","--video-multistreams","--js-runtimes node",`${s}`,"--downloader ffmpeg",`-o "${e}/%(id)s.%(ext)s"`,"--merge-output-format mp4",n.ffmpegDir?`--ffmpeg-location "${n.ffmpegDir}"`:""];return x({debug:t,command:l.join(" "),dest:i,tempDir:e,ffmpegConfig:n})},F=async({videoLink:t,dest:o,debug:a=!1,headless:i=!0})=>{try{const e=v(a);e.log(`Downloading video: ${t} to: ${o}`);const n=t,c=await u("fs"),s=await u("path"),l=await u("puppeteer");c.existsSync(s.dirname(o))||(c.mkdirSync(s.dirname(o),{recursive:!0},777),e.log(`建立 ${s.dirname(o)}`));const g={};i||(g.headless=!1);const d=await l.launch(g);e.log("啟動 puppeteer");const r=await d.newPage();e.log("開新分頁"),e.log(`前往 ${n}`),await r.goto(n,{waitUntil:"networkidle2"}),await r.waitForSelector("video"),e.log("找到 video 元素");const p=await r.$eval('video source[src^="https://www.tiktok.com/aweme/v1/play/"]',w=>w.getAttribute("src"));return e.log(`取得 video url: ${p}`),await d.close(),e.log("關閉 puppeteer"),await P(p,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/"}),e.log(`下載完成 ${p}`),[null,!0]}catch(e){return[e,null]}},W=({type:t})=>{switch(t){case"youtube":case"yt-short":return T;case"facebook":case"fb-reel":return U;case"vimeo":return j;case"instagram":case"ig":case"ig-reel":return D;case"tiktok":case"tiktok-reel":return F;default:throw new Error(`Invalid video type: ${t}`)}};exports.useDownloader=W;exports.useFacebook=U;exports.useInstagram=D;exports.useTiktok=F;exports.useVimeo=j;exports.useYoutube=T;
|
package/dist/video-dl.js
CHANGED
|
@@ -1,239 +1,261 @@
|
|
|
1
|
-
const
|
|
1
|
+
const v = (t = !1) => ({
|
|
2
2
|
log: (...o) => {
|
|
3
|
-
|
|
3
|
+
t && console.log(...o);
|
|
4
4
|
},
|
|
5
5
|
error: (...o) => {
|
|
6
|
-
|
|
6
|
+
t && console.error(...o);
|
|
7
7
|
}
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
var v, T = new Uint8Array(16);
|
|
16
|
-
function R() {
|
|
17
|
-
if (!v && (v = typeof crypto < "u" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto), !v))
|
|
18
|
-
throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
|
|
19
|
-
return v(T);
|
|
20
|
-
}
|
|
21
|
-
var W = typeof crypto < "u" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
22
|
-
const P = {
|
|
23
|
-
randomUUID: W
|
|
24
|
-
};
|
|
25
|
-
function j(e, o, n) {
|
|
26
|
-
if (P.randomUUID && !o && !e)
|
|
27
|
-
return P.randomUUID();
|
|
28
|
-
e = e || {};
|
|
29
|
-
var r = e.random || (e.rng || R)();
|
|
30
|
-
if (r[6] = r[6] & 15 | 64, r[8] = r[8] & 63 | 128, o) {
|
|
31
|
-
n = n || 0;
|
|
32
|
-
for (var t = 0; t < 16; ++t)
|
|
33
|
-
o[n + t] = r[t];
|
|
34
|
-
return o;
|
|
35
|
-
}
|
|
36
|
-
return V(r);
|
|
37
|
-
}
|
|
38
|
-
const w = (e) => new Promise((o, n) => {
|
|
39
|
-
import(e).then((r) => o(r.default)).catch(n);
|
|
40
|
-
}), b = async (e, o, n) => {
|
|
41
|
-
const r = await w("fs"), t = await w("axios");
|
|
42
|
-
return console.log(`Downloading ${e} to ${o}`), new Promise((s, i) => {
|
|
43
|
-
t.get(e, {
|
|
8
|
+
}), u = (t) => new Promise((o, a) => {
|
|
9
|
+
import(t).then((i) => o(i.default)).catch(a);
|
|
10
|
+
}), U = async (t, o, a) => {
|
|
11
|
+
const i = await u("fs"), e = await u("axios");
|
|
12
|
+
return console.log(`Downloading ${t} to ${o}`), new Promise((s, c) => {
|
|
13
|
+
e.get(t, {
|
|
44
14
|
responseType: "stream",
|
|
45
|
-
headers:
|
|
46
|
-
}).then((
|
|
47
|
-
const
|
|
48
|
-
|
|
15
|
+
headers: a
|
|
16
|
+
}).then((n) => {
|
|
17
|
+
const l = n.data, g = i.createWriteStream(o);
|
|
18
|
+
l.pipe(g), g.on("finish", function() {
|
|
49
19
|
g.close(() => {
|
|
50
20
|
s();
|
|
51
21
|
});
|
|
52
22
|
});
|
|
53
|
-
}).catch(
|
|
23
|
+
}).catch(c);
|
|
54
24
|
});
|
|
55
|
-
},
|
|
56
|
-
debug:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
ffmpegConfig: s
|
|
25
|
+
}, x = async ({
|
|
26
|
+
debug: t = !1,
|
|
27
|
+
command: o,
|
|
28
|
+
dest: a,
|
|
29
|
+
tempDir: i,
|
|
30
|
+
ffmpegConfig: e
|
|
62
31
|
}) => {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
i.log(`[yt-dlp] 執行命令: ${m}`), g(m, ($, f, k) => {
|
|
68
|
-
if (i.log(`[yt-dlp] stdout: ${f}`), $) {
|
|
69
|
-
x($);
|
|
32
|
+
const s = v(t), c = await u("fs"), n = await u("path"), { exec: l, execSync: g } = await u("child_process"), d = () => new Promise((r, m) => {
|
|
33
|
+
s.log(`[yt-dlp] 執行命令: ${o}`), l(o, (w, b, f) => {
|
|
34
|
+
if (s.log(`[yt-dlp] stdout: ${b}`), w) {
|
|
35
|
+
m(w);
|
|
70
36
|
return;
|
|
71
37
|
}
|
|
72
|
-
|
|
38
|
+
r();
|
|
73
39
|
});
|
|
74
40
|
});
|
|
75
|
-
return
|
|
41
|
+
return c.existsSync(n.dirname(a)) || (c.mkdirSync(n.dirname(a), { recursive: !0 }, 777), s.log(`建立 ${n.dirname(a)}`)), new Promise(async (r, m) => {
|
|
76
42
|
try {
|
|
77
|
-
await
|
|
78
|
-
let
|
|
79
|
-
const
|
|
80
|
-
for (const f of
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
|
|
43
|
+
await d();
|
|
44
|
+
let w = !1;
|
|
45
|
+
const b = c.readdirSync(i);
|
|
46
|
+
for (const f of b) {
|
|
47
|
+
const h = n.join(i, f), y = `${e.ffmpegProbePath} -v error -show_entries stream=codec_type -of csv=p=0 "${h}"`, p = g(y).toString("utf-8"), $ = p.includes("video"), S = p.includes("audio");
|
|
48
|
+
if ($ && S) {
|
|
49
|
+
w = !0, c.copyFileSync(h, a);
|
|
84
50
|
break;
|
|
85
51
|
}
|
|
86
52
|
}
|
|
87
|
-
if (!
|
|
53
|
+
if (!w)
|
|
88
54
|
throw new Error("無法下載影音正常的影片");
|
|
89
|
-
|
|
90
|
-
} catch (
|
|
91
|
-
|
|
55
|
+
s.log(`下載完成 ${a}`), r([null, !0]);
|
|
56
|
+
} catch (w) {
|
|
57
|
+
s.error(`下載失敗: ${w.message}`), r([w, null]);
|
|
92
58
|
}
|
|
93
59
|
});
|
|
94
|
-
},
|
|
95
|
-
debug:
|
|
60
|
+
}, D = async ({
|
|
61
|
+
debug: t = !1,
|
|
96
62
|
ytdlpPath: o,
|
|
97
|
-
videoId:
|
|
98
|
-
dest:
|
|
99
|
-
tempDir:
|
|
63
|
+
videoId: a,
|
|
64
|
+
dest: i,
|
|
65
|
+
tempDir: e,
|
|
100
66
|
ffmpegConfig: s
|
|
101
67
|
}) => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
68
|
+
const c = v(t);
|
|
69
|
+
c.log(`Downloading video: ${a} to: ${i}`);
|
|
70
|
+
const n = await u("fs"), l = await u("path"), g = await u("puppeteer"), d = `https://www.youtube.com/watch?v=${a}`, r = l.join(l.dirname(o), "cookies.txt"), m = (f = []) => {
|
|
71
|
+
const h = [
|
|
72
|
+
"# Netscape HTTP Cookie File",
|
|
73
|
+
"# https://curl.se/docs/http-cookies.html",
|
|
74
|
+
"# This file was generated by Puppeteer",
|
|
75
|
+
""
|
|
76
|
+
].join(`
|
|
77
|
+
`), y = f.map((p) => {
|
|
78
|
+
const $ = p.domain.startsWith(".") ? p.domain : `.${p.domain}`, S = "TRUE", k = p.path || "/", A = p.secure ? "TRUE" : "FALSE", P = p.expires ? Math.floor(p.expires) : Math.floor(Date.now() / 1e3) + 3600 * 24 * 365, T = p.name, j = p.value;
|
|
79
|
+
return [$, S, k, A, P, T, j].join(" ");
|
|
80
|
+
});
|
|
81
|
+
return h + `
|
|
82
|
+
` + y.join(`
|
|
83
|
+
`) + `
|
|
84
|
+
`;
|
|
85
|
+
};
|
|
86
|
+
await (async () => {
|
|
87
|
+
const f = l.join(l.dirname(o), "chrome-profile");
|
|
88
|
+
if (n.existsSync(f) || n.mkdirSync(f, { recursive: !0 }, 777), n.existsSync(r) && n.statSync(r).mtimeMs + 6e5 > Date.now()) {
|
|
89
|
+
c.log("Using existing cookies.txt");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.log("Launching Chrome…");
|
|
93
|
+
const h = await g.launch({
|
|
94
|
+
headless: !1,
|
|
95
|
+
// 必須 false
|
|
96
|
+
userDataDir: f,
|
|
97
|
+
// 關鍵
|
|
98
|
+
defaultViewport: null,
|
|
99
|
+
args: ["--disable-blink-features=AutomationControlled"]
|
|
100
|
+
}), y = await h.newPage();
|
|
101
|
+
await y.goto("https://www.youtube.com", {
|
|
102
|
+
waitUntil: "networkidle2"
|
|
103
|
+
}), console.log("If not logged in, please log in manually."), console.log("Waiting 30 seconds…"), await new Promise((k) => setTimeout(k, 3e4));
|
|
104
|
+
const $ = (await y.cookies()).filter((k) => k.domain.includes("youtube.com") || k.domain.includes("google.com"));
|
|
105
|
+
$.length === 0 && (console.error("No YouTube cookies found. Are you logged in?"), process.exit(1));
|
|
106
|
+
const S = m($);
|
|
107
|
+
n.writeFileSync(r, S, { encoding: "utf8" }), console.log(`cookies.txt written to ${r}`), console.log(`Cookies count: ${$.length}`), await h.close();
|
|
108
|
+
})();
|
|
109
|
+
const b = [
|
|
110
|
+
`${o}`,
|
|
111
|
+
'-f "bv*[vcodec^=avc1][acodec^=mp4a][height<=1080]/ba/b"',
|
|
112
|
+
"--js-runtimes node",
|
|
113
|
+
`${d}`,
|
|
114
|
+
`-o "${e}/%(id)s.%(ext)s"`,
|
|
115
|
+
`--cookies ${r}`,
|
|
116
|
+
s.ffmpegDir ? `--ffmpeg-location "${s.ffmpegDir}"` : ""
|
|
117
|
+
];
|
|
118
|
+
return x({
|
|
119
|
+
debug: t,
|
|
120
|
+
command: b.join(" "),
|
|
121
|
+
dest: i,
|
|
122
|
+
tempDir: e,
|
|
110
123
|
ffmpegConfig: s
|
|
111
124
|
});
|
|
112
|
-
},
|
|
113
|
-
videoId:
|
|
125
|
+
}, F = async ({
|
|
126
|
+
videoId: t,
|
|
114
127
|
dest: o,
|
|
115
|
-
debug:
|
|
116
|
-
headless:
|
|
128
|
+
debug: a = !1,
|
|
129
|
+
headless: i = !0
|
|
117
130
|
}) => {
|
|
118
131
|
try {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
const s = `https://m.facebook.com/watch/?v=${
|
|
122
|
-
|
|
132
|
+
const e = v(a);
|
|
133
|
+
e.log(`Downloading video: ${t} to: ${o}`);
|
|
134
|
+
const s = `https://m.facebook.com/watch/?v=${t}`, c = await u("fs"), n = await u("path"), l = await u("puppeteer");
|
|
135
|
+
c.existsSync(n.dirname(o)) || (c.mkdirSync(n.dirname(o), { recursive: !0 }, 777), e.log(`建立 ${n.dirname(o)}`));
|
|
123
136
|
const g = {};
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
await
|
|
137
|
+
i || (g.headless = !1);
|
|
138
|
+
const d = await l.launch(g);
|
|
139
|
+
e.log("啟動 puppeteer");
|
|
140
|
+
const r = await d.newPage();
|
|
141
|
+
await r.setUserAgent(
|
|
129
142
|
"'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'"
|
|
130
|
-
),
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return t.log(`取得 video url: ${p}`), await y.close(), t.log("關閉 puppeteer"), await b(p, o), t.log(`下載完成 ${p}`), [null, !0];
|
|
138
|
-
} catch (t) {
|
|
139
|
-
return [t, null];
|
|
143
|
+
), e.log("開新分頁"), e.log(`前往 ${s}`), await r.goto(s, {
|
|
144
|
+
waitUntil: "networkidle2"
|
|
145
|
+
}), await r.waitForSelector("video"), e.log("找到 video 元素");
|
|
146
|
+
const m = await r.$eval("video", (w) => w.getAttribute("src"));
|
|
147
|
+
return e.log(`取得 video url: ${m}`), await d.close(), e.log("關閉 puppeteer"), await U(m, o), e.log(`下載完成 ${m}`), [null, !0];
|
|
148
|
+
} catch (e) {
|
|
149
|
+
return [e, null];
|
|
140
150
|
}
|
|
141
|
-
},
|
|
142
|
-
debug:
|
|
151
|
+
}, M = async ({
|
|
152
|
+
debug: t = !1,
|
|
143
153
|
ytdlpPath: o,
|
|
144
|
-
videoId:
|
|
145
|
-
dest:
|
|
146
|
-
tempDir:
|
|
154
|
+
videoId: a,
|
|
155
|
+
dest: i,
|
|
156
|
+
tempDir: e,
|
|
147
157
|
ffmpegConfig: s
|
|
148
158
|
}) => {
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
159
|
+
v(t).log(`Downloading video: ${a} to: ${i}`);
|
|
160
|
+
const n = `https://vimeo.com/${a}`, l = [
|
|
161
|
+
`${o}`,
|
|
162
|
+
'-f "bv*[vcodec^=avc1][acodec^=mp4a][height<=1080]/ba/b"',
|
|
163
|
+
"--js-runtimes node",
|
|
164
|
+
`${n}`,
|
|
165
|
+
`-o "${e}/%(id)s.%(ext)s"`
|
|
166
|
+
];
|
|
167
|
+
return x({
|
|
168
|
+
debug: t,
|
|
169
|
+
command: l.join(" "),
|
|
170
|
+
dest: i,
|
|
171
|
+
tempDir: e,
|
|
157
172
|
ffmpegConfig: s
|
|
158
173
|
});
|
|
159
|
-
},
|
|
160
|
-
debug:
|
|
174
|
+
}, E = async ({
|
|
175
|
+
debug: t = !1,
|
|
161
176
|
ytdlpPath: o,
|
|
162
|
-
videoId:
|
|
163
|
-
dest:
|
|
164
|
-
tempDir:
|
|
177
|
+
videoId: a,
|
|
178
|
+
dest: i,
|
|
179
|
+
tempDir: e,
|
|
165
180
|
ffmpegConfig: s
|
|
166
181
|
}) => {
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
v(t).log(`Downloading video: ${a} to: ${i}`);
|
|
183
|
+
const n = `https://www.instagram.com/reel/${a}/`, l = [
|
|
184
|
+
`${o}`,
|
|
185
|
+
"-f mergeall",
|
|
186
|
+
"--audio-multistreams",
|
|
187
|
+
"--video-multistreams",
|
|
188
|
+
"--js-runtimes node",
|
|
189
|
+
`${n}`,
|
|
190
|
+
"--downloader ffmpeg",
|
|
191
|
+
`-o "${e}/%(id)s.%(ext)s"`,
|
|
192
|
+
"--merge-output-format mp4",
|
|
193
|
+
s.ffmpegDir ? `--ffmpeg-location "${s.ffmpegDir}"` : ""
|
|
194
|
+
];
|
|
195
|
+
return x({
|
|
196
|
+
debug: t,
|
|
197
|
+
command: l.join(" "),
|
|
198
|
+
dest: i,
|
|
199
|
+
tempDir: e,
|
|
175
200
|
ffmpegConfig: s
|
|
176
201
|
});
|
|
177
|
-
},
|
|
178
|
-
videoLink:
|
|
202
|
+
}, _ = async ({
|
|
203
|
+
videoLink: t,
|
|
179
204
|
dest: o,
|
|
180
|
-
debug:
|
|
181
|
-
headless:
|
|
205
|
+
debug: a = !1,
|
|
206
|
+
headless: i = !0
|
|
182
207
|
}) => {
|
|
183
208
|
try {
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
const s =
|
|
187
|
-
|
|
209
|
+
const e = v(a);
|
|
210
|
+
e.log(`Downloading video: ${t} to: ${o}`);
|
|
211
|
+
const s = t, c = await u("fs"), n = await u("path"), l = await u("puppeteer");
|
|
212
|
+
c.existsSync(n.dirname(o)) || (c.mkdirSync(n.dirname(o), { recursive: !0 }, 777), e.log(`建立 ${n.dirname(o)}`));
|
|
188
213
|
const g = {};
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
l.waitForSelector("video")
|
|
198
|
-
]), t.log("找到 video 元素");
|
|
199
|
-
const p = await l.$eval(
|
|
214
|
+
i || (g.headless = !1);
|
|
215
|
+
const d = await l.launch(g);
|
|
216
|
+
e.log("啟動 puppeteer");
|
|
217
|
+
const r = await d.newPage();
|
|
218
|
+
e.log("開新分頁"), e.log(`前往 ${s}`), await r.goto(s, {
|
|
219
|
+
waitUntil: "networkidle2"
|
|
220
|
+
}), await r.waitForSelector("video"), e.log("找到 video 元素");
|
|
221
|
+
const m = await r.$eval(
|
|
200
222
|
'video source[src^="https://www.tiktok.com/aweme/v1/play/"]',
|
|
201
|
-
(
|
|
223
|
+
(w) => w.getAttribute("src")
|
|
202
224
|
);
|
|
203
|
-
return
|
|
225
|
+
return e.log(`取得 video url: ${m}`), await d.close(), e.log("關閉 puppeteer"), await U(m, o, {
|
|
204
226
|
"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",
|
|
205
227
|
Referer: "https://www.tiktok.com/"
|
|
206
228
|
// 設定 Referer
|
|
207
|
-
}),
|
|
208
|
-
} catch (
|
|
209
|
-
return [
|
|
229
|
+
}), e.log(`下載完成 ${m}`), [null, !0];
|
|
230
|
+
} catch (e) {
|
|
231
|
+
return [e, null];
|
|
210
232
|
}
|
|
211
|
-
},
|
|
212
|
-
switch (
|
|
233
|
+
}, W = ({ type: t }) => {
|
|
234
|
+
switch (t) {
|
|
213
235
|
case "youtube":
|
|
214
236
|
case "yt-short":
|
|
215
|
-
return
|
|
237
|
+
return D;
|
|
216
238
|
case "facebook":
|
|
217
239
|
case "fb-reel":
|
|
218
|
-
return
|
|
240
|
+
return F;
|
|
219
241
|
case "vimeo":
|
|
220
|
-
return
|
|
242
|
+
return M;
|
|
221
243
|
case "instagram":
|
|
222
244
|
case "ig":
|
|
223
245
|
case "ig-reel":
|
|
224
|
-
return
|
|
246
|
+
return E;
|
|
225
247
|
case "tiktok":
|
|
226
248
|
case "tiktok-reel":
|
|
227
|
-
return
|
|
249
|
+
return _;
|
|
228
250
|
default:
|
|
229
|
-
throw new Error(`Invalid video type: ${
|
|
251
|
+
throw new Error(`Invalid video type: ${t}`);
|
|
230
252
|
}
|
|
231
253
|
};
|
|
232
254
|
export {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
255
|
+
W as useDownloader,
|
|
256
|
+
F as useFacebook,
|
|
257
|
+
E as useInstagram,
|
|
258
|
+
_ as useTiktok,
|
|
259
|
+
M as useVimeo,
|
|
260
|
+
D as useYoutube
|
|
239
261
|
};
|