fast-dirpy 0.3.10 → 1.0.1

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 CHANGED
@@ -22,19 +22,22 @@ A simple library/CLI to download youtube(etc.) videos.
22
22
  - [Animehentai](https://animeidhentai.com/)
23
23
  - [Koreanpornmovies](https://koreanpornmovie.com/)
24
24
  - [XVideos](https://www.xvideos.com/)
25
- - [Missav](https://missav.ws/) (m3u8)
26
25
  - [Hanime1.me](https://hanime1.me/)
27
26
  - [wow.xxx](https://www.wow.xxx/)
28
27
  - [xhamster](https://xhamster.com/) (m3u8, retry if error)
29
- </details>
28
+ - [rule34.xyz](https://rule34.xyz/) (2d/3d videos)
30
29
 
31
- And `.m3u8` videos.
30
+ > [!WARNING]
31
+ > MissAV has a cloudflare challenge page which can't be bypassed using puppeteer/playwright, so you need to download the html page manually
32
+ > (no js and css needed, only html), then pass the local file path to extract m3u8 source.
33
+ > `fast-dirpy download --json '[{"url": "missav:/home/xxx/Downloads/xxx.html", "path": "./msav-test.mp4"}]'`
34
+ >
35
+ > And this method is unstable, sometimes you'll get http 429.
32
36
 
33
- > [!IMPORTANT]
34
- > From v0.3.0, .m3u8 downloader is no longer using ffmpeg.
35
- > And it doesn't provide proxy settings, so, you need to use `export https_proxy=http://ip:port` to set proxy manually in terminal.
37
+ - [missav](https://missav.ws/)
38
+ </details>
36
39
 
37
- 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.
40
+ And `.m3u8` videos.
38
41
 
39
42
  ## Installation
40
43
 
@@ -53,10 +56,6 @@ deno add jsr:@vince-g/fast-dirpy
53
56
  npm i fast-dirpy -g
54
57
  ```
55
58
 
56
- ### Additional: download `ffmpeg`
57
-
58
- https://www.ffmpeg.org/download.html
59
-
60
59
  ## Usage
61
60
 
62
61
  ### Config file
@@ -100,7 +99,7 @@ export default defineConfig({
100
99
  # -c, --config: Specified external config file.
101
100
  # e.g.: fast-dirpy get https://xxx -c ~/Downloads/fast-dirpy.config.json
102
101
  # --chromePath: Path to your Google Chrome browser.
103
- fast-dirpy get https\://www.youtube.com/watch\?v\=6c28qWDMPBA -H 127.0.0.1 -P 7890
102
+ fast-dirpy get https://www.youtube.com/watch?v=6c28qWDMPBA -H 127.0.0.1 -P 7890
104
103
 
105
104
  # Bilibili source doesn't need any proxy, so it's disabled by default.
106
105
  fast-dirpy get https://www.bilibili.com/video/BV1TSPeeGE35
@@ -117,34 +116,27 @@ fast-dirpy get https\://www.youtube.com/watch\?v\=6c28qWDMPBA
117
116
  > [!IMPORTANT]
118
117
  >
119
118
  > 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.
120
- > 2. `.m3u8` source is handled by `ffmpeg`.
119
+ > 2. You can download multiple videos in parallel at version `v1.0.0` and above.
121
120
 
122
121
  ```shell
123
- # get video direct link
124
- # Path: --path, -p: Downloaded video save path.
125
- #
126
122
  # Proxy:
127
123
  # -H, --proxyHost: proxy host.
128
124
  # -P, --proxyPort: proxy port.
129
125
  # -c, --config: Specified external config file.
130
126
  # e.g.: fast-dirpy get https://xxx -c ~/Downloads/fast-dirpy.config.json
131
127
  # --chromePath: Path to your Google Chrome browser.
132
- fast-dirpy download https\://www.youtube.com/watch\?v\=6c28qWDMPBA -p ./test.mp4 -H 127.0.0.1 -P 7890
133
-
134
- # Bilibili source doesn't need any proxy, so it's disabled by default.
135
- fast-dirpy download https\://www.bilibili.com/video/BV1TSPeeGE35 -p ./test.mp4
136
128
 
137
- # m3u8 sources
138
- fast-dirpy download https\://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8 -p ./test.mp4
129
+ fast-dirpy download --json '[{"url": "https://www.bilibili.com/video/BV1uEAWzuEHC","path": "./cmd-test.mp4"}]' -H 127.0.0.1 -P 7890
139
130
 
140
- # mp4 sources
141
- fast-dirpy download http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 -p ./big_buck_bunny.mp4
131
+ fast-dirpy download --jsonFile ./test/params.json -H 127.0.0.1 -P 7890
142
132
  ```
143
133
 
144
134
  if you have set your proxy config in `fast-dirpy.config.ts`, you can omit proxy parameters:
145
135
 
146
136
  ```shell
147
- fast-dirpy download https\://www.youtube.com/watch\?v\=6c28qWDMPBA -p ./test.mp4
137
+ fast-dirpy download --jsonFile ./test/params.json
138
+
139
+ fast-dirpy download --json '[{"url": "https://www.bilibili.com/video/BV1uEAWzuEHC","path": "./cmd-test.mp4"}]'
148
140
  ```
149
141
 
150
142
  For further CLI help:
@@ -155,6 +147,9 @@ fast-dirpy --help
155
147
 
156
148
  ### Use as a library
157
149
 
150
+ > [!IMPORTANT]
151
+ > You can download multiple videos in parallel at version `v1.0.0` and above.
152
+
158
153
  ```ts
159
154
  import { fastLink, fastDownload, remoteM3U8ToMP4, downloadVideo } from 'fast-dirpy'
160
155
 
@@ -171,27 +166,15 @@ const link = await fastLink(
171
166
  )
172
167
 
173
168
  // download video
174
- await fastDownload({
169
+ await fastDownload([{
175
170
  url: '<url>',
176
171
  path: './download.mp4',
177
172
  cwd: '/path/to/external-config', // Optional: You can specify an external config file.
178
- },
173
+ }],
179
174
  // options (Optional, can be omitted if you have a config file, this will overwrites your config file options.)
180
175
  {
181
176
  proxy: { ... }
182
177
  })
183
-
184
- // Download `.m3u8` video
185
- await remoteM3U8ToMP4({
186
- url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
187
- path: './test.mp4',
188
- })
189
-
190
- // Download `.mp4` video
191
- await downloadVideo({
192
- url: 'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4',
193
- path: "./big_buck_bunny.mp4"
194
- })
195
178
  ```
196
179
 
197
180
  ## Test
package/dist/cli.mjs CHANGED
@@ -1 +1 @@
1
- import{E as e,S as t,T as n,_ as r,a as i,b as a,d as o,f as s,g as c,h as l,i as u,l as d,m as f,n as p,o as m,r as h,s as g,t as _,u as v,v as y,x as b,y as x}from"./judgeUrl-ChKFgqzP.mjs";import{bold as S,dim as C}from"ansis";import{cac as w}from"cac";import T from"restore-cursor";const E=w(`fast-dirpy`),{version:D}=n;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(e,n)=>{let i=_(e),{proxyHost:a,proxyPort:s,config:c,silent:d,chromePath:f}=n,h=a?{proxy:{host:a,port:s}}:void 0,g=f?{puppeteer:{executablePath:f}}:void 0;if(t(!!d),b.info(`fast-dirpy ${C(`v${D}`)} : ${S(`Direct Link Getter`)}.`),i===p.AnimeIdHentai){b.info(`Matched link source: Animeidhentai.`);let t=await x({url:e,cwd:c},{...h,...g});console.log(t)}else if(i===p.KoreanPM){b.info(`Matched link source: KoreanPM.`);let t=await o({url:e,cwd:c},h);console.log(t)}else if(i===p.Wowxxx){b.info(`Matched link source: Wowxxx.`);let t=await m({url:e,cwd:c},h);console.log(t)}else if(i===p.XHamster){b.info(`Matched link source: XHamster.`);let t=await u({url:e,cwd:c},h);console.log(t)}else if(i===p.Bilibili){if(b.info(`Matched link source: Bilibili.`),!e.includes(`bilibili.com`)){b.error(`Please provide a valid Bilibili URL.`);return}let t=await r(e);console.log(t)}else if(i===p.Dirpy){b.info(`Matched link source: Dirpy.`);let t=await l({url:e,cwd:c},h);console.log(t)}else b.error(`Your link is not supported!`)}),E.command(`download <url>`,`download a video.`).option(`--path, -p <path>`,`Download destination path + filename. e.g. /xxx/example.mp4.`).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(e,n)=>{let r=_(e),{proxyHost:o,proxyPort:l,path:u,config:m,silent:x,chromePath:w}=n,T=o?{proxy:{host:o,port:l}}:void 0,E=w?{puppeteer:{executablePath:w}}:void 0;t(!!x),b.info(`fast-dirpy ${C(`v${D}`)} : ${S(`Video Downloader`)}.`),r===p.Bilibili?(b.info(`Matched link source: Bilibili.`),await c({url:e,path:u})):r===p.Dirpy?(b.info(`Matched link source: Dirpy.`),f({url:e,path:u||`./dirpy.mp4`,cwd:m},T)):r===p.AnimeIdHentai?(b.info(`Matched link source: AnimeIdHentai.`),await y({url:e,path:u||`./animeidhentai.mp4`,cwd:m},{...T,...E})):r===p.KoreanPM?(b.info(`Matched link source: KoreanPM.`),await v({url:e,path:u||`./korean-pm.mp4`,cwd:m},T)):r===p.Wowxxx?(b.info(`Matched link source: Wowxxx.`),await i({url:e,path:u||`./wowxxx.mp4`,cwd:m},T)):r===p.XHamster?(b.info(`Matched link source: XHamster.`),await h({url:e,path:u||`./xhamster-vid.mp4`,cwd:m},T)):r===p.MissAV?(b.info(`Matched link source: MissAV.`),await g({url:e,path:u,cwd:m})):r===p.Hanime?(b.info(`Matched link source: Hanime.`),await s({url:e,path:u,cwd:m},T)):r===p.M3U8?(b.info(`Matched link source: m3u8.`),d({url:e,path:u||`./m3u8-download.mp4`,cwd:m})):r===p.MP4?(b.info(`Matched link source: mp4.`),await a({url:e,path:u,cwd:m},T)):b.error(`Your link is not supported!`)}),E.help(),E.version(e),E.parse(),T();export{};
1
+ import{A as e,E as t,S as n,T as r,_ as i,a,b as o,d as s,f as c,g as l,h as u,i as d,k as f,n as p,o as m,p as h,r as g,s as _,t as v,u as y,v as b,y as x}from"./judgeUrl-NeoaY5pF.mjs";import S from"node:fs/promises";import{bold as C,dim as w}from"ansis";import{cac as T}from"cac";import E from"restore-cursor";const D=T(`fast-dirpy`),{version:O}=f;D.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(e,n)=>{let i=v(e),{proxyHost:a,proxyPort:s,config:u,silent:f,chromePath:h}=n,g=a?{proxy:{host:a,port:s}}:void 0,_=h?{puppeteer:{executablePath:h}}:void 0;if(t(!!f),r.info(`fast-dirpy ${w(`v${O}`)} : ${C(`Direct Link Getter`)}.`),i===p.AnimeIdHentai){r.info(`Matched link source: Animeidhentai.`);let t=await o({url:e,cwd:u},{...g,..._});console.log(t)}else if(i===p.KoreanPM){r.info(`Matched link source: KoreanPM.`);let t=await c({url:e,cwd:u},g);console.log(t)}else if(i===p.Wowxxx){r.info(`Matched link source: Wowxxx.`);let t=await m({url:e,cwd:u},g);console.log(t)}else if(i===p.XHamster){r.info(`Matched link source: XHamster.`);let t=await d({url:e,cwd:u},g);console.log(t)}else if(i===p.Bilibili){if(r.info(`Matched link source: Bilibili.`),!e.includes(`bilibili.com`)){r.error(`Please provide a valid Bilibili URL.`);return}let t=b(e);console.log(t)}else if(i===p.Dirpy){r.info(`Matched link source: Dirpy.`);let t=await l({url:e,cwd:u},g);console.log(t)}else r.error(`Your link is not supported!`)}),D.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 e=>{let{json:o,jsonFile:c}=e;if(!o&&!c){r.error(`No JSON params provided.`);return}let l=await(async(e,t)=>{if(e)return JSON.parse(e);if(t){let e=await S.readFile(t,`utf-8`);return JSON.parse(e)}})(o,c);if(Array.isArray(l)||(l=[l]),l.length<1){r.error(`No params provided.`);return}let{proxyHost:d,proxyPort:f,config:m,silent:b,chromePath:T}=e,E=d?{proxy:{host:d,port:f}}:void 0,D=T?{puppeteer:{executablePath:T}}:void 0;t(!!b),r.info(`fast-dirpy ${w(`v${O}`)} : ${C(`Video Downloader`)}.`);for(let e of l)e.urlType=v(e.url),e.cwd=m;let k=l.filter(e=>e.urlType===p.Bilibili),A=l.filter(e=>e.urlType===p.AnimeIdHentai),j=l.filter(e=>e.urlType===p.KoreanPM),M=l.filter(e=>e.urlType===p.Hanime),N=l.filter(e=>e.urlType===p.Wowxxx),P=l.filter(e=>e.urlType===p.XHamster),F=l.filter(e=>e.urlType===p.Dirpy),I=l.filter(e=>e.urlType===p.MP4),L=l.filter(e=>e.urlType===p.M3U8),R=l.filter(e=>e.urlType===p.MissAV);k.length>0&&await i(k),A.length>0&&await x(A,{...E,...D}),j.length>0&&await s(j,{...E,...D}),M.length>0&&await h(M,{...E,...D}),N.length>0&&await a(N,{...E,...D}),P.length>0&&await g(P,{...E,...D}),R.length>0&&await _(R,{...E}),F.length>0&&await u(F,{...E,...D}),I.length>0&&await n(I,{...E,...D}),L.length>0&&await y(L,{...E,...D})}),D.help(),D.version(e),D.parse(),E();export{};
@@ -13,16 +13,20 @@ interface Options {
13
13
  };
14
14
  }
15
15
  interface DirectLinkParams {
16
- url: string;
16
+ url?: string;
17
17
  cwd?: string;
18
+ missavHtmlPage?: string;
18
19
  }
19
20
  interface DownloadParams {
20
21
  url: string;
21
22
  path?: string;
22
23
  cwd?: string;
24
+ urlType?: UrlType;
23
25
  }
24
26
  type M3U8Params = DownloadParams & {
25
- ffmpegPath: string;
27
+ ffmpegPath?: string;
28
+ concurrency?: number;
29
+ retries?: number;
26
30
  };
27
31
  declare enum UrlType {
28
32
  Bilibili = 0,
@@ -30,11 +34,12 @@ declare enum UrlType {
30
34
  Dirpy = 2,
31
35
  M3U8 = 3,
32
36
  KoreanPM = 4,
33
- MissAV = 5,
34
- Hanime = 6,
35
- Wowxxx = 7,
36
- XHamster = 8,
37
- MP4 = 9,
37
+ Hanime = 5,
38
+ MissAV = 6,
39
+ NJavTV = 7,
40
+ Wowxxx = 8,
41
+ XHamster = 9,
42
+ MP4 = 10
38
43
  }
39
44
  //#endregion
40
45
  //#region src/config.d.ts
package/dist/config.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { t as defineConfig } from "./config-DPmVNe2Q.mjs";
1
+ import { t as defineConfig } from "./config-Cce0JT9r.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-DPmVNe2Q.mjs";
1
+ import { a as Options, i as M3U8Params, n as DirectLinkParams, o as UrlType, r as DownloadParams, t as defineConfig } from "./config-Cce0JT9r.mjs";
2
2
 
3
3
  //#region src/constants.d.ts
4
4
  declare const DEFAULT_OPTIONS: Options;
@@ -6,47 +6,96 @@ 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(link: string): string;
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
- * Get remote m3u8 stream, parse it to mp4.
46
+ * 下载单个M3U8视频并转换为MP4
30
47
  */
31
- declare function remoteM3U8ToMP4(params: Partial<M3U8Params>): void;
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[]>;
32
59
  //#endregion
33
60
  //#region src/core/missav.d.ts
34
- declare function getMissavLink(params: DirectLinkParams): Promise<string>;
35
- declare function downloadMissav(params: Partial<DownloadParams>): Promise<void>;
61
+ declare function getMissavLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string | null>;
62
+ declare function downloadMissav(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
63
+ //#endregion
64
+ //#region src/core/rule34xyz.d.ts
65
+ declare function getRule34XyzVideoLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string>;
66
+ declare function downloadRule34XyzVideo(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
36
67
  //#endregion
37
68
  //#region src/core/wowxxx.d.ts
38
69
  declare function getWowxxxLink(params: DirectLinkParams, options?: Partial<Options>): Promise<Record<string, any>[]>;
39
- declare function downloadWowxxx(params: DownloadParams, options?: Partial<Options>): Promise<void>;
70
+ declare function downloadWowxxx(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
40
71
  //#endregion
41
72
  //#region src/core/xhamster.d.ts
42
73
  declare function getXHamsterLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string>;
43
- declare function downloadXHamster(params: DownloadParams, options?: Partial<Options>): Promise<void>;
74
+ declare function downloadXHamster(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
44
75
  //#endregion
45
76
  //#region src/utils/downloader.d.ts
46
77
  declare function downloadVideo(params: DownloadParams, options?: Partial<Options>): Promise<void>;
78
+ interface ParallelDownloadProgress {
79
+ total: number;
80
+ completed: number;
81
+ failed: number;
82
+ currentParams: DownloadParams;
83
+ identifier?: string;
84
+ status: 'pending' | 'success' | 'failed';
85
+ error?: Error;
86
+ }
87
+ /**
88
+ * 并行下载多个视频
89
+ * @param paramsList 下载参数列表
90
+ * @param options 下载选项
91
+ * @param maxConcurrent 最大并行数,默认5
92
+ * @param onProgress 进度回调函数
93
+ * @returns Promise<void[]>
94
+ */
95
+ declare function downloadVideosParallel(paramsList: DownloadParams[], options?: Partial<Options>, maxConcurrent?: number, onProgress?: (progress: ParallelDownloadProgress) => void): Promise<void[]>;
47
96
  //#endregion
48
97
  //#region src/index.d.ts
49
98
  declare function fastLink(params: DirectLinkParams, options?: Partial<Options>): Promise<string | Record<string, any>[]>;
50
- declare function fastDownload(params: DownloadParams, options?: Partial<Options>): Promise<void>;
99
+ declare function fastDownload(params: DownloadParams | DownloadParams[], options?: Partial<Options>): Promise<void>;
51
100
  //#endregion
52
- export { DEFAULT_OPTIONS, DirectLinkParams, DownloadParams, M3U8Params, Options, UrlType, __dirname, defineConfig, downloadAnimeIdHentai, downloadBilibili, downloadDirpy, downloadHanime, downloadKoreanPm, downloadMissav, downloadVideo, downloadWowxxx, downloadXHamster, fastDownload, fastLink, getAnimeIdHentaiLink, getBilibiliLink, getDirpyLink, getHanimeLink, getKoreanPmLink, getMissavLink, getWowxxxLink, getXHamsterLink, remoteM3U8ToMP4 };
101
+ export { DEFAULT_OPTIONS, DirectLinkParams, DownloadParams, M3U8DownloadProgress, M3U8Params, Options, ParallelDownloadProgress, ParallelM3U8Progress, UrlType, __dirname, defineConfig, downloadAnimeIdHentai, downloadBilibili, downloadDirpy, downloadHanime, downloadKoreanPm, downloadMissav, downloadRule34XyzVideo, downloadVideo, downloadVideosParallel, downloadWowxxx, downloadXHamster, fastDownload, fastLink, getAnimeIdHentaiLink, getBilibiliLink, getDirpyLink, getHanimeLink, getKoreanPmLink, getMissavLink, getRule34XyzVideoLink, getWowxxxLink, getXHamsterLink, remoteM3U8ToMP4, remoteM3U8ToMP4Parallel };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{C as e,T as t,_ as n,a as r,b as i,c as a,d as o,f 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,s as _,t as v,u as y,v as b,w as x,x as S,y as C}from"./judgeUrl-ChKFgqzP.mjs";import{defineConfig as w}from"./config.mjs";import{bold as T,dim as E}from"ansis";const{version:D}=t;async function O(t,r=e){let{url:i,cwd:s}=t,{proxy:c,puppeteer:d}=r,f=c||{},g=d||{},_=v(i);return S.info(`fast-dirpy ${E(`v${D}`)} : ${T(`Direct Link Getter`)}.`),_===p.Bilibili?(S.info(`Matched link source: Bilibili.`),i.includes(`bilibili.com`)?await n(i):(S.error(`Please provide a valid Bilibili URL.`),``)):_===p.AnimeIdHentai?(S.info(`Matched link source: Animeidhentai.`),await C({url:i,cwd:s},{...f,...g})):_===p.KoreanPM?(S.info(`Matched link source: KoreanPM.`),await o({url:i,cwd:s},f)):_===p.MissAV?(S.info(`Matched link source: MissAV.`),await a({url:i,cwd:s})):_===p.Hanime?(S.info(`Matched link source: Hanime.`),await h({url:i,cwd:s},f)):_===p.Wowxxx?(S.info(`Matched link source: Wowxxx.`),await m({url:i,cwd:s},f)):_===p.XHamster?(S.info(`Matched link source: XHamster.`),await u({url:i,cwd:s},f)):_===p.Dirpy?(S.info(`Matched link source: Dirpy.`),await l({url:i,cwd:s},f)):(S.error(`Your link is not supported!`),``)}async function k(t,n=e){let{url:a,path:o,cwd:l}=t,{proxy:u,puppeteer:m}=n,h=u||{},x=m||{},C=v(a);S.info(`fast-dirpy ${E(`v${D}`)} : ${T(`Video Downloader`)}.`),C===p.Bilibili?(S.info(`Matched link source: Bilibili.`),await c({url:a,path:o})):C===p.AnimeIdHentai?(S.info(`Matched link source: AnimeIdHentai.`),await b({url:a,path:o||`./animeidhentai.mp4`,cwd:l},{...h,...x})):C===p.KoreanPM?(S.info(`Matched link source: KoreanPM.`),await y({url:a,path:o||`./korean-pm.mp4`,cwd:l},h)):C===p.MissAV?(S.info(`Matched link source: MissAV.`),await _({url:a,path:o,cwd:l})):C===p.Hanime?(S.info(`Matched link source: Hanime.`),await s({url:a,path:o,cwd:l},h)):C===p.Wowxxx?(S.info(`Matched link source: Wowxxx.`),await r({url:a,path:o,cwd:l},h)):C===p.XHamster?(S.info(`Matched link source: XHamster.`),await g({url:a,path:o,cwd:l},h)):C===p.Dirpy?(S.info(`Matched link source: Dirpy.`),f({url:a,path:o||`./dirpy.mp4`,cwd:l},h)):C===p.MP4?(S.info(`Matched link source: mp4.`),await i({url:a,path:o||`./mp4-download.mp4`,cwd:l},h)):C===p.M3U8?(S.info(`Matched link source: m3u8.`),d({url:a,path:o||`./m3u8-download.mp4`,cwd:l})):S.error(`Your link is not supported!`)}export{e as DEFAULT_OPTIONS,p as UrlType,x as __dirname,w as defineConfig,b as downloadAnimeIdHentai,c as downloadBilibili,f as downloadDirpy,s as downloadHanime,y as downloadKoreanPm,_ as downloadMissav,i as downloadVideo,r as downloadWowxxx,g as downloadXHamster,k as fastDownload,O as fastLink,C as getAnimeIdHentaiLink,n as getBilibiliLink,l as getDirpyLink,h as getHanimeLink,o as getKoreanPmLink,a as getMissavLink,m as getWowxxxLink,u as getXHamsterLink,d as remoteM3U8ToMP4};
1
+ import{C as e,D as t,O 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,k as m,l as h,m as g,n as _,o as v,p as y,r as b,s as x,t as S,u as C,v as w,w as T,x as E,y as D}from"./judgeUrl-NeoaY5pF.mjs";import{defineConfig as O}from"./config.mjs";import{bold as k,dim as A}from"ansis";import j from"axios";import{load as M}from"cheerio";async function N(n,r=t){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await T(r,a),c=o?.host===``?void 0:o,{data:l}=await j.get(i,{headers:{"User-Agent":e(),Referer:`https://rule34.xyz`},proxy:c,timeout:s}),u=M(l),d=``,f=u(`source[type="video/mp4"]`).attr();return f&&(d=`https://rule34.xyz${f.src.replace(`mov480`,`mov`)}`),d}async function P(e,n=t){Array.isArray(e)||(e=[e]);let i=[];for(let t of e){let e=await N({url:t.url,cwd:t.cwd},n);i.push({...t,url:e})}await r(i)}const{version:F}=m;async function I(e,n=t){let{url:r,cwd:a}=e,{proxy:o,puppeteer:c}=n,l=o||{},f=c||{},m=S(r);return i.info(`fast-dirpy ${A(`v${F}`)} : ${k(`Direct Link Getter`)}.`),m===_.Bilibili?(i.info(`Matched link source: Bilibili.`),r.includes(`bilibili.com`)?await w({url:r,cwd:a}):(i.error(`Please provide a valid Bilibili URL.`),``)):m===_.AnimeIdHentai?(i.info(`Matched link source: Animeidhentai.`),await s({url:r,cwd:a},{...l,...f})):m===_.KoreanPM?(i.info(`Matched link source: KoreanPM.`),await u({url:r,cwd:a},l)):m===_.Hanime?(i.info(`Matched link source: Hanime.`),await g({url:r,cwd:a},l)):m===_.Wowxxx?(i.info(`Matched link source: Wowxxx.`),await v({url:r,cwd:a},l)):m===_.XHamster?(i.info(`Matched link source: XHamster.`),await p({url:r,cwd:a},l)):m===_.Dirpy?(i.info(`Matched link source: Dirpy.`),await d({url:r,cwd:a},l)):(i.error(`Your link is not supported!`),``)}async function L(e,n=t){if(Array.isArray(e)||(e=[e]),e.length<1){i.error(`No valid params provided.`);return}let{proxy:s,puppeteer:c}=n,u=s||{},d=c||{};for(let t of e)t.urlType=S(t.url);i.info(`fast-dirpy ${A(`v${F}`)} : ${k(`Video Downloader`)}.`);let p=e.filter(e=>e.urlType===_.Bilibili),m=e.filter(e=>e.urlType===_.AnimeIdHentai),h=e.filter(e=>e.urlType===_.KoreanPM),g=e.filter(e=>e.urlType===_.Hanime),v=e.filter(e=>e.urlType===_.Wowxxx),w=e.filter(e=>e.urlType===_.XHamster),T=e.filter(e=>e.urlType===_.Dirpy),E=e.filter(e=>e.urlType===_.MP4),O=e.filter(e=>e.urlType===_.M3U8),j=e.filter(e=>e.urlType===_.MissAV);p.length>0&&await a(p),m.length>0&&await D(m,{...u,...d}),h.length>0&&await l(h,{...u,...d}),g.length>0&&await y(g,{...u,...d}),v.length>0&&await o(v,{...u,...d}),w.length>0&&await b(w,{...u,...d}),j.length>0&&await x(j,{...u}),T.length>0&&await f(T,{...u,...d}),E.length>0&&await r(E,{...u,...d}),O.length>0&&await C(O,{...u,...d})}export{t as DEFAULT_OPTIONS,_ as UrlType,n as __dirname,O as defineConfig,D as downloadAnimeIdHentai,a as downloadBilibili,f as downloadDirpy,y as downloadHanime,l as downloadKoreanPm,x as downloadMissav,P as downloadRule34XyzVideo,E as downloadVideo,r as downloadVideosParallel,o as downloadWowxxx,b as downloadXHamster,L as fastDownload,I as fastLink,s as getAnimeIdHentaiLink,w as getBilibiliLink,d as getDirpyLink,g as getHanimeLink,u as getKoreanPmLink,c as getMissavLink,N as getRule34XyzVideoLink,v as getWowxxxLink,p as getXHamsterLink,h as remoteM3U8ToMP4,C as remoteM3U8ToMP4Parallel};
@@ -0,0 +1 @@
1
+ import{readFile as e}from"node:fs/promises";import t from"axios";import{load as n}from"cheerio";import r from"node:path";import{fileURLToPath as i}from"node:url";import{createConfigLoader as a}from"unconfig";import o from"node:process";import{consola as s}from"consola";import c,{createWriteStream as l}from"node:fs";import u from"puppeteer-core";import d from"m3u8stream";var f=Object.create,p=Object.defineProperty,m=Object.getOwnPropertyDescriptor,h=Object.getOwnPropertyNames,g=Object.getPrototypeOf,_=Object.prototype.hasOwnProperty,v=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),y=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=h(t),a=0,o=i.length,s;a<o;a++)s=i[a],!_.call(e,s)&&s!==n&&p(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=m(t,s))||r.enumerable});return e},ee=(e,t,n)=>(n=e==null?{}:f(g(e)),y(t||!e||!e.__esModule?p(n,`default`,{value:e,enumerable:!0}):n,e)),b=`1.0.1`,x={name:`fast-dirpy`,type:`module`,version:b,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.14.0`,cac:`^7.0.0`,cheerio:`^1.2.0`,consola:`^3.4.2`,m3u8stream:`^0.8.6`,"puppeteer-core":`^24.40.0`,"restore-cursor":`^5.1.0`,unconfig:`^7.5.0`},devDependencies:{"@antfu/eslint-config":`^8.0.0`,"@types/node":`^25.5.2`,deepmerge:`^4.3.1`,eslint:`^10.2.0`,taze:`^19.11.0`,tsdown:`^0.21.7`,tsx:`^4.21.0`,typescript:`^6.0.2`,vitest:`^4.1.2`}};const S={timeout:2e4},C=i(import.meta.url),w=r.dirname(C);var T=v(((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 E=s.withTag(`fast-dirpy`);function te(e){`CONSOLA_LEVEL`in o.env||(E.level=e?0:3)}var D=ee(T(),1);async function O(e,t){let n=S,{config:r,sources:i}=await a({sources:[{files:[`fast-dirpy.config`],extensions:[`ts`,`mts`,`cts`,`js`,`mjs`,`cjs`,`json`]}],cwd:t||process.cwd(),merge:!1}).load();return i.length?(E.info(`Config file found: ${i[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)}function M(e){return`[${e.url.split(`/`).pop()||`unknown`}]`}async function N(e,n=S){let{path:r,url:i}=e,a=M(e),{proxy:o,timeout:s}=await O(n),l=o?.host===``?void 0:o;if(i===``)return Promise.reject(Error(`Extract direct link failed!`));let u=c.createWriteStream(r||`./download.mp4`);return(await t({url:i,headers:{"User-Agent":j(),...n.headers},method:`GET`,responseType:`stream`,proxy:l,timeout:s,onDownloadProgress:e=>{let{loaded:t,total:n,progress:r}=e,i=`[${a??``}] loaded:${t} total: ${n} progress: ${(r*100).toFixed(2)}%`;E.info(i)}})).data.pipe(u),new Promise((e,t)=>{u.on(`finish`,e),u.on(`error`,t)})}async function P(e,t=S,n=5,r){let i=[],a=new Set,o=0,s=0,c=e.length;E.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),E.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 E.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 E.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 u.launch(e)}async function ne(e,r=S){let{url:i,cwd:a}=e,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await t.get(i,{headers:{"User-Agent":j()},proxy:c,timeout:s}),u=n(l),d=``,f=u(`div.embed.rad2 > iframe`).attr();return f&&(d=f.src),d}async function I(e,t=S){let{url:n,cwd:r}=e,{proxy:i,puppeteer:a}=await O(t,r),o=i?.host===``?void 0:i,s=await ne({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 re(e,t=S){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 L(e,t=S){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(/&amp;/g,`&`),{videoUrl:t}}))).filter(e=>e.videoUrl)[0]?.videoUrl}catch(e){E.error(`Error during scraping: ${e}`)}finally{E.info(`Closing browser`),await l.close()}}async function R(e){Array.isArray(e)||(e=[e]);let t=[];for(let n of e){let e=await L({url:n.url,cwd:n.cwd});t.push({...n,url:e})}await P(t)}async function z(e,r=S){let{url:i,cwd:a}=e,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await t.get(`https://dirpy.com/studio`,{params:{url:i},headers:{"User-Agent":j(),Referer:`https://dirpy.com/studio?url=${i}`},proxy:c,timeout:s}),u=n(l),d=``,f=u(`#media-source`).attr();return f&&(d=f.src),d}async function B(e,t=S){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let e=await z({url:r.url,cwd:r.cwd},t);n.push({...r,url:e})}n.length>0&&await P(n)}function V(e,t){return Number(e.size)-Number(t.size)}async function H(e,r=S){let{url:i,cwd:a}=e,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await t.get(i,{headers:{"User-Agent":j(),Referer:`https://hanime1.me/`},proxy:c,timeout:s}),u=n(l)(`source[type="video/mp4"]`);return Object.values(u).map(e=>e.attribs).filter(e=>e!=null).sort(V)}async function U(e,t=S){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let{url:e,cwd:i}=r,a=await H({url:e,cwd:i},t);a.length>0&&E.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 W(e,r=S){let{url:i,cwd:a}=e,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await t.get(i,{headers:{"User-Agent":j()},proxy:c,timeout:s}),u=n(l),d=``,f=u(`meta[itemprop="contentURL"]`).attr();return f&&(d=f.content),d}async function G(e,t=S){Array.isArray(e)||(e=[e]);let n=[];for(let r of e){let{url:e,cwd:i}=r,a=await W({url:e,cwd:i},t);n.push({...r,url:a})}n.length>0&&await P(n)}function K(e){return`[${e.url?.split(`/`).pop()||`unknown`}]`}async function q(e,t=S,n){let{url:i,cwd:a,path:o}=e,{proxy:s,timeout:c}=await O(t,a);if(!i)return Promise.reject(Error(`M3U8 URL is required!`));let u=K(e),f=o??r.resolve(w,`../m3u8-download.mp4`);return E.info(`${u} Starting M3U8 download from: ${i}`),E.info(`${u} Output path: ${f}`),new Promise((e,r)=>{try{let a=d(i,{requestOptions:{headers:t.headers,timeout:c,...s?.host?{proxy:`http://${s.host}:${s.port}`}:{}}}),o=l(f);a.on(`progress`,(e,t,r)=>{let i=r/1024/1024,a=t>0?e.num/t*100:0,o={segment:e,totalSegments:t,downloaded:r,downloadedMB:i,percent:a};E.info(`${u} Segment: ${e.num}/${t}, Downloaded: ${i.toFixed(2)}MB (${a.toFixed(2)}%)`),n?.(o)}),a.on(`error`,e=>{E.error(`${u} M3U8 stream error: ${e.message}`),o.end(),r(e)}),a.pipe(o),o.on(`finish`,()=>{E.info(`${u} M3U8 download completed successfully`),e()}),o.on(`error`,e=>{E.error(`${u} File write error: ${e.message}`),r(e)})}catch(e){let t=e instanceof Error?e.message:String(e);E.error(`${u} Failed to initialize M3U8 download: ${t}`),r(e)}})}async function J(e,t=S,n=3,r,i){let a=[],o=new Set,s=0,c=0,l=e.length;E.info(`Starting parallel M3U8 downloads: ${l} videos, max concurrent: ${n}`);for(let[u,d]of e.entries()){let e=K(d),f=q(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),E.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 E.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 E.info(`Parallel M3U8 downloads finished. Success: ${s}, Failed: ${c}, Total: ${l}`),u.filter(e=>e.status===`fulfilled`).map(e=>e.value)}async function Y(e){let t=e.match(/m3u8\|([a-f0-9|]+)\|com\|surrit\|https\|video/);return t?t[1].split(`|`).reverse().join(`-`):(E.error(`Failed to extract UUID from HTML.`),null)}async function X(e,n=S){let{cwd:r,missavHtmlPage:i}=e,{proxy:a,timeout:o}=await O(n,r);if(!i)return E.error(`missavHtmlPage is required for getMissavLink.`),null;let s=await Y(i),c=`https://surrit.com/${s}/playlist.m3u8`,{data:l}=await t.get(c,{headers:{"User-Agent":j(),Referer:n.headers?.Referer||`https://missav.ws/`},proxy:a,timeout:o});return`https://surrit.com/${s}/${l.match(/(?:\d+p|\d+x\d+)\/video\.m3u8/g).at(-1)}`}async function ie(t,n=S){Array.isArray(t)||(t=[t]);let r=[];for(let i of t){let{cwd:t,url:a}=i;if(!a||!a.includes(`missav:`)){E.warn(`Invalid missavHtmlPath: ${a}`);continue}let o=await X({missavHtmlPage:await e(a.replace(`missav:`,``).trim(),`utf-8`),cwd:t},n);r.push({...i,url:o})}await J(r,{...n,headers:{Referer:n.headers?.Referer||`https://missav.ws/`}})}function ae(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(e,r=S){let{url:i,cwd:a}=e,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await t.get(i,{headers:{"User-Agent":j(),Referer:`https://www.wow.xxx/`},proxy:c,timeout:s}),u=n(l)(`source[type="video/mp4"]`);return Object.values(u).map(e=>e.attribs).filter(e=>e!=null).sort(ae)}async function oe(e,t=S){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&&E.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(e,r=S){let{url:i,cwd:a}=e,{proxy:o,timeout:s}=await O(r,a),c=o?.host===``?void 0:o,{data:l}=await t.get(i,{headers:{"User-Agent":j(),Referer:`https://xhamster.com`},proxy:c,timeout:s}),u=n(l),d=``,f=u(`head link[rel="preload"][crossorigin="true"][as="fetch"]`).attr();return f&&(d=f.href),d}async function se(e,t=S){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.MissAV=6]=`MissAV`,e[e.NJavTV=7]=`NJavTV`,e[e.Wowxxx=8]=`Wowxxx`,e[e.XHamster=9]=`XHamster`,e[e.MP4=10]=`MP4`,e}({});function ce(e){return e.includes(`bilibili`)||/BV[a-zA-Z0-9]+/.test(e)?$.Bilibili:e.includes(`animeidhentai`)?$.AnimeIdHentai:e.includes(`koreanpornmovie`)?$.KoreanPM:e.startsWith(`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{b as A,j as C,S as D,te as E,w as O,P as S,E as T,R as _,oe as a,I as b,X as c,G as d,W as f,z as g,B as h,Q as i,x as k,q as l,H as m,$ as n,Z as o,U as p,se as r,ie as s,ce as t,J as u,L as v,O as w,N as x,re as y};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fast-dirpy",
3
3
  "type": "module",
4
- "version": "0.3.10",
4
+ "version": "1.0.1",
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.2",
41
- "cac": "^6.7.14",
42
- "cheerio": "^1.1.2",
40
+ "axios": "^1.14.0",
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.35.0",
45
+ "puppeteer-core": "^24.40.0",
46
46
  "restore-cursor": "^5.1.0",
47
- "unconfig": "^7.4.2"
47
+ "unconfig": "^7.5.0"
48
48
  },
49
49
  "devDependencies": {
50
- "@antfu/eslint-config": "^7.2.0",
51
- "@types/node": "^25.0.10",
50
+ "@antfu/eslint-config": "^8.0.0",
51
+ "@types/node": "^25.5.2",
52
52
  "deepmerge": "^4.3.1",
53
- "eslint": "^9.39.2",
54
- "taze": "^19.9.2",
55
- "tsdown": "^0.19.0",
53
+ "eslint": "^10.2.0",
54
+ "taze": "^19.11.0",
55
+ "tsdown": "^0.21.7",
56
56
  "tsx": "^4.21.0",
57
- "typescript": "^5.9.3",
58
- "vitest": "^4.0.17"
57
+ "typescript": "^6.0.2",
58
+ "vitest": "^4.1.2"
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.10`,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.35.0`,"restore-cursor":`^5.1.0`,unconfig:`^7.4.2`},devDependencies:{"@antfu/eslint-config":`^7.2.0`,"@types/node":`^25.0.10`,deepmerge:`^4.3.1`,eslint:`^9.39.2`,taze:`^19.9.2`,tsdown:`^0.19.0`,tsx:`^4.21.0`,typescript:`^5.9.3`,vitest:`^4.0.17`}};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 te(e){`CONSOLA_LEVEL`in a.env||(T.level=e?0:3)}var E=v(w(),1);async function D(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,E.default)((0,E.default)(n,r),e)):(0,E.default)(n,e)}function O(e){return e[Math.floor(Math.random()*e.length)]}const k=[`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 A(){return O(k)}async function j(t,n=x){let{path:r,url:i}=t,{proxy:a,timeout:o}=await D(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":A(),...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 M(e){return await l.launch(e)}async function ne(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await D(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":A()},proxy:c,timeout:s}),u=t(l),d=``,f=u(`div.embed.rad2 > iframe`).attr();return f&&(d=f.src),d}async function N(e,t=x){let{url:n,cwd:r}=e,{proxy:i,puppeteer:a}=await D(t,r),o=i?.host===``?void 0:i,s=await ne({url:n},{proxy:o}),{executablePath:c,headless:l}=a,u=await M({executablePath:c,headless:l,args:[`--proxy-server=http://${o?.host}:${i?.port}`]}),d=A(),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 P(e,t=x){let{path:n,url:r,cwd:i}=e;await j({url:await N({url:r},t),path:n,cwd:i},t)}function F(e){let t=e.match(/BV[a-zA-Z0-9]+/);return t?`https://bilibili-real-url.deno.dev/${t[0]}.mp4`:``}async function I(e){let{path:t,url:n}=e,r=F(n);r===``?console.error(`Extract direct link failed!`):await j({url:r,path:t||`./download.mp4`})}async function L(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await D(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(`https://dirpy.com/studio`,{params:{url:i},headers:{"User-Agent":A(),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 R(e,t=x){let{path:n,url:r,cwd:i}=e;await j({url:await L({url:r},t),path:n,cwd:i},t)}function z(e,t){return Number(e.size)-Number(t.size)}async function B(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await D(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":A(),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(z)}async function V(e,t=x){let{path:n,url:r,cwd:i}=e,a=await B({url:r},t);a.length>0&&T.success(`Successfully get video sources, size ${a[a.length-1].size} to be downloaded.`),await j({url:a[a.length-1].src,path:n,cwd:i},t)}async function H(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await D(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":A()},proxy:c,timeout:s}),u=t(l),d=``,f=u(`meta[itemprop="contentURL"]`).attr();return f&&(d=f.content),d}async function U(e,t=x){let{path:n,url:r,cwd:i}=e;await j({url:await H({url:r},t),path:n,cwd:i},t)}function W(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 G(e){return new Promise(t=>setTimeout(t,e*1e3))}async function K(e,t=x){let{url:n,cwd:r}=e,{proxy:i,puppeteer:a}=await D(t,r),o=i?.host===``?void 0:i,{executablePath:s,headless:c}=a,l=await M({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=A();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),G(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 q(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 J(e){return e.split(`/`).pop()||(T.error(`Failed to extract movie ID from URL.`),null)}async function Y(t){let{url:n,cwd:r}=t,i=await q(await K({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 X(e){let{url:t,cwd:n,path:r}=e,i=J(t);W({url:await Y({url:t,cwd:n}),cwd:n,path:r||`${i}.mp4`})}function re(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 D(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":A(),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(re)}async function ie(e,t=x){let{path:n,url:r,cwd:i}=e,a=await Z({url:r},t);a.length>0&&T.success(`Successfully get video sources, size ${a[a.length-1].label} to be downloaded.`),await j({url:a[a.length-1].src,path:n,cwd:i},t)}async function Q(n,r=x){let{url:i,cwd:a}=n,{proxy:o,timeout:s}=await D(r,a),c=o?.host===``?void 0:o,{data:l}=await e.get(i,{headers:{"User-Agent":A(),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 ae(e,t=x){let{path:n,url:r,cwd:i}=e,a=await Q({url:r},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`),W({url:a,cwd:i,path:n||`./xhamster-vid.mp4`})}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.XHamster=8]=`XHamster`,e[e.MP4=9]=`MP4`,e}({});function oe(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{x as C,y as E,te as S,b as T,F as _,ie as a,j as b,Y as c,H as d,V as f,I as g,L as h,Q as i,W as l,R as m,$ as n,Z as o,B as p,ae as r,X as s,oe as t,U as u,P as v,C as w,T as x,N as y};