fast-dirpy 0.3.9 → 1.0.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/README.md +23 -42
- package/dist/cli.mjs +1 -1
- package/dist/{config-COA6iekn.d.mts → config-pHnrv5F6.d.mts} +8 -5
- package/dist/config.d.mts +1 -1
- package/dist/index.d.mts +65 -16
- package/dist/index.mjs +1 -1
- package/dist/judgeUrl-f5ejW-iH.mjs +1 -0
- package/package.json +12 -12
- package/dist/judgeUrl-C8A0NXW8.mjs +0 -3
package/README.md
CHANGED
|
@@ -19,25 +19,23 @@ A simple library/CLI to download youtube(etc.) videos.
|
|
|
19
19
|
<details>
|
|
20
20
|
<summary>NSFW</summary>
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
- [Animehentai](https://animeidhentai.com/)
|
|
23
|
+
- [Koreanpornmovies](https://koreanpornmovie.com/)
|
|
24
|
+
- [XVideos](https://www.xvideos.com/)
|
|
25
|
+
- [Hanime1.me](https://hanime1.me/)
|
|
26
|
+
- [wow.xxx](https://www.wow.xxx/)
|
|
27
|
+
- [xhamster](https://xhamster.com/) (m3u8, retry if error)
|
|
28
|
+
- [rule34.xyz](https://rule34.xyz/) (anime style)
|
|
28
29
|
</details>
|
|
29
30
|
|
|
30
31
|
And `.m3u8` videos.
|
|
31
32
|
|
|
32
|
-
> [!IMPORTANT]
|
|
33
|
-
> From v0.3.0, .m3u8 downloader is no longer using ffmpeg.
|
|
34
|
-
> And it doesn't provide proxy settings, so, you need to use `export https_proxy=http://ip:port` to set proxy manually in terminal.
|
|
35
|
-
|
|
36
33
|
You can use this [userscript](https://greasyfork.org/zh-CN/scripts/449581-m3u8%E8%A7%86%E9%A2%91%E4%BE%A6%E6%B5%8B%E4%B8%8B%E8%BD%BD%E5%99%A8-%E8%87%AA%E5%8A%A8%E5%97%85%E6%8E%A2) to extract `.m3u8` sources from websites.
|
|
37
34
|
|
|
38
35
|
## Installation
|
|
39
36
|
|
|
40
37
|
### As a library
|
|
38
|
+
|
|
41
39
|
```shell
|
|
42
40
|
npm i fast-dirpy
|
|
43
41
|
|
|
@@ -46,14 +44,11 @@ deno add jsr:@vince-g/fast-dirpy
|
|
|
46
44
|
```
|
|
47
45
|
|
|
48
46
|
### As a **command line tool**
|
|
47
|
+
|
|
49
48
|
```shell
|
|
50
49
|
npm i fast-dirpy -g
|
|
51
50
|
```
|
|
52
51
|
|
|
53
|
-
### Additional: download `ffmpeg`
|
|
54
|
-
|
|
55
|
-
https://www.ffmpeg.org/download.html
|
|
56
|
-
|
|
57
52
|
## Usage
|
|
58
53
|
|
|
59
54
|
### Config file
|
|
@@ -97,7 +92,7 @@ export default defineConfig({
|
|
|
97
92
|
# -c, --config: Specified external config file.
|
|
98
93
|
# e.g.: fast-dirpy get https://xxx -c ~/Downloads/fast-dirpy.config.json
|
|
99
94
|
# --chromePath: Path to your Google Chrome browser.
|
|
100
|
-
fast-dirpy get https
|
|
95
|
+
fast-dirpy get https://www.youtube.com/watch?v=6c28qWDMPBA -H 127.0.0.1 -P 7890
|
|
101
96
|
|
|
102
97
|
# Bilibili source doesn't need any proxy, so it's disabled by default.
|
|
103
98
|
fast-dirpy get https://www.bilibili.com/video/BV1TSPeeGE35
|
|
@@ -112,35 +107,29 @@ fast-dirpy get https\://www.youtube.com/watch\?v\=6c28qWDMPBA
|
|
|
112
107
|
#### Download Video
|
|
113
108
|
|
|
114
109
|
> [!IMPORTANT]
|
|
110
|
+
>
|
|
115
111
|
> 1. Some website listed in [Supported Websites](#supported-websites) requires Google Chrome installed for Puppeteer use. You have to use a config file or give parameter of puppeteer executable path.
|
|
116
|
-
> 2.
|
|
112
|
+
> 2. You can download multiple videos in parallel at version `v1.0.0` and above.
|
|
117
113
|
|
|
118
114
|
```shell
|
|
119
|
-
# get video direct link
|
|
120
|
-
# Path: --path, -p: Downloaded video save path.
|
|
121
|
-
#
|
|
122
115
|
# Proxy:
|
|
123
116
|
# -H, --proxyHost: proxy host.
|
|
124
117
|
# -P, --proxyPort: proxy port.
|
|
125
118
|
# -c, --config: Specified external config file.
|
|
126
119
|
# e.g.: fast-dirpy get https://xxx -c ~/Downloads/fast-dirpy.config.json
|
|
127
120
|
# --chromePath: Path to your Google Chrome browser.
|
|
128
|
-
fast-dirpy download https\://www.youtube.com/watch\?v\=6c28qWDMPBA -p ./test.mp4 -H 127.0.0.1 -P 7890
|
|
129
|
-
|
|
130
|
-
# Bilibili source doesn't need any proxy, so it's disabled by default.
|
|
131
|
-
fast-dirpy download https\://www.bilibili.com/video/BV1TSPeeGE35 -p ./test.mp4
|
|
132
121
|
|
|
133
|
-
|
|
134
|
-
fast-dirpy download https\://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8 -p ./test.mp4
|
|
122
|
+
fast-dirpy download --json '[{"url": "https://www.bilibili.com/video/BV1uEAWzuEHC","path": "./cmd-test.mp4"}]' -H 127.0.0.1 -P 7890
|
|
135
123
|
|
|
136
|
-
|
|
137
|
-
fast-dirpy download http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 -p ./big_buck_bunny.mp4
|
|
124
|
+
fast-dirpy download --jsonFile ./test/params.json -H 127.0.0.1 -P 7890
|
|
138
125
|
```
|
|
139
126
|
|
|
140
127
|
if you have set your proxy config in `fast-dirpy.config.ts`, you can omit proxy parameters:
|
|
141
128
|
|
|
142
129
|
```shell
|
|
143
|
-
fast-dirpy download
|
|
130
|
+
fast-dirpy download --jsonFile ./test/params.json
|
|
131
|
+
|
|
132
|
+
fast-dirpy download --json '[{"url": "https://www.bilibili.com/video/BV1uEAWzuEHC","path": "./cmd-test.mp4"}]'
|
|
144
133
|
```
|
|
145
134
|
|
|
146
135
|
For further CLI help:
|
|
@@ -150,6 +139,10 @@ fast-dirpy --help
|
|
|
150
139
|
```
|
|
151
140
|
|
|
152
141
|
### Use as a library
|
|
142
|
+
|
|
143
|
+
> [!IMPORTANT]
|
|
144
|
+
> You can download multiple videos in parallel at version `v1.0.0` and above.
|
|
145
|
+
|
|
153
146
|
```ts
|
|
154
147
|
import { fastLink, fastDownload, remoteM3U8ToMP4, downloadVideo } from 'fast-dirpy'
|
|
155
148
|
|
|
@@ -166,27 +159,15 @@ const link = await fastLink(
|
|
|
166
159
|
)
|
|
167
160
|
|
|
168
161
|
// download video
|
|
169
|
-
await fastDownload({
|
|
162
|
+
await fastDownload([{
|
|
170
163
|
url: '<url>',
|
|
171
164
|
path: './download.mp4',
|
|
172
165
|
cwd: '/path/to/external-config', // Optional: You can specify an external config file.
|
|
173
|
-
},
|
|
166
|
+
}],
|
|
174
167
|
// options (Optional, can be omitted if you have a config file, this will overwrites your config file options.)
|
|
175
168
|
{
|
|
176
169
|
proxy: { ... }
|
|
177
170
|
})
|
|
178
|
-
|
|
179
|
-
// Download `.m3u8` video
|
|
180
|
-
await remoteM3U8ToMP4({
|
|
181
|
-
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
|
|
182
|
-
path: './test.mp4',
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
// Download `.mp4` video
|
|
186
|
-
await downloadVideo({
|
|
187
|
-
url: 'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4',
|
|
188
|
-
path: "./big_buck_bunny.mp4"
|
|
189
|
-
})
|
|
190
171
|
```
|
|
191
172
|
|
|
192
173
|
## Test
|
package/dist/cli.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{C as e,
|
|
1
|
+
import{C as e,D as t,O as n,_ as r,a as i,b as a,c as o,d as s,g as c,h as l,i as u,l as d,m as f,n as p,o as m,p as h,r as g,t as _,u as v,v as y,w as b}from"./judgeUrl-f5ejW-iH.mjs";import{bold as x,dim as S}from"ansis";import{cac as C}from"cac";import w from"restore-cursor";import T from"fs/promises";const E=C(`fast-dirpy`),{version:D}=t;E.command(`get <url>`,`get video direct link.`).option(`--proxyHost, -H <proxyHost>`,`Proxy host.`).option(`--proxyPort, -P <proxyPort>`,`Proxy port.`).option(`--config, -c <path>`,`Specify an external config file.`).option(`--silent`,`Suppress non-error logs`).option(`--chromePath`,`Path to your Google Chrome browser`).action(async(t,n)=>{let r=_(t),{proxyHost:i,proxyPort:a,config:o,silent:s,chromePath:l}=n,d=i?{proxy:{host:i,port:a}}:void 0,h=l?{puppeteer:{executablePath:l}}:void 0;if(b(!!s),e.info(`fast-dirpy ${S(`v${D}`)} : ${x(`Direct Link Getter`)}.`),r===p.AnimeIdHentai){e.info(`Matched link source: Animeidhentai.`);let n=await y({url:t,cwd:o},{...d,...h});console.log(n)}else if(r===p.KoreanPM){e.info(`Matched link source: KoreanPM.`);let n=await v({url:t,cwd:o},d);console.log(n)}else if(r===p.Wowxxx){e.info(`Matched link source: Wowxxx.`);let n=await m({url:t,cwd:o},d);console.log(n)}else if(r===p.XHamster){e.info(`Matched link source: XHamster.`);let n=await u({url:t,cwd:o},d);console.log(n)}else if(r===p.Bilibili){if(e.info(`Matched link source: Bilibili.`),!t.includes(`bilibili.com`)){e.error(`Please provide a valid Bilibili URL.`);return}let n=c(t);console.log(n)}else if(r===p.Dirpy){e.info(`Matched link source: Dirpy.`);let n=await f({url:t,cwd:o},d);console.log(n)}else e.error(`Your link is not supported!`)}),E.command(`download`,`download a video.`).option(`--json, -j <json>`,`JSON download params.`).option(`--jsonFile, -F <jsonFile>`,`Path to a JSON file containing download params.`).option(`--proxyHost, -H <proxyHost>`,`Proxy host.`).option(`--proxyPort, -P <proxyPort>`,`Proxy port.`).option(`--config, -c <path>`,`Specify an external config file.`).option(`--silent`,`Suppress non-error logs`).option(`--chromePath`,`Path to your Google Chrome browser`).action(async t=>{let{json:n,jsonFile:c}=t;if(!n&&!c){e.error(`No JSON params provided.`);return}let u=await(async(e,t)=>{if(e)return JSON.parse(e);if(t){let e=await T.readFile(t,`utf-8`);return JSON.parse(e)}})(n,c);if(Array.isArray(u)||(u=[u]),u.length<1){e.error(`No params provided.`);return}let{proxyHost:f,proxyPort:m,config:v,silent:y,chromePath:C}=t,w=f?{proxy:{host:f,port:m}}:void 0,E=C?{puppeteer:{executablePath:C}}:void 0;b(!!y),e.info(`fast-dirpy ${S(`v${D}`)} : ${x(`Video Downloader`)}.`);for(let e of u)e.urlType=_(e.url),e.cwd=v;let O=u.filter(e=>e.urlType===p.Bilibili),k=u.filter(e=>e.urlType===p.AnimeIdHentai),A=u.filter(e=>e.urlType===p.KoreanPM),j=u.filter(e=>e.urlType===p.Hanime),M=u.filter(e=>e.urlType===p.Wowxxx),N=u.filter(e=>e.urlType===p.XHamster),P=u.filter(e=>e.urlType===p.Dirpy),F=u.filter(e=>e.urlType===p.MP4),I=u.filter(e=>e.urlType===p.M3U8);O.length>0&&await l(O),k.length>0&&await r(k,{...w,...E}),A.length>0&&await d(A,{...w,...E}),j.length>0&&await s(j,{...w,...E}),M.length>0&&await i(M,{...w,...E}),N.length>0&&await g(N,{...w,...E}),P.length>0&&await h(P,{...w,...E}),F.length>0&&await a(F,{...w,...E}),I.length>0&&await o(I,{...w,...E})}),E.help(),E.version(n),E.parse(),w();export{};
|
|
@@ -20,9 +20,12 @@ interface DownloadParams {
|
|
|
20
20
|
url: string;
|
|
21
21
|
path?: string;
|
|
22
22
|
cwd?: string;
|
|
23
|
+
urlType?: UrlType;
|
|
23
24
|
}
|
|
24
25
|
type M3U8Params = DownloadParams & {
|
|
25
|
-
ffmpegPath
|
|
26
|
+
ffmpegPath?: string;
|
|
27
|
+
concurrency?: number;
|
|
28
|
+
retries?: number;
|
|
26
29
|
};
|
|
27
30
|
declare enum UrlType {
|
|
28
31
|
Bilibili = 0,
|
|
@@ -30,10 +33,10 @@ declare enum UrlType {
|
|
|
30
33
|
Dirpy = 2,
|
|
31
34
|
M3U8 = 3,
|
|
32
35
|
KoreanPM = 4,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
MP4 = 8
|
|
36
|
+
Hanime = 5,
|
|
37
|
+
Wowxxx = 6,
|
|
38
|
+
XHamster = 7,
|
|
39
|
+
MP4 = 8
|
|
37
40
|
}
|
|
38
41
|
//#endregion
|
|
39
42
|
//#region src/config.d.ts
|
package/dist/config.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as defineConfig } from "./config-
|
|
1
|
+
import { t as defineConfig } from "./config-pHnrv5F6.mjs";
|
|
2
2
|
export { defineConfig };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as Options, i as M3U8Params, n as DirectLinkParams, o as UrlType, r as DownloadParams, t as defineConfig } from "./config-
|
|
1
|
+
import { a as Options, i as M3U8Params, n as DirectLinkParams, o as UrlType, r as DownloadParams, t as defineConfig } from "./config-pHnrv5F6.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/constants.d.ts
|
|
4
4
|
declare const DEFAULT_OPTIONS: Options;
|
|
@@ -6,43 +6,92 @@ declare const __dirname: string;
|
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/core/animeidhentai.d.ts
|
|
8
8
|
declare function getAnimeIdHentaiLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string>;
|
|
9
|
-
declare function downloadAnimeIdHentai(params: DownloadParams, options?: Partial<Options>): Promise<void>;
|
|
9
|
+
declare function downloadAnimeIdHentai(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
|
|
10
10
|
//#endregion
|
|
11
11
|
//#region src/core/bilibili.d.ts
|
|
12
|
-
declare function getBilibiliLink(
|
|
13
|
-
declare function downloadBilibili(params: DownloadParams): Promise<void>;
|
|
12
|
+
declare function getBilibiliLink(params: DirectLinkParams, options?: Partial<Options>): Promise<any>;
|
|
13
|
+
declare function downloadBilibili(params: DownloadParams | DownloadParams[]): Promise<void>;
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/core/dirpy.d.ts
|
|
16
16
|
declare function getDirpyLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string>;
|
|
17
|
-
declare function downloadDirpy(params: DownloadParams, options?: Partial<Options>): Promise<void>;
|
|
17
|
+
declare function downloadDirpy(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/core/hanime.d.ts
|
|
20
20
|
declare function getHanimeLink(params: DirectLinkParams, options?: Partial<Options>): Promise<Record<string, any>[]>;
|
|
21
|
-
declare function downloadHanime(params: DownloadParams, options?: Partial<Options>): Promise<void>;
|
|
21
|
+
declare function downloadHanime(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/core/koreanpm.d.ts
|
|
24
24
|
declare function getKoreanPmLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string>;
|
|
25
|
-
declare function downloadKoreanPm(params: DownloadParams, options?: Partial<Options>): Promise<void>;
|
|
25
|
+
declare function downloadKoreanPm(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
|
|
26
26
|
//#endregion
|
|
27
27
|
//#region src/core/m3u8.d.ts
|
|
28
|
+
interface M3U8DownloadProgress {
|
|
29
|
+
segment: any;
|
|
30
|
+
totalSegments: number;
|
|
31
|
+
downloaded: number;
|
|
32
|
+
downloadedMB: number;
|
|
33
|
+
percent: number;
|
|
34
|
+
}
|
|
35
|
+
interface ParallelM3U8Progress {
|
|
36
|
+
total: number;
|
|
37
|
+
completed: number;
|
|
38
|
+
failed: number;
|
|
39
|
+
currentParams: M3U8Params;
|
|
40
|
+
identifier?: string;
|
|
41
|
+
status: 'pending' | 'downloading' | 'success' | 'failed';
|
|
42
|
+
downloadProgress?: M3U8DownloadProgress;
|
|
43
|
+
error?: Error;
|
|
44
|
+
}
|
|
28
45
|
/**
|
|
29
|
-
*
|
|
46
|
+
* 下载单个M3U8视频并转换为MP4
|
|
30
47
|
*/
|
|
31
|
-
declare function remoteM3U8ToMP4(params: Partial<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
declare function remoteM3U8ToMP4(params: M3U8Params, options?: Partial<Options>, onProgress?: (progress: M3U8DownloadProgress) => void): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* 并行下载多个M3U8视频
|
|
51
|
+
* @param paramsList M3U8参数列表
|
|
52
|
+
* @param options 下载选项
|
|
53
|
+
* @param maxConcurrent 最大并行数,默认3(M3U8下载较消耗资源,默认值比普通视频小)
|
|
54
|
+
* @param onProgress 总体进度回调
|
|
55
|
+
* @param onDownloadProgress 单个文件下载进度回调
|
|
56
|
+
* @returns Promise<void[]>
|
|
57
|
+
*/
|
|
58
|
+
declare function remoteM3U8ToMP4Parallel(paramsList: M3U8Params[], options?: Partial<Options>, maxConcurrent?: number, onProgress?: (progress: ParallelM3U8Progress) => void, onDownloadProgress?: (identifier: string, progress: M3U8DownloadProgress) => void): Promise<void[]>;
|
|
36
59
|
//#endregion
|
|
37
60
|
//#region src/core/wowxxx.d.ts
|
|
38
61
|
declare function getWowxxxLink(params: DirectLinkParams, options?: Partial<Options>): Promise<Record<string, any>[]>;
|
|
39
|
-
declare function downloadWowxxx(params: DownloadParams, options?: Partial<Options>): Promise<void>;
|
|
62
|
+
declare function downloadWowxxx(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/core/xhamster.d.ts
|
|
65
|
+
declare function getXHamsterLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string>;
|
|
66
|
+
declare function downloadXHamster(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/core/rule34xyz.d.ts
|
|
69
|
+
declare function getRule34XyzVideoLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string>;
|
|
70
|
+
declare function downloadRule34XyzVideo(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
|
|
40
71
|
//#endregion
|
|
41
72
|
//#region src/utils/downloader.d.ts
|
|
42
73
|
declare function downloadVideo(params: DownloadParams, options?: Partial<Options>): Promise<void>;
|
|
74
|
+
interface ParallelDownloadProgress {
|
|
75
|
+
total: number;
|
|
76
|
+
completed: number;
|
|
77
|
+
failed: number;
|
|
78
|
+
currentParams: DownloadParams;
|
|
79
|
+
identifier?: string;
|
|
80
|
+
status: 'pending' | 'success' | 'failed';
|
|
81
|
+
error?: Error;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 并行下载多个视频
|
|
85
|
+
* @param paramsList 下载参数列表
|
|
86
|
+
* @param options 下载选项
|
|
87
|
+
* @param maxConcurrent 最大并行数,默认5
|
|
88
|
+
* @param onProgress 进度回调函数
|
|
89
|
+
* @returns Promise<void[]>
|
|
90
|
+
*/
|
|
91
|
+
declare function downloadVideosParallel(paramsList: DownloadParams[], options?: Partial<Options>, maxConcurrent?: number, onProgress?: (progress: ParallelDownloadProgress) => void): Promise<void[]>;
|
|
43
92
|
//#endregion
|
|
44
93
|
//#region src/index.d.ts
|
|
45
94
|
declare function fastLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string | Record<string, any>[]>;
|
|
46
|
-
declare function fastDownload(params: DownloadParams, options?: Partial<Options>): Promise<void>;
|
|
95
|
+
declare function fastDownload(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
|
|
47
96
|
//#endregion
|
|
48
|
-
export { DEFAULT_OPTIONS, DirectLinkParams, DownloadParams, M3U8Params, Options, UrlType, __dirname, defineConfig, downloadAnimeIdHentai, downloadBilibili, downloadDirpy, downloadHanime, downloadKoreanPm,
|
|
97
|
+
export { DEFAULT_OPTIONS, DirectLinkParams, DownloadParams, M3U8DownloadProgress, M3U8Params, Options, ParallelDownloadProgress, ParallelM3U8Progress, UrlType, __dirname, defineConfig, downloadAnimeIdHentai, downloadBilibili, downloadDirpy, downloadHanime, downloadKoreanPm, downloadRule34XyzVideo, downloadVideo, downloadVideosParallel, downloadWowxxx, downloadXHamster, fastDownload, fastLink, getAnimeIdHentaiLink, getBilibiliLink, getDirpyLink, getHanimeLink, getKoreanPmLink, getRule34XyzVideoLink, getWowxxxLink, getXHamsterLink, remoteM3U8ToMP4, remoteM3U8ToMP4Parallel };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{C as e,
|
|
1
|
+
import{C as e,D as t,E as n,S as r,T as i,_ as a,a as o,b as s,c,d as l,f as u,g as d,h as f,i as p,l as m,m as h,n as g,o as _,p as v,r as y,s as b,t as x,u as S,v as C,x as w,y as T}from"./judgeUrl-f5ejW-iH.mjs";import{defineConfig as E}from"./config.mjs";import{bold as D,dim as O}from"ansis";import k from"axios";import{load as A}from"cheerio";async function j(e,t=i){let{url:n,cwd:a}=e,{proxy:o,timeout:s}=await r(t,a),c=o?.host===``?void 0:o,{data:l}=await k.get(n,{headers:{"User-Agent":w(),Referer:`https://rule34.xyz`},proxy:c,timeout:s}),u=A(l),d=``,f=u(`source[type="video/mp4"]`).attr();return f&&(d=`https://rule34.xyz${f.src.replace(`mov480`,`mov`)}`),d}async function M(e,t=i){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let e=await j({url:r.url,cwd:r.cwd},t);n.push({...r,url:e})}await s(n)}const{version:N}=t;async function P(t,n=i){let{url:r,cwd:a}=t,{proxy:o,puppeteer:s}=n,c=o||{},l=s||{},f=x(r);return e.info(`fast-dirpy ${O(`v${N}`)} : ${D(`Direct Link Getter`)}.`),f===g.Bilibili?(e.info(`Matched link source: Bilibili.`),r.includes(`bilibili.com`)?await d({url:r,cwd:a}):(e.error(`Please provide a valid Bilibili URL.`),``)):f===g.AnimeIdHentai?(e.info(`Matched link source: Animeidhentai.`),await C({url:r,cwd:a},{...c,...l})):f===g.KoreanPM?(e.info(`Matched link source: KoreanPM.`),await S({url:r,cwd:a},c)):f===g.Hanime?(e.info(`Matched link source: Hanime.`),await u({url:r,cwd:a},c)):f===g.Wowxxx?(e.info(`Matched link source: Wowxxx.`),await _({url:r,cwd:a},c)):f===g.XHamster?(e.info(`Matched link source: XHamster.`),await p({url:r,cwd:a},c)):f===g.Dirpy?(e.info(`Matched link source: Dirpy.`),await h({url:r,cwd:a},c)):(e.error(`Your link is not supported!`),``)}async function F(t,n=i){if(Array.isArray(t)||(t=[t]),t.length<1){e.error(`No valid params provided.`);return}let{proxy:r,puppeteer:u}=n,d=r||{},p=u||{};for(let e of t)e.urlType=x(e.url);e.info(`fast-dirpy ${O(`v${N}`)} : ${D(`Video Downloader`)}.`);let h=t.filter(e=>e.urlType===g.Bilibili),_=t.filter(e=>e.urlType===g.AnimeIdHentai),b=t.filter(e=>e.urlType===g.KoreanPM),S=t.filter(e=>e.urlType===g.Hanime),C=t.filter(e=>e.urlType===g.Wowxxx),w=t.filter(e=>e.urlType===g.XHamster),T=t.filter(e=>e.urlType===g.Dirpy),E=t.filter(e=>e.urlType===g.MP4),k=t.filter(e=>e.urlType===g.M3U8);h.length>0&&await f(h),_.length>0&&await a(_,{...d,...p}),b.length>0&&await m(b,{...d,...p}),S.length>0&&await l(S,{...d,...p}),C.length>0&&await o(C,{...d,...p}),w.length>0&&await y(w,{...d,...p}),T.length>0&&await v(T,{...d,...p}),E.length>0&&await s(E,{...d,...p}),k.length>0&&await c(k,{...d,...p})}export{i as DEFAULT_OPTIONS,g as UrlType,n as __dirname,E as defineConfig,a as downloadAnimeIdHentai,f as downloadBilibili,v as downloadDirpy,l as downloadHanime,m as downloadKoreanPm,M as downloadRule34XyzVideo,T as downloadVideo,s as downloadVideosParallel,o as downloadWowxxx,y as downloadXHamster,F as fastDownload,P as fastLink,C as getAnimeIdHentaiLink,d as getBilibiliLink,h as getDirpyLink,u as getHanimeLink,S as getKoreanPmLink,j as getRule34XyzVideoLink,_ as getWowxxxLink,p as getXHamsterLink,b as remoteM3U8ToMP4,c as remoteM3U8ToMP4Parallel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"axios";import{load as t}from"cheerio";import n from"node:path";import{fileURLToPath as r}from"node:url";import{createConfigLoader as i}from"unconfig";import a from"node:process";import{consola as o}from"consola";import s,{createWriteStream as c}from"node:fs";import l from"puppeteer-core";import u from"m3u8stream";var d=Object.create,f=Object.defineProperty,p=Object.getOwnPropertyDescriptor,m=Object.getOwnPropertyNames,h=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty,_=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),v=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=m(t),a=0,o=i.length,s;a<o;a++)s=i[a],!g.call(e,s)&&s!==n&&f(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=p(t,s))||r.enumerable});return e},ee=(e,t,n)=>(n=e==null?{}:d(h(e)),v(t||!e||!e.__esModule?f(n,`default`,{value:e,enumerable:!0}):n,e)),y=`1.0.0`,b={name:`fast-dirpy`,type:`module`,version:y,description:`A simple library/CLI to download video from several websites.`,author:`Vincent-the-gamer`,license:`MIT`,homepage:`https://github.com/Vincent-the-gamer/fast-dirpy#readme`,repository:{type:`git`,url:`git+https://github.com/Vincent-the-gamer/fast-dirpy.git`},bugs:{url:`https://github.com/Vincent-the-gamer/fast-dirpy/issues`},sideEffects:!1,main:`dist/index.mjs`,module:`dist/index.mjs`,types:`dist/index.d.mts`,typesVersions:{"*":{".":[`./dist/index.d.mts`,`./dist/cli.d.mts`]}},bin:{"fast-dirpy":`bin/fast-dirpy.js`},files:[`dist`],scripts:{tsx:`tsx`,build:`tsdown`,test:`vitest`,dep:`taze major -I`,"lint:fix":`eslint . --fix`,login:`pnpm login --registry https://registry.npmjs.com`},publishConfig:{registry:`https://registry.npmjs.com`,access:`public`},dependencies:{ansis:`^4.2.0`,axios:`^1.13.6`,cac:`^7.0.0`,cheerio:`^1.2.0`,consola:`^3.4.2`,m3u8stream:`^0.8.6`,"puppeteer-core":`^24.38.0`,"restore-cursor":`^5.1.0`,unconfig:`^7.5.0`},devDependencies:{"@antfu/eslint-config":`^7.7.0`,"@types/node":`^25.3.5`,deepmerge:`^4.3.1`,eslint:`^10.0.3`,taze:`^19.10.0`,tsdown:`^0.21.0`,tsx:`^4.21.0`,typescript:`^5.9.3`,vitest:`^4.0.18`}};const x={timeout:2e4},S=r(import.meta.url),C=n.dirname(S);var w=_(((e,t)=>{var n=function(e){return r(e)&&!i(e)};function r(e){return!!e&&typeof e==`object`}function i(e){var t=Object.prototype.toString.call(e);return t===`[object RegExp]`||t===`[object Date]`||o(e)}var a=typeof Symbol==`function`&&Symbol.for?Symbol.for(`react.element`):60103;function o(e){return e.$$typeof===a}function s(e){return Array.isArray(e)?[]:{}}function c(e,t){return t.clone!==!1&&t.isMergeableObject(e)?g(s(e),e,t):e}function l(e,t,n){return e.concat(t).map(function(e){return c(e,n)})}function u(e,t){if(!t.customMerge)return g;var n=t.customMerge(e);return typeof n==`function`?n:g}function d(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter(function(t){return Object.propertyIsEnumerable.call(e,t)}):[]}function f(e){return Object.keys(e).concat(d(e))}function p(e,t){try{return t in e}catch{return!1}}function m(e,t){return p(e,t)&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))}function h(e,t,n){var r={};return n.isMergeableObject(e)&&f(e).forEach(function(t){r[t]=c(e[t],n)}),f(t).forEach(function(i){m(e,i)||(p(e,i)&&n.isMergeableObject(t[i])?r[i]=u(i,n)(e[i],t[i],n):r[i]=c(t[i],n))}),r}function g(e,t,r){r||={},r.arrayMerge=r.arrayMerge||l,r.isMergeableObject=r.isMergeableObject||n,r.cloneUnlessOtherwiseSpecified=c;var i=Array.isArray(t);return i===Array.isArray(e)?i?r.arrayMerge(e,t,r):h(e,t,r):c(t,r)}g.all=function(e,t){if(!Array.isArray(e))throw Error(`first argument should be an array`);return e.reduce(function(e,n){return g(e,n,t)},{})},t.exports=g}));const T=o.withTag(`fast-dirpy`);function E(e){`CONSOLA_LEVEL`in a.env||(T.level=e?0:3)}var D=ee(w(),1);async function O(e,t){let n=x,{config:r,sources:a}=await i({sources:[{files:[`fast-dirpy.config`],extensions:[`ts`,`mts`,`cts`,`js`,`mjs`,`cjs`,`json`]}],cwd:t||process.cwd(),merge:!1}).load();return a.length?(T.info(`Config file found: ${a[0]}`),(0,D.default)((0,D.default)(n,r),e)):(0,D.default)(n,e)}function k(e){return e[Math.floor(Math.random()*e.length)]}const A=[`Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10`,`Mozilla/5.0 (Windows NT 6.1; rv,2.0.1) Gecko/20100101 Firefox/4.0.1`,`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36`,`Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36`,`Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36`];function j(){return k(A)}const M=e=>`[${e.url.split(`/`).pop()||`unknown`}]`;async function N(t,n=x){let{path:r,url:i}=t,a=M(t),{proxy:o,timeout:c}=await O(n),l=o?.host===``?void 0:o;if(i===``)return Promise.reject(Error(`Extract direct link failed!`));let u=s.createWriteStream(r||`./download.mp4`);return(await e({url:i,headers:{"User-Agent":j(),...n.headers},method:`GET`,responseType:`stream`,proxy:l,timeout:c,onDownloadProgress:e=>{let{loaded:t,total:n,progress:r}=e,i=`[${a??``}] loaded:${t} total: ${n} progress: ${(r*100).toFixed(2)}%`;T.info(i)}})).data.pipe(u),new Promise((e,t)=>{u.on(`finish`,e),u.on(`error`,t)})}async function P(e,t=x,n=5,r){let i=[],a=new Set,o=0,s=0,c=e.length;T.info(`Starting parallel downloads: ${c} videos, max concurrent: ${n}`);for(let[l,u]of e.entries()){let e=M(u),d=N(u,t).then(t=>(o++,a.delete(d),T.info(`${l+1}/${c} ${e} Download completed`),r?.({total:c,completed:o,failed:s,currentParams:u,identifier:e,status:`success`}),t)).catch(t=>{s++,a.delete(d);let n=t instanceof Error?t.message:String(t);return T.error(`${e} Download failed: ${n}`),r?.({total:c,completed:o,failed:s,currentParams:u,identifier:e,status:`failed`,error:t}),Promise.resolve()});i.push(d),a.add(d),a.size>=n&&await Promise.race(a)}let l=await Promise.allSettled(i);return T.info(`Parallel downloads finished. Success: ${o}, Failed: ${s}, Total: ${c}`),l.filter(e=>e.status===`fulfilled`).map(e=>e.value)}async function F(e){return await l.launch(e)}async function te(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j()},proxy:c,timeout:s}),u=t(l),d=``,f=u(`div.embed.rad2 > iframe`).attr();return f&&(d=f.src),d}async function I(e,t=x){let{url:n,cwd:r}=e,{proxy:i,puppeteer:a}=await O(t,r),o=i?.host===``?void 0:i,s=await te({url:n},{proxy:o}),{executablePath:c,headless:l}=a,u=await F({executablePath:c,headless:l,args:[`--proxy-server=http://${o?.host}:${i?.port}`]}),d=j(),f=await u.newPage();await f.setUserAgent(d),await f.goto(s),await f.waitForSelector(`div.play.p-pulse`),await f.click(`div.play.p-pulse`),await f.waitForSelector(`div.frame > iframe`);let p=await f.$eval(`div.frame > iframe`,e=>e.src),m=await u.newPage();await m.goto(`${p}`),await m.waitForSelector(`video.jw-video.jw-reset`);let h=await m.$eval(`video.jw-video.jw-reset`,e=>e.src);return await u.close(),h}async function L(e,t=x){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let{url:e,cwd:i}=r,a=await I({url:e,cwd:i},t);n.push({...r,url:a})}n.length>0&&await P(n)}async function R(e,t=x){let{url:n,cwd:r}=e,{proxy:i,puppeteer:a}=await O(t,r),o=i?.host===``?void 0:i,{executablePath:s,headless:c}=a,l=await F({executablePath:s,headless:c,args:[`--proxy-server=http://${o?.host}:${i?.port}`,`--disable-features=IsolateOrigins,site-per-process`,`--disable-site-isolation-trials`,`--disable-web-security`,`--disable-setuid-sandbox`,`--no-sandbox`,`--disable-gpu`,`--disable-dev-shm-usage`,`--disable-accelerated-2d-canvas`,`--no-first-run`,`--no-zygote`,`--window-size=1920,1080`],slowMo:10}),u=await l.newPage(),d=j();await u.setUserAgent(d);try{await u.goto(`https://snapany.com/zh/bilibili`),await u.waitForNetworkIdle();let e=`input[name='link']`;await u.waitForSelector(e),await u.type(e,n,{delay:10});let t=`button[type='submit']`;return await u.waitForSelector(t),await u.click(t),await u.waitForSelector(`div[data-testid="flowbite-card"]`),(await u.$$eval(`div[data-testid="flowbite-card"]`,e=>e.map(e=>{let t=e.querySelector(`a[href*=".mp4"]`)?.getAttribute(`href`)||``;return t=t.replace(/&/g,`&`),{videoUrl:t}}))).filter(e=>e.videoUrl)[0]?.videoUrl}catch(e){T.error(`Error during scraping: ${e}`)}finally{T.info(`Closing browser`),await l.close()}}async function z(e){Array.isArray(e)||(e=[e]);let t=[];for(let n of e){let e=await R({url:n.url,cwd:n.cwd});t.push({...n,url:e})}await P(t)}async function B(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(`https://dirpy.com/studio`,{params:{url:i},headers:{"User-Agent":j(),Referer:`https://dirpy.com/studio?url=${i}`},proxy:c,timeout:s}),u=t(l),d=``,f=u(`#media-source`).attr();return f&&(d=f.src),d}async function V(e,t=x){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let e=await B({url:r.url,cwd:r.cwd},t);n.push({...r,url:e})}n.length>0&&await P(n)}function H(e,t){return Number(e.size)-Number(t.size)}async function U(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j(),Referer:`https://hanime1.me/`},proxy:c,timeout:s}),u=t(l)(`source[type="video/mp4"]`);return Object.values(u).map(e=>e.attribs).filter(e=>e!=null).sort(H)}async function W(e,t=x){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let{url:e,cwd:i}=r,a=await U({url:e,cwd:i},t);a.length>0&&T.success(`Successfully get video sources, size ${a.at(-1).size} to be downloaded.`),n.push({...r,url:a.at(-1).src})}n.length>0&&await P(n)}async function G(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j()},proxy:c,timeout:s}),u=t(l),d=``,f=u(`meta[itemprop="contentURL"]`).attr();return f&&(d=f.content),d}async function K(e,t=x){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let{url:e,cwd:i}=r,a=await G({url:e,cwd:i},t);n.push({...r,url:a})}n.length>0&&await P(n)}const q=e=>`[${e.url?.split(`/`).pop()||`unknown`}]`;async function J(e,t=x,r){let{url:i,cwd:a,path:o}=e,{proxy:s,timeout:l}=await O(t,a);if(!i)return Promise.reject(Error(`M3U8 URL is required!`));let d=q(e),f=o??n.resolve(C,`../m3u8-download.mp4`);return T.info(`${d} Starting M3U8 download from: ${i}`),T.info(`${d} Output path: ${f}`),new Promise((e,n)=>{try{let a=u(i,{requestOptions:{headers:t.headers,timeout:l,...s?.host?{proxy:`http://${s.host}:${s.port}`}:{}}}),o=c(f);a.on(`progress`,(e,t,n)=>{let i=n/1024/1024,a=t>0?e.num/t*100:0,o={segment:e,totalSegments:t,downloaded:n,downloadedMB:i,percent:a};T.info(`${d} Segment: ${e.num}/${t}, Downloaded: ${i.toFixed(2)}MB (${a.toFixed(2)}%)`),r?.(o)}),a.on(`error`,e=>{T.error(`${d} M3U8 stream error: ${e.message}`),o.end(),n(e)}),a.pipe(o),o.on(`finish`,()=>{T.info(`${d} M3U8 download completed successfully`),e()}),o.on(`error`,e=>{T.error(`${d} File write error: ${e.message}`),n(e)})}catch(e){let t=e instanceof Error?e.message:String(e);T.error(`${d} Failed to initialize M3U8 download: ${t}`),n(e)}})}async function Y(e,t=x,n=3,r,i){let a=[],o=new Set,s=0,c=0,l=e.length;T.info(`Starting parallel M3U8 downloads: ${l} videos, max concurrent: ${n}`);for(let[u,d]of e.entries()){let e=q(d),f=J(d,t,t=>{i?.(e,t),r?.({total:l,completed:s,failed:c,currentParams:d,identifier:e,status:`downloading`,downloadProgress:t})}).then(t=>(s++,o.delete(f),T.info(`${u+1}/${l} ${e} M3U8 download completed`),r?.({total:l,completed:s,failed:c,currentParams:d,identifier:e,status:`success`}),t)).catch(t=>{c++,o.delete(f);let n=t instanceof Error?t.message:String(t);return T.error(`${e} M3U8 download failed: ${n}`),r?.({total:l,completed:s,failed:c,currentParams:d,identifier:e,status:`failed`,error:t}),Promise.resolve()});a.push(f),o.add(f),o.size>=n&&await Promise.race(o)}let u=await Promise.allSettled(a);return T.info(`Parallel M3U8 downloads finished. Success: ${s}, Failed: ${c}, Total: ${l}`),u.filter(e=>e.status===`fulfilled`).map(e=>e.value)}function X(e,t){let n=e.label.slice(0,e.label.length-1),r=t.label.slice(0,t.label.length-1);return Number(n)-Number(r)}async function Z(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j(),Referer:`https://www.wow.xxx/`},proxy:c,timeout:s}),u=t(l)(`source[type="video/mp4"]`);return Object.values(u).map(e=>e.attribs).filter(e=>e!=null).sort(X)}async function ne(e,t=x){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let{url:e,cwd:i}=r,a=await Z({url:e,cwd:i},t);a.length>0&&T.success(`Successfully get video sources, size ${a.at(-1).size} to be downloaded.`),n.push({...r,url:a.at(-1).src})}await P(n)}async function Q(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j(),Referer:`https://xhamster.com`},proxy:c,timeout:s}),u=t(l),d=``,f=u(`head link[rel="preload"][crossorigin="true"][as="fetch"]`).attr();return f&&(d=f.href),d}async function re(e,t=x){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let{url:e,cwd:i}=r,a=await Q({url:e,cwd:i},t);if(!a)return Promise.reject(Error(`Failed to fetch XHamster video link`));a=a.includes(`1080p`)?a.replace(`_TPL_`,`1080p`):a.includes(`720p`)?a.replace(`_TPL_`,`720p`):a.includes(`480p`)?a.replace(`_TPL_`,`480p`):a.includes(`240p`)?a.replace(`_TPL_`,`240p`):a.replace(`_TPL_`,`144p`),n.push({...r,url:a})}await P(n)}let $=function(e){return e[e.Bilibili=0]=`Bilibili`,e[e.AnimeIdHentai=1]=`AnimeIdHentai`,e[e.Dirpy=2]=`Dirpy`,e[e.M3U8=3]=`M3U8`,e[e.KoreanPM=4]=`KoreanPM`,e[e.Hanime=5]=`Hanime`,e[e.Wowxxx=6]=`Wowxxx`,e[e.XHamster=7]=`XHamster`,e[e.MP4=8]=`MP4`,e}({});function ie(e){return e.includes(`bilibili`)||/BV[a-zA-Z0-9]+/.test(e)?$.Bilibili:e.includes(`animeidhentai`)?$.AnimeIdHentai:e.includes(`koreanpornmovie`)?$.KoreanPM:e.includes(`missav`)?$.MissAV:e.includes(`hanime1.me`)?$.Hanime:e.includes(`wow.xxx`)?$.Wowxxx:e.includes(`xhamster.com`)?$.XHamster:e.endsWith(`.m3u8`)||e.includes(`.m3u8`)&&!e.endsWith(`.mp4`)?$.M3U8:e.endsWith(`.mp4`)||e.includes(`.mp4`)&&!e.endsWith(`.m3u8`)?$.MP4:$.Dirpy}export{T as C,b as D,C as E,y as O,O as S,x as T,L as _,ne as a,P as b,Y as c,W as d,U as f,R as g,z as h,Q as i,K as l,B as m,$ as n,Z as o,V as p,re as r,J as s,ie as t,G as u,I as v,E as w,j as x,N as y};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-dirpy",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"description": "A simple library/CLI to download video from several websites.",
|
|
6
6
|
"author": "Vincent-the-gamer",
|
|
7
7
|
"license": "MIT",
|
|
@@ -37,25 +37,25 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"ansis": "^4.2.0",
|
|
40
|
-
"axios": "^1.13.
|
|
41
|
-
"cac": "^
|
|
42
|
-
"cheerio": "^1.
|
|
40
|
+
"axios": "^1.13.6",
|
|
41
|
+
"cac": "^7.0.0",
|
|
42
|
+
"cheerio": "^1.2.0",
|
|
43
43
|
"consola": "^3.4.2",
|
|
44
44
|
"m3u8stream": "^0.8.6",
|
|
45
|
-
"puppeteer-core": "^24.
|
|
45
|
+
"puppeteer-core": "^24.38.0",
|
|
46
46
|
"restore-cursor": "^5.1.0",
|
|
47
|
-
"unconfig": "^7.
|
|
47
|
+
"unconfig": "^7.5.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@antfu/eslint-config": "^
|
|
51
|
-
"@types/node": "^25.
|
|
50
|
+
"@antfu/eslint-config": "^7.7.0",
|
|
51
|
+
"@types/node": "^25.3.5",
|
|
52
52
|
"deepmerge": "^4.3.1",
|
|
53
|
-
"eslint": "^
|
|
54
|
-
"taze": "^19.
|
|
55
|
-
"tsdown": "^0.
|
|
53
|
+
"eslint": "^10.0.3",
|
|
54
|
+
"taze": "^19.10.0",
|
|
55
|
+
"tsdown": "^0.21.0",
|
|
56
56
|
"tsx": "^4.21.0",
|
|
57
57
|
"typescript": "^5.9.3",
|
|
58
|
-
"vitest": "^4.0.
|
|
58
|
+
"vitest": "^4.0.18"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"tsx": "tsx",
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import e from"axios";import{load as t}from"cheerio";import n from"node:path";import{fileURLToPath as r}from"node:url";import{createConfigLoader as i}from"unconfig";import a from"node:process";import{consola as o}from"consola";import s,{createWriteStream as c}from"node:fs";import l from"puppeteer-core";import u from"m3u8stream";var d=Object.create,f=Object.defineProperty,p=Object.getOwnPropertyDescriptor,m=Object.getOwnPropertyNames,h=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty,ee=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),_=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=m(t),a=0,o=i.length,s;a<o;a++)s=i[a],!g.call(e,s)&&s!==n&&f(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=p(t,s))||r.enumerable});return e},v=(e,t,n)=>(n=e==null?{}:d(h(e)),_(t||!e||!e.__esModule?f(n,`default`,{value:e,enumerable:!0}):n,e)),y=`0.3.9`,b={name:`fast-dirpy`,type:`module`,version:y,description:`A simple library/CLI to download video from several websites.`,author:`Vincent-the-gamer`,license:`MIT`,homepage:`https://github.com/Vincent-the-gamer/fast-dirpy#readme`,repository:{type:`git`,url:`git+https://github.com/Vincent-the-gamer/fast-dirpy.git`},bugs:{url:`https://github.com/Vincent-the-gamer/fast-dirpy/issues`},sideEffects:!1,main:`dist/index.mjs`,module:`dist/index.mjs`,types:`dist/index.d.mts`,typesVersions:{"*":{".":[`./dist/index.d.mts`,`./dist/cli.d.mts`]}},bin:{"fast-dirpy":`bin/fast-dirpy.js`},files:[`dist`],scripts:{tsx:`tsx`,build:`tsdown`,test:`vitest`,dep:`taze major -I`,"lint:fix":`eslint . --fix`,login:`pnpm login --registry https://registry.npmjs.com`},publishConfig:{registry:`https://registry.npmjs.com`,access:`public`},dependencies:{ansis:`^4.2.0`,axios:`^1.13.2`,cac:`^6.7.14`,cheerio:`^1.1.2`,consola:`^3.4.2`,m3u8stream:`^0.8.6`,"puppeteer-core":`^24.34.0`,"restore-cursor":`^5.1.0`,unconfig:`^7.4.2`},devDependencies:{"@antfu/eslint-config":`^6.7.3`,"@types/node":`^25.0.3`,deepmerge:`^4.3.1`,eslint:`^9.39.2`,taze:`^19.9.2`,tsdown:`^0.18.3`,tsx:`^4.21.0`,typescript:`^5.9.3`,vitest:`^4.0.16`}};const x={timeout:2e4},S=r(import.meta.url),C=n.dirname(S);var w=ee(((e,t)=>{var n=function(e){return r(e)&&!i(e)};function r(e){return!!e&&typeof e==`object`}function i(e){var t=Object.prototype.toString.call(e);return t===`[object RegExp]`||t===`[object Date]`||o(e)}var a=typeof Symbol==`function`&&Symbol.for?Symbol.for(`react.element`):60103;function o(e){return e.$$typeof===a}function s(e){return Array.isArray(e)?[]:{}}function c(e,t){return t.clone!==!1&&t.isMergeableObject(e)?g(s(e),e,t):e}function l(e,t,n){return e.concat(t).map(function(e){return c(e,n)})}function u(e,t){if(!t.customMerge)return g;var n=t.customMerge(e);return typeof n==`function`?n:g}function d(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter(function(t){return Object.propertyIsEnumerable.call(e,t)}):[]}function f(e){return Object.keys(e).concat(d(e))}function p(e,t){try{return t in e}catch{return!1}}function m(e,t){return p(e,t)&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))}function h(e,t,n){var r={};return n.isMergeableObject(e)&&f(e).forEach(function(t){r[t]=c(e[t],n)}),f(t).forEach(function(i){m(e,i)||(p(e,i)&&n.isMergeableObject(t[i])?r[i]=u(i,n)(e[i],t[i],n):r[i]=c(t[i],n))}),r}function g(e,t,r){r||={},r.arrayMerge=r.arrayMerge||l,r.isMergeableObject=r.isMergeableObject||n,r.cloneUnlessOtherwiseSpecified=c;var i=Array.isArray(t);return i===Array.isArray(e)?i?r.arrayMerge(e,t,r):h(e,t,r):c(t,r)}g.all=function(e,t){if(!Array.isArray(e))throw Error(`first argument should be an array`);return e.reduce(function(e,n){return g(e,n,t)},{})},t.exports=g}));const T=o.withTag(`fast-dirpy`);function E(e){`CONSOLA_LEVEL`in a.env||(T.level=e?0:3)}var D=v(w(),1);async function O(e,t){let n=x,{config:r,sources:a}=await i({sources:[{files:[`fast-dirpy.config`],extensions:[`ts`,`mts`,`cts`,`js`,`mjs`,`cjs`,`json`]}],cwd:t||process.cwd(),merge:!1}).load();return a.length?(T.info(`Config file found: ${a[0]}`),(0,D.default)((0,D.default)(n,r),e)):(0,D.default)(n,e)}function k(e){return e[Math.floor(Math.random()*e.length)]}const A=[`Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10`,`Mozilla/5.0 (Windows NT 6.1; rv,2.0.1) Gecko/20100101 Firefox/4.0.1`,`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36`,`Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36`,`Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36`];function j(){return k(A)}async function M(t,n=x){let{path:r,url:i}=t,{proxy:a,timeout:o}=await O(n),c=a?.host===``?void 0:a;if(i===``)return Promise.reject(`Extract direct link failed!`);let l=s.createWriteStream(r||`./download.mp4`);return(await e({url:i,headers:{"User-Agent":j(),...n.headers},method:`GET`,responseType:`stream`,proxy:c,timeout:o,onDownloadProgress:e=>{let{loaded:t,total:n,progress:r}=e,i=`loaded:${t} total: ${n} progress: ${(r*100).toFixed(2)}%`;T.info(i)}})).data.pipe(l),new Promise((e,t)=>{l.on(`finish`,e),l.on(`error`,t)})}async function N(e){return await l.launch(e)}async function te(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j()},proxy:c,timeout:s}),u=t(l),d=``,f=u(`div.embed.rad2 > iframe`).attr();return f&&(d=f.src),d}async function P(e,t=x){let{url:n,cwd:r}=e,{proxy:i,puppeteer:a}=await O(t,r),o=i?.host===``?void 0:i,s=await te({url:n},{proxy:o}),{executablePath:c,headless:l}=a,u=await N({executablePath:c,headless:l,args:[`--proxy-server=http://${o?.host}:${i?.port}`]}),d=j(),f=await u.newPage();await f.setUserAgent(d),await f.goto(s),await f.waitForSelector(`div.play.p-pulse`),await f.click(`div.play.p-pulse`),await f.waitForSelector(`div.frame > iframe`);let p=await f.$eval(`div.frame > iframe`,e=>e.src),m=await u.newPage();await m.goto(`${p}`),await m.waitForSelector(`video.jw-video.jw-reset`);let h=await m.$eval(`video.jw-video.jw-reset`,e=>e.src);return await u.close(),h}async function F(e,t=x){let{path:n,url:r,cwd:i}=e;await M({url:await P({url:r},t),path:n,cwd:i},t)}function I(e){let t=e.match(/BV[a-zA-Z0-9]+/);return t?`https://bilibili-real-url.deno.dev/${t[0]}.mp4`:``}async function L(e){let{path:t,url:n}=e,r=I(n);r===``?console.error(`Extract direct link failed!`):await M({url:r,path:t||`./download.mp4`})}async function R(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(`https://dirpy.com/studio`,{params:{url:i},headers:{"User-Agent":j(),Referer:`https://dirpy.com/studio?url=${i}`},proxy:c,timeout:s}),u=t(l),d=``,f=u(`#media-source`).attr();return f&&(d=f.src),d}async function z(e,t=x){let{path:n,url:r,cwd:i}=e;await M({url:await R({url:r},t),path:n,cwd:i},t)}function B(e,t){return Number(e.size)-Number(t.size)}async function V(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j(),Referer:`https://hanime1.me/`},proxy:c,timeout:s}),u=t(l)(`source[type="video/mp4"]`);return Object.values(u).map(e=>e.attribs).filter(e=>e!=null).sort(B)}async function H(e,t=x){let{path:n,url:r,cwd:i}=e,a=await V({url:r},t);a.length>0&&T.success(`Successfully get video sources, size ${a[a.length-1].size} to be downloaded.`),await M({url:a[a.length-1].src,path:n,cwd:i},t)}async function U(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j()},proxy:c,timeout:s}),u=t(l),d=``,f=u(`meta[itemprop="contentURL"]`).attr();return f&&(d=f.content),d}async function W(e,t=x){let{path:n,url:r,cwd:i}=e;await M({url:await U({url:r},t),path:n,cwd:i},t)}function G(e){let{url:t,path:r}=e,i=r??n.resolve(C,`../m3u8-download.mp4`),a=u(t);a.pipe(c(i)),a.on(`progress`,(e,t,n)=>{T.info(`Segment: ${JSON.stringify(e)},
|
|
2
|
-
Total Segments: ${t},
|
|
3
|
-
downloaded: ${(n/1024/1024).toFixed(2)}MB Downloaded`),e.num>=t&&a.end()})}function K(e){return new Promise(t=>setTimeout(t,e*1e3))}async function q(e,t=x){let{url:n,cwd:r}=e,{proxy:i,puppeteer:a}=await O(t,r),o=i?.host===``?void 0:i,{executablePath:s,headless:c}=a,l=await N({executablePath:s,headless:c,args:[`--proxy-server=http://${o?.host}:${i?.port}`,`--disable-features=IsolateOrigins,site-per-process`,`--disable-site-isolation-trials`,`--disable-web-security`,`--disable-setuid-sandbox`,`--no-sandbox`,`--disable-gpu`,`--disable-dev-shm-usage`,`--disable-accelerated-2d-canvas`,`--no-first-run`,`--no-zygote`,`--single-process`,`--window-size=1920,1080`],slowMo:50,timezoneId:`America/New_York`,locale:`en-US`}),u=await l.newPage(),d=j();await u.setUserAgent(d);try{let e=await u.goto(n,{waitUntil:`domcontentloaded`});e&&T.info(`http status: ${e.status()}`);let t=await u.title(),r=await u.content();if(T.info(`Page title: ${t}`),t.includes(`Just a moment`)||r.includes(`Checking your browser`)){T.info(`Cloudflare challenge detected, waiting for it to complete...`);try{T.info(`Waiting for page title to change...`),await u.waitForFunction(`document.title != 'Just a moment...'`,{timeout:3e4}),T.info(`Page title has changed`)}catch(e){T.error(`Timeout waiting for title change: ${e}`);try{for(let e of[`input[type='checkbox']`,`.ray-button`,`#challenge-stage button`,`button:has-text('Verify')`,`button:has-text('Continue')`])if(await u.$(e)){T.info(`Found possible verification button: ${e}`),await u.click(e),K(5);break}}catch(e){T.error(`Failed to click verification button: ${e}`)}}}let i=await u.title();T.info(`current page title: ${i}`),T.info(`Simulating page scroll...`);for(let e=0;e<3;e++)await u.evaluate(`window.scrollBy(0, window.innerHeight / 2)`),await u.evaluate(`window.scrollBy(0, window.innerHeight / 4)`);T.info(`Getting page content...`);let a=await u.content();return T.info(`Page content retrieved successfully.`),a}catch(e){T.error(`Error during scraping: ${e}`)}finally{T.info(`Closing browser`),await l.close()}}async function J(e){let t=e.match(/m3u8\|([a-f0-9|]+)\|com\|surrit\|https\|video/);return t?t[1].split(`|`).reverse().join(`-`):(T.error(`Failed to extract UUID from HTML.`),null)}function Y(e){return e.split(`/`).pop()||(T.error(`Failed to extract movie ID from URL.`),null)}async function X(t){let{url:n,cwd:r}=t,i=await J(await q({url:n,cwd:r})),a=`https://surrit.com/${i}/playlist.m3u8`,{data:o}=await e.get(a),s=o.match(/(?:\d+p|\d+x\d+)\/video\.m3u8/g);return`https://surrit.com/${i}/${s[s.length-1]}`}async function Z(e){let{url:t,cwd:n,path:r}=e,i=Y(t);await G({url:await X({url:t,cwd:n}),cwd:n,path:r||`${i}.mp4`})}function ne(e,t){let n=e.label.slice(0,e.label.length-1),r=t.label.slice(0,t.label.length-1);return Number(n)-Number(r)}async function Q(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":j(),Referer:`https://www.wow.xxx/`},proxy:c,timeout:s}),u=t(l)(`source[type="video/mp4"]`);return Object.values(u).map(e=>e.attribs).filter(e=>e!=null).sort(ne)}async function re(e,t=x){let{path:n,url:r,cwd:i}=e,a=await Q({url:r},t);a.length>0&&T.success(`Successfully get video sources, size ${a[a.length-1].label} to be downloaded.`),await M({url:a[a.length-1].src,path:n,cwd:i},t)}let $=function(e){return e[e.Bilibili=0]=`Bilibili`,e[e.AnimeIdHentai=1]=`AnimeIdHentai`,e[e.Dirpy=2]=`Dirpy`,e[e.M3U8=3]=`M3U8`,e[e.KoreanPM=4]=`KoreanPM`,e[e.MissAV=5]=`MissAV`,e[e.Hanime=6]=`Hanime`,e[e.Wowxxx=7]=`Wowxxx`,e[e.MP4=8]=`MP4`,e}({});function ie(e){return e.includes(`bilibili`)||/BV[a-zA-Z0-9]+/.test(e)?$.Bilibili:e.includes(`animeidhentai`)?$.AnimeIdHentai:e.includes(`koreanpornmovie`)?$.KoreanPM:e.includes(`missav`)?$.MissAV:e.includes(`hanime1.me`)?$.Hanime:e.includes(`wow.xxx`)?$.Wowxxx:e.endsWith(`.m3u8`)||e.includes(`.m3u8`)&&!e.endsWith(`.mp4`)?$.M3U8:e.endsWith(`.mp4`)||e.includes(`.mp4`)&&!e.endsWith(`.m3u8`)?$.MP4:$.Dirpy}export{b as C,C as S,P as _,Z as a,E as b,W as c,V as d,z as f,F as g,I as h,Q as i,U as l,L as m,$ as n,X as o,R as p,re as r,G as s,ie as t,H as u,M as v,y as w,x,T as y};
|