multporn-api-sdk 0.1.2 → 0.1.4

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
@@ -1,8 +1,14 @@
1
- # @e18lab/multporn-api
1
+ # `multporn-api-sdk`
2
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.
3
+ **Unofficial** typed SDK for Multiporn HTML parsing. It works in **Node 18+** and in **Expo/React Native** (without Node-stdlib), uses `fetch` + `AbortController' (timeouts/delays), `cheerio` for parsing, supports:
4
4
 
5
- > ⚠️ This library is an unofficial scraper. Use responsibly, respect the target’s terms/robots, and add caching/throttling in production.
5
+ * feeds/hubs (including pagination),
6
+ * **alphabetical** lists,
7
+ * **search** (HTML → fallback on Drupal AJAX),
8
+ * **posts/viewer** (images, videos, metadata, recommendations),
9
+ * "smart" route resolution (hub vs viewer).
10
+
11
+ > ⚠️ This is an **unofficial** scraper. Use it responsibly, follow the rules of the site and add cache/throttling in production.
6
12
 
7
13
  ---
8
14
 
@@ -11,76 +17,82 @@
11
17
  ```bash
12
18
  yarn add multporn-api-sdk
13
19
  # or
14
- npm i multporn-api-sdk
15
- ````
20
+ npm i multiporn-api-sdk
21
+ ```
16
22
 
17
- Node v24.11.0 is required.
23
+ ### Requirements and compatibility
24
+
25
+ * **Node**: ≥ **18.17** ( Cheerio 1.x requirement). ([GitHub][2])
26
+ * **Expo/React Native**: compatible out of the box (the library does not use standard Node library modules that are missing from RN/Expo). Details: Expo does not supply Node-stdlib ("`node:stream`", etc.) — this is correct and expected. ([Expo Documentation][1])
18
27
 
19
28
  ---
20
29
 
21
30
  ## Quick start
22
31
 
32
+ ### Node / Bun / Deno (Node-compatible runtime)
33
+
23
34
  ```ts
24
- import { MultpornClient } from '@e18lab/multporn-api';
35
+ import { MultpornClient } from 'multporn-api-sdk';
25
36
 
26
37
  const mp = new MultpornClient({
27
- baseURL: 'https://multporn.net', // default
38
+ baseURL: 'https://multporn.net',
28
39
  timeoutMs: 15000,
29
40
  retry: { retries: 3 },
30
41
  });
31
42
 
32
- // Latest posts (homepage “New”)
33
43
  const latest = await mp.latest(0);
34
- console.log('latest:', latest.items.slice(0, 3));
44
+ console.log(latest.items.slice(0, 3));
35
45
 
36
- // “Manga” hub
37
46
  const manga = await mp.listByPath('/munga', 0);
38
- console.log('manga page0 items:', manga.items.length, 'hasNext:', manga.hasNext);
47
+ console.log(manga.items.length, manga.hasNext);
39
48
 
40
- // Alphabet: letters for Manga
41
49
  const letters = await mp.alphabetLetters('manga');
42
- console.log('letters:', letters.map(l => l.label).join(' '));
43
-
44
- // Alphabet: entries for letter A
45
50
  const mangaA = await mp.alphabet('manga', 'A', 0);
46
- // same via listByPath:
47
- const mangaA2 = await mp.listByPath('/munga', 0, { letter: 'A' });
48
51
 
49
- // Search
50
52
  const found = await mp.search('naruto', 0);
51
- console.log('found:', found.items.slice(0, 3));
53
+ console.log(found.items.slice(0, 3));
52
54
 
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);
55
+ const post = await mp.getPost('/comics/haywire');
56
+ console.log(post.title, post.images?.length || 0);
56
57
 
57
- // Smart resolve: detect hub vs post
58
- const resolved = await mp.resolveSmart('https://multporn.net/munga');
58
+ const resolved = await mp.resolveSmart('https://multporn.net/munga ');
59
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);
60
+ console.log('Hub, elements:', resolved.data.items.length);
61
+ } else {
62
+ console.log('Post, type:', resolved.data.viewer.kind);
63
63
  }
64
64
  ```
65
65
 
66
- ---
66
+ ### Expo / React Native
67
+
68
+ The library uses **only the Web API** (`fetch`, `AbortController') and does not pull `node:*`, so it can be connected directly:
69
+
70
+ ```ts
71
+ import { MultpornClient } from 'multporn-api-sdk';
72
+
73
+ const mp = new MultpornClient({ timeoutMs: 15000 });
74
+
75
+ export async function fetchLatest() {
76
+ const page0 = await mp.latest(0);
77
+ return page0.items; // draw a FlatList, etc.
78
+ }
79
+ ```
67
80
 
68
- ## API Overview
81
+ > Note: Expo/RN does not contain modules of the Node standard library (for example, `node:stream`). This is standard: choose libraries that are independent of Node-stdlib (like this SDK). ([Expo Documentation][1])
69
82
 
70
- ### Constructor
83
+ ---
84
+
85
+ ## API (overview)
71
86
 
72
87
  ```ts
73
88
  new MultpornClient(options?: {
74
- baseURL?: string; // default: https://multporn.net
75
- timeoutMs?: number; // request timeout
76
- retry?: { retries?: number };
89
+ baseURL?: string;
90
+ timeoutMs?: number;
91
+ retry?: { retries?: number; factor?: number; minDelayMs?: number; maxDelayMs?: number };
77
92
  headers?: Record<string, string>;
93
+ userAgent?: string;
78
94
  })
79
- ```
80
-
81
- ### Client methods
82
95
 
83
- ```ts
84
96
  latest(page?: number, params?: ListingQuery): Promise<Page<ListingItem>>
85
97
 
86
98
  listByPath(
@@ -101,36 +113,32 @@ updates(params?: MultpornUpdatesParams): Promise<UpdatesResult>
101
113
 
102
114
  viewUpdates(viewName: ViewName, params?: Omit<MultpornUpdatesParams, 'view_name'>): Promise<UpdatesResult>
103
115
 
104
- alphabetLetters(section: 'comics' | 'manga' | 'pictures' | 'video' | 'games'): Promise<AlphabetLetter[]>
116
+ alphabetLetters(section: AlphabetSection): Promise<AlphabetLetter[]>
105
117
 
106
118
  alphabet(section: AlphabetSection, letter: string, page?: number): Promise<Page<ListingItem>>
107
119
  ```
108
120
 
109
- ### Key types (simplified)
121
+ ### Important types (simplified)
110
122
 
111
123
  ```ts
112
- type ListingItem = {
113
- title: string;
114
- url: string;
115
- thumb?: string;
116
- };
124
+ type ListingItem = { title: string; url: string; thumb?: string; };
117
125
 
118
126
  type Page<T> = {
119
127
  items: T[];
120
128
  page: number;
121
129
  hasNext: boolean;
122
- totalPages: number;
130
+ totalPages?: number;
131
+ pageSize?: number;
132
+ alphabet?: AlphabetBlock;
133
+ sorting?: SortingUI;
123
134
  };
124
135
 
125
136
  type Post = {
126
- url: string;
127
137
  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[];
138
+ url: string;
139
+ images: string[];
140
+ tags: string[];
141
+ author: string | null;
134
142
  };
135
143
  ```
136
144
 
@@ -138,13 +146,11 @@ type Post = {
138
146
 
139
147
  ## Pagination
140
148
 
141
- All listing methods return `Page<ListingItem>` with `page`, `hasNext`, and `totalPages`.
142
-
143
149
  ```ts
144
150
  let p = 0;
145
151
  for (;;) {
146
152
  const page = await mp.listByPath('/munga', p);
147
- // process page.items
153
+ // processing of page.items
148
154
  if (!page.hasNext) break;
149
155
  p += 1;
150
156
  }
@@ -154,118 +160,60 @@ for (;;) {
154
160
 
155
161
  ## Search
156
162
 
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.
163
+ First, the usual HTML output is parsed; if empty, Drupal AJAX (`/views/ajax`) is used. This covers different search patterns.
158
164
 
159
165
  ```ts
160
166
  const res = await mp.search('genshin', 0);
161
167
  res.items.forEach(i => console.log(i.title, i.url, i.thumb));
162
168
  ```
163
169
 
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
170
  ---
167
171
 
168
172
  ## Alphabet
169
173
 
170
- Some hubs expose an alphabet. Use:
171
-
172
174
  ```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:
175
+ const letters = await mp.alphabetLetters('manga');
176
+ const pageA = await mp.alphabet('manga', 'A', 0);
177
+
178
+ // Equivalent via listByPath:
176
179
  const pageA2 = await mp.listByPath('/munga', 0, { letter: 'A' });
177
180
  ```
178
181
 
179
182
  ---
180
183
 
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**
184
+ ## Updates (Drupal Views)
202
185
 
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**
186
+ ``ts
187
+ // universal
188
+ const upd = await mp.updates({ view_name: 'new_mini', first: 0, last: 8 });
207
189
 
208
- * Swagger UI at `/docs` backed by `/openapi.json` (endpoints, params, schemas, examples)
190
+ // or wrapper presets
191
+ await mp.viewUpdates('updated_manga');
192
+ await mp.viewUpdates('random_top_comics');
193
+ ```
209
194
 
210
- ### Environment
195
+ ---
211
196
 
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)
197
+ ## Example of a dev server (for testing the SDK in the repository)
216
198
 
217
- ### Run
199
+ The repo has an example of an Express server with HTML pages and REST endpoints (Swagger/OpenAPI). It is **not required** for the Expo application, but it is convenient for debugging in a Node environment.
218
200
 
219
201
  ```bash
220
- # 1) Build the SDK (to produce dist/*)
202
+ #1) Build SDK (dist/*)
221
203
  npm run build
222
204
 
223
- # 2) Start the dev server
205
+ #2) Run an example
224
206
  node examples/dev-server.mjs
225
207
 
226
- # Then open:
208
+ # Open:
227
209
  # http://localhost:5173/docs
228
210
  # http://localhost:5173/hub?path=/munga
229
211
  # http://localhost:5173/search?q=genshin
230
212
  # http://localhost:5173/viewer?url=https://multporn.net/comics/...
231
213
  ```
232
214
 
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
215
  ---
267
216
 
268
- ## Notes
217
+ ## License
269
218
 
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.
219
+ MIT