diff --git a/.gitignore b/.gitignore index fd3dbb5..0f13ab6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ # next.js /.next/ /out/ +websocket.js +test.js # production /build diff --git a/package-lock.json b/package-lock.json index 562ead8..f8e9863 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "name": "my-anime-site", "version": "0.1.0", "dependencies": { + "@headlessui/react": "^2.1.2", + "@heroicons/react": "^2.1.5", "axios": "^1.7.2", "bcryptjs": "^2.4.3", "cache-manager": "^5.6.1", @@ -28,11 +30,13 @@ "react-cookie-consent": "^9.0.0", "react-dom": "^18", "react-icons": "^5.2.1", + "react-iframe": "^1.8.5", "react-markdown": "^9.0.1", "react-modal": "^3.16.1", "react-player": "^2.16.0", "redis": "^4.6.14", "sharp": "^0.33.4", + "socket.io-client": "^4.7.5", "swr": "^2.2.5", "tls": "^0.0.1" }, @@ -131,6 +135,80 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz", + "integrity": "sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==", + "dependencies": { + "@floating-ui/utils": "^0.2.4" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz", + "integrity": "sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.4" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.19", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.19.tgz", + "integrity": "sha512-Jk6zITdjjIvjO/VdQFvpRaD3qPwOHH6AoDHxjhpy+oK4KFgaSP871HYWUAPdnLmx1gQ+w/pB312co3tVml+BXA==", + "dependencies": { + "@floating-ui/react-dom": "^2.1.1", + "@floating-ui/utils": "^0.2.4", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + }, + "node_modules/@headlessui/react": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.1.2.tgz", + "integrity": "sha512-Kb3hgk9gRNRcTZktBrKdHhF3xFhYkca1Rk6e1/im2ENf83dgN54orMW0uSKTXFnUpZOUFZ+wcY05LlipwgZIFQ==", + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.17.1", + "@react-aria/interactions": "^3.21.3", + "@tanstack/react-virtual": "^3.8.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^18", + "react-dom": "^18" + } + }, + "node_modules/@heroicons/react": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.5.tgz", + "integrity": "sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA==", + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -899,6 +977,83 @@ "node": ">=14" } }, + "node_modules/@react-aria/focus": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.17.1.tgz", + "integrity": "sha512-FLTySoSNqX++u0nWZJPPN5etXY0WBxaIe/YuL/GTEeuqUIuC/2bJSaw5hlsM6T2yjy6Y/VAxBcKSdAFUlU6njQ==", + "dependencies": { + "@react-aria/interactions": "^3.21.3", + "@react-aria/utils": "^3.24.1", + "@react-types/shared": "^3.23.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.21.3", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.21.3.tgz", + "integrity": "sha512-BWIuf4qCs5FreDJ9AguawLVS0lV9UU+sK4CCnbCNNmYqOWY+1+gRXCsnOM32K+oMESBxilAjdHW5n1hsMqYMpA==", + "dependencies": { + "@react-aria/ssr": "^3.9.4", + "@react-aria/utils": "^3.24.1", + "@react-types/shared": "^3.23.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.4.tgz", + "integrity": "sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ==", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.24.1.tgz", + "integrity": "sha512-O3s9qhPMd6n42x9sKeJ3lhu5V1Tlnzhu6Yk8QOvDuXf7UGuUjXf9mzfHJt1dYzID4l9Fwm8toczBzPM9t0jc8Q==", + "dependencies": { + "@react-aria/ssr": "^3.9.4", + "@react-stately/utils": "^3.10.1", + "@react-types/shared": "^3.23.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.1.tgz", + "integrity": "sha512-VS/EHRyicef25zDZcM/ClpzYMC5i2YGN6uegOeQawmgfGjb02yaCX0F0zR69Pod9m2Hr3wunTbtpgVXvYbZItg==", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, + "node_modules/@react-types/shared": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.23.1.tgz", + "integrity": "sha512-5d+3HbFDxGZjhbMBeFHRQhexMFt4pUce3okyRtUVKbbedQFUrtXSBg9VszgF2RTeQDKDkMCIQDtz5ccP/Lk1gw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + } + }, "node_modules/@redis/bloom": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", @@ -958,6 +1113,11 @@ "integrity": "sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==", "dev": true }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -972,6 +1132,31 @@ "tslib": "^2.4.0" } }, + "node_modules/@tanstack/react-virtual": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.8.3.tgz", + "integrity": "sha512-9ICwbDUUzN99CJIGc373i8NLoj6zFTKI2Hlcmo0+lCSAhPQ5mxq4dGOMKmLYoEFyHcGQ64Bd6ZVbnPpM6lNK5w==", + "dependencies": { + "@tanstack/virtual-core": "3.8.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.8.3.tgz", + "integrity": "sha512-vd2A2TnM5lbnWZnHi9B+L2gPtkSeOtJOAw358JqokIH1+v2J7vUAzFVPwB/wrye12RFOurffXu33plm4uQ+JBQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -1871,6 +2056,14 @@ "node": ">=0.8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", @@ -2394,6 +2587,26 @@ "node": ">= 0.8" } }, + "node_modules/engine.io-client": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", + "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", @@ -6453,6 +6666,17 @@ "react": "*" } }, + "node_modules/react-iframe": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/react-iframe/-/react-iframe-1.8.5.tgz", + "integrity": "sha512-F4cQJGs3ydaG6fJWfuz9yLwOU0Trzl6kttXuUG+vYwosH8enOOFxZWEDQCSbNVO8ayjfYZeqLxEvdvcsSy4GvA==", + "dependencies": { + "object-assign": "^4.1.1" + }, + "peerDependencies": { + "react": ">=16.x.x" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -7027,6 +7251,32 @@ "node": ">=8" } }, + "node_modules/socket.io-client": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", + "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", @@ -7390,6 +7640,11 @@ "react": "^16.11.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, "node_modules/tailwindcss": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", @@ -8066,6 +8321,34 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 66c032b..01bf0ea 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "lint": "next lint" }, "dependencies": { + "@headlessui/react": "^2.1.2", + "@heroicons/react": "^2.1.5", "axios": "^1.7.2", "bcryptjs": "^2.4.3", "cache-manager": "^5.6.1", @@ -30,11 +32,13 @@ "react-cookie-consent": "^9.0.0", "react-dom": "^18", "react-icons": "^5.2.1", + "react-iframe": "^1.8.5", "react-markdown": "^9.0.1", "react-modal": "^3.16.1", "react-player": "^2.16.0", "redis": "^4.6.14", "sharp": "^0.33.4", + "socket.io-client": "^4.7.5", "swr": "^2.2.5", "tls": "^0.0.1" }, diff --git a/src/components/EpisodePlayer.js b/src/components/EpisodePlayer.js index e54608a..0f6adc1 100644 --- a/src/components/EpisodePlayer.js +++ b/src/components/EpisodePlayer.js @@ -1,70 +1,56 @@ -import React, { useState, useEffect, useMemo, useRef } from 'react'; -import axios from 'axios'; -import CustomDropdown from '@/components/CustomDropdown'; -import ReactPlayer from 'react-player'; +// EpisodePlayer.jsx +import React, { useState, useEffect } from 'react'; +import ReactIframe from 'react-iframe'; -const EpisodePlayer = ({ episode, selectedQuality, setSelectedQuality, setSelectedServer, selectedServer }) => { - const [sources, setSources] = useState({}); +const EpisodePlayer = ({ episode, setSelectedServer, selectedServer }) => { const [loading, setLoading] = useState(true); const [playerUrl, setPlayerUrl] = useState(''); - const iframeRef = useRef(null); - const cache = useRef({}); + const [episodeLoaded, setEpisodeLoaded] = useState(false); + const [prefetchedEpisode, setPrefetchedEpisode] = useState(null); useEffect(() => { - if (episode && episode.animeId && episode.episodeNumber) { - const fetchSources = async () => { - setLoading(true); // Start loading when fetching sources - const cacheKey = `${episode.animeId}-${episode.episodeNumber}`; - if (cache.current[cacheKey]) { - setSources(cache.current[cacheKey]); - setLoading(false); - } else { - try { - const response = await axios.get(`https://player.nekonode.net/sources?anime_id=${episode.animeId}&episode=${episode.episodeNumber}`); - setSources(response.data); - cache.current[cacheKey] = response.data; // Cache the response - setLoading(false); // Stop loading when sources are fetched - } catch (error) { - console.error('Error fetching sources:', error); - setSources({}); - setLoading(false); // Stop loading even if there is an error - } - } - }; - - fetchSources(); - } - }, [episode]); - - const serverSources = useMemo(() => (Array.isArray(sources[selectedServer]) ? sources[selectedServer] : []), [sources, selectedServer]); - - useEffect(() => { - if (!episode || !episode.animeId || !episode.episodeNumber || serverSources.length === 0) { + if (!episode || !episode.episodeId) { + console.log('No episode or episode ID available'); setPlayerUrl(''); + setLoading(false); return; } - let source = serverSources.find(source => source.quality === selectedQuality); - if (!source) { - if (selectedServer === 'gogocdn') { - source = serverSources.find(source => source.quality === 'backup') || serverSources[0]; - } else if (selectedServer === 'streamwish') { - source = serverSources.find(source => source.quality === 'default') || serverSources[0]; + console.log('Loading new episode...'); + setLoading(true); + setEpisodeLoaded(false); + + // Simulate episode loading + const timer = setTimeout(() => { + setEpisodeLoaded(true); + }, 1000); // Simulate 1-second episode loading time + + return () => clearTimeout(timer); + }, [selectedServer, episode]); + + useEffect(() => { + if (episodeLoaded) { + console.log('Setting player URL'); + const url = `http://localhost:4000/?anime_id=${episode.episodeId}&server=${selectedServer}`; + if (playerUrl !== url) { + setPlayerUrl(url); } + setLoading(false); } + }, [episodeLoaded, selectedServer, episode, playerUrl]); - if (!source) { - console.error('No suitable source found for the selected server and quality.'); - setPlayerUrl(''); - } else { - const animeId = episode.animeId; - const episodeNumber = episode.episodeNumber; - const quality = source.quality; - setPlayerUrl(`https://player.nekonode.net/?anime_id=${animeId}&episode=${episodeNumber}&quality=${quality}&server=${selectedServer}`); + useEffect(() => { + // Pre-fetch the next episode data (example implementation) + if (episode && episode.nextEpisodeId) { + fetch(`http://localhost:4000/next_episode?anime_id=${episode.nextEpisodeId}`) + .then(response => response.json()) + .then(data => setPrefetchedEpisode(data)) + .catch(error => console.error('Error pre-fetching next episode:', error)); } - }, [serverSources, selectedQuality, selectedServer, episode]); + }, [episode]); const handleIframeLoad = () => { + console.log('Iframe loaded'); setLoading(false); }; @@ -73,24 +59,23 @@ const EpisodePlayer = ({ episode, selectedQuality, setSelectedQuality, setSelect
No suitable source found for the selected server and quality.
@@ -101,7 +86,7 @@ const EpisodePlayer = ({ episode, selectedQuality, setSelectedQuality, setSelectSelect Server:
If one server isn't working, Try the next
+If one server isn't working, try the next
Main Domain
+{domains.main}
+Name: {session.user.name}
-ID: {session.user.id}
-Created At: {formatDate(session.user.createdAt)}
+Name: {session.user.name}
+ID: {session.user.id}
+Created At: {formatDate(session.user.createdAt)}
Loading anime list...
+Loading anime list...
) : error ? ( -{error}
+{error}
) : animeList.length === 0 ? ( -No anime in your list.
+No anime in your list.
) : ( animeList.map((item, index) => ( -{nametolong(item.name)}
-Status: {capitalize(item.status)}
-Last Time Watched: {formatDate(item.lastWatchedAt)}
+{nametolong(item.name)}
+Status: {capitalize(item.status)}
+Last Time Watched: {formatDate(item.lastWatchedAt)}
Watch Anime
-