multporn-api-sdk 0.1.0 → 0.1.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.
Files changed (2) hide show
  1. package/README.md +271 -271
  2. package/package.json +2 -1
package/README.md CHANGED
@@ -1,271 +1,271 @@
1
- # @e18lab/multporn-api
2
-
3
- **Unofficial** HTML scraper for Multporn (Node 18+). Supports hub pagination (`/comic`, `/munga`, etc.), **alphabet** views, **search** (HTML and Drupal AJAX), **posts** (images, video metadata, related), plus a smart resolver to tell whether a link is a hub or a post.
4
-
5
- > ⚠️ This library is an unofficial scraper. Use responsibly, respect the target’s terms/robots, and add caching/throttling in production.
6
-
7
- ---
8
-
9
- ## Installation
10
-
11
- ```bash
12
- yarn add @e18lab/multporn-api
13
- # or
14
- npm i @e18lab/multporn-api
15
- ````
16
-
17
- Node v24.11.0 is required.
18
-
19
- ---
20
-
21
- ## Quick start
22
-
23
- ```ts
24
- import { MultpornClient } from '@e18lab/multporn-api';
25
-
26
- const mp = new MultpornClient({
27
- baseURL: 'https://multporn.net', // default
28
- timeoutMs: 15000,
29
- retry: { retries: 3 },
30
- });
31
-
32
- // Latest posts (homepage “New”)
33
- const latest = await mp.latest(0);
34
- console.log('latest:', latest.items.slice(0, 3));
35
-
36
- // “Manga” hub
37
- const manga = await mp.listByPath('/munga', 0);
38
- console.log('manga page0 items:', manga.items.length, 'hasNext:', manga.hasNext);
39
-
40
- // Alphabet: letters for Manga
41
- const letters = await mp.alphabetLetters('manga');
42
- console.log('letters:', letters.map(l => l.label).join(' '));
43
-
44
- // Alphabet: entries for letter A
45
- const mangaA = await mp.alphabet('manga', 'A', 0);
46
- // same via listByPath:
47
- const mangaA2 = await mp.listByPath('/munga', 0, { letter: 'A' });
48
-
49
- // Search
50
- const found = await mp.search('naruto', 0);
51
- console.log('found:', found.items.slice(0, 3));
52
-
53
- // Post (URL or relative slug)
54
- const post = await mp.getPost('/comics/haywire'); // full URL is also fine
55
- console.log(post.title, 'images:', post.images?.length || 0);
56
-
57
- // Smart resolve: detect hub vs post
58
- const resolved = await mp.resolveSmart('https://multporn.net/munga');
59
- if (resolved.route === 'listing') {
60
- console.log('This is a hub. items:', resolved.data.items.length);
61
- } else if (resolved.route === 'viewer') {
62
- console.log('This is a post. kind:', resolved.data.viewer.kind);
63
- }
64
- ```
65
-
66
- ---
67
-
68
- ## API Overview
69
-
70
- ### Constructor
71
-
72
- ```ts
73
- new MultpornClient(options?: {
74
- baseURL?: string; // default: https://multporn.net
75
- timeoutMs?: number; // request timeout
76
- retry?: { retries?: number };
77
- headers?: Record<string, string>;
78
- })
79
- ```
80
-
81
- ### Client methods
82
-
83
- ```ts
84
- latest(page?: number, params?: ListingQuery): Promise<Page<ListingItem>>
85
-
86
- listByPath(
87
- path: string,
88
- page?: number,
89
- params?: ListingQuery & { letter?: string },
90
- ): Promise<Page<ListingItem>>
91
-
92
- search(query: string, page?: number): Promise<Page<ListingItem>>
93
-
94
- getPost(urlOrSlug: string): Promise<Post>
95
-
96
- resolve(urlOrSlug: string, opts?: ResolveOptions): Promise<ViewerResult>
97
-
98
- resolveSmart(urlOrSlug: string, opts?: ResolveOptions): Promise<ResolvedRoute>
99
-
100
- updates(params?: MultpornUpdatesParams): Promise<UpdatesResult>
101
-
102
- viewUpdates(viewName: ViewName, params?: Omit<MultpornUpdatesParams, 'view_name'>): Promise<UpdatesResult>
103
-
104
- alphabetLetters(section: 'comics' | 'manga' | 'pictures' | 'video' | 'games'): Promise<AlphabetLetter[]>
105
-
106
- alphabet(section: AlphabetSection, letter: string, page?: number): Promise<Page<ListingItem>>
107
- ```
108
-
109
- ### Key types (simplified)
110
-
111
- ```ts
112
- type ListingItem = {
113
- title: string;
114
- url: string;
115
- thumb?: string;
116
- };
117
-
118
- type Page<T> = {
119
- items: T[];
120
- page: number;
121
- hasNext: boolean;
122
- totalPages: number;
123
- };
124
-
125
- type Post = {
126
- url: string;
127
- title: string;
128
- description?: string;
129
- images?: string[];
130
- videos?: string[]; // may be HLS files and/or direct MP4s
131
- thumb?: string;
132
- tags?: string[];
133
- recommendations?: ListingItem[];
134
- };
135
- ```
136
-
137
- ---
138
-
139
- ## Pagination
140
-
141
- All listing methods return `Page<ListingItem>` with `page`, `hasNext`, and `totalPages`.
142
-
143
- ```ts
144
- let p = 0;
145
- for (;;) {
146
- const page = await mp.listByPath('/munga', p);
147
- // process page.items
148
- if (!page.hasNext) break;
149
- p += 1;
150
- }
151
- ```
152
-
153
- ---
154
-
155
- ## Search
156
-
157
- Search uses a dual strategy: parse the regular HTML results first; if empty, fall back to Drupal AJAX (`/views/ajax`). That covers most search pages reliably.
158
-
159
- ```ts
160
- const res = await mp.search('genshin', 0);
161
- res.items.forEach(i => console.log(i.title, i.url, i.thumb));
162
- ```
163
-
164
- If you want to display category badges like “Comics”, “Manga”, “Pictures”, “Gay porn comics”, derive a label from the first URL path segment (e.g. `comics`, `hentai_manga`, `pictures`, `gay_porn_comics`) and show it next to the title.
165
-
166
- ---
167
-
168
- ## Alphabet
169
-
170
- Some hubs expose an alphabet. Use:
171
-
172
- ```ts
173
- const letters = await mp.alphabetLetters('manga'); // list of available letters
174
- const pageA = await mp.alphabet('manga', 'A', 0); // items for letter A
175
- // or:
176
- const pageA2 = await mp.listByPath('/munga', 0, { letter: 'A' });
177
- ```
178
-
179
- ---
180
-
181
- ## Example Dev Server
182
-
183
- `examples/dev-server.mjs` ships a ready-to-use Express server over the SDK. It includes HTML pages for quick UI testing, REST endpoints, media proxies, and Swagger docs.
184
-
185
- ### Features
186
-
187
- * **HTML pages**
188
-
189
- * `/hub?path=/munga[&letter=A][&page=0]` – hub preview with alphabet (pager hidden when there’s only one page)
190
- * `/viewer?url=...` – post preview (images as a gallery, videos via embedded `player.html`)
191
- * `/search?q=genshin[&page=0]` – search page with grouping and pagination
192
- * **REST endpoints**
193
-
194
- * `/api/list` – hub listing (root `/` serves “latest”)
195
- * `/api/search` – search with pagination
196
- * `/api/resolve` – smart route detection (hub vs post)
197
- * `/api/post` – post details
198
- * `/api/updates` – Drupal Views feeds (e.g., `new_mini`, `updated_manga`, etc.)
199
- * `/api/alphabet/letters` – alphabet letters for a section
200
- * `/api/alphabet/items` – items for a letter in a section
201
- * **Proxies**
202
-
203
- * `/img?url=...` – image proxy with proper `Referer`/`Origin`
204
- * `/vid?url=...` – video proxy with `Range` support (HLS/MP4)
205
- * `/raw?url=...` – raw upstream fetch
206
- * **Docs**
207
-
208
- * Swagger UI at `/docs` backed by `/openapi.json` (endpoints, params, schemas, examples)
209
-
210
- ### Environment
211
-
212
- * `BASE_URL` – upstream origin (default: `https://multporn.net`)
213
- * `HOST` – bind host (default: `0.0.0.0`)
214
- * `PORT` – server port (default: `5173`)
215
- * `PUBLIC_BASE_URL` – public base URL (for links in OpenAPI/Swagger)
216
-
217
- ### Run
218
-
219
- ```bash
220
- # 1) Build the SDK (to produce dist/*)
221
- npm run build
222
-
223
- # 2) Start the dev server
224
- node examples/dev-server.mjs
225
-
226
- # Then open:
227
- # http://localhost:5173/docs
228
- # http://localhost:5173/hub?path=/munga
229
- # http://localhost:5173/search?q=genshin
230
- # http://localhost:5173/viewer?url=https://multporn.net/comics/...
231
- ```
232
-
233
- ### REST examples
234
-
235
- ```bash
236
- # Search
237
- curl 'http://localhost:5173/api/search?q=genshin&page=0'
238
-
239
- # Hub listing (page 0)
240
- curl 'http://localhost:5173/api/list?path=/munga&page=0'
241
-
242
- # Latest (homepage)
243
- curl 'http://localhost:5173/api/list?page=0'
244
-
245
- # Post
246
- curl 'http://localhost:5173/api/post?url=https://multporn.net/comics/haywire'
247
-
248
- # Smart resolve
249
- curl 'http://localhost:5173/api/resolve?url=https://multporn.net/munga'
250
- ```
251
-
252
- ---
253
-
254
- ## Swagger / OpenAPI
255
-
256
- The dev server serves an extended OpenAPI spec at `/openapi.json` and Swagger UI at `/docs`. All HTML pages and REST endpoints are listed with parameters, responses, and example payloads to simplify testing and integration.
257
-
258
- ---
259
-
260
- ## Frontend tips
261
-
262
- * Always load thumbs through the image proxy: `/img?url=…`.
263
- * Some cards may not have a `thumb`. Show a placeholder (e.g., “No image available”) instead of leaving the image empty.
264
- * For search results, derive a readable badge from the first URL segment (e.g., `comics`, `hentai_manga`, `pictures`, `gay_porn_comics`) and prefix the title with it to clarify the type.
265
-
266
- ---
267
-
268
- ## Notes
269
-
270
- * This is an **unofficial** scraper, intended for research/testing. Production usage should add caching, rate limits, retries, backoff, and robust error handling.
271
- * If site structure changes, update parsers accordingly.
1
+ # @e18lab/multporn-api
2
+
3
+ **Unofficial** HTML scraper for Multporn (Node 18+). Supports hub pagination (`/comic`, `/munga`, etc.), **alphabet** views, **search** (HTML and Drupal AJAX), **posts** (images, video metadata, related), plus a smart resolver to tell whether a link is a hub or a post.
4
+
5
+ > ⚠️ This library is an unofficial scraper. Use responsibly, respect the target’s terms/robots, and add caching/throttling in production.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ yarn add multporn-api-sdk
13
+ # or
14
+ npm i multporn-api-sdk
15
+ ````
16
+
17
+ Node v24.11.0 is required.
18
+
19
+ ---
20
+
21
+ ## Quick start
22
+
23
+ ```ts
24
+ import { MultpornClient } from '@e18lab/multporn-api';
25
+
26
+ const mp = new MultpornClient({
27
+ baseURL: 'https://multporn.net', // default
28
+ timeoutMs: 15000,
29
+ retry: { retries: 3 },
30
+ });
31
+
32
+ // Latest posts (homepage “New”)
33
+ const latest = await mp.latest(0);
34
+ console.log('latest:', latest.items.slice(0, 3));
35
+
36
+ // “Manga” hub
37
+ const manga = await mp.listByPath('/munga', 0);
38
+ console.log('manga page0 items:', manga.items.length, 'hasNext:', manga.hasNext);
39
+
40
+ // Alphabet: letters for Manga
41
+ const letters = await mp.alphabetLetters('manga');
42
+ console.log('letters:', letters.map(l => l.label).join(' '));
43
+
44
+ // Alphabet: entries for letter A
45
+ const mangaA = await mp.alphabet('manga', 'A', 0);
46
+ // same via listByPath:
47
+ const mangaA2 = await mp.listByPath('/munga', 0, { letter: 'A' });
48
+
49
+ // Search
50
+ const found = await mp.search('naruto', 0);
51
+ console.log('found:', found.items.slice(0, 3));
52
+
53
+ // Post (URL or relative slug)
54
+ const post = await mp.getPost('/comics/haywire'); // full URL is also fine
55
+ console.log(post.title, 'images:', post.images?.length || 0);
56
+
57
+ // Smart resolve: detect hub vs post
58
+ const resolved = await mp.resolveSmart('https://multporn.net/munga');
59
+ if (resolved.route === 'listing') {
60
+ console.log('This is a hub. items:', resolved.data.items.length);
61
+ } else if (resolved.route === 'viewer') {
62
+ console.log('This is a post. kind:', resolved.data.viewer.kind);
63
+ }
64
+ ```
65
+
66
+ ---
67
+
68
+ ## API Overview
69
+
70
+ ### Constructor
71
+
72
+ ```ts
73
+ new MultpornClient(options?: {
74
+ baseURL?: string; // default: https://multporn.net
75
+ timeoutMs?: number; // request timeout
76
+ retry?: { retries?: number };
77
+ headers?: Record<string, string>;
78
+ })
79
+ ```
80
+
81
+ ### Client methods
82
+
83
+ ```ts
84
+ latest(page?: number, params?: ListingQuery): Promise<Page<ListingItem>>
85
+
86
+ listByPath(
87
+ path: string,
88
+ page?: number,
89
+ params?: ListingQuery & { letter?: string },
90
+ ): Promise<Page<ListingItem>>
91
+
92
+ search(query: string, page?: number): Promise<Page<ListingItem>>
93
+
94
+ getPost(urlOrSlug: string): Promise<Post>
95
+
96
+ resolve(urlOrSlug: string, opts?: ResolveOptions): Promise<ViewerResult>
97
+
98
+ resolveSmart(urlOrSlug: string, opts?: ResolveOptions): Promise<ResolvedRoute>
99
+
100
+ updates(params?: MultpornUpdatesParams): Promise<UpdatesResult>
101
+
102
+ viewUpdates(viewName: ViewName, params?: Omit<MultpornUpdatesParams, 'view_name'>): Promise<UpdatesResult>
103
+
104
+ alphabetLetters(section: 'comics' | 'manga' | 'pictures' | 'video' | 'games'): Promise<AlphabetLetter[]>
105
+
106
+ alphabet(section: AlphabetSection, letter: string, page?: number): Promise<Page<ListingItem>>
107
+ ```
108
+
109
+ ### Key types (simplified)
110
+
111
+ ```ts
112
+ type ListingItem = {
113
+ title: string;
114
+ url: string;
115
+ thumb?: string;
116
+ };
117
+
118
+ type Page<T> = {
119
+ items: T[];
120
+ page: number;
121
+ hasNext: boolean;
122
+ totalPages: number;
123
+ };
124
+
125
+ type Post = {
126
+ url: string;
127
+ title: string;
128
+ description?: string;
129
+ images?: string[];
130
+ videos?: string[]; // may be HLS files and/or direct MP4s
131
+ thumb?: string;
132
+ tags?: string[];
133
+ recommendations?: ListingItem[];
134
+ };
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Pagination
140
+
141
+ All listing methods return `Page<ListingItem>` with `page`, `hasNext`, and `totalPages`.
142
+
143
+ ```ts
144
+ let p = 0;
145
+ for (;;) {
146
+ const page = await mp.listByPath('/munga', p);
147
+ // process page.items
148
+ if (!page.hasNext) break;
149
+ p += 1;
150
+ }
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Search
156
+
157
+ Search uses a dual strategy: parse the regular HTML results first; if empty, fall back to Drupal AJAX (`/views/ajax`). That covers most search pages reliably.
158
+
159
+ ```ts
160
+ const res = await mp.search('genshin', 0);
161
+ res.items.forEach(i => console.log(i.title, i.url, i.thumb));
162
+ ```
163
+
164
+ If you want to display category badges like “Comics”, “Manga”, “Pictures”, “Gay porn comics”, derive a label from the first URL path segment (e.g. `comics`, `hentai_manga`, `pictures`, `gay_porn_comics`) and show it next to the title.
165
+
166
+ ---
167
+
168
+ ## Alphabet
169
+
170
+ Some hubs expose an alphabet. Use:
171
+
172
+ ```ts
173
+ const letters = await mp.alphabetLetters('manga'); // list of available letters
174
+ const pageA = await mp.alphabet('manga', 'A', 0); // items for letter A
175
+ // or:
176
+ const pageA2 = await mp.listByPath('/munga', 0, { letter: 'A' });
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Example Dev Server
182
+
183
+ `examples/dev-server.mjs` ships a ready-to-use Express server over the SDK. It includes HTML pages for quick UI testing, REST endpoints, media proxies, and Swagger docs.
184
+
185
+ ### Features
186
+
187
+ * **HTML pages**
188
+
189
+ * `/hub?path=/munga[&letter=A][&page=0]` – hub preview with alphabet (pager hidden when there’s only one page)
190
+ * `/viewer?url=...` – post preview (images as a gallery, videos via embedded `player.html`)
191
+ * `/search?q=genshin[&page=0]` – search page with grouping and pagination
192
+ * **REST endpoints**
193
+
194
+ * `/api/list` – hub listing (root `/` serves “latest”)
195
+ * `/api/search` – search with pagination
196
+ * `/api/resolve` – smart route detection (hub vs post)
197
+ * `/api/post` – post details
198
+ * `/api/updates` – Drupal Views feeds (e.g., `new_mini`, `updated_manga`, etc.)
199
+ * `/api/alphabet/letters` – alphabet letters for a section
200
+ * `/api/alphabet/items` – items for a letter in a section
201
+ * **Proxies**
202
+
203
+ * `/img?url=...` – image proxy with proper `Referer`/`Origin`
204
+ * `/vid?url=...` – video proxy with `Range` support (HLS/MP4)
205
+ * `/raw?url=...` – raw upstream fetch
206
+ * **Docs**
207
+
208
+ * Swagger UI at `/docs` backed by `/openapi.json` (endpoints, params, schemas, examples)
209
+
210
+ ### Environment
211
+
212
+ * `BASE_URL` – upstream origin (default: `https://multporn.net`)
213
+ * `HOST` – bind host (default: `0.0.0.0`)
214
+ * `PORT` – server port (default: `5173`)
215
+ * `PUBLIC_BASE_URL` – public base URL (for links in OpenAPI/Swagger)
216
+
217
+ ### Run
218
+
219
+ ```bash
220
+ # 1) Build the SDK (to produce dist/*)
221
+ npm run build
222
+
223
+ # 2) Start the dev server
224
+ node examples/dev-server.mjs
225
+
226
+ # Then open:
227
+ # http://localhost:5173/docs
228
+ # http://localhost:5173/hub?path=/munga
229
+ # http://localhost:5173/search?q=genshin
230
+ # http://localhost:5173/viewer?url=https://multporn.net/comics/...
231
+ ```
232
+
233
+ ### REST examples
234
+
235
+ ```bash
236
+ # Search
237
+ curl 'http://localhost:5173/api/search?q=genshin&page=0'
238
+
239
+ # Hub listing (page 0)
240
+ curl 'http://localhost:5173/api/list?path=/munga&page=0'
241
+
242
+ # Latest (homepage)
243
+ curl 'http://localhost:5173/api/list?page=0'
244
+
245
+ # Post
246
+ curl 'http://localhost:5173/api/post?url=https://multporn.net/comics/haywire'
247
+
248
+ # Smart resolve
249
+ curl 'http://localhost:5173/api/resolve?url=https://multporn.net/munga'
250
+ ```
251
+
252
+ ---
253
+
254
+ ## Swagger / OpenAPI
255
+
256
+ The dev server serves an extended OpenAPI spec at `/openapi.json` and Swagger UI at `/docs`. All HTML pages and REST endpoints are listed with parameters, responses, and example payloads to simplify testing and integration.
257
+
258
+ ---
259
+
260
+ ## Frontend tips
261
+
262
+ * Always load thumbs through the image proxy: `/img?url=…`.
263
+ * Some cards may not have a `thumb`. Show a placeholder (e.g., “No image available”) instead of leaving the image empty.
264
+ * For search results, derive a readable badge from the first URL segment (e.g., `comics`, `hentai_manga`, `pictures`, `gay_porn_comics`) and prefix the title with it to clarify the type.
265
+
266
+ ---
267
+
268
+ ## Notes
269
+
270
+ * This is an **unofficial** scraper, intended for research/testing. Production usage should add caching, rate limits, retries, backoff, and robust error handling.
271
+ * If site structure changes, update parsers accordingly.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multporn-api-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Unofficial Multporn HTML scraping SDK Node. Typed, with retries/timeouts.",
5
5
  "license": "MIT",
6
6
  "author": "Maks1mio",
@@ -8,6 +8,7 @@
8
8
  "main": "./dist/index.cjs",
9
9
  "module": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",
11
+ "publishConfig": { "access": "public" },
11
12
  "exports": {
12
13
  ".": {
13
14
  "types": "./dist/index.d.ts",