diff --git a/src/meta/data.ts b/src/meta/data.ts index 054d714..80ca26e 100644 --- a/src/meta/data.ts +++ b/src/meta/data.ts @@ -16,4 +16,9 @@ export interface VideoData { lowResUrl: string, hiResUrl?: string, hlsUrl?: string +} + +export interface VideoAgent { + getGallery(params?: FetchParams): Promise + getVideo(id: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> } \ No newline at end of file diff --git a/src/utils/agent.ts b/src/utils/agent.ts index eb42c27..32f766a 100644 --- a/src/utils/agent.ts +++ b/src/utils/agent.ts @@ -2,11 +2,13 @@ import { FetchParams, GalleryData, VideoData } from "@/meta/data"; import { Platforms } from "@/meta/settings"; -import { fetchXVideosGalleryData } from "./scrape/xvideos/gallery"; -import { fetchXvideosVideoData } from "./scrape/xvideos/video"; +import { XVideosAgent } from "./scrape/xvideos/agent"; +import { XNXXAgent } from "./scrape/xnxx/agent"; -import { fetchXNXXGalleryData } from "./scrape/xnxx/gallery"; -import { XNXX_BASE_URL } from "@/constants/urls"; +const AgentMapper = { + [Platforms.xvideos]: XVideosAgent, + [Platforms.xnxx]: XNXXAgent +} export class VideoAgent { platform: Platforms; @@ -16,25 +18,10 @@ export class VideoAgent { } public getGallery = async (params?: FetchParams): Promise => { - switch (this.platform) { - case Platforms.xvideos: - return await fetchXVideosGalleryData(params) - case Platforms.xnxx: - return await fetchXNXXGalleryData(params) - default: - return [] - } + return await new AgentMapper[this.platform]().getGallery(params) } public getVideo = async (id: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => { - switch (this.platform) { - case Platforms.xvideos: - return await fetchXvideosVideoData(id, params) - case Platforms.xnxx: - return await fetchXvideosVideoData(id, { ...params, baseUrl: XNXX_BASE_URL }) - default: - return [{ lowResUrl: '' }, []] - } + return await new AgentMapper[this.platform]().getVideo(id, params) } - } \ No newline at end of file diff --git a/src/utils/scrape/headers.ts b/src/utils/scrape/common/headers.ts similarity index 97% rename from src/utils/scrape/headers.ts rename to src/utils/scrape/common/headers.ts index c66bc7a..87287be 100644 --- a/src/utils/scrape/headers.ts +++ b/src/utils/scrape/common/headers.ts @@ -1,5 +1,5 @@ import { XVIDEOS_BASE_URL } from "@/constants/urls"; -import { removeHttpS } from "../string"; +import { removeHttpS } from "@/utils/string"; const getRandomUserAgent = (): string => { diff --git a/src/utils/scrape/common/wgcz.ts b/src/utils/scrape/common/wgcz.ts new file mode 100644 index 0000000..79f572b --- /dev/null +++ b/src/utils/scrape/common/wgcz.ts @@ -0,0 +1,44 @@ +import { GalleryData } from "@/meta/data"; +import { Platforms } from "@/meta/settings"; + +export const findVideoUrlInsideTagStringByFunctionNameAndExtension = ( + tagBlock: string, functionName: string, extension: string): string | null => { + const start = tagBlock.indexOf(`html5player.${functionName}('`) + `html5player.${functionName}('`.length; + const end = tagBlock.toString().indexOf("'", start); + + const substr = tagBlock.substring(start, end); + + if (substr.includes(extension)) { + return substr + } + + return null +} + +export const findRelatedVideos = (tagBlock: string, platform: Platforms): GalleryData[] | null => { + if (!(tagBlock.includes('video_related=['))) { + return null + } + + // Trova l'inizio e la fine dell'array di oggetti nell'input + const start = tagBlock.indexOf('[{'); + const end = tagBlock.lastIndexOf('}]') + 2; + + // Estrai la sottostringa contenente l'array di oggetti + const jsonString = tagBlock.substring(start, end); + + // Parsea la stringa JSON in un array di oggetti + const videoRelatedArray = JSON.parse(jsonString); + + // Mappa ogni oggetto nell'array per rinominare le chiavi + //@ts-ignore + const parsedArray = videoRelatedArray.map(obj => ({ + //@ts-ignore + videoUrl: obj.u, + imgUrl: obj.i, + text: obj.tf, + platform + })); + + return parsedArray; +} diff --git a/src/utils/scrape/xnxx/agent.ts b/src/utils/scrape/xnxx/agent.ts new file mode 100644 index 0000000..9006390 --- /dev/null +++ b/src/utils/scrape/xnxx/agent.ts @@ -0,0 +1,15 @@ +import { FetchParams, GalleryData, VideoAgent, VideoData } from "@/meta/data"; +import { fetchXNXXGalleryData, } from "./gallery"; +import { fetchXNXXVideoData } from "./video"; + +export class XNXXAgent implements VideoAgent { + + public getGallery = async (params?: FetchParams): Promise => { + return await fetchXNXXGalleryData(params) + } + + public getVideo = async (id: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => { + return await fetchXNXXVideoData(id, params) + } + +} \ No newline at end of file diff --git a/src/utils/scrape/xnxx/gallery.ts b/src/utils/scrape/xnxx/gallery.ts index 89d2697..3f7fec1 100644 --- a/src/utils/scrape/xnxx/gallery.ts +++ b/src/utils/scrape/xnxx/gallery.ts @@ -3,7 +3,7 @@ import axios, { AxiosError } from 'axios'; import * as cheerio from "cheerio"; -import { getHeaders } from '../headers'; +import { getHeaders } from '@/utils/scrape/common/headers'; import { getXNXXQueryUrl } from './url'; import { Platforms } from '@/meta/settings'; diff --git a/src/utils/scrape/xnxx/video.ts b/src/utils/scrape/xnxx/video.ts new file mode 100644 index 0000000..1cf066e --- /dev/null +++ b/src/utils/scrape/xnxx/video.ts @@ -0,0 +1,71 @@ +import { XNXX_BASE_URL } from '@/constants/urls'; +import { FetchParams, GalleryData, VideoData } from '@/meta/data'; + +import axios, { AxiosError } from 'axios'; + +import * as cheerio from "cheerio"; + +import { Platforms } from '@/meta/settings'; +import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '@/utils/scrape/common/wgcz'; +import { getHeaders } from '@/utils/scrape/common/headers'; + +export const fetchXNXXVideoData = async (videoId: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => { + + let data: VideoData = { + lowResUrl: '' + } + + let related: GalleryData[] = []; + + const host = XNXX_BASE_URL + + const reqHeaders = getHeaders(host) + + const queryUrl = `${host}${videoId}` + + await axios.get(queryUrl, reqHeaders) + + .then(response => { + + const html = response.data; + + const $ = cheerio.load(html); + + const scriptTags = $("script"); + + // populate video data object + scriptTags.map((idx, elem) => { + + const lowResUrl = findVideoUrlInsideTagStringByFunctionNameAndExtension($(elem).toString(), 'setVideoUrlLow', '.mp4') + const hiResUrl = findVideoUrlInsideTagStringByFunctionNameAndExtension($(elem).toString(), 'setVideoUrlHigh', '.mp4') + const hlsUrl = findVideoUrlInsideTagStringByFunctionNameAndExtension($(elem).toString(), 'setVideoHLS', '.m3u8') + + if (lowResUrl) { + data.lowResUrl = lowResUrl; + } + + if (hiResUrl) { + data.hiResUrl = hiResUrl + } + + if (hlsUrl) { + data.hlsUrl = hlsUrl + } + + }) + + // populate related gallery + scriptTags.map((idx, elem) => { + const relatedVideos = findRelatedVideos($(elem).toString(), Platforms.xnxx) + + if (relatedVideos) { + related = relatedVideos + } + }) + + }).catch((error: AxiosError) => { + // handle errors + }); + + return [data, related]; +} \ No newline at end of file diff --git a/src/utils/scrape/xvideos/agent.ts b/src/utils/scrape/xvideos/agent.ts new file mode 100644 index 0000000..c144486 --- /dev/null +++ b/src/utils/scrape/xvideos/agent.ts @@ -0,0 +1,15 @@ +import { FetchParams, GalleryData, VideoAgent, VideoData } from "@/meta/data"; +import { fetchXVideosGalleryData } from "./gallery"; +import { fetchXvideosVideoData } from "./video"; + +export class XVideosAgent implements VideoAgent { + + public getGallery = async (params?: FetchParams): Promise => { + return await fetchXVideosGalleryData(params) + } + + public getVideo = async (id: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => { + return await fetchXvideosVideoData(id, params) + } + +} \ No newline at end of file diff --git a/src/utils/scrape/xvideos/gallery.ts b/src/utils/scrape/xvideos/gallery.ts index 8bd0822..2a941e0 100644 --- a/src/utils/scrape/xvideos/gallery.ts +++ b/src/utils/scrape/xvideos/gallery.ts @@ -2,7 +2,7 @@ import { FetchParams, GalleryData } from '@/meta/data'; import axios, { AxiosError } from 'axios'; import * as cheerio from "cheerio"; -import { getHeaders } from '../headers'; +import { getHeaders } from '@/utils/scrape/common/headers'; import { getXVideosQueryUrl } from './url'; import { Platforms } from '@/meta/settings'; diff --git a/src/utils/scrape/xvideos/video.ts b/src/utils/scrape/xvideos/video.ts index 5e8cedd..c323be1 100644 --- a/src/utils/scrape/xvideos/video.ts +++ b/src/utils/scrape/xvideos/video.ts @@ -4,8 +4,10 @@ import { FetchParams, GalleryData, VideoData } from '@/meta/data'; import axios, { AxiosError } from 'axios'; import * as cheerio from "cheerio"; -import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '../../string'; -import { getHeaders } from '../headers'; +import { getHeaders } from '@/utils/scrape/common/headers'; +import { Platforms } from '@/meta/settings'; + +import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '@/utils/scrape/common/wgcz'; export const fetchXvideosVideoData = async (videoId: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => { @@ -15,9 +17,11 @@ export const fetchXvideosVideoData = async (videoId: string, params?: FetchParam let related: GalleryData[] = []; - const reqHeaders = getHeaders() + const host = XVIDEOS_BASE_URL - const queryUrl = `${(params && params.baseUrl) ?? XVIDEOS_BASE_URL}${videoId}` + const reqHeaders = getHeaders(host) + + const queryUrl = `${host}${videoId}` await axios.get(queryUrl, reqHeaders) @@ -25,7 +29,6 @@ export const fetchXvideosVideoData = async (videoId: string, params?: FetchParam const html = response.data; - const $ = cheerio.load(html); const scriptTags = $("script"); @@ -53,7 +56,7 @@ export const fetchXvideosVideoData = async (videoId: string, params?: FetchParam // populate related gallery scriptTags.map((idx, elem) => { - const relatedVideos = findRelatedVideos($(elem).toString()) + const relatedVideos = findRelatedVideos($(elem).toString(), Platforms.xvideos) if (relatedVideos) { related = relatedVideos diff --git a/src/utils/string.ts b/src/utils/string.ts index a1c0225..3c71166 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -1,46 +1,3 @@ -import { GalleryData } from "@/meta/data"; - -export const findVideoUrlInsideTagStringByFunctionNameAndExtension = ( - tagBlock: string, functionName: string, extension: string): string | null => { - const start = tagBlock.indexOf(`html5player.${functionName}('`) + `html5player.${functionName}('`.length; - const end = tagBlock.toString().indexOf("'", start); - - const substr = tagBlock.substring(start, end); - - if (substr.includes(extension)) { - return substr - } - - return null -} - -export const findRelatedVideos = (tagBlock: string): GalleryData[] | null => { - if (!(tagBlock.includes('video_related=['))) { - return null - } - - // Trova l'inizio e la fine dell'array di oggetti nell'input - const start = tagBlock.indexOf('[{'); - const end = tagBlock.lastIndexOf('}]') + 2; - - // Estrai la sottostringa contenente l'array di oggetti - const jsonString = tagBlock.substring(start, end); - - // Parsea la stringa JSON in un array di oggetti - const videoRelatedArray = JSON.parse(jsonString); - - // Mappa ogni oggetto nell'array per rinominare le chiavi - //@ts-ignore - const parsedArray = videoRelatedArray.map(obj => ({ - //@ts-ignore - videoUrl: obj.u, - imgUrl: obj.i, - text: obj.tf - })); - - return parsedArray; -} - export const removeHttpS = (url: string): string => { if (url.startsWith("http://")) { return url.slice(7);