v0.1/code-improvements #53

Merged
lamacchinadesiderante merged 10 commits from v0.1/code-improvements into main 2024-04-28 19:53:31 +00:00
28 changed files with 219 additions and 38 deletions

View File

@ -8,6 +8,13 @@ services:
restart: always restart: always
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:3000/api/status || exit 1
interval: 60s
retries: 5
start_period: 20s
timeout: 10s
build: . build: .
ports: ports:

View File

@ -10,6 +10,11 @@
"disclaimer_5": "No banners or annoying popups. You can jerk off with no hassle!", "disclaimer_5": "No banners or annoying popups. You can jerk off with no hassle!",
"disclaimer_6": "You're choosing image over imagination. What if they're not in antithesis?" "disclaimer_6": "You're choosing image over imagination. What if they're not in antithesis?"
}, },
"NotFound": {
"uh_oh": "Uh Oh...",
"something_wrong": "Something went wrong :|",
"back_to_home": "Back to homepage"
},
"Search": { "Search": {
"placeholder": "categories, pornostars, etc...", "placeholder": "categories, pornostars, etc...",
"submit": "Search" "submit": "Search"

View File

@ -10,6 +10,11 @@
"disclaimer_5": "Niente banner o popup fastidiosi. Puoi masturbarti in santa pace.", "disclaimer_5": "Niente banner o popup fastidiosi. Puoi masturbarti in santa pace.",
"disclaimer_6": "Stai preferendo l'immagine all'immaginazione. E se immagine e immaginazione non fossero in antitesi?" "disclaimer_6": "Stai preferendo l'immagine all'immaginazione. E se immagine e immaginazione non fossero in antitesi?"
}, },
"NotFound": {
"uh_oh": "Uh Oh...",
"something_wrong": "Qualcosa è andato storto :|",
"back_to_home": "Torna alla home"
},
"Search": { "Search": {
"placeholder": "categorie, pornostar, ecc...", "placeholder": "categorie, pornostar, ecc...",
"submit": "Cerca" "submit": "Cerca"

View File

@ -8,4 +8,18 @@ module.exports = withNextIntl({
sassOptions: { sassOptions: {
includePaths: [path.join(__dirname, 'src/styles')], includePaths: [path.join(__dirname, 'src/styles')],
}, },
async headers() {
return [
{
// matching all API routes
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "*" },
{ key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" },
]
}
]
}
}) })

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
public/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

BIN
public/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

1
public/site.webmanifest Normal file
View File

@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

@ -0,0 +1,11 @@
import Layout from "@/components/Layout";
import NotFound from "@/components/Pages/NotFound";
export default function NotFoundPage() {
return (
<Layout>
<NotFound />
</Layout>
);
}

View File

@ -1,12 +1,8 @@
import axios from 'axios';
import * as cheerio from "cheerio";
import Layout from "@/components/Layout"; import Layout from "@/components/Layout";
import Home from "@/components/Pages/Home"; import Home from "@/components/Pages/Home";
import { fetchGalleryData } from '@/utils/scrape/gallery'; import { fetchGalleryData } from '@/utils/scrape/xvideos/gallery';
export default async function HomePage() { export default async function HomePage() {

View File

@ -2,7 +2,7 @@ import Layout from "@/components/Layout";
import Search from "@/components/Pages/Search"; import Search from "@/components/Pages/Search";
import { fetchGalleryData } from "@/utils/scrape/gallery"; import { fetchGalleryData } from "@/utils/scrape/xvideos/gallery";
export default async function SearchPage({ params }: { params: { query: string } }) { export default async function SearchPage({ params }: { params: { query: string } }) {

View File

@ -4,7 +4,9 @@ import Layout from "@/components/Layout";
import Video from "@/components/Pages/Video"; import Video from "@/components/Pages/Video";
import { fetchVideoData } from "@/utils/scrape/video"; import { decodeVideoUrlPath } from '@/utils/string';
import { fetchVideoData } from '@/utils/scrape/xvideos/video';
import { useLocale } from 'next-intl'; import { useLocale } from 'next-intl';
@ -12,7 +14,7 @@ export default async function VideoPage({ params }: { params: { id: string } })
const locale = useLocale() const locale = useLocale()
const decodedId = decodeURIComponent(params.id) const decodedId = decodeVideoUrlPath(params.id)
const [data, related] = await fetchVideoData(decodedId) const [data, related] = await fetchVideoData(decodedId)

View File

@ -0,0 +1,7 @@
import { getAppVersion } from '@/utils/info/version'
import { NextResponse } from 'next/server'
export async function GET() {
const version = await getAppVersion()
return NextResponse.json({ version })
}

View File

@ -0,0 +1,5 @@
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
return NextResponse.json({ msg: 'OK' })
}

View File

@ -9,6 +9,7 @@ import classNames from 'classnames';
import Link from 'next/link' import Link from 'next/link'
import style from './Thumbnail.module.scss' import style from './Thumbnail.module.scss'
import { encodeVideoUrlPath } from '@/utils/string';
interface Props { interface Props {
locale: string locale: string
@ -22,7 +23,7 @@ const Thumbnail: React.FC<Props> = (props) => {
const { locale, videoUrl, imgUrl, text, show } = props const { locale, videoUrl, imgUrl, text, show } = props
const encodedUri = encodeURIComponent(videoUrl) const encodedUri = encodeVideoUrlPath(videoUrl)
return ( return (
<div className={classNames(style.thumbnailContainer, { [style.show]: show } )}> <div className={classNames(style.thumbnailContainer, { [style.show]: show } )}>

View File

@ -9,6 +9,7 @@
.query{ .query{
flex: 6; flex: 6;
margin-right: $spacing_16; margin-right: $spacing_16;
transition: none !important;
} }
.query:hover { .query:hover {
@ -24,6 +25,7 @@
background-color: var(--primary); background-color: var(--primary);
border-color: var(--primary); border-color: var(--primary);
color: var(--primary-inverse); color: var(--primary-inverse);
transition: none !important;
} }
.submitBtn:hover { .submitBtn:hover {

View File

@ -21,7 +21,7 @@ const Layout: React.FC<React.PropsWithChildren> = (props) => {
<Head> <Head>
<meta charSet="utf-8" /> <meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Proxy Raye: un proxy per XVideos basato su PornInvidious</title> <title>Proxy Raye: watch porn videos without tracking or annoying ads!</title>
</Head> </Head>
<body> <body>
<main className="container">{children}</main> <main className="container">{children}</main>

View File

@ -0,0 +1,13 @@
@import 'fontsize';
.header {
font-size: $font-size-xlarge;
}
.msg {
font-size: $font-size-large;
}
.link {
color: var(--primary);
}

View File

@ -0,0 +1,22 @@
import React, { } from 'react';
import style from './Msg.module.scss';
import { useTranslations } from 'next-intl';
import Link from 'next/link';
const Msg: React.FC = () => {
const t = useTranslations('NotFound');
return (
<div className={style.container}>
<div className={style.header}>{t('uh_oh')}</div>
<p className={style.msg}>{t('something_wrong')}</p>
<Link className={style.link} href="/">{t('back_to_home')}</Link>
</div>
);
};
export default Msg;

View File

@ -0,0 +1,18 @@
import React from 'react';
import Header from '@/components/Layout/Header';
import SearchBar from '@/components/Layout/SearchBar';
import Msg from './Msg';
const NotFound: React.FC = (props) => {
return (
<>
<Header />
<SearchBar />
<Msg />
</>
);
};
export default NotFound;

23
src/utils/info/version.ts Normal file
View File

@ -0,0 +1,23 @@
import fs from 'fs/promises';
import path from 'path';
export const getAppVersion = async (): Promise<string> => {
let version = ''
try {
const packageJsonPath = path.resolve(process.cwd(), 'package.json');
const data = await fs.readFile(packageJsonPath, 'utf8');
const packageJson = JSON.parse(data);
version = packageJson.version
} catch (error) {
// handle error
}
return version
}

View File

@ -0,0 +1,38 @@
import { XVIDEOS_BASE_URL } from "@/constants/urls";
import { removeHttpS } from "../string";
const getRandomUserAgent = (): string => {
const userAgents: string[] = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5397.215 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.2420.81',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 OPR/109.0.0.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14.4; rv:124.0) Gecko/20100101 Firefox/124.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 OPR/109.0.0.0',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux i686; rv:124.0) Gecko/20100101 Firefox/124.0'
];
const rand = Math.floor(Math.random() * userAgents.length);
return userAgents[rand]
}
export const getHeaders = (host:string = XVIDEOS_BASE_URL) => {
return {
headers: {
"User-Agent": getRandomUserAgent(),
"Accept-Language": "en-gb, en, en-US, it",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Host": removeHttpS(host)
},
}
};

View File

@ -1,8 +1,9 @@
import { XVIDEOS_BASE_URL } from '@/constants/urls'; import { XVIDEOS_BASE_URL } from '@/constants/urls';
import { GalleryData, VideoData } from '@/meta/data'; import { GalleryData } from '@/meta/data';
import axios, { AxiosError } from 'axios'; import axios, { AxiosError } from 'axios';
import * as cheerio from "cheerio"; import * as cheerio from "cheerio";
import { getHeaders } from '../headers';
interface FetchParams { interface FetchParams {
baseUrl?: string baseUrl?: string
@ -13,11 +14,7 @@ export const fetchGalleryData = async (params?: FetchParams): Promise<GalleryDat
let data: GalleryData[] = []; let data: GalleryData[] = [];
const reqHeaders = { const reqHeaders = getHeaders()
headers: {
"User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5397.215 Safari/537.36'
},
};
const queryUrl = `${(params && params.baseUrl) ?? XVIDEOS_BASE_URL}${params && params.query ? '/?k=' + params.query : ''}` const queryUrl = `${(params && params.baseUrl) ?? XVIDEOS_BASE_URL}${params && params.query ? '/?k=' + params.query : ''}`

View File

@ -4,7 +4,8 @@ import { GalleryData, VideoData } from '@/meta/data';
import axios, { AxiosError } from 'axios'; import axios, { AxiosError } from 'axios';
import * as cheerio from "cheerio"; import * as cheerio from "cheerio";
import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '../string'; import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '../../string';
import { getHeaders } from '../headers';
interface FetchParams { interface FetchParams {
baseUrl?: string baseUrl?: string
@ -19,11 +20,7 @@ export const fetchVideoData = async (videoId: string, params?: FetchParams): Pro
let related: GalleryData[] = []; let related: GalleryData[] = [];
const reqHeaders = { const reqHeaders = getHeaders()
headers: {
"User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5397.215 Safari/537.36'
},
};
const queryUrl = `${(params && params.baseUrl) ?? XVIDEOS_BASE_URL}${videoId}` const queryUrl = `${(params && params.baseUrl) ?? XVIDEOS_BASE_URL}${videoId}`

View File

@ -1,7 +1,7 @@
import { GalleryData } from "@/meta/data"; import { GalleryData } from "@/meta/data";
export const findVideoUrlInsideTagStringByFunctionNameAndExtension = ( export const findVideoUrlInsideTagStringByFunctionNameAndExtension = (
tagBlock: string, functionName: string, extension: string): string|null => { tagBlock: string, functionName: string, extension: string): string | null => {
const start = tagBlock.indexOf(`html5player.${functionName}('`) + `html5player.${functionName}('`.length; const start = tagBlock.indexOf(`html5player.${functionName}('`) + `html5player.${functionName}('`.length;
const end = tagBlock.toString().indexOf("'", start); const end = tagBlock.toString().indexOf("'", start);
@ -14,7 +14,7 @@ export const findVideoUrlInsideTagStringByFunctionNameAndExtension = (
return null return null
} }
export const findRelatedVideos = (tagBlock: string): GalleryData[]|null => { export const findRelatedVideos = (tagBlock: string): GalleryData[] | null => {
if (!(tagBlock.includes('video_related=['))) { if (!(tagBlock.includes('video_related=['))) {
return null return null
} }
@ -40,3 +40,20 @@ export const findRelatedVideos = (tagBlock: string): GalleryData[]|null => {
return parsedArray; return parsedArray;
} }
export const removeHttpS = (url: string): string => {
if (url.startsWith("http://")) {
return url.slice(7);
} else if (url.startsWith("https://")) {
return url.slice(8);
}
return url;
};
export const encodeVideoUrlPath = (input: string): string => {
return encodeURIComponent(input.replace(/^\/+/, ''))
};
export const decodeVideoUrlPath = (input: string): string => {
return `/${decodeURIComponent(input)}`;
};