7 Commits

Author SHA1 Message Date
Indrawan I.
67be3acc6e fix: proper error handler (#23)
* re use legacy errors

* 8.3.6-alpha
2026-05-14 09:56:52 +07:00
SNEK WAIFU
e92cb6ca8a ee 2026-05-14 08:09:23 +07:00
SNEK WAIFU
85a45cf575 eeee 2026-05-14 08:09:04 +07:00
SNEK WAIFU
fe225e1090 8.3.4-alpha 2026-05-14 07:25:26 +07:00
SNEK WAIFU
6ed1567f0e need testing 2026-05-14 07:24:58 +07:00
Indrawan I.
67445ed648 fix: resolve cache ttl calculation (#22) 2026-05-14 06:38:19 +07:00
Indrawan I.
e2c59b032b docs: elysia changes & ph fixes (#21) 2026-05-14 05:36:33 +07:00
5 changed files with 98 additions and 75 deletions

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@ p.ts
CHANGELOG.md CHANGELOG.md
theme.zip theme.zip
AGENTS.md AGENTS.md
lustpress-express

View File

@@ -7,8 +7,8 @@
<a href="https://codeclimate.com/github/sinkaroid/lustpress/maintainability"><img src="https://api.codeclimate.com/v1/badges/29a2be78f853f9e3a4a3/maintainability" /></a> <a href="https://codeclimate.com/github/sinkaroid/lustpress/maintainability"><img src="https://api.codeclimate.com/v1/badges/29a2be78f853f9e3a4a3/maintainability" /></a>
</p> </p>
Lustpress was originally named Lust and Express (legacy name) and now runs on **Bun** + **Elysia** a high-performance remake from the ground up using Bun. Lustpress was originally named Lust and Express (legacy name) and now runs on **Bun** + **Elysia**.
The motivation of this project is to bring you an actionable data related to pornhub and other r18 sites with gather, similar design pattern, endpoint bindings, and consistent structure in mind. The motivation of this project is carry an actionable data related to pornhub and other r18 sites with gather, similar design pattern, endpoint bindings, and consistent structure in mind.
<a href="https://sinkaroid.github.io/lustpress">Playground</a> • <a href="https://sinkaroid.github.io/lustpress">Playground</a> •
<a href="https://github.com/sinkaroid/lustpress/blob/master/CONTRIBUTING.md">Contributing</a> • <a href="https://github.com/sinkaroid/lustpress/blob/master/CONTRIBUTING.md">Contributing</a> •
@@ -28,11 +28,11 @@ The motivation of this project is to bring you an actionable data related to por
- [Installation](#installation) - [Installation](#installation)
- [Docker](#docker) - [Docker](#docker)
- [Manual](#manual) - [Manual](#manual)
- [Tests case](#tests) - [Tests](#tests)
- [Playground](https://sinkaroid.github.io/lustpress) - [Playground](https://sinkaroid.github.io/lustpress)
- [Routing](#playground) - [Routing](#playground)
- [Status response](#status-response) - [Status response](#status-response)
- [Pornhub JS Challenge Solver](#pornhub-js-challenge-solver) - [Ph Challenge Solver](#pornhub-js-challenge-solver)
- [CLosing remarks](https://github.com/sinkaroid/lustpress/blob/master/CLOSING_REMARKS.md) - [CLosing remarks](https://github.com/sinkaroid/lustpress/blob/master/CLOSING_REMARKS.md)
- [Alternative links](https://github.com/sinkaroid/lustpress/blob/master/CLOSING_REMARKS.md#alternative-links) - [Alternative links](https://github.com/sinkaroid/lustpress/blob/master/CLOSING_REMARKS.md#alternative-links)
- [Pronunciation](#Pronunciation) - [Pronunciation](#Pronunciation)
@@ -99,7 +99,7 @@ REDIS_URL = redis://default:somenicepassword@redis-666.c10.us-east-6-6.ec666.clo
EXPIRE_CACHE = 1 EXPIRE_CACHE = 1
# you must identify your origin, if not set it will use default # you must identify your origin, if not set it will use default
USER_AGENT = "lustpress/8.2.0-alpha Bun/1.3.13" USER_AGENT = "lustpress/8.2.3-alpha Bun/1.3.13"
``` ```
### Docker ### Docker
@@ -114,7 +114,7 @@ docker run -d \
-p 3028:3000 \ -p 3028:3000 \
-e REDIS_URL='redis://default:somenicepassword@redis-666.c10.us-east-6-6.ec666.cloud.redislabs.com:1337' \ -e REDIS_URL='redis://default:somenicepassword@redis-666.c10.us-east-6-6.ec666.cloud.redislabs.com:1337' \
-e EXPIRE_CACHE='1' \ -e EXPIRE_CACHE='1' \
-e USER_AGENT='lustpress/8.2.0-alpha Bun/1.3.13' \ -e USER_AGENT='lustpress/8.2.3-alpha Bun/1.3.13' \
ghcr.io/sinkaroid/lustpress:latest ghcr.io/sinkaroid/lustpress:latest
``` ```
@@ -129,7 +129,7 @@ docker run -d \
- Lustpress testing and hot reload - Lustpress testing and hot reload
- `bun run start:dev` - `bun run start:dev`
## Running tests ## Tests
Run the following commands to execute tests for each supported source: Run the following commands to execute tests for each supported source:
```bash ```bash

View File

@@ -1,6 +1,6 @@
{ {
"name": "lustpress", "name": "lustpress",
"version": "8.2.2-alpha", "version": "8.3.6-alpha",
"description": "RESTful and experimental API for PH and other R18 websites", "description": "RESTful and experimental API for PH and other R18 websites",
"main": "src/index.ts", "main": "src/index.ts",
"scripts": { "scripts": {

View File

@@ -9,7 +9,7 @@ const keyv = process.env.REDIS_URL
: new Keyv(); : new Keyv();
keyv.on("error", (err) => console.log("Connection Error", err)); keyv.on("error", (err) => console.log("Connection Error", err));
const ttl = 1000 * 60 * 60 * Number(process.env.EXPIRE_CACHE); const ttl = 1000 * 60 * 60 * Number(process.env.EXPIRE_CACHE || "1");
const GEO_TIMEOUT_MS = 3000; const GEO_TIMEOUT_MS = 3000;
let cachedLastLocation: string | null = null; let cachedLastLocation: string | null = null;
@@ -25,12 +25,14 @@ function cachedLocationOrUnknown(): string {
class LustPress { class LustPress {
url: string; url: string;
useragent: string; useragent: string;
private browserUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"; private browserUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36";
private cookieCache: { [domain: string]: string } = {}; private cookieCache: { [domain: string]: string } = {};
constructor() { constructor() {
this.url = ""; this.url = "";
this.useragent = `${pkg.name}/${pkg.version} Bun/${Bun.version}`; this.browserUA =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36";
this.useragent = process.env.USER_AGENT || `${pkg.name}/${pkg.version} Bun/${Bun.version}`;
} }
async getPornhubCookies(): Promise<string> { async getPornhubCookies(): Promise<string> {
@@ -77,13 +79,16 @@ class LustPress {
async fetchBody(url: string): Promise<Buffer> { async fetchBody(url: string): Promise<Buffer> {
const cached = await keyv.get(url); const cached = await keyv.get(url);
if (cached) return cached; if (cached) {
console.log(`[CACHE HIT] ${url}`);
return cached;
}
const isPornhub = /pornhub\.com/i.test(url); const isPornhub = /pornhub\.com/i.test(url);
const domain = new URL(url).hostname; const domain = new URL(url).hostname;
const headers: Record<string, string> = { const headers: Record<string, string> = {
"User-Agent": isPornhub ? this.browserUA : this.useragent, "User-Agent": isPornhub ? this.browserUA : this.useragent
}; };
if (isPornhub) { if (isPornhub) {
@@ -96,21 +101,25 @@ class LustPress {
headers["Accept-Language"] = "en-US,en;q=0.9"; headers["Accept-Language"] = "en-US,en;q=0.9";
} }
console.log(`[FETCH] ${url}`);
let res = await fetch(url, { headers, redirect: "follow" }); let res = await fetch(url, { headers, redirect: "follow" });
let text = await res.text(); let arrayBuf = await res.arrayBuffer();
let body = Buffer.from(arrayBuf);
if (isPornhub && text.includes("leastFactor")) { if (isPornhub && body.toString("utf8").includes("leastFactor")) {
console.log("Challenge detected at target URL. Re-authenticating..."); console.log("Challenge detected at target URL. Re-authenticating...");
this.cookieCache[domain] = await this.getPornhubCookies(); this.cookieCache[domain] = await this.getPornhubCookies();
res = await fetch(url, { res = await fetch(url, {
headers: { ...headers, Cookie: this.cookieCache[domain] }, headers: { ...headers, Cookie: this.cookieCache[domain] },
redirect: "follow" redirect: "follow"
}); });
text = await res.text(); arrayBuf = await res.arrayBuffer();
body = Buffer.from(arrayBuf);
} }
const body = Buffer.from(text); if (res.ok && !url.includes("/random")) {
if (!url.includes("/random")) await keyv.set(url, body, ttl); await keyv.set(url, body, ttl);
}
return body; return body;
} }

View File

@@ -30,9 +30,7 @@ const app = new Elysia()
server: await lust.getServer(), server: await lust.getServer(),
version: pkg.version, version: pkg.version,
})) }))
.use(scrapeRoutes)
.onError(({ code, error, set }) => { .onError(({ code, error, set }) => {
console.log("Error occurred:", error);
if (code === "NOT_FOUND") { if (code === "NOT_FOUND") {
set.status = 404; set.status = 404;
return { return {
@@ -40,6 +38,20 @@ const app = new Elysia()
message: (error as Error).message || "Not Found", message: (error as Error).message || "Not Found",
}; };
} }
if (code === "VALIDATION") {
set.status = 400;
return {
success: false,
message: JSON.parse((error as Error).message)[0]?.message || "Validation Error",
};
}
if (code === "UNKNOWN") {
set.status = 400;
return {
success: false,
message: (error as Error).message,
};
}
set.status = 500; set.status = 500;
return { return {
success: false, success: false,
@@ -47,6 +59,7 @@ const app = new Elysia()
stack: (error as Error).stack, stack: (error as Error).stack,
}; };
}) })
.use(scrapeRoutes) // reuse legacy error handling
.listen(process.env.PORT || 3000); .listen(process.env.PORT || 3000);
console.log( console.log(