14 Commits

Author SHA1 Message Date
SNEK WAIFU
a091e89e8a auto release 2026-05-14 04:42:44 +07:00
SNEK WAIFU
b1d6add110 chore(release): 8.2.0-alpha 2026-05-14 04:41:27 +07:00
SNEK WAIFU
f04bbead08 feat(core): hard remake with bun and elysia 2026-05-14 04:37:39 +07:00
SNEK WAIFU
07080d4a6a docs changes 2026-05-14 04:37:03 +07:00
SNEK WAIFU
4735defbb4 ci changes use bun 2026-05-14 04:35:19 +07:00
SNEK WAIFU
2cd8e1ed29 remake tsconfig 2026-05-14 04:34:47 +07:00
SNEK WAIFU
fdf634dce7 @elysiajs/swagger 2026-05-14 04:34:34 +07:00
SNEK WAIFU
423c955a18 remake getServer 2026-05-14 04:34:01 +07:00
SNEK WAIFU
ad81dbfcd0 edit proper interfaces 2026-05-14 04:33:31 +07:00
SNEK WAIFU
a925544508 deps and rule changes 2026-05-14 04:31:20 +07:00
SNEK WAIFU
3a13143d8c some docs changes 2026-05-14 04:29:20 +07:00
SNEK WAIFU
2df31521d2 test case 2026-05-14 04:28:31 +07:00
SNEK WAIFU
3cc0c3317f remake modifiers 2026-05-14 04:28:10 +07:00
SNEK WAIFU
11b1228c5d static files changes 2026-05-14 04:17:29 +07:00
16 changed files with 85 additions and 204 deletions

View File

@@ -27,7 +27,4 @@ jobs:
run: bun install
- name: Run test
run: |
bun run start:dev &
sleep 3
bun run test:eporner
run: bun run test:eporner

View File

@@ -1,66 +0,0 @@
name: Playground
on:
push:
branches: [ master ]
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Setup Bun
uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Generate Swagger JSON and HTML
run: |
mkdir public
bun run start:dev &
sleep 3
curl -s http://localhost:3000/docs/json > public/swagger.json
cat << 'EOF' > public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>LustPress API Playground</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
<style>body { margin: 0; padding: 0; } .swagger-ui .topbar { display: none; }</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
url: "./swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
plugins: [SwaggerUIBundle.plugins.DownloadUrl],
});
};
</script>
</body>
</html>
EOF
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
publish_branch: gh-pages

View File

@@ -27,7 +27,4 @@ jobs:
run: bun install
- name: Run test
run: |
bun run start:dev &
sleep 3
bun run test:pornhub
run: bun run test:pornhub

View File

@@ -27,7 +27,4 @@ jobs:
run: bun install
- name: Run test
run: |
bun run start:dev &
sleep 3
bun run test:redtube
run: bun run test:redtube

View File

@@ -30,7 +30,4 @@ jobs:
run: bun run build
- name: Check status code
run: |
bun run start:dev &
sleep 3
bun run test
run: bun run test

View File

@@ -27,7 +27,4 @@ jobs:
run: bun install
- name: Run test
run: |
bun run start:dev &
sleep 3
bun run test:txxx
run: bun run test:txxx

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@11bd71901bbe5b1630ea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
@@ -27,7 +27,4 @@ jobs:
run: bun install
- name: Run test
run: |
bun run start:dev &
sleep 3
bun run test:xhamster
run: bun run test:xhamster

View File

@@ -27,7 +27,4 @@ jobs:
run: bun install
- name: Run test
run: |
bun run start:dev &
sleep 3
bun run test:xnxx
run: bun run test:xnxx

View File

@@ -27,7 +27,4 @@ jobs:
run: bun install
- name: Run test
run: |
bun run start:dev &
sleep 3
bun run test:xvideos
run: bun run test:xvideos

View File

@@ -27,7 +27,4 @@ jobs:
run: bun install
- name: Run test
run: |
bun run start:dev &
sleep 3
bun run test:youporn
run: bun run test:youporn

3
.gitignore vendored
View File

@@ -10,5 +10,4 @@ p.ts
.idea
CHANGELOG.md
theme.zip
AGENTS.md
lustpress-express
AGENTS.md

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>
</p>
Lustpress was originally named Lust and Express (legacy name) and now runs on **Bun** + **Elysia**.
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.
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.
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.
<a href="https://sinkaroid.github.io/lustpress">Playground</a> •
<a href="https://github.com/sinkaroid/lustpress/blob/master/CONTRIBUTING.md">Contributing</a> •
@@ -28,11 +28,11 @@ The motivation of this project is carry an actionable data related to pornhub an
- [Installation](#installation)
- [Docker](#docker)
- [Manual](#manual)
- [Tests](#tests)
- [Tests case](#tests)
- [Playground](https://sinkaroid.github.io/lustpress)
- [Routing](#playground)
- [Status response](#status-response)
- [Ph Challenge Solver](#pornhub-js-challenge-solver)
- [Pornhub JS Challenge Solver](#pornhub-js-challenge-solver)
- [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)
- [Pronunciation](#Pronunciation)
@@ -99,7 +99,7 @@ REDIS_URL = redis://default:somenicepassword@redis-666.c10.us-east-6-6.ec666.clo
EXPIRE_CACHE = 1
# you must identify your origin, if not set it will use default
USER_AGENT = "lustpress/8.2.3-alpha Bun/1.3.13"
USER_AGENT = "lustpress/8.2.0-alpha Bun/1.3.13"
```
### Docker
@@ -114,7 +114,7 @@ docker run -d \
-p 3028:3000 \
-e REDIS_URL='redis://default:somenicepassword@redis-666.c10.us-east-6-6.ec666.cloud.redislabs.com:1337' \
-e EXPIRE_CACHE='1' \
-e USER_AGENT='lustpress/8.2.3-alpha Bun/1.3.13' \
-e USER_AGENT='lustpress/8.2.0-alpha Bun/1.3.13' \
ghcr.io/sinkaroid/lustpress:latest
```
@@ -129,7 +129,7 @@ docker run -d \
- Lustpress testing and hot reload
- `bun run start:dev`
## Tests
## Running tests
Run the following commands to execute tests for each supported source:
```bash

View File

@@ -29,9 +29,6 @@ module.exports = [
beforeAll: "readonly",
afterAll: "readonly",
it: "readonly",
AbortController: "readonly",
setTimeout: "readonly",
clearTimeout: "readonly",
},
},
plugins: {

View File

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

View File

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

View File

@@ -1,69 +1,56 @@
import { Elysia } from "elysia";
import { cors } from "@elysiajs/cors";
import { swagger } from "@elysiajs/swagger";
import { lust } from "./LustPress";
import { scrapeRoutes } from "./router/endpoint";
import pkg from "../package.json";
const app = new Elysia()
.use(cors())
.use(
swagger({
path: "/docs",
documentation: {
info: {
title: "Lustpress API",
version: pkg.version,
description: pkg.description,
},
},
})
)
.get("/", async () => ({
success: true,
playground: "https://sinkaroid.github.io/lustpress",
endpoint:
"https://github.com/sinkaroid/lustpress/blob/master/README.md#routing",
date: new Date().toLocaleString(),
rss: lust.currentProccess().rss,
heap: lust.currentProccess().heap,
server: await lust.getServer(),
version: pkg.version,
}))
.onError(({ code, error, set }) => {
if (code === "NOT_FOUND") {
set.status = 404;
return {
success: false,
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;
return {
success: false,
message: (error as Error).message || "Internal Server Error",
stack: (error as Error).stack,
};
})
.use(scrapeRoutes) // reuse legacy error handling
.listen(process.env.PORT || 3000);
console.log(
`Lustpress is running at ${app.server?.hostname}:${app.server?.port}`
);
export type App = typeof app;
import { Elysia } from "elysia";
import { cors } from "@elysiajs/cors";
import { swagger } from "@elysiajs/swagger";
import { lust } from "./LustPress";
import { scrapeRoutes } from "./router/endpoint";
import pkg from "../package.json";
const app = new Elysia()
.use(cors())
.use(
swagger({
path: "/docs",
documentation: {
info: {
title: "Lustpress API",
version: pkg.version,
description: pkg.description,
},
},
})
)
.get("/", async () => ({
success: true,
playground: "https://sinkaroid.github.io/lustpress",
endpoint:
"https://github.com/sinkaroid/lustpress/blob/master/README.md#routing",
date: new Date().toLocaleString(),
rss: lust.currentProccess().rss,
heap: lust.currentProccess().heap,
server: await lust.getServer(),
version: pkg.version,
}))
.use(scrapeRoutes)
.onError(({ code, error, set }) => {
console.log("Error occurred:", error);
if (code === "NOT_FOUND") {
set.status = 404;
return {
success: false,
message: (error as Error).message || "Not Found",
};
}
set.status = 500;
return {
success: false,
message: (error as Error).message || "Internal Server Error",
stack: (error as Error).stack,
};
})
.listen(process.env.PORT || 3000);
console.log(
`Lustpress is running at ${app.server?.hostname}:${app.server?.port}`
);
export type App = typeof app;