Release v0.4: Add PornHub support / Server-side streaming / Plyr.js / Video srcset #96

Merged
lamacchinadesiderante merged 18 commits from feature/pornhub-support into develop 2024-05-25 11:46:42 +00:00
7 changed files with 53 additions and 4 deletions
Showing only changes of commit 702b67bdd7 - Show all commits

View File

@ -6,3 +6,10 @@ ENABLE_REDIS=true
# if cache enabled, set redis url for external redis # if cache enabled, set redis url for external redis
REDIS_URL='redis://127.0.0.1:6379' REDIS_URL='redis://127.0.0.1:6379'
# this key is necessary to encrypt/decrypt urls for server-side stream
# if not set, a default value (check const DEFAULT_ENCODING_KEY inside src/constants/encoding.ts ) will be used
# please generate a new one with command `pwgen 20 1` (pwgen command needs to be installed)
# uncomment variable below and add generated value
# ENCODING_KEY=''

View File

@ -23,6 +23,8 @@ services:
environment: environment:
- ENABLE_REDIS=true - ENABLE_REDIS=true
- REDIS_URL=redis://redis:6379 - REDIS_URL=redis://redis:6379
# Please generate a new encoding key with command `pwgen 20 1`, decomment following variable and insert result into it:
# - ENCODING_KEY=
redis: redis:
image: redis:alpine image: redis:alpine

View File

@ -1,4 +1,5 @@
import { Platforms } from "@/meta/settings"; import { Platforms } from "@/meta/settings";
import { decodeUrl } from "@/utils/string";
import axios from "axios"; import axios from "axios";
type GetParams = { type GetParams = {
@ -22,7 +23,7 @@ export async function GET(req: Request, { params }: GetParams) {
) )
} }
const decodedUrl = decodeURIComponent(encodedUrl) const decodedUrl = decodeUrl(encodedUrl)
const response = await axios.get<ReadableStream>(decodedUrl, { const response = await axios.get<ReadableStream>(decodedUrl, {
responseType: "stream", responseType: "stream",

View File

@ -0,0 +1 @@
export const DEFAULT_ENCODING_KEY = 'oom2oz8ut0ieshie1Hae'

1
src/constants/stream.ts Normal file
View File

@ -0,0 +1 @@
export const DEFAULT_VIDEO_STREAM_ROUTE_PREFIX = '/api/stream'

View File

@ -4,6 +4,8 @@ import { getHeadersWithCookie } from "../common/headers"
import { GalleryData, VideoSourceItem } from "@/meta/data" import { GalleryData, VideoSourceItem } from "@/meta/data"
import { Cookies, Platforms, PornHubOrientations } from "@/meta/settings" import { Cookies, Platforms, PornHubOrientations } from "@/meta/settings"
import { getCookie } from "@/utils/cookies/read" import { getCookie } from "@/utils/cookies/read"
import { encodeUrl } from "@/utils/string"
import { DEFAULT_VIDEO_STREAM_ROUTE_PREFIX } from "@/constants/stream"
interface PornHubVideoSrcElem { interface PornHubVideoSrcElem {
videoUrl: string videoUrl: string
@ -48,7 +50,7 @@ export const getPornHubMediaUrlList = async (url: string, sessionCookie: string)
if (response.data) { if (response.data) {
videos = await response.data.map((elem: PornHubVideoSrcElem) => ({ videos = await response.data.map((elem: PornHubVideoSrcElem) => ({
src: `/api/stream/${Platforms.pornhub}/${encodeURIComponent(elem?.videoUrl)}`, src: `${DEFAULT_VIDEO_STREAM_ROUTE_PREFIX}/${Platforms.pornhub}/${encodeUrl(elem?.videoUrl)}`,
type: 'video/mp4', type: 'video/mp4',
size: elem?.quality size: elem?.quality
})) as VideoSourceItem[] })) as VideoSourceItem[]

View File

@ -1,3 +1,5 @@
import { DEFAULT_ENCODING_KEY } from "@/constants/encoding";
export const removeHttpS = (url: string): string => { export const removeHttpS = (url: string): string => {
if (url.startsWith("http://")) { if (url.startsWith("http://")) {
return url.slice(7); return url.slice(7);
@ -14,3 +16,36 @@ export const encodeVideoUrlPath = (input: string): string => {
export const decodeVideoUrlPath = (input: string): string => { export const decodeVideoUrlPath = (input: string): string => {
return `/${decodeURIComponent(input)}`; return `/${decodeURIComponent(input)}`;
}; };
const getEncodingKey = ():string => {
return process.env.ENCODING_KEY ?? DEFAULT_ENCODING_KEY;
}
export function encodeUrl(url: string): string {
const key = getEncodingKey()
// Convert the URL and key to UTF-8 bytes
const urlBytes = new TextEncoder().encode(url);
const keyBytes = new TextEncoder().encode(key);
// XOR the bytes of the URL with the key bytes
const encodedBytes = urlBytes.map((byte, index) => byte ^ keyBytes[index % keyBytes.length]);
// Convert the XORed bytes to a base64 string
//@ts-ignore
return btoa(String.fromCharCode(...encodedBytes));
}
export function decodeUrl(encodedUrl: string): string {
const key = getEncodingKey()
// Decode the base64 string to get the XORed bytes
const encodedBytes = Uint8Array.from(atob(encodedUrl), char => char.charCodeAt(0));
const keyBytes = new TextEncoder().encode(key);
// XOR the encoded bytes with the key bytes to get the original URL bytes
const urlBytes = encodedBytes.map((byte, index) => byte ^ keyBytes[index % keyBytes.length]);
// Convert the bytes back to a string
return new TextDecoder().decode(urlBytes);
}