Release v0.4.0: Add Redtube support #103
|
@ -8,6 +8,7 @@ Proxy Raye is an alternative front-end for adult websites. Watch videos on a cle
|
||||||
- XNXX
|
- XNXX
|
||||||
- PornHub (experimental)
|
- PornHub (experimental)
|
||||||
- YouPorn
|
- YouPorn
|
||||||
|
- RedTube
|
||||||
|
|
||||||
### How to switch between platforms
|
### How to switch between platforms
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.24.5",
|
"version": "7.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz",
|
||||||
"integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==",
|
"integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
|
@ -1289,13 +1289,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
@ -1343,9 +1343,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001620",
|
"version": "1.0.30001621",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz",
|
||||||
"integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==",
|
"integrity": "sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
@ -2547,9 +2547,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -3111,6 +3111,7 @@
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||||
|
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -3705,9 +3706,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/language-subtag-registry": {
|
"node_modules/language-subtag-registry": {
|
||||||
"version": "0.3.22",
|
"version": "0.3.23",
|
||||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
|
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
|
||||||
"integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
|
"integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "CC0-1.0"
|
"license": "CC0-1.0"
|
||||||
},
|
},
|
||||||
|
@ -3826,13 +3827,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"braces": "^3.0.2",
|
"braces": "^3.0.3",
|
||||||
"picomatch": "^2.3.1"
|
"picomatch": "^2.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3892,9 +3893,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minipass": {
|
"node_modules/minipass": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||||
"integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==",
|
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -4828,6 +4829,7 @@
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -4844,6 +4846,7 @@
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||||
|
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -5578,9 +5581,9 @@
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/use-intl": {
|
"node_modules/use-intl": {
|
||||||
"version": "3.14.0",
|
"version": "3.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.14.1.tgz",
|
||||||
"integrity": "sha512-Dy3B4C7ICGDM5ZDrnNpf8bDfFbnYYjK5vNzij0kPfJNM2G0nfLWGQvhBXEyPPKZpNvnkKkFasXR8AAxSwXTAoA==",
|
"integrity": "sha512-LVjHUSnQxryiWY+zCFkwoe+a8LK4RIM/4+lV54FSLehOH3gO1JcnXQ85TbfKUTfvEDY7B0DkH7WOM+CWppZanA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formatjs/ecma402-abstract": "^1.11.4",
|
"@formatjs/ecma402-abstract": "^1.11.4",
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
"next": "14.2.2",
|
"next": "14.2.2",
|
||||||
"next-intl": "3.11.3",
|
"next-intl": "3.11.3",
|
||||||
"next-nprogress-bar": "2.3.11",
|
"next-nprogress-bar": "2.3.11",
|
||||||
"plyr-react": "^5.3.0",
|
"plyr-react": "5.3.0",
|
||||||
"react": "18.3.0",
|
"react": "18.3.0",
|
||||||
"react-cookie": "7.1.4",
|
"react-cookie": "7.1.4",
|
||||||
"react-dom": "18.3.0",
|
"react-dom": "18.3.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { Cookies, Platforms, XVideosOrientations, PornHubOrientations, YouPornOrientations } from '@/meta/settings';
|
import { Cookies, Platforms, XVideosOrientations, PornHubOrientations, YouPornOrientations, RedTubeOrientations } from '@/meta/settings';
|
||||||
|
|
||||||
import css from './Orientation.module.scss'
|
import css from './Orientation.module.scss'
|
||||||
|
|
||||||
|
@ -25,6 +25,10 @@ const getOrientations = (platform: Platforms):Object => {
|
||||||
return YouPornOrientations
|
return YouPornOrientations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if([Platforms.redtube].includes(platform)) {
|
||||||
|
return RedTubeOrientations
|
||||||
|
}
|
||||||
|
|
||||||
return PornHubOrientations
|
return PornHubOrientations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { Cookies, Platforms, PornHubOrientations, XVideosOrientations, YouPornOrientations } from '@/meta/settings';
|
import { Cookies, Platforms, PornHubOrientations, RedTubeOrientations, XVideosOrientations, YouPornOrientations } from '@/meta/settings';
|
||||||
|
|
||||||
import css from './Platform.module.scss'
|
import css from './Platform.module.scss'
|
||||||
|
|
||||||
|
@ -26,6 +26,10 @@ const mapOrientationToPlatform = (platform: string, orientation: string): string
|
||||||
return Object.keys(PornHubOrientations).includes(orientation) ? orientation : String(PornHubOrientations.generic)
|
return Object.keys(PornHubOrientations).includes(orientation) ? orientation : String(PornHubOrientations.generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ([String(Platforms.redtube)].includes(platform)) {
|
||||||
|
return Object.keys(RedTubeOrientations).includes(orientation) ? orientation : String(RedTubeOrientations.etero)
|
||||||
|
}
|
||||||
|
|
||||||
if ([String(Platforms.youporn)].includes(platform)) {
|
if ([String(Platforms.youporn)].includes(platform)) {
|
||||||
return String(YouPornOrientations.generic)
|
return String(YouPornOrientations.generic)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,7 @@ export const DEFAULT_XNXX_CONTENT_EXPIRY = { EX: EX_HOURLY };
|
||||||
export const DEFAULT_YOUPORN_GALLERY_EXPIRY = { EX: EX_HOURLY };
|
export const DEFAULT_YOUPORN_GALLERY_EXPIRY = { EX: EX_HOURLY };
|
||||||
export const DEFAULT_YOUPORN_VIDEO_EXPIRY = { EX: EX_HOURLY };
|
export const DEFAULT_YOUPORN_VIDEO_EXPIRY = { EX: EX_HOURLY };
|
||||||
|
|
||||||
|
export const DEFAULT_REDTUBE_GALLERY_EXPIRY = { EX: EX_HOURLY };
|
||||||
|
export const DEFAULT_REDTUBE_VIDEO_EXPIRY = { EX: EX_HOURLY };
|
||||||
|
|
||||||
export const DEFAULT_RELATED_VIDEO_KEY_PATH = '/related/'
|
export const DEFAULT_RELATED_VIDEO_KEY_PATH = '/related/'
|
|
@ -29,3 +29,12 @@ export const YOUPORN_BASE_URL: string = 'https://www.youporn.com'
|
||||||
export const YOUPORN_BASE_URL_VIDEO: string = 'https://www.youporn.com/watch'
|
export const YOUPORN_BASE_URL_VIDEO: string = 'https://www.youporn.com/watch'
|
||||||
|
|
||||||
export const YOUPORN_BASE_SEARCH: string = 'https://www.youporn.com/search/?search-btn=&query='
|
export const YOUPORN_BASE_SEARCH: string = 'https://www.youporn.com/search/?search-btn=&query='
|
||||||
|
|
||||||
|
// REDTUBE
|
||||||
|
|
||||||
|
export const REDTUBE_BASE_URL: string = 'https://www.redtube.com'
|
||||||
|
export const REDTUBE_BASE_URL_GAY: string = 'https://www.redtube.com/gay'
|
||||||
|
export const REDTUBE_BASE_URL_TRANS: string = 'https://www.redtube.com/redtube/transgender'
|
||||||
|
|
||||||
|
export const REDTUBE_BASE_SEARCH: string = 'https://www.redtube.com/?search='
|
||||||
|
export const REDTUBE_BASE_GAY_SEARCH: string = 'https://www.redtube.com/gay?search='
|
|
@ -8,7 +8,8 @@ export enum Platforms {
|
||||||
xvideos= 'xvideos',
|
xvideos= 'xvideos',
|
||||||
xnxx= 'xnxx',
|
xnxx= 'xnxx',
|
||||||
pornhub= 'pornhub',
|
pornhub= 'pornhub',
|
||||||
youporn= 'youporn'
|
youporn= 'youporn',
|
||||||
|
redtube= 'redtube'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum XVideosCatQueryMap {
|
export enum XVideosCatQueryMap {
|
||||||
|
@ -32,6 +33,12 @@ export enum YouPornOrientations {
|
||||||
generic= 'generic'
|
generic= 'generic'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum RedTubeOrientations {
|
||||||
|
etero= 'etero',
|
||||||
|
gay= 'gay',
|
||||||
|
trans= 'trans'
|
||||||
|
}
|
||||||
|
|
||||||
export enum Themes {
|
export enum Themes {
|
||||||
light= 'light',
|
light= 'light',
|
||||||
dark= 'dark',
|
dark= 'dark',
|
||||||
|
|
|
@ -6,12 +6,14 @@ import { XVideosAgent } from "./scrape/xvideos/agent";
|
||||||
import { XNXXAgent } from "./scrape/xnxx/agent";
|
import { XNXXAgent } from "./scrape/xnxx/agent";
|
||||||
import { PornHubAgent } from "./scrape/pornhub/agent";
|
import { PornHubAgent } from "./scrape/pornhub/agent";
|
||||||
import { YouPornAgent } from "./scrape/youporn/agent";
|
import { YouPornAgent } from "./scrape/youporn/agent";
|
||||||
|
import { RedTubeAgent } from "./scrape/redtube/agent";
|
||||||
|
|
||||||
const AgentMapper = {
|
const AgentMapper = {
|
||||||
[Platforms.xvideos]: XVideosAgent,
|
[Platforms.xvideos]: XVideosAgent,
|
||||||
[Platforms.xnxx]: XNXXAgent,
|
[Platforms.xnxx]: XNXXAgent,
|
||||||
[Platforms.pornhub]: PornHubAgent,
|
[Platforms.pornhub]: PornHubAgent,
|
||||||
[Platforms.youporn]: YouPornAgent,
|
[Platforms.youporn]: YouPornAgent,
|
||||||
|
[Platforms.redtube]: RedTubeAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
export class VideoAgent {
|
export class VideoAgent {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { FetchParams, GalleryData, VideoAgent, VideoData } from "@/meta/data";
|
||||||
|
import { fetchRedTubeGalleryData } from "./gallery";
|
||||||
|
import { fetchRedTubeVideoData } from "./video";
|
||||||
|
|
||||||
|
export class RedTubeAgent implements VideoAgent {
|
||||||
|
|
||||||
|
public getGallery = async (params?: FetchParams): Promise<GalleryData[]> => {
|
||||||
|
return await fetchRedTubeGalleryData(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getVideo = async (id: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => {
|
||||||
|
return await fetchRedTubeVideoData(id, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { FetchParams, GalleryData } from "@/meta/data";
|
||||||
|
import { getHeaders } from "../common/headers";
|
||||||
|
import { REDTUBE_BASE_URL } from "@/constants/urls";
|
||||||
|
import { getRedTubeQueryUrl, getRedTubeResultsWrapperId } from "./url";
|
||||||
|
import { getDataFromRedis, storeDataIntoRedis } from "@/redis/client";
|
||||||
|
|
||||||
|
import * as cheerio from "cheerio";
|
||||||
|
|
||||||
|
import axios, { AxiosError } from "axios";
|
||||||
|
import { Platforms } from "@/meta/settings";
|
||||||
|
import { DEFAULT_REDTUBE_GALLERY_EXPIRY } from "@/constants/redis";
|
||||||
|
|
||||||
|
export const fetchRedTubeGalleryData = async (params?: FetchParams): Promise<GalleryData[]> => {
|
||||||
|
|
||||||
|
let data: GalleryData[] = [];
|
||||||
|
|
||||||
|
const reqHeaders = getHeaders(REDTUBE_BASE_URL)
|
||||||
|
|
||||||
|
const queryUrl = await getRedTubeQueryUrl(params?.query)
|
||||||
|
|
||||||
|
const cachedData = await getDataFromRedis(queryUrl)
|
||||||
|
|
||||||
|
if (cachedData) {
|
||||||
|
return cachedData as GalleryData[]
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.get(queryUrl, reqHeaders)
|
||||||
|
|
||||||
|
.then(async response => {
|
||||||
|
|
||||||
|
const html = response.data;
|
||||||
|
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
const wrapperId = await getRedTubeResultsWrapperId(params?.query)
|
||||||
|
|
||||||
|
const thumbs = $(wrapperId);
|
||||||
|
|
||||||
|
thumbs.map((key, thumb) => {
|
||||||
|
|
||||||
|
const videoUrl = $(thumb).find("a.video_link").attr("href")?.split('/')[1];
|
||||||
|
const imgUrl = $(thumb).find("img.js_thumbImageTag").attr("data-src")
|
||||||
|
const text = $(thumb).find("a.tm_video_title").attr("title");
|
||||||
|
|
||||||
|
videoUrl && imgUrl && text && data.push({
|
||||||
|
videoUrl,
|
||||||
|
imgUrl,
|
||||||
|
text,
|
||||||
|
platform: Platforms.redtube
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await storeDataIntoRedis(queryUrl, data, DEFAULT_REDTUBE_GALLERY_EXPIRY);
|
||||||
|
|
||||||
|
}).catch((error: AxiosError) => {
|
||||||
|
// handle errors
|
||||||
|
});
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
import { getCookie } from "@/utils/cookies/read"
|
||||||
|
|
||||||
|
import { Cookies, RedTubeOrientations } from "@/meta/settings"
|
||||||
|
import { REDTUBE_BASE_SEARCH, REDTUBE_BASE_GAY_SEARCH, REDTUBE_BASE_URL_GAY, REDTUBE_BASE_URL, REDTUBE_BASE_URL_TRANS } from "@/constants/urls"
|
||||||
|
import { getHeadersWithCookie } from "../common/headers"
|
||||||
|
import { MindGeekVideoSrcElem, VideoSourceItem } from "@/meta/data"
|
||||||
|
|
||||||
|
import axios from "axios"
|
||||||
|
|
||||||
|
export const getRedTubeQueryUrl = async (query?: string): Promise<string> => {
|
||||||
|
const orientation = await getCookie(Cookies.orientation)
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
return `${orientation && orientation.value == RedTubeOrientations.gay ?
|
||||||
|
REDTUBE_BASE_GAY_SEARCH :
|
||||||
|
REDTUBE_BASE_SEARCH}${query}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation && orientation.value == RedTubeOrientations.gay ) {
|
||||||
|
return REDTUBE_BASE_URL_GAY
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation && orientation.value == RedTubeOrientations.trans ) {
|
||||||
|
return REDTUBE_BASE_URL_TRANS
|
||||||
|
}
|
||||||
|
|
||||||
|
return REDTUBE_BASE_URL
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRedTubeResultsWrapperId = async (query?: string): Promise<string> => {
|
||||||
|
const orientation = await getCookie(Cookies.orientation)
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
return ".videos_grid li"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation && ((orientation.value == RedTubeOrientations.gay) || (orientation.value == RedTubeOrientations.trans))) {
|
||||||
|
return "#block_browse li"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "#most_recent_videos li"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getRedTubeMediaUrlList = async (url: string, sessionCookie: string): Promise<VideoSourceItem[]> => {
|
||||||
|
|
||||||
|
const headersWithCookie = getHeadersWithCookie(REDTUBE_BASE_URL, sessionCookie)
|
||||||
|
|
||||||
|
let videos: VideoSourceItem[] = []
|
||||||
|
|
||||||
|
await axios.get(url, headersWithCookie)
|
||||||
|
.then(async response => {
|
||||||
|
|
||||||
|
if (response.data) {
|
||||||
|
|
||||||
|
videos = await response.data.map((elem: MindGeekVideoSrcElem) => ({
|
||||||
|
src: elem?.videoUrl,
|
||||||
|
type: 'video/mp4',
|
||||||
|
size: elem?.quality
|
||||||
|
})) as VideoSourceItem[]
|
||||||
|
|
||||||
|
return videos
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error => console.log(error))
|
||||||
|
|
||||||
|
return videos
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
import { REDTUBE_BASE_URL } from "@/constants/urls";
|
||||||
|
import { FetchParams, GalleryData, VideoData, VideoSourceItem } from "@/meta/data";
|
||||||
|
import { getHeaders } from "../common/headers";
|
||||||
|
import { getDataFromRedis, storeDataIntoRedis } from "@/redis/client";
|
||||||
|
import { DEFAULT_REDTUBE_GALLERY_EXPIRY, DEFAULT_REDTUBE_VIDEO_EXPIRY, DEFAULT_RELATED_VIDEO_KEY_PATH } from "@/constants/redis";
|
||||||
|
|
||||||
|
import * as cheerio from "cheerio";
|
||||||
|
|
||||||
|
import axios, { AxiosError } from "axios";
|
||||||
|
import { createSessionCookie, findGetMediaUrlInTagblock } from "../common/mindgeek";
|
||||||
|
import { Platforms } from "@/meta/settings";
|
||||||
|
import { getRedTubeMediaUrlList } from "./url";
|
||||||
|
|
||||||
|
export const fetchRedTubeVideoData = async (videoId: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => {
|
||||||
|
|
||||||
|
let data: VideoData = {
|
||||||
|
hlsUrl: '',
|
||||||
|
srcSet: []
|
||||||
|
}
|
||||||
|
|
||||||
|
let relatedData: GalleryData[] = [];
|
||||||
|
|
||||||
|
let mediaUrl, sessionCookie, convertedData: VideoSourceItem[]
|
||||||
|
|
||||||
|
let reqHeaders = getHeaders(REDTUBE_BASE_URL)
|
||||||
|
|
||||||
|
const queryUrl = `${REDTUBE_BASE_URL}/${videoId.replace(/\//g, '')}`
|
||||||
|
|
||||||
|
const cachedVideoData = await getDataFromRedis(queryUrl)
|
||||||
|
const cachedRelatedData = await getDataFromRedis(queryUrl + DEFAULT_RELATED_VIDEO_KEY_PATH)
|
||||||
|
|
||||||
|
if (cachedVideoData) {
|
||||||
|
return [cachedVideoData as VideoData, cachedRelatedData as GalleryData[] ?? []]
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.get(queryUrl, reqHeaders)
|
||||||
|
|
||||||
|
.then(async response => {
|
||||||
|
|
||||||
|
sessionCookie = response?.headers["set-cookie"] ? createSessionCookie(response?.headers["set-cookie"]) : '';
|
||||||
|
|
||||||
|
const html = response.data;
|
||||||
|
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
|
const scriptTags = $("script");
|
||||||
|
|
||||||
|
scriptTags.map((idx, elem) => {
|
||||||
|
const getMediaUrl = findGetMediaUrlInTagblock($(elem).toString().replace(/\\/g, ''), 'media/mp4') ?? null
|
||||||
|
|
||||||
|
if (getMediaUrl) {
|
||||||
|
mediaUrl = `${REDTUBE_BASE_URL}${getMediaUrl}`
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapperId = "#related_videos_center li.tm_video_block"
|
||||||
|
|
||||||
|
const thumbs = $(wrapperId);
|
||||||
|
|
||||||
|
thumbs.map((key, thumb) => {
|
||||||
|
|
||||||
|
const videoUrl = $(thumb).find("a.tm_video_link").attr("href")?.split('/')[1];
|
||||||
|
const imgUrl = $(thumb).find("img.js_thumbImageTag").attr("data-src")
|
||||||
|
const text = $(thumb).find("a.tm_video_title").attr("title");
|
||||||
|
|
||||||
|
videoUrl && imgUrl && text && relatedData.push({
|
||||||
|
videoUrl,
|
||||||
|
imgUrl,
|
||||||
|
text,
|
||||||
|
platform: Platforms.redtube
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}).catch((error: AxiosError) => {
|
||||||
|
// error handling goes here
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sessionCookie && mediaUrl) {
|
||||||
|
convertedData = await getRedTubeMediaUrlList(mediaUrl, sessionCookie)
|
||||||
|
data.srcSet = convertedData.reverse()
|
||||||
|
|
||||||
|
await storeDataIntoRedis(queryUrl, data, DEFAULT_REDTUBE_VIDEO_EXPIRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relatedData.length > 0) {
|
||||||
|
await storeDataIntoRedis(queryUrl + DEFAULT_RELATED_VIDEO_KEY_PATH, relatedData, DEFAULT_REDTUBE_GALLERY_EXPIRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [ data, relatedData ]
|
||||||
|
}
|
Loading…
Reference in New Issue