feat: add Eporner and Txxx along with minor fixes (#16)
Co-authored-by: Pi Patel <pi.patel@gmail.com>
This commit is contained in:
66
src/controller/eporner/epornerGet.ts
Normal file
66
src/controller/eporner/epornerGet.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { scrapeContent } from "../../scraper/eporner/epornerGetController";
|
||||
import c from "../../utils/options";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { maybeError } from "../../utils/modifier";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function getEporner(req: Request, res: Response) {
|
||||
try {
|
||||
const id = req.query.id as string;
|
||||
if (!id) throw Error("Parameter id is required");
|
||||
|
||||
/**
|
||||
* @api {get} /eporner/get?id=:id Get eporner
|
||||
* @apiName Get eporner
|
||||
* @apiGroup eporner
|
||||
* @apiDescription Get a eporner video based on id
|
||||
*
|
||||
* @apiParam {String} id Video ID
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* HTTP/1.1 400 Bad Request
|
||||
*
|
||||
* @apiExample {curl} curl
|
||||
* curl -i https://lust.scathach.id/eporner/get?id=ibvqvezXzcs
|
||||
*
|
||||
* @apiExample {js} JS/TS
|
||||
* import axios from "axios"
|
||||
*
|
||||
* axios.get("https://lust.scathach.id/eporner/get?id=ibvqvezXzcs")
|
||||
* .then(res => console.log(res.data))
|
||||
* .catch(err => console.error(err))
|
||||
*
|
||||
* @apiExample {python} Python
|
||||
* import aiohttp
|
||||
* async with aiohttp.ClientSession() as session:
|
||||
* async with session.get("https://lust.scathach.id/eporner/get?id=ibvqvezXzcs") as resp:
|
||||
* print(await resp.json())
|
||||
*/
|
||||
// https://www.eporner.com/video-ibvqvezXzcs/ivy-seduces-her-dad-s-friend/
|
||||
// https://www.eporner.com/hd-porn/hgovoiPexQe/Risa-Tsukino/
|
||||
|
||||
let path: string;
|
||||
|
||||
if (id.startsWith("video-")) {
|
||||
path = id;
|
||||
} else {
|
||||
path = `hd-porn/${id}`;
|
||||
}
|
||||
|
||||
const url = `${c.EPORNER}/${path}`;
|
||||
|
||||
const data = await scrapeContent(url);
|
||||
logger.info({
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent"),
|
||||
});
|
||||
return res.json(data);
|
||||
} catch (err) {
|
||||
const e = err as Error;
|
||||
res.status(400).json(maybeError(false, e.message));
|
||||
}
|
||||
}
|
||||
28
src/controller/eporner/epornerGetRelated.ts
Normal file
28
src/controller/eporner/epornerGetRelated.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { scrapeContent } from "../../scraper/eporner/epornerGetRelatedController";
|
||||
import c from "../../utils/options";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { maybeError } from "../../utils/modifier";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function relatedEporner(req: Request, res: Response) {
|
||||
try {
|
||||
const id = req.query.id as string;
|
||||
if (!id) throw Error("Parameter id is required");
|
||||
|
||||
const url = `${c.EPORNER}/video-${id}`;
|
||||
const data = await scrapeContent(url);
|
||||
|
||||
logger.info({
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent")
|
||||
});
|
||||
|
||||
return res.json(data);
|
||||
} catch (err) {
|
||||
const e = err as Error;
|
||||
res.status(400).json(maybeError(false, e.message));
|
||||
}
|
||||
}
|
||||
75
src/controller/eporner/epornerRandom.ts
Normal file
75
src/controller/eporner/epornerRandom.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { scrapeContent as searchScrape } from "../../scraper/eporner/epornerSearchController";
|
||||
import { scrapeContent as videoScrape } from "../../scraper/eporner/epornerGetController";
|
||||
import c from "../../utils/options";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { maybeError } from "../../utils/modifier";
|
||||
import { Request, Response } from "express";
|
||||
import LustPress from "../../LustPress";
|
||||
|
||||
const lust = new LustPress();
|
||||
|
||||
export async function randomEporner(req: Request, res: Response) {
|
||||
/**
|
||||
* @api {get} /eporner/random Get random eporner
|
||||
* @apiName Get random eporner
|
||||
* @apiGroup eporner
|
||||
* @apiDescription Get a random eporner video
|
||||
*
|
||||
* @apiParam {String} id Video ID
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* HTTP/1.1 400 Bad Request
|
||||
*
|
||||
* @apiExample {curl} curl
|
||||
* curl -i https://lust.scathach.id/eporner/random
|
||||
*
|
||||
* @apiExample {js} JS/TS
|
||||
* import axios from "axios"
|
||||
*
|
||||
* axios.get("https://lust.scathach.id/eporner/random")
|
||||
* .then(res => console.log(res.data))
|
||||
* .catch(err => console.error(err))
|
||||
*
|
||||
* @apiExample {python} Python
|
||||
* import aiohttp
|
||||
* async with aiohttp.ClientSession() as session:
|
||||
* async with session.get("https://lust.scathach.id/eporner/random") as resp:
|
||||
* print(await resp.json())
|
||||
*/
|
||||
|
||||
// cat/all/SORT-top-weekly/
|
||||
|
||||
try {
|
||||
const weeklyUrl = `${c.EPORNER}/cat/all/SORT-top-weekly/`;
|
||||
const list = await searchScrape(weeklyUrl);
|
||||
|
||||
if (!list.data.length) {
|
||||
throw new Error("No weekly top videos found");
|
||||
}
|
||||
|
||||
const random = list.data[Math.floor(Math.random() * list.data.length)];
|
||||
|
||||
let path: string;
|
||||
|
||||
if (random.id.startsWith("video-")) {
|
||||
path = random.id;
|
||||
} else {
|
||||
path = `hd-porn/${random.id}`;
|
||||
}
|
||||
|
||||
const url = `${c.EPORNER}/${path}`;
|
||||
const data = await videoScrape(url);
|
||||
|
||||
logger.info({
|
||||
path: req.path,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent"),
|
||||
});
|
||||
|
||||
return res.json(data);
|
||||
} catch (err) {
|
||||
res.status(400).json(maybeError(false, (err as Error).message));
|
||||
}
|
||||
}
|
||||
72
src/controller/eporner/epornerSearch.ts
Normal file
72
src/controller/eporner/epornerSearch.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { scrapeContent } from "../../scraper/eporner/epornerSearchController";
|
||||
import c from "../../utils/options";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { maybeError, spacer } from "../../utils/modifier";
|
||||
import { Request, Response } from "express";
|
||||
|
||||
export async function searchEporner(req: Request, res: Response) {
|
||||
try {
|
||||
/**
|
||||
* @api {get} /eporner/search Search eporner videos
|
||||
* @apiName Search eporner
|
||||
* @apiGroup eporner
|
||||
* @apiDescription Search eporner videos
|
||||
* @apiParam {String} key Keyword to search
|
||||
* @apiParam {Number} [page=1] Page number
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* HTTP/1.1 400 Bad Request
|
||||
*
|
||||
* @apiExample {curl} curl
|
||||
* curl -i https://lust.scathach.id/eporner/search?key=milf
|
||||
* curl -i https://lust.scathach.id/eporner/search?key=milf&page=2
|
||||
*
|
||||
* @apiExample {js} JS/TS
|
||||
* import axios from "axios"
|
||||
*
|
||||
* axios.get("https://lust.scathach.id/eporner/search?key=milf")
|
||||
* .then(res => console.log(res.data))
|
||||
* .catch(err => console.error(err))
|
||||
*
|
||||
* @apiExample {python} Python
|
||||
* import aiohttp
|
||||
* async with aiohttp.ClientSession() as session:
|
||||
* async with session.get("https://lust.scathach.id/eporner/search?key=milf") as resp:
|
||||
* print(await resp.json())
|
||||
*/
|
||||
|
||||
// https://www.eporner.com/tag/milf/
|
||||
|
||||
const key = req.query.key as string;
|
||||
const page = Number(req.query.page || 1);
|
||||
|
||||
if (!key) throw Error("Parameter key is required");
|
||||
if (isNaN(page)) throw Error("Parameter page must be a number");
|
||||
|
||||
const slug = key
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/\s+/g, "-");
|
||||
|
||||
const url =
|
||||
page === 1
|
||||
? `${c.EPORNER}/tag/${slug}/`
|
||||
: `${c.EPORNER}/tag/${slug}/${page}/`;
|
||||
|
||||
const data = await scrapeContent(url);
|
||||
|
||||
logger.info({
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent")
|
||||
});
|
||||
|
||||
return res.json(data);
|
||||
} catch (err) {
|
||||
const e = err as Error;
|
||||
res.status(400).json(maybeError(false, e.message));
|
||||
}
|
||||
}
|
||||
82
src/controller/txxx/txxxGet.ts
Normal file
82
src/controller/txxx/txxxGet.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Request, Response } from "express";
|
||||
import LustPress from "../../LustPress";
|
||||
import { maybeError } from "../../utils/modifier";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { IVideoData } from "../../interfaces";
|
||||
|
||||
const lust = new LustPress();
|
||||
|
||||
// Generate sharded API URL exactly like TXXX expects
|
||||
function getApiUrl(videoId: string): string {
|
||||
const id = Number(videoId);
|
||||
if (Number.isNaN(id)) throw new Error("Invalid video id");
|
||||
|
||||
const million = Math.floor(id / 1_000_000) * 1_000_000;
|
||||
const thousand = Math.floor(id / 1_000) * 1_000;
|
||||
|
||||
return `https://txxx.com/api/json/video/86400/${million}/${thousand}/${id}.json`;
|
||||
}
|
||||
|
||||
export async function getTxxx(req: Request, res: Response) {
|
||||
try {
|
||||
const id = String(req.query.id || "").trim();
|
||||
if (!id) throw new Error("Parameter id is required");
|
||||
|
||||
const apiUrl = getApiUrl(id);
|
||||
|
||||
const buffer = await lust.fetchBody(apiUrl);
|
||||
const parsed = JSON.parse(buffer.toString("utf-8"));
|
||||
|
||||
if (!parsed?.video) {
|
||||
throw new Error("Invalid API response");
|
||||
}
|
||||
|
||||
const video = parsed.video;
|
||||
|
||||
const categories = Object.values(video.categories || {}).map(
|
||||
(c: any) => c.title,
|
||||
);
|
||||
|
||||
const tags = Object.values(video.tags || {}).map((t: any) => t.title);
|
||||
|
||||
const models = Object.values(video.models || {}).map((m: any) => m.title);
|
||||
|
||||
const videoDir = video.dir || "";
|
||||
const videoId = video.video_id;
|
||||
|
||||
const embed = `https://txxx.com/embed/${videoId}/`;
|
||||
|
||||
const response: IVideoData = {
|
||||
success: true,
|
||||
data: {
|
||||
title: video.title || "None",
|
||||
id: `${videoId}`,
|
||||
image: video.thumbsrc || video.thumb || "None",
|
||||
duration: video.duration || "None",
|
||||
views: video.statistics?.viewed || "0",
|
||||
rating: video.statistics?.rating || "0.00",
|
||||
uploaded: video.post_date || "None",
|
||||
upvoted: String(video.statistics?.likes || "0"),
|
||||
downvoted: String(video.statistics?.dislikes || "0"),
|
||||
channel: video.channel?.title || "",
|
||||
models: models.length > 0 ? models : video.models_suggested || [],
|
||||
tags: [...categories, ...tags],
|
||||
},
|
||||
source: `https://txxx.com/videos/${videoId}/${videoDir}/`,
|
||||
assets: [embed, video.thumbsrc].filter(Boolean),
|
||||
};
|
||||
|
||||
logger.info({
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent"),
|
||||
});
|
||||
|
||||
return res.json(response);
|
||||
} catch (err) {
|
||||
const e = err as Error;
|
||||
return res.status(400).json(maybeError(false, e.message));
|
||||
}
|
||||
}
|
||||
69
src/controller/txxx/txxxGetRelated.ts
Normal file
69
src/controller/txxx/txxxGetRelated.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Request, Response } from "express";
|
||||
import LustPress from "../../LustPress";
|
||||
import { maybeError } from "../../utils/modifier";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { ISearchVideoData } from "../../interfaces";
|
||||
|
||||
const lust = new LustPress();
|
||||
|
||||
function getRelatedApiUrl(videoId: string, page = 1, count = 50): string {
|
||||
const id = Number(videoId);
|
||||
if (Number.isNaN(id)) throw new Error("Invalid video id");
|
||||
|
||||
const million = Math.floor(id / 1_000_000) * 1_000_000;
|
||||
const thousand = Math.floor(id / 1_000) * 1_000;
|
||||
|
||||
return (
|
||||
`https://txxx.com/api/json/videos_related2/` +
|
||||
`432000/${count}/${million}/${thousand}/${id}.all.${page}.json`
|
||||
);
|
||||
}
|
||||
|
||||
export async function relatedTxxx(req: Request, res: Response) {
|
||||
try {
|
||||
const id = String(req.query.id || "").trim();
|
||||
const page = Number(req.query.page || 1);
|
||||
|
||||
if (!id) throw new Error("Parameter id is required");
|
||||
if (Number.isNaN(page)) throw new Error("Parameter page must be a number");
|
||||
|
||||
const apiUrl = getRelatedApiUrl(id, page);
|
||||
|
||||
const buffer = await lust.fetchBody(apiUrl);
|
||||
const rawData = JSON.parse(buffer.toString("utf-8"));
|
||||
|
||||
const videos = Array.isArray(rawData.videos) ? rawData.videos : [];
|
||||
|
||||
const data = videos.map((v: any) => ({
|
||||
id: v.video_id,
|
||||
title: v.title,
|
||||
image: v.scr || v.thumb || null,
|
||||
duration: v.duration || "None",
|
||||
views: v.video_viewed || "0",
|
||||
rating: v.rating || "0",
|
||||
uploader: v.username || v.display_name || "",
|
||||
link: `https://txxx.com/videos/${v.video_id}/${v.dir}/`,
|
||||
video: `https://txxx.com/embed/${v.video_id}/`,
|
||||
}));
|
||||
|
||||
logger.info({
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent"),
|
||||
});
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
total_count: rawData.total_count || "0",
|
||||
pages: rawData.pages || 1,
|
||||
page,
|
||||
data,
|
||||
source: `https://txxx.com/videos/${id}/`,
|
||||
} as ISearchVideoData);
|
||||
} catch (err) {
|
||||
const e = err as Error;
|
||||
return res.status(400).json(maybeError(false, e.message));
|
||||
}
|
||||
}
|
||||
58
src/controller/txxx/txxxRandom.ts
Normal file
58
src/controller/txxx/txxxRandom.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Request, Response } from "express";
|
||||
import LustPress from "../../LustPress";
|
||||
import { maybeError } from "../../utils/modifier";
|
||||
import { logger } from "../../utils/logger";
|
||||
|
||||
const lust = new LustPress();
|
||||
|
||||
export async function randomTxxx(req: Request, res: Response) {
|
||||
try {
|
||||
const apiUrl =
|
||||
"https://txxx.com/api/json/videos2/14400/str/most-popular/60/..1.all..day.json";
|
||||
|
||||
const buffer = await lust.fetchBody(apiUrl);
|
||||
const rawData = JSON.parse(buffer.toString("utf-8"));
|
||||
|
||||
const videos = Array.isArray(rawData.videos)
|
||||
? rawData.videos
|
||||
: [];
|
||||
|
||||
if (videos.length === 0) {
|
||||
throw new Error("No videos returned from upstream");
|
||||
}
|
||||
|
||||
// Pick one random video
|
||||
const v = videos[Math.floor(Math.random() * videos.length)];
|
||||
|
||||
const data = {
|
||||
video_id: v.video_id,
|
||||
title: v.title,
|
||||
dir: v.dir,
|
||||
duration: v.duration,
|
||||
views: v.video_viewed,
|
||||
rating: v.rating,
|
||||
uploaded: v.post_date,
|
||||
likes: v.likes,
|
||||
dislikes: v.dislikes,
|
||||
image: v.scr,
|
||||
categories: v.categories ? v.categories.split(",") : [],
|
||||
embed: `https://txxx.com/embed/${v.video_id}/`,
|
||||
};
|
||||
|
||||
logger.info({
|
||||
path: req.path,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent"),
|
||||
});
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data,
|
||||
source: apiUrl,
|
||||
});
|
||||
} catch (err) {
|
||||
const e = err as Error;
|
||||
return res.status(400).json(maybeError(false, e.message));
|
||||
}
|
||||
}
|
||||
63
src/controller/txxx/txxxSearch.ts
Normal file
63
src/controller/txxx/txxxSearch.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Request, Response } from "express";
|
||||
import LustPress from "../../LustPress";
|
||||
import { maybeError } from "../../utils/modifier";
|
||||
|
||||
const lust = new LustPress();
|
||||
|
||||
export async function searchTxxx(req: Request, res: Response) {
|
||||
try {
|
||||
const key = String(req.query.key || "").trim();
|
||||
const page = Number(req.query.page || 1);
|
||||
|
||||
if (!key) {
|
||||
return res.json({
|
||||
success: false,
|
||||
error: "Parameter key is required",
|
||||
});
|
||||
}
|
||||
|
||||
if (Number.isNaN(page)) {
|
||||
return res.json({
|
||||
success: false,
|
||||
error: "Parameter page must be a number",
|
||||
});
|
||||
}
|
||||
|
||||
const apiUrl =
|
||||
`https://txxx.com/api/videos2.php` +
|
||||
`?params=259200/str/relevance/60/search..${page}.all..` +
|
||||
`&s=${encodeURIComponent(key)}`;
|
||||
|
||||
// Fetch from API directly
|
||||
const buffer = await lust.fetchBody(apiUrl);
|
||||
const rawData = JSON.parse(buffer.toString("utf-8"));
|
||||
|
||||
const videos = Array.isArray(rawData.videos) ? rawData.videos : [];
|
||||
|
||||
const data = videos.map((v: any) => ({
|
||||
video_id: v.video_id,
|
||||
title: v.title,
|
||||
dir: v.dir,
|
||||
duration: v.duration,
|
||||
views: v.video_viewed,
|
||||
rating: v.rating,
|
||||
uploaded: v.post_date,
|
||||
likes: v.likes,
|
||||
dislikes: v.dislikes,
|
||||
image: v.scr,
|
||||
categories: v.categories ? v.categories.split(",") : [],
|
||||
embed: `https://txxx.com/embed/${v.video_id}/`,
|
||||
}));
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
total_count: String(rawData.total_count ?? videos.length),
|
||||
pages: Number(rawData.pages ?? 1),
|
||||
page,
|
||||
data,
|
||||
});
|
||||
} catch (err) {
|
||||
const e = err as Error;
|
||||
return res.json(maybeError(false, e.message));
|
||||
}
|
||||
}
|
||||
@@ -14,23 +14,23 @@ export async function getXhamster(req: Request, res: Response) {
|
||||
* @apiName Get xhamster
|
||||
* @apiGroup xhamster
|
||||
* @apiDescription Get a xhamster video based on id
|
||||
*
|
||||
*
|
||||
* @apiParam {String} id Video ID
|
||||
*
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* HTTP/1.1 400 Bad Request
|
||||
*
|
||||
*
|
||||
* @apiExample {curl} curl
|
||||
* curl -i https://lust.scathach.id/xhamster/get?id=videos/horny-makima-tests-new-toy-and-cums-intensely-xhAa5wx
|
||||
*
|
||||
*
|
||||
* @apiExample {js} JS/TS
|
||||
* import axios from "axios"
|
||||
*
|
||||
*
|
||||
* axios.get("https://lust.scathach.id/xhamster/get?id=videos/horny-makima-tests-new-toy-and-cums-intensely-xhAa5wx")
|
||||
* .then(res => console.log(res.data))
|
||||
* .catch(err => console.error(err))
|
||||
*
|
||||
*
|
||||
* @apiExample {python} Python
|
||||
* import aiohttp
|
||||
* async with aiohttp.ClientSession() as session:
|
||||
@@ -38,14 +38,14 @@ export async function getXhamster(req: Request, res: Response) {
|
||||
* print(await resp.json())
|
||||
*/
|
||||
|
||||
const url = `${c.XHAMSTER}/${id}`;
|
||||
const url = `${c.XHAMSTER}/videos/${id}`;
|
||||
const data = await scrapeContent(url);
|
||||
logger.info({
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent")
|
||||
useragent: req.get("User-Agent"),
|
||||
});
|
||||
return res.json(data);
|
||||
} catch (err) {
|
||||
|
||||
@@ -10,51 +10,58 @@ const lust = new LustPress();
|
||||
|
||||
export async function randomXhamster(req: Request, res: Response) {
|
||||
try {
|
||||
|
||||
|
||||
/**
|
||||
* @api {get} /xhamster/random Get random xhamster
|
||||
* @api {get} /xhamster/random Get random xhamster video
|
||||
* @apiName Get random xhamster
|
||||
* @apiGroup xhamster
|
||||
* @apiDescription Get a random xhamster video
|
||||
*
|
||||
* @apiDescription Get a random xhamster video from the list of newest videos.
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* HTTP/1.1 400 Bad Request
|
||||
*
|
||||
*
|
||||
* @apiExample {curl} curl
|
||||
* curl -i https://lust.scathach.id/xhamster/random
|
||||
*
|
||||
*
|
||||
* @apiExample {js} JS/TS
|
||||
* import axios from "axios"
|
||||
*
|
||||
*
|
||||
* axios.get("https://lust.scathach.id/xhamster/random")
|
||||
* .then(res => console.log(res.data))
|
||||
* .catch(err => console.error(err))
|
||||
*
|
||||
*
|
||||
* @apiExample {python} Python
|
||||
* import aiohttp
|
||||
* async with aiohttp.ClientSession() as session:
|
||||
* async with session.get("https://lust.scathach.id/xhamster/random") as resp:
|
||||
* print(await resp.json())
|
||||
*/
|
||||
|
||||
const resolve = await lust.fetchBody(`${c.XHAMSTER}/newest`);
|
||||
const $ = load(resolve);
|
||||
const search = $("a.root-9d8b4.video-thumb-info__name.role-pop.with-dropdown")
|
||||
.map((i, el) => $(el).attr("href"))
|
||||
.get();
|
||||
|
||||
const search_ = search.map((el) => el.replace(c.XHAMSTER, ""));
|
||||
const random = Math.floor(Math.random() * search_.length);
|
||||
const url = c.XHAMSTER + search_[random];
|
||||
const data = await scrapeContent(url);
|
||||
const videoLinks = $("div.thumb-list__item[data-video-id]")
|
||||
.map((_, el) => {
|
||||
const href = $(el).find("a[data-role='thumb-link']").attr("href");
|
||||
return href && href.includes("/videos/") ? href : null;
|
||||
})
|
||||
.get()
|
||||
.filter(Boolean);
|
||||
|
||||
// Select a random video URL from the list
|
||||
const randomIndex = Math.floor(Math.random() * videoLinks.length);
|
||||
const randomUrl = videoLinks[randomIndex];
|
||||
|
||||
const data = await scrapeContent(randomUrl);
|
||||
|
||||
logger.info({
|
||||
path: req.path,
|
||||
query: req.query,
|
||||
method: req.method,
|
||||
ip: req.ip,
|
||||
useragent: req.get("User-Agent")
|
||||
useragent: req.get("User-Agent"),
|
||||
});
|
||||
|
||||
return res.json(data);
|
||||
} catch (err) {
|
||||
const e = err as Error;
|
||||
|
||||
Reference in New Issue
Block a user