diff --git a/locale/en.json b/locale/en.json
new file mode 100644
index 0000000..e6661d1
--- /dev/null
+++ b/locale/en.json
@@ -0,0 +1,22 @@
+{
+ "Header": {
+ "title": "Proxy Raye",
+ "description": "A proxy for XVideos",
+ "disclaimer_0": "Genital sexuality is only one of the many possible conceptions of sexuality",
+ "disclaimer_1": "Platform capitalism makes money on desire flow. Proxies avoid this to happen.",
+ "disclaimer_2": "Platform capitalism is narcissism-driven",
+ "disclaimer_3": "Pornhub annoying elements (like ads) are put there intentionally to make you upgrade to premium",
+ "disclaimer_4": "You're going to masturbate on someone else's imaginary",
+ "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?"
+ },
+ "Search": {
+ "placeholder": "categories, pornostars, etc...",
+ "submit": "Search"
+ },
+ "Results": {
+ "query": "Search results for: {{ query }}",
+ "toggle": "Show preview",
+ "noData": "No videos found :("
+ }
+}
\ No newline at end of file
diff --git a/locale/it.json b/locale/it.json
new file mode 100644
index 0000000..c10a51f
--- /dev/null
+++ b/locale/it.json
@@ -0,0 +1,22 @@
+{
+ "Header": {
+ "title": "Proxy Raye",
+ "description": "Un proxy per XVideos",
+ "disclaimer_0": "Quella genitale è solo una delle possibili concezioni della sessualità.",
+ "disclaimer_1": "Le piattaforme monetizzano i flussi di desiderio. I proxy impediscono che questo accada.",
+ "disclaimer_2": "Le piattaforme si alimentano del narcisisismo degli utenti.",
+ "disclaimer_3": "Gli elementi di disturbo su PornHub sono messi lì a posta per farti passare alla versione Premium.",
+ "disclaimer_4": "Stai per masturbarti sull'immaginario di qualcun altro.",
+ "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?"
+ },
+ "Search": {
+ "placeholder": "categorie, pornostar, ecc...",
+ "submit": "Cerca"
+ },
+ "Results": {
+ "query": "Risultati della ricerca per: {{ query }}",
+ "toggle": "Mostra anteprime risultati",
+ "noData": "Nessun video trovato :("
+ }
+}
\ No newline at end of file
diff --git a/next.config.js b/next.config.js
new file mode 100644
index 0000000..bb0375e
--- /dev/null
+++ b/next.config.js
@@ -0,0 +1,11 @@
+const createNextIntlPlugin = require('next-intl/plugin');
+
+const withNextIntl = createNextIntlPlugin();
+
+const path = require('path')
+
+module.exports = withNextIntl({
+ sassOptions: {
+ includePaths: [path.join(__dirname, 'src/styles')],
+ },
+})
\ No newline at end of file
diff --git a/next.config.mjs b/next.config.mjs
deleted file mode 100644
index 4678774..0000000
--- a/next.config.mjs
+++ /dev/null
@@ -1,4 +0,0 @@
-/** @type {import('next').NextConfig} */
-const nextConfig = {};
-
-export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
index 02aeca1..020ab5e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,9 +8,16 @@
"name": "proxyraye-next",
"version": "0.1.0",
"dependencies": {
+ "@picocss/pico": "^2.0.6",
+ "axios": "^1.6.8",
+ "cheerio": "^1.0.0-rc.12",
+ "classnames": "^2.5.1",
"next": "14.2.2",
+ "next-intl": "^3.11.3",
"react": "^18",
- "react-dom": "^18"
+ "react-dom": "^18",
+ "video.js": "^8.10.0",
+ "videojs-hls-quality-selector": "^2.0.0"
},
"devDependencies": {
"@types/node": "^20",
@@ -18,6 +25,7 @@
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.2",
+ "sass": "^1.75.0",
"typescript": "^5"
}
},
@@ -34,7 +42,6 @@
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
- "dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -98,6 +105,92 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@formatjs/ecma402-abstract": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz",
+ "integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==",
+ "dependencies": {
+ "@formatjs/intl-localematcher": "0.5.4",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
+ "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/fast-memoize": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz",
+ "integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/icu-messageformat-parser": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz",
+ "integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.11.4",
+ "@formatjs/icu-skeleton-parser": "1.3.6",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/ecma402-abstract": {
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz",
+ "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==",
+ "dependencies": {
+ "@formatjs/intl-localematcher": "0.2.25",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/intl-localematcher": {
+ "version": "0.2.25",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz",
+ "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/icu-skeleton-parser": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz",
+ "integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.11.4",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/ecma402-abstract": {
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz",
+ "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==",
+ "dependencies": {
+ "@formatjs/intl-localematcher": "0.2.25",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/intl-localematcher": {
+ "version": "0.2.25",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz",
+ "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/intl-localematcher": {
+ "version": "0.2.32",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz",
+ "integrity": "sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -359,6 +452,14 @@
"node": ">= 8"
}
},
+ "node_modules/@picocss/pico": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@picocss/pico/-/pico-2.0.6.tgz",
+ "integrity": "sha512-/d8qsykowelD6g8k8JYgmCagOIulCPHMEc2NC4u7OjmpQLmtSetLhEbt0j1n3fPNJVcrT84dRp0RfJBn3wJROA==",
+ "engines": {
+ "node": ">=18.19.0"
+ }
+ },
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -562,6 +663,76 @@
"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
"dev": true
},
+ "node_modules/@videojs/http-streaming": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-3.10.0.tgz",
+ "integrity": "sha512-Lf1rmhTalV4Gw0bJqHmH4lfk/FlepUDs9smuMtorblAYnqDlE2tbUOb7sBXVYoXGdbWbdTW8jH2cnS+6HWYJ4Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/vhs-utils": "4.0.0",
+ "aes-decrypter": "4.0.1",
+ "global": "^4.4.0",
+ "m3u8-parser": "^7.1.0",
+ "mpd-parser": "^1.3.0",
+ "mux.js": "7.0.2",
+ "video.js": "^7 || ^8"
+ },
+ "engines": {
+ "node": ">=8",
+ "npm": ">=5"
+ },
+ "peerDependencies": {
+ "video.js": "^7 || ^8"
+ }
+ },
+ "node_modules/@videojs/http-streaming/node_modules/mux.js": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-7.0.2.tgz",
+ "integrity": "sha512-CM6+QuyDbc0qW1OfEjkd2+jVKzTXF+z5VOKH0eZxtZtnrG/ilkW/U7l7IXGtBNLASF9sKZMcK1u669cq50Qq0A==",
+ "dependencies": {
+ "@babel/runtime": "^7.11.2",
+ "global": "^4.4.0"
+ },
+ "bin": {
+ "muxjs-transmux": "bin/transmux.js"
+ },
+ "engines": {
+ "node": ">=8",
+ "npm": ">=5"
+ }
+ },
+ "node_modules/@videojs/vhs-utils": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-4.0.0.tgz",
+ "integrity": "sha512-xJp7Yd4jMLwje2vHCUmi8MOUU76nxiwII3z4Eg3Ucb+6rrkFVGosrXlMgGnaLjq724j3wzNElRZ71D/CKrTtxg==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "global": "^4.4.0",
+ "url-toolkit": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8",
+ "npm": ">=5"
+ }
+ },
+ "node_modules/@videojs/xhr": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.6.0.tgz",
+ "integrity": "sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "global": "~4.4.0",
+ "is-function": "^1.0.1"
+ }
+ },
+ "node_modules/@xmldom/xmldom": {
+ "version": "0.8.10",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+ "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
@@ -583,6 +754,31 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/aes-decrypter": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-4.0.1.tgz",
+ "integrity": "sha512-H1nh/P9VZXUf17AA5NQfJML88CFjVBDuGkp5zDHa7oEhYN9TTpNLJknRY1ie0iSKWlDf6JRnJKaZVDSQdPy6Cg==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/vhs-utils": "^3.0.5",
+ "global": "^4.4.0",
+ "pkcs7": "^1.0.4"
+ }
+ },
+ "node_modules/aes-decrypter/node_modules/@videojs/vhs-utils": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
+ "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "global": "^4.4.0",
+ "url-toolkit": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8",
+ "npm": ">=5"
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -623,6 +819,19 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "devOptional": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -812,6 +1021,11 @@
"integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
"dev": true
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -836,6 +1050,16 @@
"node": ">=4"
}
},
+ "node_modules/axios": {
+ "version": "1.6.8",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
+ "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"node_modules/axobject-query": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
@@ -851,6 +1075,23 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "devOptional": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -865,7 +1106,7 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"fill-range": "^7.0.1"
},
@@ -913,9 +1154,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001611",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001611.tgz",
- "integrity": "sha512-19NuN1/3PjA3QI8Eki55N8my4LzfkMCRLgCVfrl/slbSAchQfV0+GwjPrK3rq37As4UCLlM/DHajbKkAqbv92Q==",
+ "version": "1.0.30001612",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
+ "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
"funding": [
{
"type": "opencollective",
@@ -947,6 +1188,83 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/cheerio": {
+ "version": "1.0.0-rc.12",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz",
+ "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "htmlparser2": "^8.0.1",
+ "parse5": "^7.0.0",
+ "parse5-htmlparser2-tree-adapter": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+ "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "devOptional": true,
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "devOptional": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/classnames": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
+ "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
+ },
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
@@ -970,6 +1288,17 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -990,6 +1319,32 @@
"node": ">= 8"
}
},
+ "node_modules/css-select": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
+ "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -1110,6 +1465,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@@ -1143,6 +1506,62 @@
"node": ">=6.0.0"
}
},
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/dom-walk": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
+ "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ]
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
+ "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -1168,6 +1587,17 @@
"node": ">=10.13.0"
}
},
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/es-abstract": {
"version": "1.23.3",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
@@ -1821,7 +2251,7 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -1865,6 +2295,25 @@
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -1890,12 +2339,39 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -2038,6 +2514,15 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/global": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
+ "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
+ "dependencies": {
+ "min-document": "^2.19.0",
+ "process": "^0.11.10"
+ }
+ },
"node_modules/globals": {
"version": "13.24.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
@@ -2192,6 +2677,24 @@
"node": ">= 0.4"
}
},
+ "node_modules/htmlparser2": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+ "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "entities": "^4.4.0"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
@@ -2201,6 +2704,12 @@
"node": ">= 4"
}
},
+ "node_modules/immutable": {
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz",
+ "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==",
+ "devOptional": true
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -2226,6 +2735,11 @@
"node": ">=0.8.19"
}
},
+ "node_modules/individual": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz",
+ "integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g=="
+ },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -2256,6 +2770,34 @@
"node": ">= 0.4"
}
},
+ "node_modules/intl-messageformat": {
+ "version": "9.13.0",
+ "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz",
+ "integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.11.4",
+ "@formatjs/fast-memoize": "1.2.1",
+ "@formatjs/icu-messageformat-parser": "2.1.0",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/intl-messageformat/node_modules/@formatjs/ecma402-abstract": {
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz",
+ "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==",
+ "dependencies": {
+ "@formatjs/intl-localematcher": "0.2.25",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/intl-messageformat/node_modules/@formatjs/intl-localematcher": {
+ "version": "0.2.25",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz",
+ "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/is-array-buffer": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
@@ -2299,6 +2841,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "devOptional": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-boolean-object": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
@@ -2373,7 +2927,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=0.10.0"
}
@@ -2399,6 +2953,11 @@
"node": ">=8"
}
},
+ "node_modules/is-function": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
+ "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="
+ },
"node_modules/is-generator-function": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
@@ -2418,7 +2977,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -2454,7 +3013,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=0.12.0"
}
@@ -2716,6 +3275,11 @@
"node": ">=4.0"
}
},
+ "node_modules/keycode": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
+ "integrity": "sha512-ps3I9jAdNtRpJrbBvQjpzyFbss/skHqzS+eu4RxKLaEAtFqkjZaB6TZMSivPbLxf4K7VI4SjR0P5mRCX5+Q25A=="
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -2797,6 +3361,30 @@
"node": "14 || >=16.14"
}
},
+ "node_modules/m3u8-parser": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-7.1.0.tgz",
+ "integrity": "sha512-7N+pk79EH4oLKPEYdgRXgAsKDyA/VCo0qCHlUwacttQA0WqsjZQYmNfywMvjlY9MpEBVZEt0jKFd73Kv15EBYQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/vhs-utils": "^3.0.5",
+ "global": "^4.4.0"
+ }
+ },
+ "node_modules/m3u8-parser/node_modules/@videojs/vhs-utils": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
+ "integrity": "sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "global": "^4.4.0",
+ "url-toolkit": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8",
+ "npm": ">=5"
+ }
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -2819,6 +3407,33 @@
"node": ">=8.6"
}
},
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/min-document": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
+ "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",
+ "dependencies": {
+ "dom-walk": "^0.1.0"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -2849,12 +3464,42 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/mpd-parser": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-1.3.0.tgz",
+ "integrity": "sha512-WgeIwxAqkmb9uTn4ClicXpEQYCEduDqRKfmUdp4X8vmghKfBNXZLYpREn9eqrDx/Tf5LhzRcJLSpi4ohfV742Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/vhs-utils": "^4.0.0",
+ "@xmldom/xmldom": "^0.8.3",
+ "global": "^4.4.0"
+ },
+ "bin": {
+ "mpd-to-m3u8-json": "bin/parse.js"
+ }
+ },
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
+ "node_modules/mux.js": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-7.0.3.tgz",
+ "integrity": "sha512-gzlzJVEGFYPtl2vvEiJneSWAWD4nfYRHD5XgxmB2gWvXraMPOYk+sxfvexmNfjQUFpmk6hwLR5C6iSFmuwCHdQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.11.2",
+ "global": "^4.4.0"
+ },
+ "bin": {
+ "muxjs-transmux": "bin/transmux.js"
+ },
+ "engines": {
+ "node": ">=8",
+ "npm": ">=5"
+ }
+ },
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
@@ -2878,6 +3523,14 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/next": {
"version": "14.2.2",
"resolved": "https://registry.npmjs.org/next/-/next-14.2.2.tgz",
@@ -2927,6 +3580,46 @@
}
}
},
+ "node_modules/next-intl": {
+ "version": "3.11.3",
+ "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-3.11.3.tgz",
+ "integrity": "sha512-l961i+Jf0PJA+EEhlP+K8LiUyu36c6j8esmlOxaJ0A5z+YTto0RmA3XTQ1dTibl1Fkkopt2fnp6r4BZplRxvTg==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/amannn"
+ }
+ ],
+ "dependencies": {
+ "@formatjs/intl-localematcher": "^0.2.32",
+ "negotiator": "^0.6.3",
+ "use-intl": "^3.11.3"
+ },
+ "peerDependencies": {
+ "next": "^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "devOptional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -3120,6 +3813,29 @@
"node": ">=6"
}
},
+ "node_modules/parse5": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+ "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+ "dependencies": {
+ "entities": "^4.4.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-htmlparser2-tree-adapter": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
+ "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
+ "dependencies": {
+ "domhandler": "^5.0.2",
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -3187,7 +3903,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=8.6"
},
@@ -3195,6 +3911,17 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pkcs7": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz",
+ "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5"
+ },
+ "bin": {
+ "pkcs7": "bin/cli.js"
+ }
+ },
"node_modules/possible-typed-array-names": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
@@ -3240,6 +3967,14 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -3251,6 +3986,11 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -3309,6 +4049,18 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
},
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "devOptional": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
@@ -3333,8 +4085,7 @@
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
- "dev": true
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/regexp.prototype.flags": {
"version": "1.5.2",
@@ -3457,6 +4208,14 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/rust-result": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz",
+ "integrity": "sha512-6cJzSBU+J/RJCF063onnQf0cDUOHs9uZI1oroSGnHOph+CQTIJ5Pp2hK5kEQq1+7yE/EEWfulSNXAQ2jikPthA==",
+ "dependencies": {
+ "individual": "^2.0.0"
+ }
+ },
"node_modules/safe-array-concat": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
@@ -3475,6 +4234,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safe-json-parse": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz",
+ "integrity": "sha512-RjZPPHugjK0TOzFrLZ8inw44s9bKox99/0AZW9o/BEQVrJfhI+fIHMErnPyRa89/yRXUUr93q+tiN6zhoVV4wQ==",
+ "dependencies": {
+ "rust-result": "^1.0.0"
+ }
+ },
"node_modules/safe-regex-test": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
@@ -3492,6 +4259,23 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/sass": {
+ "version": "1.75.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.75.0.tgz",
+ "integrity": "sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==",
+ "devOptional": true,
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
@@ -3886,7 +4670,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"is-number": "^7.0.0"
},
@@ -4063,6 +4847,85 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/url-toolkit": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz",
+ "integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg=="
+ },
+ "node_modules/use-intl": {
+ "version": "3.11.3",
+ "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.11.3.tgz",
+ "integrity": "sha512-qxW2CiDWQY6ilR7AxrQPp5qiU6hWWh7Ek8uBEKGjcO7KoRuJ/4/ybIi/Z7rTXnEHHvQyCT1dotyDT9WIBGwCWg==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "^1.11.4",
+ "intl-messageformat": "^9.3.18"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/video.js": {
+ "version": "8.10.0",
+ "resolved": "https://registry.npmjs.org/video.js/-/video.js-8.10.0.tgz",
+ "integrity": "sha512-7UeG/flj/pp8tNGW8WKPP1VJb3x2FgLoqUWzpZqkoq5YIyf6MNzmIrKtxprl438T5RVkcj+OzV8IX4jYSAn4Sw==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "@videojs/http-streaming": "3.10.0",
+ "@videojs/vhs-utils": "^4.0.0",
+ "@videojs/xhr": "2.6.0",
+ "aes-decrypter": "^4.0.1",
+ "global": "4.4.0",
+ "keycode": "2.2.0",
+ "m3u8-parser": "^7.1.0",
+ "mpd-parser": "^1.2.2",
+ "mux.js": "^7.0.1",
+ "safe-json-parse": "4.0.0",
+ "videojs-contrib-quality-levels": "4.0.0",
+ "videojs-font": "4.1.0",
+ "videojs-vtt.js": "0.15.5"
+ }
+ },
+ "node_modules/video.js/node_modules/videojs-contrib-quality-levels": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.0.0.tgz",
+ "integrity": "sha512-u5rmd8BjLwANp7XwuQ0Q/me34bMe6zg9PQdHfTS7aXgiVRbNTb4djcmfG7aeSrkpZjg+XCLezFNenlJaCjBHKw==",
+ "dependencies": {
+ "global": "^4.4.0"
+ },
+ "engines": {
+ "node": ">=14",
+ "npm": ">=6"
+ },
+ "peerDependencies": {
+ "video.js": "^8"
+ }
+ },
+ "node_modules/videojs-font": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-4.1.0.tgz",
+ "integrity": "sha512-X1LuPfLZPisPLrANIAKCknZbZu5obVM/ylfd1CN+SsCmPZQ3UMDPcvLTpPBJxcBuTpHQq2MO1QCFt7p8spnZ/w=="
+ },
+ "node_modules/videojs-hls-quality-selector": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/videojs-hls-quality-selector/-/videojs-hls-quality-selector-2.0.0.tgz",
+ "integrity": "sha512-x0AQKGwryDdD94s1it+Jolb6j1mg4Q+c7g1PlCIG6dXBdipVPaZmg71fxaFZJgx1k326DFnRaWrLxQ72/TKd2A==",
+ "dependencies": {
+ "global": "^4.4.0",
+ "video.js": "^8"
+ },
+ "engines": {
+ "node": ">=14",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/videojs-vtt.js": {
+ "version": "0.15.5",
+ "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz",
+ "integrity": "sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==",
+ "dependencies": {
+ "global": "^4.3.1"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index d17aea5..d1628c4 100644
--- a/package.json
+++ b/package.json
@@ -9,16 +9,24 @@
"lint": "next lint"
},
"dependencies": {
+ "@picocss/pico": "^2.0.6",
+ "axios": "^1.6.8",
+ "cheerio": "^1.0.0-rc.12",
+ "classnames": "^2.5.1",
+ "next": "14.2.2",
+ "next-intl": "^3.11.3",
"react": "^18",
"react-dom": "^18",
- "next": "14.2.2"
+ "video.js": "^8.10.0",
+ "videojs-hls-quality-selector": "^2.0.0"
},
"devDependencies": {
- "typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
- "eslint-config-next": "14.2.2"
+ "eslint-config-next": "14.2.2",
+ "sass": "^1.75.0",
+ "typescript": "^5"
}
}
diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx
new file mode 100644
index 0000000..273a6ac
--- /dev/null
+++ b/src/app/[locale]/layout.tsx
@@ -0,0 +1,20 @@
+import "@/styles/globals.scss"
+
+export default function RootLayout({
+ children,
+ params: {locale}
+}: Readonly<{
+ children: React.ReactNode;
+ params: {locale: string};
+}>) {
+ return (
+
+
+
+
+ Proxy Raye: un proxy per XVideos basato su PornInvidious
+
+ {children}
+
+ );
+}
diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx
new file mode 100644
index 0000000..3ea0f04
--- /dev/null
+++ b/src/app/[locale]/page.tsx
@@ -0,0 +1,20 @@
+import axios from 'axios';
+
+import * as cheerio from "cheerio";
+
+import Layout from "@/components/Layout";
+
+import Home from "@/components/Pages/Home";
+
+import { fetchGalleryData } from '@/utils/scrape/gallery';
+
+export default async function HomePage() {
+
+ const data = await fetchGalleryData()
+
+ return (
+
+
+
+ );
+}
diff --git a/src/app/[locale]/search/[query]/page.tsx b/src/app/[locale]/search/[query]/page.tsx
new file mode 100644
index 0000000..50a69a9
--- /dev/null
+++ b/src/app/[locale]/search/[query]/page.tsx
@@ -0,0 +1,14 @@
+import Layout from "@/components/Layout";
+
+import Search from "@/components/Pages/Search";
+
+import { fetchGalleryData } from "@/utils/scrape/gallery";
+
+export default async function SearchPage({ params }: { params: { query: string } }) {
+
+ const data = await fetchGalleryData({ query: params.query })
+
+ return
+
+
+}
\ No newline at end of file
diff --git a/src/app/[locale]/search/page.tsx b/src/app/[locale]/search/page.tsx
new file mode 100644
index 0000000..18b80c9
--- /dev/null
+++ b/src/app/[locale]/search/page.tsx
@@ -0,0 +1,10 @@
+import Layout from "@/components/Layout";
+
+import Search from "@/components/Pages/Search";
+
+export default async function SearchNoQueryPage() {
+
+ return
+
+
+}
\ No newline at end of file
diff --git a/src/app/[locale]/video/[id]/page.tsx b/src/app/[locale]/video/[id]/page.tsx
new file mode 100644
index 0000000..0aba08d
--- /dev/null
+++ b/src/app/[locale]/video/[id]/page.tsx
@@ -0,0 +1,26 @@
+import { redirect } from 'next/navigation';
+
+import Layout from "@/components/Layout";
+
+import Video from "@/components/Pages/Video";
+
+import { fetchVideoData } from "@/utils/scrape/video";
+
+import { useLocale } from 'next-intl';
+
+export default async function VideoPage({ params }: { params: { id: string } }) {
+
+ const locale = useLocale()
+
+ const decodedId = decodeURIComponent(params.id)
+
+ const [data, related] = await fetchVideoData(decodedId)
+
+ if (!data.lowResUrl) {
+ redirect(`/${locale}/404`)
+ }
+
+ return
+
+}
\ No newline at end of file
diff --git a/src/app/favicon.ico b/src/app/favicon.ico
deleted file mode 100644
index 718d6fe..0000000
Binary files a/src/app/favicon.ico and /dev/null differ
diff --git a/src/app/globals.css b/src/app/globals.css
deleted file mode 100644
index f4bd77c..0000000
--- a/src/app/globals.css
+++ /dev/null
@@ -1,107 +0,0 @@
-:root {
- --max-width: 1100px;
- --border-radius: 12px;
- --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
- "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
- "Fira Mono", "Droid Sans Mono", "Courier New", monospace;
-
- --foreground-rgb: 0, 0, 0;
- --background-start-rgb: 214, 219, 220;
- --background-end-rgb: 255, 255, 255;
-
- --primary-glow: conic-gradient(
- from 180deg at 50% 50%,
- #16abff33 0deg,
- #0885ff33 55deg,
- #54d6ff33 120deg,
- #0071ff33 160deg,
- transparent 360deg
- );
- --secondary-glow: radial-gradient(
- rgba(255, 255, 255, 1),
- rgba(255, 255, 255, 0)
- );
-
- --tile-start-rgb: 239, 245, 249;
- --tile-end-rgb: 228, 232, 233;
- --tile-border: conic-gradient(
- #00000080,
- #00000040,
- #00000030,
- #00000020,
- #00000010,
- #00000010,
- #00000080
- );
-
- --callout-rgb: 238, 240, 241;
- --callout-border-rgb: 172, 175, 176;
- --card-rgb: 180, 185, 188;
- --card-border-rgb: 131, 134, 135;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
-
- --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
- --secondary-glow: linear-gradient(
- to bottom right,
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0.3)
- );
-
- --tile-start-rgb: 2, 13, 46;
- --tile-end-rgb: 2, 5, 19;
- --tile-border: conic-gradient(
- #ffffff80,
- #ffffff40,
- #ffffff30,
- #ffffff20,
- #ffffff10,
- #ffffff10,
- #ffffff80
- );
-
- --callout-rgb: 20, 20, 20;
- --callout-border-rgb: 108, 108, 108;
- --card-rgb: 100, 100, 100;
- --card-border-rgb: 200, 200, 200;
- }
-}
-
-* {
- box-sizing: border-box;
- padding: 0;
- margin: 0;
-}
-
-html,
-body {
- max-width: 100vw;
- overflow-x: hidden;
-}
-
-body {
- color: rgb(var(--foreground-rgb));
- background: linear-gradient(
- to bottom,
- transparent,
- rgb(var(--background-end-rgb))
- )
- rgb(var(--background-start-rgb));
-}
-
-a {
- color: inherit;
- text-decoration: none;
-}
-
-@media (prefers-color-scheme: dark) {
- html {
- color-scheme: dark;
- }
-}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
deleted file mode 100644
index 3314e47..0000000
--- a/src/app/layout.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { Metadata } from "next";
-import { Inter } from "next/font/google";
-import "./globals.css";
-
-const inter = Inter({ subsets: ["latin"] });
-
-export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
-};
-
-export default function RootLayout({
- children,
-}: Readonly<{
- children: React.ReactNode;
-}>) {
- return (
-
- {children}
-
- );
-}
diff --git a/src/app/page.module.css b/src/app/page.module.css
deleted file mode 100644
index 5c4b1e6..0000000
--- a/src/app/page.module.css
+++ /dev/null
@@ -1,230 +0,0 @@
-.main {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- align-items: center;
- padding: 6rem;
- min-height: 100vh;
-}
-
-.description {
- display: inherit;
- justify-content: inherit;
- align-items: inherit;
- font-size: 0.85rem;
- max-width: var(--max-width);
- width: 100%;
- z-index: 2;
- font-family: var(--font-mono);
-}
-
-.description a {
- display: flex;
- justify-content: center;
- align-items: center;
- gap: 0.5rem;
-}
-
-.description p {
- position: relative;
- margin: 0;
- padding: 1rem;
- background-color: rgba(var(--callout-rgb), 0.5);
- border: 1px solid rgba(var(--callout-border-rgb), 0.3);
- border-radius: var(--border-radius);
-}
-
-.code {
- font-weight: 700;
- font-family: var(--font-mono);
-}
-
-.grid {
- display: grid;
- grid-template-columns: repeat(4, minmax(25%, auto));
- max-width: 100%;
- width: var(--max-width);
-}
-
-.card {
- padding: 1rem 1.2rem;
- border-radius: var(--border-radius);
- background: rgba(var(--card-rgb), 0);
- border: 1px solid rgba(var(--card-border-rgb), 0);
- transition: background 200ms, border 200ms;
-}
-
-.card span {
- display: inline-block;
- transition: transform 200ms;
-}
-
-.card h2 {
- font-weight: 600;
- margin-bottom: 0.7rem;
-}
-
-.card p {
- margin: 0;
- opacity: 0.6;
- font-size: 0.9rem;
- line-height: 1.5;
- max-width: 30ch;
- text-wrap: balance;
-}
-
-.center {
- display: flex;
- justify-content: center;
- align-items: center;
- position: relative;
- padding: 4rem 0;
-}
-
-.center::before {
- background: var(--secondary-glow);
- border-radius: 50%;
- width: 480px;
- height: 360px;
- margin-left: -400px;
-}
-
-.center::after {
- background: var(--primary-glow);
- width: 240px;
- height: 180px;
- z-index: -1;
-}
-
-.center::before,
-.center::after {
- content: "";
- left: 50%;
- position: absolute;
- filter: blur(45px);
- transform: translateZ(0);
-}
-
-.logo {
- position: relative;
-}
-/* Enable hover only on non-touch devices */
-@media (hover: hover) and (pointer: fine) {
- .card:hover {
- background: rgba(var(--card-rgb), 0.1);
- border: 1px solid rgba(var(--card-border-rgb), 0.15);
- }
-
- .card:hover span {
- transform: translateX(4px);
- }
-}
-
-@media (prefers-reduced-motion) {
- .card:hover span {
- transform: none;
- }
-}
-
-/* Mobile */
-@media (max-width: 700px) {
- .content {
- padding: 4rem;
- }
-
- .grid {
- grid-template-columns: 1fr;
- margin-bottom: 120px;
- max-width: 320px;
- text-align: center;
- }
-
- .card {
- padding: 1rem 2.5rem;
- }
-
- .card h2 {
- margin-bottom: 0.5rem;
- }
-
- .center {
- padding: 8rem 0 6rem;
- }
-
- .center::before {
- transform: none;
- height: 300px;
- }
-
- .description {
- font-size: 0.8rem;
- }
-
- .description a {
- padding: 1rem;
- }
-
- .description p,
- .description div {
- display: flex;
- justify-content: center;
- position: fixed;
- width: 100%;
- }
-
- .description p {
- align-items: center;
- inset: 0 0 auto;
- padding: 2rem 1rem 1.4rem;
- border-radius: 0;
- border: none;
- border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);
- background: linear-gradient(
- to bottom,
- rgba(var(--background-start-rgb), 1),
- rgba(var(--callout-rgb), 0.5)
- );
- background-clip: padding-box;
- backdrop-filter: blur(24px);
- }
-
- .description div {
- align-items: flex-end;
- pointer-events: none;
- inset: auto 0 0;
- padding: 2rem;
- height: 200px;
- background: linear-gradient(
- to bottom,
- transparent 0%,
- rgb(var(--background-end-rgb)) 40%
- );
- z-index: 1;
- }
-}
-
-/* Tablet and Smaller Desktop */
-@media (min-width: 701px) and (max-width: 1120px) {
- .grid {
- grid-template-columns: repeat(2, 50%);
- }
-}
-
-@media (prefers-color-scheme: dark) {
- .vercelLogo {
- filter: invert(1);
- }
-
- .logo {
- filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);
- }
-}
-
-@keyframes rotate {
- from {
- transform: rotate(360deg);
- }
- to {
- transform: rotate(0deg);
- }
-}
diff --git a/src/app/page.tsx b/src/app/page.tsx
deleted file mode 100644
index d2c63a4..0000000
--- a/src/app/page.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import Image from "next/image";
-import styles from "./page.module.css";
-
-export default function Home() {
- return (
-
-
-
- Get started by editing
- src/app/page.tsx
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/components/Layout/Header/Description/index.tsx b/src/components/Layout/Header/Description/index.tsx
new file mode 100644
index 0000000..7f8f446
--- /dev/null
+++ b/src/components/Layout/Header/Description/index.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import {useTranslations} from 'next-intl';
+
+const Description: React.FC = () => {
+
+ const t = useTranslations('Header');
+
+ return (
+ {t('description')}
+ );
+};
+
+export default Description;
\ No newline at end of file
diff --git a/src/components/Layout/Header/Disclaimer/Disclaimer.module.scss b/src/components/Layout/Header/Disclaimer/Disclaimer.module.scss
new file mode 100644
index 0000000..f495791
--- /dev/null
+++ b/src/components/Layout/Header/Disclaimer/Disclaimer.module.scss
@@ -0,0 +1,10 @@
+@import 'colors';
+@import 'spacing';
+
+.messageBox {
+ border: 1px solid $colors_yellow;
+ text-align: center;
+ padding: $spacing_8;
+ border-radius: $spacing_4;
+ margin-bottom: $spacing_32;
+}
\ No newline at end of file
diff --git a/src/components/Layout/Header/Disclaimer/index.tsx b/src/components/Layout/Header/Disclaimer/index.tsx
new file mode 100644
index 0000000..fa1e02f
--- /dev/null
+++ b/src/components/Layout/Header/Disclaimer/index.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+
+import style from './Disclaimer.module.scss'
+
+import { useTranslations } from 'next-intl';
+
+const Disclaimer: React.FC = () => {
+
+ const MAX_DISCLAIMER_NO = 6
+
+ const t = useTranslations('Header');
+
+ const getRandomArbitrary = (max: number) => {
+ return Math.floor( Math.random() * max);
+ }
+
+ return (
+ {t(`disclaimer_${getRandomArbitrary(MAX_DISCLAIMER_NO)}`)}
+ );
+};
+
+export default Disclaimer;
\ No newline at end of file
diff --git a/src/components/Layout/Header/Title/index.tsx b/src/components/Layout/Header/Title/index.tsx
new file mode 100644
index 0000000..135c599
--- /dev/null
+++ b/src/components/Layout/Header/Title/index.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+
+import {useTranslations} from 'next-intl';
+import Link from 'next/link';
+
+const Title: React.FC = () => {
+
+ const t = useTranslations('Header');
+
+ return (
+ {t('title')}
+
+ );
+};
+
+export default Title;
\ No newline at end of file
diff --git a/src/components/Layout/Header/index.tsx b/src/components/Layout/Header/index.tsx
new file mode 100644
index 0000000..d2e7f73
--- /dev/null
+++ b/src/components/Layout/Header/index.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+
+import Title from './Title';
+import Description from './Description';
+import Disclaimer from './Disclaimer';
+
+const Header: React.FC = () => {
+
+ return (
+ <>
+
+
+
+ >
+ );
+};
+
+export default Header;
\ No newline at end of file
diff --git a/src/components/Layout/Player/Player.module.scss b/src/components/Layout/Player/Player.module.scss
new file mode 100644
index 0000000..4b42929
--- /dev/null
+++ b/src/components/Layout/Player/Player.module.scss
@@ -0,0 +1,5 @@
+@import 'spacing';
+
+.container {
+ margin-bottom: $spacing_32;
+}
\ No newline at end of file
diff --git a/src/components/Layout/Player/VideoJS/index.tsx b/src/components/Layout/Player/VideoJS/index.tsx
new file mode 100644
index 0000000..e5df0e1
--- /dev/null
+++ b/src/components/Layout/Player/VideoJS/index.tsx
@@ -0,0 +1,65 @@
+'use client';
+
+import React from 'react';
+
+import videojs from 'video.js';
+
+import 'video.js/dist/video-js.css';
+
+export const VideoJS = (props: { options: any; onReady: any; }) => {
+ const videoRef = React.useRef(null);
+ const playerRef = React.useRef(null);
+ const {options, onReady} = props;
+
+ React.useEffect(() => {
+
+ // Make sure Video.js player is only initialized once
+ if (!playerRef.current) {
+ // The Video.js player needs to be _inside_ the component el for React 18 Strict Mode.
+ const videoElement = document.createElement("video-js");
+
+ videoElement.classList.add('vjs-big-play-centered');
+ //@ts-ignore
+ videoRef.current.appendChild(videoElement);
+
+ //@ts-ignore
+ const player = playerRef.current = videojs(videoElement, options, () => {
+ videojs.log('player is ready');
+ onReady && onReady(player);
+ });
+
+ // You could update an existing player in the `else` block here
+ // on prop change, for example:
+ } else {
+ const player = playerRef.current;
+
+ //@ts-ignore
+ player.autoplay(options.autoplay);
+
+ //@ts-ignore
+ player.src(options.sources);
+ }
+ }, [options, videoRef]);
+
+ // Dispose the Video.js player when the functional component unmounts
+ React.useEffect(() => {
+ const player = playerRef.current;
+
+ return () => {
+ //@ts-ignore
+ if (player && !player.isDisposed()) {
+ //@ts-ignore
+ player.dispose();
+ playerRef.current = null;
+ }
+ };
+ }, [playerRef]);
+
+ return (
+
+ );
+}
+
+export default VideoJS;
\ No newline at end of file
diff --git a/src/components/Layout/Player/index.tsx b/src/components/Layout/Player/index.tsx
new file mode 100644
index 0000000..5ca3312
--- /dev/null
+++ b/src/components/Layout/Player/index.tsx
@@ -0,0 +1,63 @@
+'use client'
+
+import React from 'react';
+
+import style from './Player.module.scss'
+
+import VideoJS from './VideoJS';
+import { VideoData } from '@/meta/data';
+
+import 'videojs-hls-quality-selector';
+
+interface Props {
+ data: VideoData
+}
+
+const Player: React.FC = (props) => {
+
+ const { data } = props;
+
+ const videoSrc = data.hlsUrl ?? data.lowResUrl
+ const videoType = data.hlsUrl ? 'application/x-mpegURL' : 'video/mp4'
+
+ const playerRef = React.useRef(null);
+
+ const videoJsOptions = {
+ autoplay: true,
+ controls: true,
+ responsive: true,
+ fluid: true,
+ sources: [{
+ src: videoSrc,
+ type: videoType
+ }]
+ };
+
+ //@ts-ignore
+ const handlePlayerReady = (player) => {
+ playerRef.current = player;
+
+ player.hlsQualitySelector({
+ vjsIconClass: "vjs-icon-hd"
+ })
+
+ // You can handle player events here, for example:
+ player.on('waiting', () => {
+ console.log('player is waiting');
+ });
+
+ player.on('dispose', () => {
+ console.log('player will dispose');
+ });
+
+ };
+
+
+ return (
+
+
+
+ );
+};
+
+export default Player;
\ No newline at end of file
diff --git a/src/components/Layout/Results/Results.module.scss b/src/components/Layout/Results/Results.module.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/Layout/Results/Wrapper/Gallery/Gallery.module.scss b/src/components/Layout/Results/Wrapper/Gallery/Gallery.module.scss
new file mode 100644
index 0000000..cab4276
--- /dev/null
+++ b/src/components/Layout/Results/Wrapper/Gallery/Gallery.module.scss
@@ -0,0 +1,31 @@
+@import 'spacing';
+@import 'breakpoints';
+
+.galleryContainer {
+ display: grid;
+ gap: $spacing_16;
+ grid-template-columns: repeat(3, 1fr);
+
+ @media only screen and (min-width: $portrait) {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ @media only screen and (min-width: $tablet) {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ @media only screen and (min-width: $laptop) {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ @media only screen and (min-width: $desktop) {
+ grid-template-columns: repeat(4, 1fr);
+ }
+
+}
+
+.galleryContainer.show {
+ @media only screen and (max-width: $portrait) {
+ grid-template-columns: repeat(1, 1fr);
+ }
+}
\ No newline at end of file
diff --git a/src/components/Layout/Results/Wrapper/Gallery/Thumbnail/Thumbnail.module.scss b/src/components/Layout/Results/Wrapper/Gallery/Thumbnail/Thumbnail.module.scss
new file mode 100644
index 0000000..aac0a82
--- /dev/null
+++ b/src/components/Layout/Results/Wrapper/Gallery/Thumbnail/Thumbnail.module.scss
@@ -0,0 +1,50 @@
+@import 'spacing';
+@import 'colors';
+@import 'breakpoints';
+
+.text {
+ font-size: 12px;
+ color: $colors_yellow;
+ text-decoration: none;
+
+ display: none;
+
+ @media only screen and (min-width: $tablet) {
+ display: block;
+ }
+}
+
+.image {
+ border-radius: $spacing_4;
+ width: 100%;
+}
+
+.thumbnailContainer {
+ opacity: 0.1;
+ transition: 1s;
+
+ a {
+ text-decoration: none !important;
+ }
+}
+
+.thumbnailContainer:hover {
+ opacity: 1;
+}
+
+.thumbnailContainer.show {
+ opacity: 1;
+
+ .text {
+ display: block;
+ }
+
+ .image {
+ width: 100%;
+
+ @media only screen and (min-width: $tablet) {
+ width: auto;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/components/Layout/Results/Wrapper/Gallery/Thumbnail/index.tsx b/src/components/Layout/Results/Wrapper/Gallery/Thumbnail/index.tsx
new file mode 100644
index 0000000..9f99b46
--- /dev/null
+++ b/src/components/Layout/Results/Wrapper/Gallery/Thumbnail/index.tsx
@@ -0,0 +1,35 @@
+'use client'
+
+import React from 'react';
+
+import classNames from 'classnames';
+
+import Link from 'next/link'
+
+import style from './Thumbnail.module.scss'
+
+interface Props {
+ locale: string
+ videoUrl: string
+ imgUrl: string
+ text: string
+ show: boolean
+}
+
+const Thumbnail: React.FC = (props) => {
+
+ const { locale, videoUrl, imgUrl, text, show } = props
+
+ const encodedUri = encodeURIComponent(videoUrl)
+
+ return (
+
+
+
+
{text}
+
+
+ );
+};
+
+export default Thumbnail;
\ No newline at end of file
diff --git a/src/components/Layout/Results/Wrapper/Gallery/index.tsx b/src/components/Layout/Results/Wrapper/Gallery/index.tsx
new file mode 100644
index 0000000..7953758
--- /dev/null
+++ b/src/components/Layout/Results/Wrapper/Gallery/index.tsx
@@ -0,0 +1,38 @@
+'use client'
+
+import React from 'react';
+
+import classNames from 'classnames';
+
+import style from './Gallery.module.scss'
+import Thumbnail from './Thumbnail';
+import { GalleryData } from '@/meta/data';
+
+interface Props {
+ data: GalleryData[]
+ show: boolean
+ locale: string
+}
+
+const Gallery: React.FC = (props) => {
+
+ const { show, locale, data } = props
+
+ return (
+ <>
+
+ {data && data.map((elem, key) => {
+ return
+ })}
+
+ >
+ );
+};
+
+export default Gallery;
\ No newline at end of file
diff --git a/src/components/Layout/Results/Wrapper/NoData/NoData.module.scss b/src/components/Layout/Results/Wrapper/NoData/NoData.module.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/Layout/Results/Wrapper/NoData/index.tsx b/src/components/Layout/Results/Wrapper/NoData/index.tsx
new file mode 100644
index 0000000..5653e6b
--- /dev/null
+++ b/src/components/Layout/Results/Wrapper/NoData/index.tsx
@@ -0,0 +1,22 @@
+'use client'
+
+import React, { useState } from 'react';
+
+import style from './NoData.module.scss';
+
+interface Props {
+ msg: string
+}
+
+const NoData: React.FC = (props) => {
+
+ const { msg } = props;
+
+ return (
+
+ {msg}
+
+ );
+};
+
+export default NoData;
\ No newline at end of file
diff --git a/src/components/Layout/Results/Wrapper/Toggle/Toggle.module.scss b/src/components/Layout/Results/Wrapper/Toggle/Toggle.module.scss
new file mode 100644
index 0000000..51d5e53
--- /dev/null
+++ b/src/components/Layout/Results/Wrapper/Toggle/Toggle.module.scss
@@ -0,0 +1,7 @@
+@import 'breakpoints';
+
+.toggleContainer {
+ @media only screen and (min-width: $tablet) {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/src/components/Layout/Results/Wrapper/Toggle/index.tsx b/src/components/Layout/Results/Wrapper/Toggle/index.tsx
new file mode 100644
index 0000000..777ec79
--- /dev/null
+++ b/src/components/Layout/Results/Wrapper/Toggle/index.tsx
@@ -0,0 +1,24 @@
+'use client'
+
+import React from 'react';
+
+import style from './Toggle.module.scss'
+
+interface Props {
+ label: string
+ handleClick: () => void
+}
+
+const Toggle: React.FC = (props) => {
+
+ const { label, handleClick } = props
+
+ return (
+
+ );
+};
+
+export default Toggle;
\ No newline at end of file
diff --git a/src/components/Layout/Results/Wrapper/Wrapper.module.scss b/src/components/Layout/Results/Wrapper/Wrapper.module.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/Layout/Results/Wrapper/index.tsx b/src/components/Layout/Results/Wrapper/index.tsx
new file mode 100644
index 0000000..37650b6
--- /dev/null
+++ b/src/components/Layout/Results/Wrapper/index.tsx
@@ -0,0 +1,38 @@
+'use client'
+
+import React, { useState } from 'react';
+
+import style from './Wrapper.module.scss';
+
+import Gallery from './Gallery';
+import Toggle from './Toggle';
+import { GalleryData } from '@/meta/data';
+import NoData from './NoData';
+
+interface Props {
+ data: GalleryData[]
+ locale: string
+ labels: {
+ toggle: string
+ noData: string
+ }
+}
+
+const Wrapper: React.FC = (props) => {
+
+ const { labels, locale, data } = props
+
+ const [show, setShow] = useState(false)
+
+ return (
+
+ {(data && data.length > 0) && <>
+ setShow(!show)} />
+
+ >}
+ {(!data || data.length == 0) && }
+
+ );
+};
+
+export default Wrapper;
\ No newline at end of file
diff --git a/src/components/Layout/Results/index.tsx b/src/components/Layout/Results/index.tsx
new file mode 100644
index 0000000..5a92d69
--- /dev/null
+++ b/src/components/Layout/Results/index.tsx
@@ -0,0 +1,22 @@
+import React, { } from 'react';
+
+import { useLocale, useTranslations } from 'next-intl';
+
+import Wrapper from './Wrapper';
+import { GalleryData } from '@/meta/data';
+
+interface Props {
+ data: GalleryData[]
+}
+
+const Results: React.FC = (props) => {
+
+ const { data } = props
+
+ const t = useTranslations('Results');
+ const locale = useLocale()
+
+ return ();
+};
+
+export default Results;
\ No newline at end of file
diff --git a/src/components/Layout/SearchBar/SearchBarForm/SearchBarForm.module.scss b/src/components/Layout/SearchBar/SearchBarForm/SearchBarForm.module.scss
new file mode 100644
index 0000000..0709149
--- /dev/null
+++ b/src/components/Layout/SearchBar/SearchBarForm/SearchBarForm.module.scss
@@ -0,0 +1,30 @@
+@import 'spacing';
+@import 'colors';
+
+.searchForm {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.query{
+ flex: 6;
+ margin-right: $spacing_16;
+}
+
+.submitBtn{
+ flex: 1;
+ background-color: $colors_yellow;
+ border-color: $colors_yellow;
+ color: $colors_yellow_inverse;
+}
+
+.submitBtn:hover {
+ background-color: $colors_yellow_hover;
+ border-color: $colors_yellow_hover;
+}
+
+.submitBtn:focus {
+ background-color: $colors_yellow_focus;
+ border-color: $colors_yellow_focus;
+}
\ No newline at end of file
diff --git a/src/components/Layout/SearchBar/SearchBarForm/index.tsx b/src/components/Layout/SearchBar/SearchBarForm/index.tsx
new file mode 100644
index 0000000..7d7c455
--- /dev/null
+++ b/src/components/Layout/SearchBar/SearchBarForm/index.tsx
@@ -0,0 +1,45 @@
+'use client'
+
+import React from 'react';
+
+import style from './SearchBarForm.module.scss'
+
+import { useRouter } from 'next/navigation'
+
+interface Props {
+ query?: string
+ locale: string
+ labels: {
+ query: { placeholder: string }
+ submit: { value: string }
+ }
+}
+
+const MAX_SEARCH_LENGTH = 50;
+
+const SearchBarForm: React.FC = (props) => {
+
+ const { query, labels, locale } = props;
+
+ const router = useRouter()
+
+ const handleSubmit = (event: React.FormEvent) => {
+ event.preventDefault();
+
+ //@ts-ignore
+ const query = event.target.query.value
+
+ if (query.length > 0) {
+ router.push(`/${locale}/search/${query}`)
+ }
+ }
+
+ return (
+
+ );
+};
+
+export default SearchBarForm;
\ No newline at end of file
diff --git a/src/components/Layout/SearchBar/index.tsx b/src/components/Layout/SearchBar/index.tsx
new file mode 100644
index 0000000..50807e0
--- /dev/null
+++ b/src/components/Layout/SearchBar/index.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+
+import { useTranslations, useLocale } from 'next-intl';
+import SearchBarForm from './SearchBarForm';
+
+interface Props {
+ query?: string
+}
+
+const SearchBar: React.FC = (props) => {
+
+ const { query } = props;
+
+ const t = useTranslations('Search');
+ const locale = useLocale()
+
+ return (
+
+ );
+};
+
+export default SearchBar;
\ No newline at end of file
diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx
new file mode 100644
index 0000000..3b19154
--- /dev/null
+++ b/src/components/Layout/index.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+const Layout: React.FC = (props) => {
+
+ const { children } = props;
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default Layout;
\ No newline at end of file
diff --git a/src/components/Pages/Home/index.tsx b/src/components/Pages/Home/index.tsx
new file mode 100644
index 0000000..23d6d03
--- /dev/null
+++ b/src/components/Pages/Home/index.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+
+import Header from '@/components/Layout/Header';
+import SearchBar from '@/components/Layout/SearchBar';
+import Results from '@/components/Layout/Results';
+
+import { GalleryData } from '@/meta/data';
+
+interface Props {
+ data: GalleryData[]
+}
+
+const Home: React.FC = (props) => {
+
+ const { data } = props;
+
+ return (
+ <>
+
+
+
+ >
+ );
+};
+
+export default Home;
\ No newline at end of file
diff --git a/src/components/Pages/Search/index.tsx b/src/components/Pages/Search/index.tsx
new file mode 100644
index 0000000..e0017d9
--- /dev/null
+++ b/src/components/Pages/Search/index.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+
+import Header from '@/components/Layout/Header';
+import SearchBar from '@/components/Layout/SearchBar';
+import Results from '@/components/Layout/Results';
+import { GalleryData } from '@/meta/data';
+
+interface Props {
+ query: string
+ data: GalleryData[]
+}
+
+const Search: React.FC = (props) => {
+
+ const { query, data } = props;
+
+ return (
+ <>
+
+
+
+ >
+ );
+};
+
+export default Search;
\ No newline at end of file
diff --git a/src/components/Pages/Video/index.tsx b/src/components/Pages/Video/index.tsx
new file mode 100644
index 0000000..100de32
--- /dev/null
+++ b/src/components/Pages/Video/index.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+
+import Header from '@/components/Layout/Header';
+import Player from '@/components/Layout/Player';
+import SearchBar from '@/components/Layout/SearchBar';
+import Results from '@/components/Layout/Results';
+
+import { GalleryData, VideoData } from '@/meta/data';
+
+
+interface Props {
+ id: string
+ data: VideoData
+ related: GalleryData[]
+}
+
+const Video: React.FC = (props) => {
+
+ const { data, related } = props;
+
+ return (
+ <>
+
+
+
+ {related && }
+ >
+ );
+};
+
+export default Video;
\ No newline at end of file
diff --git a/src/constants/urls.ts b/src/constants/urls.ts
new file mode 100644
index 0000000..87953cd
--- /dev/null
+++ b/src/constants/urls.ts
@@ -0,0 +1 @@
+export const XVIDEOS_BASE_URL: string = "https://www.xvideos.com"
\ No newline at end of file
diff --git a/src/i18n.ts b/src/i18n.ts
new file mode 100644
index 0000000..1c87455
--- /dev/null
+++ b/src/i18n.ts
@@ -0,0 +1,14 @@
+import {notFound} from 'next/navigation';
+import {getRequestConfig} from 'next-intl/server';
+
+// Can be imported from a shared config
+const locales = ['en', 'it'];
+
+export default getRequestConfig(async ({locale}) => {
+ // Validate that the incoming `locale` parameter is valid
+ if (!locales.includes(locale as any)) notFound();
+
+ return {
+ messages: (await import(`../locale/${locale}.json`)).default
+ };
+});
\ No newline at end of file
diff --git a/src/meta/data.ts b/src/meta/data.ts
new file mode 100644
index 0000000..f8bc93e
--- /dev/null
+++ b/src/meta/data.ts
@@ -0,0 +1,11 @@
+export interface GalleryData {
+ videoUrl: string
+ imgUrl: string
+ text: string
+}
+
+export interface VideoData {
+ lowResUrl: string,
+ hiResUrl?: string,
+ hlsUrl?: string
+}
\ No newline at end of file
diff --git a/src/middleware.ts b/src/middleware.ts
new file mode 100644
index 0000000..7fb17b3
--- /dev/null
+++ b/src/middleware.ts
@@ -0,0 +1,14 @@
+import createMiddleware from 'next-intl/middleware';
+
+export default createMiddleware({
+ // A list of all locales that are supported
+ locales: ['en', 'it'],
+
+ // Used when no locale matches
+ defaultLocale: 'it'
+});
+
+export const config = {
+ // Match only internationalized pathnames
+ matcher: ['/', '/(en|it)/:path*']
+};
\ No newline at end of file
diff --git a/src/styles/_breakpoints.scss b/src/styles/_breakpoints.scss
new file mode 100644
index 0000000..4284207
--- /dev/null
+++ b/src/styles/_breakpoints.scss
@@ -0,0 +1,4 @@
+$portrait: 40em;
+$tablet: 48em;
+$laptop: 64em;
+$desktop: 80em;
\ No newline at end of file
diff --git a/src/styles/_colors.scss b/src/styles/_colors.scss
new file mode 100644
index 0000000..c485a02
--- /dev/null
+++ b/src/styles/_colors.scss
@@ -0,0 +1,5 @@
+// primaries
+$colors_yellow: #fdd835;
+$colors_yellow_hover: #fbc02d;
+$colors_yellow_focus: rgba(253, 216, 53, 0.125);
+$colors_yellow_inverse: rgba(0, 0, 0, 0.75);
\ No newline at end of file
diff --git a/src/styles/_spacing.scss b/src/styles/_spacing.scss
new file mode 100644
index 0000000..1f70fcb
--- /dev/null
+++ b/src/styles/_spacing.scss
@@ -0,0 +1,4 @@
+$spacing_4: 4px;
+$spacing_8: 8px;
+$spacing_16: 16px;
+$spacing_32: 32px;
\ No newline at end of file
diff --git a/src/styles/globals.scss b/src/styles/globals.scss
new file mode 100644
index 0000000..19bd624
--- /dev/null
+++ b/src/styles/globals.scss
@@ -0,0 +1 @@
+@use "@picocss/pico";
\ No newline at end of file
diff --git a/src/utils/scrape/gallery.ts b/src/utils/scrape/gallery.ts
new file mode 100644
index 0000000..a53aec7
--- /dev/null
+++ b/src/utils/scrape/gallery.ts
@@ -0,0 +1,53 @@
+import { XVIDEOS_BASE_URL } from '@/constants/urls';
+import { GalleryData, VideoData } from '@/meta/data';
+import axios, { AxiosError } from 'axios';
+
+import * as cheerio from "cheerio";
+
+interface FetchParams {
+ baseUrl?: string
+ query?: string
+}
+
+export const fetchGalleryData = async (params?: FetchParams): Promise => {
+
+ let data: GalleryData[] = [];
+
+ const reqHeaders = {
+ 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 : ''}`
+
+ await axios.get(queryUrl, reqHeaders)
+
+ .then(response => {
+
+ const html = response.data;
+
+ const $ = cheerio.load(html);
+
+ const thumbs = $(".thumb-block");
+
+ thumbs.map((key, thumb) => {
+
+ const videoUrl = $(thumb).find(".thumb a").attr("href")
+ const imgUrl = $(thumb).find(".thumb img").attr("data-src")
+ const text = $(thumb).find(".thumb-under a").attr("title")
+
+ videoUrl && imgUrl && text && data.push({
+ videoUrl,
+ imgUrl,
+ text
+ })
+ })
+
+ }).catch((error: AxiosError) => {
+ // handle errors
+ });
+
+
+ return data
+}
\ No newline at end of file
diff --git a/src/utils/scrape/video.ts b/src/utils/scrape/video.ts
new file mode 100644
index 0000000..e06383d
--- /dev/null
+++ b/src/utils/scrape/video.ts
@@ -0,0 +1,76 @@
+import { XVIDEOS_BASE_URL } from '@/constants/urls';
+import { GalleryData, VideoData } from '@/meta/data';
+
+import axios, { AxiosError } from 'axios';
+
+import * as cheerio from "cheerio";
+import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '../string';
+
+interface FetchParams {
+ baseUrl?: string
+ query?: string
+}
+
+export const fetchVideoData = async (videoId: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => {
+
+ let data: VideoData = {
+ lowResUrl: ''
+ }
+
+ let related: GalleryData[] = [];
+
+ const reqHeaders = {
+ 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}`
+
+ 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())
+
+ if (relatedVideos) {
+ related = relatedVideos
+ }
+ })
+
+ }).catch((error: AxiosError) => {
+ // handle errors
+ });
+
+ return [data, related];
+}
\ No newline at end of file
diff --git a/src/utils/string.ts b/src/utils/string.ts
new file mode 100644
index 0000000..5217a5b
--- /dev/null
+++ b/src/utils/string.ts
@@ -0,0 +1,42 @@
+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;
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 7b28589..56e0fa9 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -23,4 +23,4 @@
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
-}
+}
\ No newline at end of file
diff --git a/video.html b/video.html
new file mode 100644
index 0000000..d9516fa
--- /dev/null
+++ b/video.html
@@ -0,0 +1,199 @@
+
+
+
+Oops! Wrong hole, but he continues and cums inside (Accidental anal creampie) - XVIDEOS.COM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Oops! Wrong hole, but he continues and cums inside (Accidental anal creampie) 10 min 1440p
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Copy page link
Embed this video to your page with this code
Share this video
Report this video