forked from tpd94/CDRM-Project
		
	add prettier formatting
This commit is contained in:
		
							parent
							
								
									a82a3fd106
								
							
						
					
					
						commit
						2828edd6b7
					
				
							
								
								
									
										1
									
								
								cdrm-frontend/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								cdrm-frontend/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -10,6 +10,7 @@ lerna-debug.log*
 | 
			
		||||
node_modules
 | 
			
		||||
dist-ssr
 | 
			
		||||
*.local
 | 
			
		||||
dist
 | 
			
		||||
 | 
			
		||||
# Editor directories and files
 | 
			
		||||
.vscode/*
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								cdrm-frontend/.prettierignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								cdrm-frontend/.prettierignore
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
dist/
 | 
			
		||||
node_modules/
 | 
			
		||||
src/assets/icons/
 | 
			
		||||
src/components/Functions/protobuf.min.js
 | 
			
		||||
src/components/Functions/license_protocol.min.js
 | 
			
		||||
							
								
								
									
										8
									
								
								cdrm-frontend/.prettierrc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								cdrm-frontend/.prettierrc.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
    "trailingComma": "es5",
 | 
			
		||||
    "tabWidth": 4,
 | 
			
		||||
    "semi": true,
 | 
			
		||||
    "singleQuote": false,
 | 
			
		||||
    "useTabs": false,
 | 
			
		||||
    "printWidth": 100
 | 
			
		||||
}
 | 
			
		||||
@ -1,33 +1,30 @@
 | 
			
		||||
import js from '@eslint/js'
 | 
			
		||||
import globals from 'globals'
 | 
			
		||||
import reactHooks from 'eslint-plugin-react-hooks'
 | 
			
		||||
import reactRefresh from 'eslint-plugin-react-refresh'
 | 
			
		||||
import js from "@eslint/js";
 | 
			
		||||
import globals from "globals";
 | 
			
		||||
import reactHooks from "eslint-plugin-react-hooks";
 | 
			
		||||
import reactRefresh from "eslint-plugin-react-refresh";
 | 
			
		||||
 | 
			
		||||
export default [
 | 
			
		||||
  { ignores: ['dist'] },
 | 
			
		||||
    { ignores: ["dist"] },
 | 
			
		||||
    {
 | 
			
		||||
    files: ['**/*.{js,jsx}'],
 | 
			
		||||
        files: ["**/*.{js,jsx}"],
 | 
			
		||||
        languageOptions: {
 | 
			
		||||
            ecmaVersion: 2020,
 | 
			
		||||
            globals: globals.browser,
 | 
			
		||||
            parserOptions: {
 | 
			
		||||
        ecmaVersion: 'latest',
 | 
			
		||||
                ecmaVersion: "latest",
 | 
			
		||||
                ecmaFeatures: { jsx: true },
 | 
			
		||||
        sourceType: 'module',
 | 
			
		||||
                sourceType: "module",
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
        plugins: {
 | 
			
		||||
      'react-hooks': reactHooks,
 | 
			
		||||
      'react-refresh': reactRefresh,
 | 
			
		||||
            "react-hooks": reactHooks,
 | 
			
		||||
            "react-refresh": reactRefresh,
 | 
			
		||||
        },
 | 
			
		||||
        rules: {
 | 
			
		||||
            ...js.configs.recommended.rules,
 | 
			
		||||
            ...reactHooks.configs.recommended.rules,
 | 
			
		||||
      'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
 | 
			
		||||
      'react-refresh/only-export-components': [
 | 
			
		||||
        'warn',
 | 
			
		||||
        { allowConstantExport: true },
 | 
			
		||||
      ],
 | 
			
		||||
            "no-unused-vars": ["error", { varsIgnorePattern: "^[A-Z_]" }],
 | 
			
		||||
            "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
]
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@ -4,13 +4,13 @@
 | 
			
		||||
        <meta charset="UTF-8" />
 | 
			
		||||
        <link rel="icon" type="image/svg+xml" href="/favico.png" />
 | 
			
		||||
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
    <meta name="description" content="{{ data.description }}"/>
 | 
			
		||||
    <meta name="keywords" content="{{ data.keywords }}"/>
 | 
			
		||||
    <meta property='og:title' content="{{ data.opengraph_title }}" />
 | 
			
		||||
    <meta property='og:description' content="{{ data.opengraph_description }}" />
 | 
			
		||||
    <meta property='og:image' content="{{ data.opengraph_image }}" />
 | 
			
		||||
    <meta property='og:url' content="{{ data.opengraph_url }}" />
 | 
			
		||||
    <meta property='og:locale' content='en_US' />
 | 
			
		||||
        <meta name="description" content="{{ data.description }}" />
 | 
			
		||||
        <meta name="keywords" content="{{ data.keywords }}" />
 | 
			
		||||
        <meta property="og:title" content="{{ data.opengraph_title }}" />
 | 
			
		||||
        <meta property="og:description" content="{{ data.opengraph_description }}" />
 | 
			
		||||
        <meta property="og:image" content="{{ data.opengraph_image }}" />
 | 
			
		||||
        <meta property="og:url" content="{{ data.opengraph_url }}" />
 | 
			
		||||
        <meta property="og:locale" content="en_US" />
 | 
			
		||||
        <title>{{ data.tab_title }}</title>
 | 
			
		||||
    </head>
 | 
			
		||||
    <body class="w-full h-full">
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										875
									
								
								cdrm-frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										875
									
								
								cdrm-frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -10,24 +10,24 @@
 | 
			
		||||
        "preview": "vite preview"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
    "@tailwindcss/vite": "^4.1.4",
 | 
			
		||||
    "axios": "^1.9.0",
 | 
			
		||||
    "react": "^19.0.0",
 | 
			
		||||
    "react-dom": "^19.0.0",
 | 
			
		||||
        "@tailwindcss/vite": "^4.1.11",
 | 
			
		||||
        "axios": "^1.10.0",
 | 
			
		||||
        "react": "^19.1.0",
 | 
			
		||||
        "react-dom": "^19.1.0",
 | 
			
		||||
        "react-helmet": "^6.1.0",
 | 
			
		||||
    "react-router-dom": "^7.5.2",
 | 
			
		||||
    "shaka-player": "^4.14.9",
 | 
			
		||||
    "tailwindcss": "^4.1.4"
 | 
			
		||||
        "react-router-dom": "^7.7.0",
 | 
			
		||||
        "shaka-player": "^4.15.8",
 | 
			
		||||
        "tailwindcss": "^4.1.11"
 | 
			
		||||
    },
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
    "@eslint/js": "^9.22.0",
 | 
			
		||||
    "@types/react": "^19.0.10",
 | 
			
		||||
    "@types/react-dom": "^19.0.4",
 | 
			
		||||
    "@vitejs/plugin-react": "^4.3.4",
 | 
			
		||||
    "eslint": "^9.22.0",
 | 
			
		||||
        "@eslint/js": "^9.31.0",
 | 
			
		||||
        "@types/react": "^19.1.8",
 | 
			
		||||
        "@types/react-dom": "^19.1.6",
 | 
			
		||||
        "@vitejs/plugin-react": "^4.7.0",
 | 
			
		||||
        "eslint": "^9.31.0",
 | 
			
		||||
        "eslint-plugin-react-hooks": "^5.2.0",
 | 
			
		||||
    "eslint-plugin-react-refresh": "^0.4.19",
 | 
			
		||||
    "globals": "^16.0.0",
 | 
			
		||||
    "vite": "^6.3.1"
 | 
			
		||||
        "eslint-plugin-react-refresh": "^0.4.20",
 | 
			
		||||
        "globals": "^16.3.0",
 | 
			
		||||
        "vite": "^7.0.5"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,12 +17,18 @@ function App() {
 | 
			
		||||
            {/* The SideMenu should be visible when isMenuOpen is true */}
 | 
			
		||||
            <SideMenu isMenuOpen={isMenuOpen} setIsMenuOpen={setIsMenuOpen} />
 | 
			
		||||
 | 
			
		||||
      <div id="navbarcontainer" className="hidden lg:flex lg:w-2xs bg-gray-950/55 border-r border-white/5 shrink-0">
 | 
			
		||||
            <div
 | 
			
		||||
                id="navbarcontainer"
 | 
			
		||||
                className="hidden lg:flex lg:w-2xs bg-gray-950/55 border-r border-white/5 shrink-0"
 | 
			
		||||
            >
 | 
			
		||||
                <NavBar />
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div id="maincontainer" className="w-full lg:w-5/6 bg-gray-950/50 flex flex-col grow">
 | 
			
		||||
        <div id="navbarmaincontainer" className="w-full lg:hidden h-16 bg-gray-950/10 border-b border-white/5  sticky top-0 z-10">
 | 
			
		||||
                <div
 | 
			
		||||
                    id="navbarmaincontainer"
 | 
			
		||||
                    className="w-full lg:hidden h-16 bg-gray-950/10 border-b border-white/5  sticky top-0 z-10"
 | 
			
		||||
                >
 | 
			
		||||
                    <NavBarMain setIsMenuOpen={setIsMenuOpen} />
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,8 @@ const { SignedMessage, LicenseRequest } = protobuf.roots.default.license_protoco
 | 
			
		||||
 | 
			
		||||
function uint8ArrayToBase64(uint8Array) {
 | 
			
		||||
    const binaryString = Array.from(uint8Array)
 | 
			
		||||
    .map(b => String.fromCharCode(b))
 | 
			
		||||
    .join('');
 | 
			
		||||
        .map((b) => String.fromCharCode(b))
 | 
			
		||||
        .join("");
 | 
			
		||||
 | 
			
		||||
    return btoa(binaryString);
 | 
			
		||||
}
 | 
			
		||||
@ -17,10 +17,13 @@ function parseFetch(fetchString) {
 | 
			
		||||
 | 
			
		||||
    // Use a more lenient regex to capture the fetch pattern (including complex bodies)
 | 
			
		||||
    const fetchRegex = /fetch\(['"](.+?)['"],\s*(\{.+?\})\)/s; // Non-greedy match for JSON
 | 
			
		||||
    const lines = fetchString.split('\n').map(line => line.trim()).filter(Boolean);
 | 
			
		||||
    const lines = fetchString
 | 
			
		||||
        .split("\n")
 | 
			
		||||
        .map((line) => line.trim())
 | 
			
		||||
        .filter(Boolean);
 | 
			
		||||
    const result = {
 | 
			
		||||
        method: 'UNDEFINED',
 | 
			
		||||
        url: '',
 | 
			
		||||
        method: "UNDEFINED",
 | 
			
		||||
        url: "",
 | 
			
		||||
        headers: {},
 | 
			
		||||
        body: null,
 | 
			
		||||
    };
 | 
			
		||||
@ -47,9 +50,12 @@ function parseFetch(fetchString) {
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const WIDEVINE_SYSTEM_ID = new Uint8Array([0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed]);
 | 
			
		||||
const PLAYREADY_SYSTEM_ID = new Uint8Array([0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95]);
 | 
			
		||||
const WIDEVINE_SYSTEM_ID = new Uint8Array([
 | 
			
		||||
    0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed,
 | 
			
		||||
]);
 | 
			
		||||
const PLAYREADY_SYSTEM_ID = new Uint8Array([
 | 
			
		||||
    0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40, 0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b, 0xe0, 0x88, 0x5f, 0x95,
 | 
			
		||||
]);
 | 
			
		||||
const PSSH_MAGIC = new Uint8Array([0x70, 0x73, 0x73, 0x68]);
 | 
			
		||||
 | 
			
		||||
function intToUint8Array(num, endian) {
 | 
			
		||||
@ -75,22 +81,22 @@ function psshDataToPsshBoxB64(pssh_data, system_id) {
 | 
			
		||||
        ...new Uint8Array(4),
 | 
			
		||||
        ...system_id,
 | 
			
		||||
        ...intToUint8Array(dataLength, false),
 | 
			
		||||
        ...pssh_data
 | 
			
		||||
        ...pssh_data,
 | 
			
		||||
    ]);
 | 
			
		||||
    return uint8ArrayToBase64(pssh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function wrmHeaderToPlayReadyHeader(wrm_header){
 | 
			
		||||
function wrmHeaderToPlayReadyHeader(wrm_header) {
 | 
			
		||||
    const playready_object = new Uint8Array([
 | 
			
		||||
        ...shortToUint8Array(1, true),
 | 
			
		||||
        ...shortToUint8Array(wrm_header.length, true),
 | 
			
		||||
        ...wrm_header
 | 
			
		||||
        ...wrm_header,
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    return new Uint8Array([
 | 
			
		||||
        ...intToUint8Array(playready_object.length + 2 + 4, true),
 | 
			
		||||
        ...shortToUint8Array(1, true),
 | 
			
		||||
        ...playready_object
 | 
			
		||||
        ...playready_object,
 | 
			
		||||
    ]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -105,7 +111,7 @@ function encodeUtf16LE(str) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function stringToUint8Array(string) {
 | 
			
		||||
    return Uint8Array.from(string.split("").map(x => x.charCodeAt()));
 | 
			
		||||
    return Uint8Array.from(string.split("").map((x) => x.charCodeAt()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function readTextFromClipboard() {
 | 
			
		||||
@ -136,11 +142,15 @@ export async function readTextFromClipboard() {
 | 
			
		||||
                license_request = LicenseRequest.decode(signed_message.msg);
 | 
			
		||||
            } catch (decodeError) {
 | 
			
		||||
                // If error occurs during decoding, return an empty pssh
 | 
			
		||||
                console.error('Decoding failed, returning empty pssh', decodeError);
 | 
			
		||||
                pssh_data_string = '';  // Empty pssh if decoding fails
 | 
			
		||||
                console.error("Decoding failed, returning empty pssh", decodeError);
 | 
			
		||||
                pssh_data_string = ""; // Empty pssh if decoding fails
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (license_request && license_request.contentId && license_request.contentId.widevinePsshData) {
 | 
			
		||||
            if (
 | 
			
		||||
                license_request &&
 | 
			
		||||
                license_request.contentId &&
 | 
			
		||||
                license_request.contentId.widevinePsshData
 | 
			
		||||
            ) {
 | 
			
		||||
                const pssh_data = license_request.contentId.widevinePsshData.psshData[0];
 | 
			
		||||
                pssh_data_string = psshDataToPsshBoxB64(pssh_data, WIDEVINE_SYSTEM_ID);
 | 
			
		||||
            }
 | 
			
		||||
@ -160,14 +170,12 @@ export async function readTextFromClipboard() {
 | 
			
		||||
        document.getElementById("pssh").value = pssh_data_string;
 | 
			
		||||
        document.getElementById("data").value = payload_string;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        console.error('Failed to read clipboard contents:', error);
 | 
			
		||||
        console.error("Failed to read clipboard contents:", error);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper function to check if the data is binary
 | 
			
		||||
function isBinary(uint8Array) {
 | 
			
		||||
    // Check for non-text (non-ASCII) bytes (basic heuristic)
 | 
			
		||||
    return uint8Array.some(byte => byte > 127); // Non-ASCII byte indicates binary
 | 
			
		||||
    return uint8Array.some((byte) => byte > 127); // Non-ASCII byte indicates binary
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,26 +1,26 @@
 | 
			
		||||
import { useEffect, useState } from 'react';
 | 
			
		||||
import { NavLink } from 'react-router-dom';
 | 
			
		||||
import homeIcon from '../assets/icons/home.svg';
 | 
			
		||||
import cacheIcon from '../assets/icons/cache.svg';
 | 
			
		||||
import apiIcon from '../assets/icons/api.svg';
 | 
			
		||||
import testPlayerIcon from '../assets/icons/testplayer.svg';
 | 
			
		||||
import accountIcon from '../assets/icons/account.svg'; 
 | 
			
		||||
import discordIcon from '../assets/icons/discord.svg';
 | 
			
		||||
import telegramIcon from '../assets/icons/telegram.svg';
 | 
			
		||||
import giteaIcon from '../assets/icons/gitea.svg';
 | 
			
		||||
import { useEffect, useState } from "react";
 | 
			
		||||
import { NavLink } from "react-router-dom";
 | 
			
		||||
import homeIcon from "../assets/icons/home.svg";
 | 
			
		||||
import cacheIcon from "../assets/icons/cache.svg";
 | 
			
		||||
import apiIcon from "../assets/icons/api.svg";
 | 
			
		||||
import testPlayerIcon from "../assets/icons/testplayer.svg";
 | 
			
		||||
import accountIcon from "../assets/icons/account.svg";
 | 
			
		||||
import discordIcon from "../assets/icons/discord.svg";
 | 
			
		||||
import telegramIcon from "../assets/icons/telegram.svg";
 | 
			
		||||
import giteaIcon from "../assets/icons/gitea.svg";
 | 
			
		||||
 | 
			
		||||
function NavBar() {
 | 
			
		||||
    const [externalLinks, setExternalLinks] = useState({
 | 
			
		||||
        discord: '#',
 | 
			
		||||
        telegram: '#',
 | 
			
		||||
        gitea: '#',
 | 
			
		||||
        discord: "#",
 | 
			
		||||
        telegram: "#",
 | 
			
		||||
        gitea: "#",
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        fetch('/api/links')
 | 
			
		||||
            .then(response => response.json())
 | 
			
		||||
            .then(data => setExternalLinks(data))
 | 
			
		||||
            .catch(error => console.error('Error fetching links:', error));
 | 
			
		||||
        fetch("/api/links")
 | 
			
		||||
            .then((response) => response.json())
 | 
			
		||||
            .then((data) => setExternalLinks(data))
 | 
			
		||||
            .catch((error) => console.error("Error fetching links:", error));
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
@ -40,8 +40,8 @@ function NavBar() {
 | 
			
		||||
                    className={({ isActive }) =>
 | 
			
		||||
                        `flex flex-row p-3 border-l-3 ${
 | 
			
		||||
                            isActive
 | 
			
		||||
                                ? 'border-l-sky-500/50 bg-black/50'
 | 
			
		||||
                                : 'hover:border-l-sky-500/50 hover:bg-white/5'
 | 
			
		||||
                                ? "border-l-sky-500/50 bg-black/50"
 | 
			
		||||
                                : "hover:border-l-sky-500/50 hover:bg-white/5"
 | 
			
		||||
                        }`
 | 
			
		||||
                    }
 | 
			
		||||
                >
 | 
			
		||||
@ -58,8 +58,8 @@ function NavBar() {
 | 
			
		||||
                    className={({ isActive }) =>
 | 
			
		||||
                        `flex flex-row p-3 border-l-3 ${
 | 
			
		||||
                            isActive
 | 
			
		||||
                                ? 'border-l-emerald-500/50 bg-black/50'
 | 
			
		||||
                                : 'hover:border-l-emerald-500/50 hover:bg-white/5'
 | 
			
		||||
                                ? "border-l-emerald-500/50 bg-black/50"
 | 
			
		||||
                                : "hover:border-l-emerald-500/50 hover:bg-white/5"
 | 
			
		||||
                        }`
 | 
			
		||||
                    }
 | 
			
		||||
                >
 | 
			
		||||
@ -76,8 +76,8 @@ function NavBar() {
 | 
			
		||||
                    className={({ isActive }) =>
 | 
			
		||||
                        `flex flex-row p-3 border-l-3 ${
 | 
			
		||||
                            isActive
 | 
			
		||||
                                ? 'border-l-indigo-500/50 bg-black/50'
 | 
			
		||||
                                : 'hover:border-l-indigo-500/50 hover:bg-white/5'
 | 
			
		||||
                                ? "border-l-indigo-500/50 bg-black/50"
 | 
			
		||||
                                : "hover:border-l-indigo-500/50 hover:bg-white/5"
 | 
			
		||||
                        }`
 | 
			
		||||
                    }
 | 
			
		||||
                >
 | 
			
		||||
@ -94,13 +94,17 @@ function NavBar() {
 | 
			
		||||
                    className={({ isActive }) =>
 | 
			
		||||
                        `flex flex-row p-3 border-l-3 ${
 | 
			
		||||
                            isActive
 | 
			
		||||
                                ? 'border-l-rose-500/50 bg-black/50'
 | 
			
		||||
                                : 'hover:border-l-rose-500/50 hover:bg-white/5'
 | 
			
		||||
                                ? "border-l-rose-500/50 bg-black/50"
 | 
			
		||||
                                : "hover:border-l-rose-500/50 hover:bg-white/5"
 | 
			
		||||
                        }`
 | 
			
		||||
                    }
 | 
			
		||||
                >
 | 
			
		||||
                    <button className="w-1/3 p-3 flex flex-col items-center justify-center cursor-pointer">
 | 
			
		||||
                        <img src={testPlayerIcon} alt="Test Player" className="w-1/2 cursor-pointer" />
 | 
			
		||||
                        <img
 | 
			
		||||
                            src={testPlayerIcon}
 | 
			
		||||
                            alt="Test Player"
 | 
			
		||||
                            className="w-1/2 cursor-pointer"
 | 
			
		||||
                        />
 | 
			
		||||
                    </button>
 | 
			
		||||
                    <p className="grow text-white md:text-2xl font-bold flex items-center justify-start">
 | 
			
		||||
                        Test Player
 | 
			
		||||
@ -114,8 +118,8 @@ function NavBar() {
 | 
			
		||||
                        className={({ isActive }) =>
 | 
			
		||||
                            `flex flex-row p-3 border-l-3 ${
 | 
			
		||||
                                isActive
 | 
			
		||||
                                    ? 'border-l-yellow-500/50 bg-black/50'
 | 
			
		||||
                                    : 'hover:border-l-yellow-500/50 hover:bg-white/5'
 | 
			
		||||
                                    ? "border-l-yellow-500/50 bg-black/50"
 | 
			
		||||
                                    : "hover:border-l-yellow-500/50 hover:bg-white/5"
 | 
			
		||||
                            }`
 | 
			
		||||
                        }
 | 
			
		||||
                    >
 | 
			
		||||
@ -137,7 +141,11 @@ function NavBar() {
 | 
			
		||||
                    rel="noopener noreferrer"
 | 
			
		||||
                    className="w-1/3 p-3 flex flex-col items-center justify-center cursor-pointer hover:bg-blue-950 group"
 | 
			
		||||
                >
 | 
			
		||||
                    <img src={discordIcon} alt="Discord" className="w-1/2 group-hover:animate-bounce" />
 | 
			
		||||
                    <img
 | 
			
		||||
                        src={discordIcon}
 | 
			
		||||
                        alt="Discord"
 | 
			
		||||
                        className="w-1/2 group-hover:animate-bounce"
 | 
			
		||||
                    />
 | 
			
		||||
                </a>
 | 
			
		||||
                <a
 | 
			
		||||
                    href={externalLinks.telegram}
 | 
			
		||||
@ -145,7 +153,11 @@ function NavBar() {
 | 
			
		||||
                    rel="noopener noreferrer"
 | 
			
		||||
                    className="w-1/3 p-3 flex flex-col items-center justify-center cursor-pointer hover:bg-blue-400 group"
 | 
			
		||||
                >
 | 
			
		||||
                    <img src={telegramIcon} alt="Telegram" className="w-1/2 group-hover:animate-bounce" />
 | 
			
		||||
                    <img
 | 
			
		||||
                        src={telegramIcon}
 | 
			
		||||
                        alt="Telegram"
 | 
			
		||||
                        className="w-1/2 group-hover:animate-bounce"
 | 
			
		||||
                    />
 | 
			
		||||
                </a>
 | 
			
		||||
                <a
 | 
			
		||||
                    href={externalLinks.gitea}
 | 
			
		||||
 | 
			
		||||
@ -1,61 +1,61 @@
 | 
			
		||||
import React, { useState, useEffect } from 'react';
 | 
			
		||||
import { Helmet } from 'react-helmet'; // Import Helmet
 | 
			
		||||
import React, { useState, useEffect } from "react";
 | 
			
		||||
import { Helmet } from "react-helmet"; // Import Helmet
 | 
			
		||||
 | 
			
		||||
const { protocol, hostname, port } = window.location;
 | 
			
		||||
 | 
			
		||||
let fullHost = `${protocol}//${hostname}`;
 | 
			
		||||
if (
 | 
			
		||||
  (protocol === 'http:' && port !== '80') ||
 | 
			
		||||
  (protocol === 'https:' && port !== '443' && port !== '')
 | 
			
		||||
    (protocol === "http:" && port !== "80") ||
 | 
			
		||||
    (protocol === "https:" && port !== "443" && port !== "")
 | 
			
		||||
) {
 | 
			
		||||
    fullHost += `:${port}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function API() {
 | 
			
		||||
    const [deviceInfo, setDeviceInfo] = useState({
 | 
			
		||||
    device_type: '',
 | 
			
		||||
    system_id: '',
 | 
			
		||||
    security_level: '',
 | 
			
		||||
    host: '',
 | 
			
		||||
    secret: '',
 | 
			
		||||
    device_name: ''
 | 
			
		||||
        device_type: "",
 | 
			
		||||
        system_id: "",
 | 
			
		||||
        security_level: "",
 | 
			
		||||
        host: "",
 | 
			
		||||
        secret: "",
 | 
			
		||||
        device_name: "",
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const [prDeviceInfo, setPrDeviceInfo] = useState({
 | 
			
		||||
    security_level: '',
 | 
			
		||||
    host: '',
 | 
			
		||||
    secret: '',
 | 
			
		||||
    device_name: ''
 | 
			
		||||
        security_level: "",
 | 
			
		||||
        host: "",
 | 
			
		||||
        secret: "",
 | 
			
		||||
        device_name: "",
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        // Fetch Widevine info
 | 
			
		||||
    fetch('/remotecdm/widevine/deviceinfo')
 | 
			
		||||
      .then(response => response.json())
 | 
			
		||||
      .then(data => {
 | 
			
		||||
        fetch("/remotecdm/widevine/deviceinfo")
 | 
			
		||||
            .then((response) => response.json())
 | 
			
		||||
            .then((data) => {
 | 
			
		||||
                setDeviceInfo({
 | 
			
		||||
                    device_type: data.device_type,
 | 
			
		||||
                    system_id: data.system_id,
 | 
			
		||||
                    security_level: data.security_level,
 | 
			
		||||
                    host: data.host,
 | 
			
		||||
                    secret: data.secret,
 | 
			
		||||
          device_name: data.device_name
 | 
			
		||||
                    device_name: data.device_name,
 | 
			
		||||
                });
 | 
			
		||||
            })
 | 
			
		||||
      .catch(error => console.error('Error fetching Widevine info:', error));
 | 
			
		||||
            .catch((error) => console.error("Error fetching Widevine info:", error));
 | 
			
		||||
 | 
			
		||||
        // Fetch PlayReady info
 | 
			
		||||
    fetch('/remotecdm/playready/deviceinfo')
 | 
			
		||||
      .then(response => response.json())
 | 
			
		||||
      .then(data => {
 | 
			
		||||
        fetch("/remotecdm/playready/deviceinfo")
 | 
			
		||||
            .then((response) => response.json())
 | 
			
		||||
            .then((data) => {
 | 
			
		||||
                setPrDeviceInfo({
 | 
			
		||||
                    security_level: data.security_level,
 | 
			
		||||
                    host: data.host,
 | 
			
		||||
                    secret: data.secret,
 | 
			
		||||
          device_name: data.device_name
 | 
			
		||||
                    device_name: data.device_name,
 | 
			
		||||
                });
 | 
			
		||||
            })
 | 
			
		||||
      .catch(error => console.error('Error fetching PlayReady info:', error));
 | 
			
		||||
            .catch((error) => console.error("Error fetching PlayReady info:", error));
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
@ -63,10 +63,10 @@ function API() {
 | 
			
		||||
            <Helmet>
 | 
			
		||||
                <title>API</title>
 | 
			
		||||
            </Helmet>
 | 
			
		||||
        <details open className='w-full list-none'>
 | 
			
		||||
            <summary className='text-2xl'>Sending a decryption request</summary>
 | 
			
		||||
            <div className='mt-5 p-5 rounded-lg border-2 border-indigo-500/50'>  
 | 
			
		||||
              <pre className='rounded-lg font-mono whitespace-pre-wrap text-white overflow-auto'>
 | 
			
		||||
            <details open className="w-full list-none">
 | 
			
		||||
                <summary className="text-2xl">Sending a decryption request</summary>
 | 
			
		||||
                <div className="mt-5 p-5 rounded-lg border-2 border-indigo-500/50">
 | 
			
		||||
                    <pre className="rounded-lg font-mono whitespace-pre-wrap text-white overflow-auto">
 | 
			
		||||
                        {`import requests
 | 
			
		||||
 | 
			
		||||
print(requests.post(
 | 
			
		||||
@ -87,11 +87,11 @@ print(requests.post(
 | 
			
		||||
                    </pre>
 | 
			
		||||
                </div>
 | 
			
		||||
            </details>
 | 
			
		||||
        <details open className='w-full list-none mt-5'>
 | 
			
		||||
            <summary className='text-2xl'>Sending a search request</summary>
 | 
			
		||||
            <div className='mt-5 border-2 border-indigo-500/50 p-5 rounded-lg'>
 | 
			
		||||
            <details open className="w-full list-none mt-5">
 | 
			
		||||
                <summary className="text-2xl">Sending a search request</summary>
 | 
			
		||||
                <div className="mt-5 border-2 border-indigo-500/50 p-5 rounded-lg">
 | 
			
		||||
                    <pre className="rounded-lg font-mono whitespace-pre text-white overflow-x-auto max-w-full p-5">
 | 
			
		||||
{`import requests
 | 
			
		||||
                        {`import requests
 | 
			
		||||
 | 
			
		||||
print(requests.post(
 | 
			
		||||
    url='${fullHost}/api/cache/search',
 | 
			
		||||
@ -99,34 +99,38 @@ print(requests.post(
 | 
			
		||||
        'input': 'AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAADsIARIQ62dqu8s0Xpa7z2FmMPGj2hoNd2lkZXZpbmVfdGVzdCIQZmtqM2xqYVNkZmFsa3IzaioCSEQyAA=='
 | 
			
		||||
    }
 | 
			
		||||
).json())`}
 | 
			
		||||
</pre>
 | 
			
		||||
                    </pre>
 | 
			
		||||
                </div>
 | 
			
		||||
            </details>
 | 
			
		||||
        <details open className='w-full list-none mt-5'>
 | 
			
		||||
            <summary className='text-2xl'>PyWidevine RemoteCDM info</summary>
 | 
			
		||||
            <div className='mt-5 border-2 border-indigo-500/50 p-5 rounded-lg overflow-x-auto'>
 | 
			
		||||
            <details open className="w-full list-none mt-5">
 | 
			
		||||
                <summary className="text-2xl">PyWidevine RemoteCDM info</summary>
 | 
			
		||||
                <div className="mt-5 border-2 border-indigo-500/50 p-5 rounded-lg overflow-x-auto">
 | 
			
		||||
                    <p>
 | 
			
		||||
                        <strong>Device Type:</strong> '{deviceInfo.device_type}'<br />
 | 
			
		||||
                    <strong>System ID:</strong> {deviceInfo.system_id}<br />
 | 
			
		||||
                    <strong>Security Level:</strong> {deviceInfo.security_level}<br />
 | 
			
		||||
                    <strong>Host:</strong> {fullHost}/remotecdm/widevine<br />
 | 
			
		||||
                        <strong>System ID:</strong> {deviceInfo.system_id}
 | 
			
		||||
                        <br />
 | 
			
		||||
                        <strong>Security Level:</strong> {deviceInfo.security_level}
 | 
			
		||||
                        <br />
 | 
			
		||||
                        <strong>Host:</strong> {fullHost}/remotecdm/widevine
 | 
			
		||||
                        <br />
 | 
			
		||||
                        <strong>Secret:</strong> '{deviceInfo.secret}'<br />
 | 
			
		||||
                        <strong>Device Name:</strong> {deviceInfo.device_name}
 | 
			
		||||
                    </p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </details>
 | 
			
		||||
        <details open className='w-full list-none mt-5'>
 | 
			
		||||
            <summary className='text-2xl'>PyPlayready RemoteCDM info</summary>
 | 
			
		||||
            <div className='mt-5 border-2 border-indigo-500/50 p-5 rounded-lg overflow-x-auto'>
 | 
			
		||||
            <details open className="w-full list-none mt-5">
 | 
			
		||||
                <summary className="text-2xl">PyPlayready RemoteCDM info</summary>
 | 
			
		||||
                <div className="mt-5 border-2 border-indigo-500/50 p-5 rounded-lg overflow-x-auto">
 | 
			
		||||
                    <p>
 | 
			
		||||
                    <strong>Security Level:</strong> {prDeviceInfo.security_level}<br />
 | 
			
		||||
                    <strong>Host:</strong> {fullHost}/remotecdm/playready<br />
 | 
			
		||||
                        <strong>Security Level:</strong> {prDeviceInfo.security_level}
 | 
			
		||||
                        <br />
 | 
			
		||||
                        <strong>Host:</strong> {fullHost}/remotecdm/playready
 | 
			
		||||
                        <br />
 | 
			
		||||
                        <strong>Secret:</strong> '{prDeviceInfo.secret}'<br />
 | 
			
		||||
                        <strong>Device Name:</strong> {prDeviceInfo.device_name}
 | 
			
		||||
                    </p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </details>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,19 +6,19 @@ function Account() {
 | 
			
		||||
    const [isLoggedIn, setIsLoggedIn] = useState(null); // null = loading state
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
    fetch('/login/status', {
 | 
			
		||||
      method: 'POST',
 | 
			
		||||
      credentials: 'include', // Sends cookies with request
 | 
			
		||||
        fetch("/login/status", {
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            credentials: "include", // Sends cookies with request
 | 
			
		||||
        })
 | 
			
		||||
    .then(res => res.json())
 | 
			
		||||
    .then(data => {
 | 
			
		||||
      if (data.message === 'True') {
 | 
			
		||||
            .then((res) => res.json())
 | 
			
		||||
            .then((data) => {
 | 
			
		||||
                if (data.message === "True") {
 | 
			
		||||
                    setIsLoggedIn(true);
 | 
			
		||||
                } else {
 | 
			
		||||
                    setIsLoggedIn(false);
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
    .catch(err => {
 | 
			
		||||
            .catch((err) => {
 | 
			
		||||
                console.error("Error checking login status:", err);
 | 
			
		||||
                setIsLoggedIn(false); // Assume not logged in on error
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { useState, useEffect, useRef } from 'react';
 | 
			
		||||
import { Helmet } from 'react-helmet'; // Import Helmet
 | 
			
		||||
import { useState, useEffect, useRef } from "react";
 | 
			
		||||
import { Helmet } from "react-helmet"; // Import Helmet
 | 
			
		||||
 | 
			
		||||
function Cache() {
 | 
			
		||||
    const [searchQuery, setSearchQuery] = useState('');
 | 
			
		||||
    const [searchQuery, setSearchQuery] = useState("");
 | 
			
		||||
    const [cacheData, setCacheData] = useState([]);
 | 
			
		||||
    const [keyCount, setKeyCount] = useState(0); // New state to store the key count
 | 
			
		||||
    const debounceTimeout = useRef(null);
 | 
			
		||||
@ -11,11 +11,11 @@ function Cache() {
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        const fetchKeyCount = async () => {
 | 
			
		||||
            try {
 | 
			
		||||
                const response = await fetch('/api/cache/keycount');
 | 
			
		||||
                const response = await fetch("/api/cache/keycount");
 | 
			
		||||
                const data = await response.json();
 | 
			
		||||
                setKeyCount(data.count); // Update key count
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                console.error('Error fetching key count:', error);
 | 
			
		||||
                console.error("Error fetching key count:", error);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ function Cache() {
 | 
			
		||||
 | 
			
		||||
        // Set a new timeout to send the API call after 1 second of no typing
 | 
			
		||||
        debounceTimeout.current = setTimeout(() => {
 | 
			
		||||
            if (query.trim() !== '') {
 | 
			
		||||
            if (query.trim() !== "") {
 | 
			
		||||
                sendApiCall(query); // Only call the API if the query is not empty
 | 
			
		||||
            } else {
 | 
			
		||||
                setCacheData([]); // Clear results if query is empty
 | 
			
		||||
@ -42,14 +42,14 @@ function Cache() {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const sendApiCall = (text) => {
 | 
			
		||||
        fetch('/api/cache/search', {
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            headers: { 'Content-Type': 'application/json' },
 | 
			
		||||
        fetch("/api/cache/search", {
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            headers: { "Content-Type": "application/json" },
 | 
			
		||||
            body: JSON.stringify({ input: text }),
 | 
			
		||||
        })
 | 
			
		||||
            .then((response) => response.json())
 | 
			
		||||
            .then((data) => setCacheData(data)) // Update cache data with the results
 | 
			
		||||
            .catch((error) => console.error('Error:', error));
 | 
			
		||||
            .catch((error) => console.error("Error:", error));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,18 @@
 | 
			
		||||
import React, { useState, useEffect, useRef } from 'react';
 | 
			
		||||
import { readTextFromClipboard } from '../Functions/ParseChallenge';
 | 
			
		||||
import { Helmet } from 'react-helmet'; // Import Helmet
 | 
			
		||||
import React, { useState, useEffect, useRef } from "react";
 | 
			
		||||
import { readTextFromClipboard } from "../Functions/ParseChallenge";
 | 
			
		||||
import { Helmet } from "react-helmet"; // Import Helmet
 | 
			
		||||
 | 
			
		||||
function HomePage() {
 | 
			
		||||
  const [pssh, setPssh] = useState('');
 | 
			
		||||
  const [licurl, setLicurl] = useState('');
 | 
			
		||||
  const [proxy, setProxy] = useState('');
 | 
			
		||||
  const [headers, setHeaders] = useState('');
 | 
			
		||||
  const [cookies, setCookies] = useState('');
 | 
			
		||||
  const [data, setData] = useState('');
 | 
			
		||||
  const [message, setMessage] = useState('');
 | 
			
		||||
    const [pssh, setPssh] = useState("");
 | 
			
		||||
    const [licurl, setLicurl] = useState("");
 | 
			
		||||
    const [proxy, setProxy] = useState("");
 | 
			
		||||
    const [headers, setHeaders] = useState("");
 | 
			
		||||
    const [cookies, setCookies] = useState("");
 | 
			
		||||
    const [data, setData] = useState("");
 | 
			
		||||
    const [message, setMessage] = useState("");
 | 
			
		||||
    const [isVisible, setIsVisible] = useState(false);
 | 
			
		||||
    const [devices, setDevices] = useState([]);
 | 
			
		||||
  const [selectedDevice, setSelectedDevice] = useState('default');
 | 
			
		||||
    const [selectedDevice, setSelectedDevice] = useState("default");
 | 
			
		||||
 | 
			
		||||
    const bottomRef = useRef(null);
 | 
			
		||||
    const messageRef = useRef(null); // Reference to result container
 | 
			
		||||
@ -21,21 +21,21 @@ function HomePage() {
 | 
			
		||||
        if (isVisible) {
 | 
			
		||||
            setIsVisible(false);
 | 
			
		||||
        }
 | 
			
		||||
    setPssh('');
 | 
			
		||||
    setLicurl('');
 | 
			
		||||
    setProxy('');
 | 
			
		||||
    setHeaders('');
 | 
			
		||||
    setCookies('');
 | 
			
		||||
    setData('');
 | 
			
		||||
        setPssh("");
 | 
			
		||||
        setLicurl("");
 | 
			
		||||
        setProxy("");
 | 
			
		||||
        setHeaders("");
 | 
			
		||||
        setCookies("");
 | 
			
		||||
        setData("");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const handleSubmitButton = (event) => {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
 | 
			
		||||
    fetch('/api/decrypt', {
 | 
			
		||||
      method: 'POST',
 | 
			
		||||
        fetch("/api/decrypt", {
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            headers: {
 | 
			
		||||
        'Content-Type': 'application/json',
 | 
			
		||||
                "Content-Type": "application/json",
 | 
			
		||||
            },
 | 
			
		||||
            body: JSON.stringify({
 | 
			
		||||
                pssh: pssh,
 | 
			
		||||
@ -47,15 +47,15 @@ function HomePage() {
 | 
			
		||||
                device: selectedDevice, // Include selected device in the request
 | 
			
		||||
            }),
 | 
			
		||||
        })
 | 
			
		||||
      .then(response => response.json())
 | 
			
		||||
      .then(data => {
 | 
			
		||||
        const resultMessage = data['message'].replace(/\n/g, '<br />');
 | 
			
		||||
            .then((response) => response.json())
 | 
			
		||||
            .then((data) => {
 | 
			
		||||
                const resultMessage = data["message"].replace(/\n/g, "<br />");
 | 
			
		||||
                setMessage(resultMessage);
 | 
			
		||||
                setIsVisible(true);
 | 
			
		||||
            })
 | 
			
		||||
            .catch((error) => {
 | 
			
		||||
        console.error('Error during decryption request:', error);
 | 
			
		||||
        setMessage('Error: Unable to process request.');
 | 
			
		||||
                console.error("Error during decryption request:", error);
 | 
			
		||||
                setMessage("Error: Unable to process request.");
 | 
			
		||||
                setIsVisible(true);
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
@ -64,8 +64,8 @@ function HomePage() {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        if (messageRef.current) {
 | 
			
		||||
            const textToCopy = messageRef.current.innerText; // Grab the plain text (with visual line breaks)
 | 
			
		||||
      navigator.clipboard.writeText(textToCopy).catch(err => {
 | 
			
		||||
        alert('Failed to copy!');
 | 
			
		||||
            navigator.clipboard.writeText(textToCopy).catch((err) => {
 | 
			
		||||
                alert("Failed to copy!");
 | 
			
		||||
                console.error(err);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
@ -73,36 +73,38 @@ function HomePage() {
 | 
			
		||||
 | 
			
		||||
    const handleFetchPaste = () => {
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
    readTextFromClipboard().then(() => {
 | 
			
		||||
        readTextFromClipboard()
 | 
			
		||||
            .then(() => {
 | 
			
		||||
                setPssh(document.getElementById("pssh").value);
 | 
			
		||||
                setLicurl(document.getElementById("licurl").value);
 | 
			
		||||
                setHeaders(document.getElementById("headers").value);
 | 
			
		||||
                setData(document.getElementById("data").value);
 | 
			
		||||
    }).catch(err => {
 | 
			
		||||
      alert('Failed to paste from fetch!');
 | 
			
		||||
            })
 | 
			
		||||
            .catch((err) => {
 | 
			
		||||
                alert("Failed to paste from fetch!");
 | 
			
		||||
            });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        if (isVisible && bottomRef.current) {
 | 
			
		||||
      bottomRef.current.scrollIntoView({ behavior: 'smooth' });
 | 
			
		||||
            bottomRef.current.scrollIntoView({ behavior: "smooth" });
 | 
			
		||||
        }
 | 
			
		||||
    }, [message, isVisible]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
    fetch('/login/status', {
 | 
			
		||||
      method: 'POST',
 | 
			
		||||
        fetch("/login/status", {
 | 
			
		||||
            method: "POST",
 | 
			
		||||
        })
 | 
			
		||||
      .then(res => res.json())
 | 
			
		||||
      .then(statusData => {
 | 
			
		||||
        if (statusData.message === 'True') {
 | 
			
		||||
          return fetch('/userinfo', { method: 'POST' });
 | 
			
		||||
            .then((res) => res.json())
 | 
			
		||||
            .then((statusData) => {
 | 
			
		||||
                if (statusData.message === "True") {
 | 
			
		||||
                    return fetch("/userinfo", { method: "POST" });
 | 
			
		||||
                } else {
 | 
			
		||||
          throw new Error('Not logged in');
 | 
			
		||||
                    throw new Error("Not logged in");
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
      .then(res => res.json())
 | 
			
		||||
      .then(deviceData => {
 | 
			
		||||
            .then((res) => res.json())
 | 
			
		||||
            .then((deviceData) => {
 | 
			
		||||
                const combinedDevices = [
 | 
			
		||||
                    ...deviceData.Widevine_Devices,
 | 
			
		||||
                    ...deviceData.Playready_Devices,
 | 
			
		||||
@ -117,12 +119,12 @@ function HomePage() {
 | 
			
		||||
 | 
			
		||||
                // Set devices and select a device if logged in
 | 
			
		||||
                setDevices(allDevices.length > 0 ? allDevices : []);
 | 
			
		||||
        setSelectedDevice(allDevices.length > 0 ? allDevices[0] : 'default');
 | 
			
		||||
                setSelectedDevice(allDevices.length > 0 ? allDevices[0] : "default");
 | 
			
		||||
            })
 | 
			
		||||
            .catch(() => {
 | 
			
		||||
                // User isn't logged in, set default device to 'default'
 | 
			
		||||
                setDevices([]); // Don't display devices list
 | 
			
		||||
        setSelectedDevice('default');
 | 
			
		||||
                setSelectedDevice("default");
 | 
			
		||||
            });
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
@ -133,7 +135,9 @@ function HomePage() {
 | 
			
		||||
                    <title>CDRM-Project</title>
 | 
			
		||||
                </Helmet>
 | 
			
		||||
                <form className="flex flex-col w-full h-full bg-black/5 p-4 overflow-y-auto">
 | 
			
		||||
          <label htmlFor="pssh" className="text-white w-8/10 self-center">PSSH: </label>
 | 
			
		||||
                    <label htmlFor="pssh" className="text-white w-8/10 self-center">
 | 
			
		||||
                        PSSH:{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        id="pssh"
 | 
			
		||||
@ -141,7 +145,9 @@ function HomePage() {
 | 
			
		||||
                        value={pssh}
 | 
			
		||||
                        onChange={(e) => setPssh(e.target.value)}
 | 
			
		||||
                    />
 | 
			
		||||
          <label htmlFor="licurl" className="text-white w-8/10 self-center">License URL: </label>
 | 
			
		||||
                    <label htmlFor="licurl" className="text-white w-8/10 self-center">
 | 
			
		||||
                        License URL:{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        id="licurl"
 | 
			
		||||
@ -149,7 +155,9 @@ function HomePage() {
 | 
			
		||||
                        value={licurl}
 | 
			
		||||
                        onChange={(e) => setLicurl(e.target.value)}
 | 
			
		||||
                    />
 | 
			
		||||
          <label htmlFor="proxy" className="text-white w-8/10 self-center">Proxy: </label>
 | 
			
		||||
                    <label htmlFor="proxy" className="text-white w-8/10 self-center">
 | 
			
		||||
                        Proxy:{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        id="proxy"
 | 
			
		||||
@ -157,21 +165,27 @@ function HomePage() {
 | 
			
		||||
                        value={proxy}
 | 
			
		||||
                        onChange={(e) => setProxy(e.target.value)}
 | 
			
		||||
                    />
 | 
			
		||||
          <label htmlFor="headers" className="text-white w-8/10 self-center">Headers: </label>
 | 
			
		||||
                    <label htmlFor="headers" className="text-white w-8/10 self-center">
 | 
			
		||||
                        Headers:{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <textarea
 | 
			
		||||
                        id="headers"
 | 
			
		||||
                        className="w-8/10 border-2 border-sky-500/25 rounded-xl self-center m-2 text-white p-1 h-48"
 | 
			
		||||
                        value={headers}
 | 
			
		||||
                        onChange={(e) => setHeaders(e.target.value)}
 | 
			
		||||
                    />
 | 
			
		||||
          <label htmlFor="cookies" className="text-white w-8/10 self-center">Cookies: </label>
 | 
			
		||||
                    <label htmlFor="cookies" className="text-white w-8/10 self-center">
 | 
			
		||||
                        Cookies:{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <textarea
 | 
			
		||||
                        id="cookies"
 | 
			
		||||
                        className="w-8/10 border-2 border-sky-500/25 rounded-xl self-center m-2 text-white p-1 h-48"
 | 
			
		||||
                        value={cookies}
 | 
			
		||||
                        onChange={(e) => setCookies(e.target.value)}
 | 
			
		||||
                    />
 | 
			
		||||
          <label htmlFor="data" className="text-white w-8/10 self-center">Data: </label>
 | 
			
		||||
                    <label htmlFor="data" className="text-white w-8/10 self-center">
 | 
			
		||||
                        Data:{" "}
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <textarea
 | 
			
		||||
                        id="data"
 | 
			
		||||
                        className="w-8/10 border-2 border-sky-500/25 rounded-xl self-center m-2 text-white p-1 h-48"
 | 
			
		||||
@ -182,7 +196,9 @@ function HomePage() {
 | 
			
		||||
                    {/* Device Selection Dropdown, only show if logged in */}
 | 
			
		||||
                    {devices.length > 0 && (
 | 
			
		||||
                        <>
 | 
			
		||||
              <label htmlFor="device" className="text-white w-8/10 self-center">Select Device:</label>
 | 
			
		||||
                            <label htmlFor="device" className="text-white w-8/10 self-center">
 | 
			
		||||
                                Select Device:
 | 
			
		||||
                            </label>
 | 
			
		||||
                            <select
 | 
			
		||||
                                id="device"
 | 
			
		||||
                                className="w-8/10 border-2 border-sky-500/25 rounded-xl h-10 self-center m-2 text-white bg-black p-1"
 | 
			
		||||
@ -190,7 +206,9 @@ function HomePage() {
 | 
			
		||||
                                onChange={(e) => setSelectedDevice(e.target.value)}
 | 
			
		||||
                            >
 | 
			
		||||
                                {devices.map((device, index) => (
 | 
			
		||||
                  <option key={index} value={device}>{device}</option>
 | 
			
		||||
                                    <option key={index} value={device}>
 | 
			
		||||
                                        {device}
 | 
			
		||||
                                    </option>
 | 
			
		||||
                                ))}
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </>
 | 
			
		||||
@ -204,7 +222,10 @@ function HomePage() {
 | 
			
		||||
                        >
 | 
			
		||||
                            Submit
 | 
			
		||||
                        </button>
 | 
			
		||||
            <button onClick={handleFetchPaste} className="bg-yellow-500/50 rounded-xl text-white text-bold text-xl p-1 lg:w-1/5 lg:h-12 truncate mt-5 w-1/2 lg:mt-0">
 | 
			
		||||
                        <button
 | 
			
		||||
                            onClick={handleFetchPaste}
 | 
			
		||||
                            className="bg-yellow-500/50 rounded-xl text-white text-bold text-xl p-1 lg:w-1/5 lg:h-12 truncate mt-5 w-1/2 lg:mt-0"
 | 
			
		||||
                        >
 | 
			
		||||
                            Paste from fetch
 | 
			
		||||
                        </button>
 | 
			
		||||
                        <button
 | 
			
		||||
@ -219,9 +240,12 @@ function HomePage() {
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {isVisible && (
 | 
			
		||||
        <div id="main_content" className="flex-col w-full h-full p-10 items-center justify-center self-center">
 | 
			
		||||
                <div
 | 
			
		||||
                    id="main_content"
 | 
			
		||||
                    className="flex-col w-full h-full p-10 items-center justify-center self-center"
 | 
			
		||||
                >
 | 
			
		||||
                    <div className="flex flex-col w-full h-full overflow-y-auto items-center">
 | 
			
		||||
            <div className='w-8/10 grow p-4 text-white text-bold text-center text-xl md:text-3xl border-2 border-sky-500/25 rounded-xl bg-black/5'>
 | 
			
		||||
                        <div className="w-8/10 grow p-4 text-white text-bold text-center text-xl md:text-3xl border-2 border-sky-500/25 rounded-xl bg-black/5">
 | 
			
		||||
                            <p className="w-full border-b-2 border-white/75 pb-2">Results:</p>
 | 
			
		||||
                            <p
 | 
			
		||||
                                className="w-full grow pt-10 break-words overflow-y-auto"
 | 
			
		||||
 | 
			
		||||
@ -1,27 +1,27 @@
 | 
			
		||||
import React, { useState, useEffect } from 'react';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import React, { useState, useEffect } from "react";
 | 
			
		||||
import axios from "axios";
 | 
			
		||||
 | 
			
		||||
function MyAccount() {
 | 
			
		||||
    const [wvList, setWvList] = useState([]);
 | 
			
		||||
    const [prList, setPrList] = useState([]);
 | 
			
		||||
    const [uploading, setUploading] = useState(false);
 | 
			
		||||
  const [username, setUsername] = useState('');
 | 
			
		||||
  const [apiKey, setApiKey] = useState('');
 | 
			
		||||
  const [password, setPassword] = useState('');
 | 
			
		||||
  const [passwordError, setPasswordError] = useState('');
 | 
			
		||||
  const [newApiKey, setNewApiKey] = useState('');
 | 
			
		||||
  const [apiKeyError, setApiKeyError] = useState('');
 | 
			
		||||
    const [username, setUsername] = useState("");
 | 
			
		||||
    const [apiKey, setApiKey] = useState("");
 | 
			
		||||
    const [password, setPassword] = useState("");
 | 
			
		||||
    const [passwordError, setPasswordError] = useState("");
 | 
			
		||||
    const [newApiKey, setNewApiKey] = useState("");
 | 
			
		||||
    const [apiKeyError, setApiKeyError] = useState("");
 | 
			
		||||
 | 
			
		||||
    // Fetch user info
 | 
			
		||||
    const fetchUserInfo = async () => {
 | 
			
		||||
        try {
 | 
			
		||||
      const response = await axios.post('/userinfo');
 | 
			
		||||
            const response = await axios.post("/userinfo");
 | 
			
		||||
            setWvList(response.data.Widevine_Devices || []);
 | 
			
		||||
            setPrList(response.data.Playready_Devices || []);
 | 
			
		||||
      setUsername(response.data.Styled_Username || '');
 | 
			
		||||
      setApiKey(response.data.API_Key || '');
 | 
			
		||||
            setUsername(response.data.Styled_Username || "");
 | 
			
		||||
            setApiKey(response.data.API_Key || "");
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
      console.error('Failed to fetch user info', err);
 | 
			
		||||
            console.error("Failed to fetch user info", err);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -34,22 +34,25 @@ function MyAccount() {
 | 
			
		||||
        const file = event.target.files[0];
 | 
			
		||||
        if (!file) return;
 | 
			
		||||
 | 
			
		||||
    const extension = file.name.split('.').pop();
 | 
			
		||||
    if ((cdmType === 'PR' && extension !== 'prd') || (cdmType === 'WV' && extension !== 'wvd')) {
 | 
			
		||||
      alert(`Please upload a .${cdmType === 'PR' ? 'prd' : 'wvd'} file.`);
 | 
			
		||||
        const extension = file.name.split(".").pop();
 | 
			
		||||
        if (
 | 
			
		||||
            (cdmType === "PR" && extension !== "prd") ||
 | 
			
		||||
            (cdmType === "WV" && extension !== "wvd")
 | 
			
		||||
        ) {
 | 
			
		||||
            alert(`Please upload a .${cdmType === "PR" ? "prd" : "wvd"} file.`);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const formData = new FormData();
 | 
			
		||||
    formData.append('file', file);
 | 
			
		||||
        formData.append("file", file);
 | 
			
		||||
 | 
			
		||||
        setUploading(true);
 | 
			
		||||
        try {
 | 
			
		||||
            await axios.post(`/upload/${cdmType}`, formData);
 | 
			
		||||
            await fetchUserInfo(); // Refresh list after upload
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
      console.error('Upload failed', err);
 | 
			
		||||
      alert('Upload failed');
 | 
			
		||||
            console.error("Upload failed", err);
 | 
			
		||||
            alert("Upload failed");
 | 
			
		||||
        } finally {
 | 
			
		||||
            setUploading(false);
 | 
			
		||||
        }
 | 
			
		||||
@ -58,75 +61,80 @@ function MyAccount() {
 | 
			
		||||
    // Handle logout
 | 
			
		||||
    const handleLogout = async () => {
 | 
			
		||||
        try {
 | 
			
		||||
      await axios.post('/logout');
 | 
			
		||||
            await axios.post("/logout");
 | 
			
		||||
            window.location.reload();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
      console.error('Logout failed:', error);
 | 
			
		||||
      alert('Logout failed!');
 | 
			
		||||
            console.error("Logout failed:", error);
 | 
			
		||||
            alert("Logout failed!");
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Handle change password
 | 
			
		||||
    const handleChangePassword = async () => {
 | 
			
		||||
    if (passwordError || password === '') {
 | 
			
		||||
      alert('Please enter a valid password.');
 | 
			
		||||
        if (passwordError || password === "") {
 | 
			
		||||
            alert("Please enter a valid password.");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
      const response = await axios.post('/user/change_password', {
 | 
			
		||||
        new_password: password
 | 
			
		||||
            const response = await axios.post("/user/change_password", {
 | 
			
		||||
                new_password: password,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
      if (response.data.message === 'True') {
 | 
			
		||||
        alert('Password changed successfully.');
 | 
			
		||||
        setPassword('');
 | 
			
		||||
            if (response.data.message === "True") {
 | 
			
		||||
                alert("Password changed successfully.");
 | 
			
		||||
                setPassword("");
 | 
			
		||||
            } else {
 | 
			
		||||
        alert('Failed to change password.');
 | 
			
		||||
                alert("Failed to change password.");
 | 
			
		||||
            }
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
      if (error.response && error.response.data?.message === 'Invalid password format') {
 | 
			
		||||
        alert('Password format is invalid. Please try again.');
 | 
			
		||||
            if (error.response && error.response.data?.message === "Invalid password format") {
 | 
			
		||||
                alert("Password format is invalid. Please try again.");
 | 
			
		||||
            } else {
 | 
			
		||||
        alert('Error occurred while changing password.');
 | 
			
		||||
                alert("Error occurred while changing password.");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Handle change API key
 | 
			
		||||
    const handleChangeApiKey = async () => {
 | 
			
		||||
    if (apiKeyError || newApiKey === '') {
 | 
			
		||||
      alert('Please enter a valid API key.');
 | 
			
		||||
        if (apiKeyError || newApiKey === "") {
 | 
			
		||||
            alert("Please enter a valid API key.");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
      const response = await axios.post('/user/change_api_key', {
 | 
			
		||||
            const response = await axios.post("/user/change_api_key", {
 | 
			
		||||
                new_api_key: newApiKey,
 | 
			
		||||
            });
 | 
			
		||||
      if (response.data.message === 'True') {
 | 
			
		||||
        alert('API key changed successfully.');
 | 
			
		||||
            if (response.data.message === "True") {
 | 
			
		||||
                alert("API key changed successfully.");
 | 
			
		||||
                setApiKey(newApiKey);
 | 
			
		||||
        setNewApiKey('');
 | 
			
		||||
                setNewApiKey("");
 | 
			
		||||
            } else {
 | 
			
		||||
        alert('Failed to change API key.');
 | 
			
		||||
                alert("Failed to change API key.");
 | 
			
		||||
            }
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
      alert('Error occurred while changing API key.');
 | 
			
		||||
            alert("Error occurred while changing API key.");
 | 
			
		||||
            console.error(error);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
    <div id="myaccount" className="flex flex-col lg:flex-row gap-4 w-full min-h-full overflow-y-auto p-4">
 | 
			
		||||
        <div
 | 
			
		||||
            id="myaccount"
 | 
			
		||||
            className="flex flex-col lg:flex-row gap-4 w-full min-h-full overflow-y-auto p-4"
 | 
			
		||||
        >
 | 
			
		||||
            <div className="flex-col w-full min-h-164 lg:h-full lg:w-96 border-2 border-yellow-500/50 rounded-2xl p-4 flex items-center overflow-y-auto">
 | 
			
		||||
                <h1 className="text-2xl font-bold text-white border-b-2 border-white p-2 w-full text-center mb-2">
 | 
			
		||||
          {username ? `${username}` : 'My Account'}
 | 
			
		||||
                    {username ? `${username}` : "My Account"}
 | 
			
		||||
                </h1>
 | 
			
		||||
 | 
			
		||||
                {/* API Key Section */}
 | 
			
		||||
                <div className="w-full flex flex-col items-center">
 | 
			
		||||
          <label htmlFor="apiKey" className="text-white font-semibold mb-1">API Key</label>
 | 
			
		||||
                    <label htmlFor="apiKey" className="text-white font-semibold mb-1">
 | 
			
		||||
                        API Key
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                        id="apiKey"
 | 
			
		||||
                        type="text"
 | 
			
		||||
@ -136,7 +144,9 @@ function MyAccount() {
 | 
			
		||||
                    />
 | 
			
		||||
 | 
			
		||||
                    {/* New API Key Section */}
 | 
			
		||||
          <label htmlFor="newApiKey" className="text-white font-semibold mt-4 mb-1">New API Key</label>
 | 
			
		||||
                    <label htmlFor="newApiKey" className="text-white font-semibold mt-4 mb-1">
 | 
			
		||||
                        New API Key
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                        id="newApiKey"
 | 
			
		||||
                        type="text"
 | 
			
		||||
@ -145,9 +155,9 @@ function MyAccount() {
 | 
			
		||||
                            const value = e.target.value;
 | 
			
		||||
                            const isValid = /^[^\s]+$/.test(value); // No spaces
 | 
			
		||||
                            if (!isValid) {
 | 
			
		||||
                setApiKeyError('API key must not contain spaces.');
 | 
			
		||||
                                setApiKeyError("API key must not contain spaces.");
 | 
			
		||||
                            } else {
 | 
			
		||||
                setApiKeyError('');
 | 
			
		||||
                                setApiKeyError("");
 | 
			
		||||
                            }
 | 
			
		||||
                            setNewApiKey(value);
 | 
			
		||||
                        }}
 | 
			
		||||
@ -163,18 +173,23 @@ function MyAccount() {
 | 
			
		||||
                    </button>
 | 
			
		||||
 | 
			
		||||
                    {/* Change Password Section */}
 | 
			
		||||
          <label htmlFor="password" className="text-white font-semibold mt-4 mb-1">Change Password</label>
 | 
			
		||||
                    <label htmlFor="password" className="text-white font-semibold mt-4 mb-1">
 | 
			
		||||
                        Change Password
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                        id="password"
 | 
			
		||||
                        type="password"
 | 
			
		||||
                        value={password}
 | 
			
		||||
                        onChange={(e) => {
 | 
			
		||||
                            const value = e.target.value;
 | 
			
		||||
              const isValid = /^[A-Za-z0-9!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?`~]*$/.test(value);
 | 
			
		||||
                            const isValid =
 | 
			
		||||
                                /^[A-Za-z0-9!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?`~]*$/.test(value);
 | 
			
		||||
                            if (!isValid) {
 | 
			
		||||
                setPasswordError('Password must not contain spaces or invalid characters.');
 | 
			
		||||
                                setPasswordError(
 | 
			
		||||
                                    "Password must not contain spaces or invalid characters."
 | 
			
		||||
                                );
 | 
			
		||||
                            } else {
 | 
			
		||||
                setPasswordError('');
 | 
			
		||||
                                setPasswordError("");
 | 
			
		||||
                            }
 | 
			
		||||
                            setPassword(value);
 | 
			
		||||
                        }}
 | 
			
		||||
@ -201,15 +216,19 @@ function MyAccount() {
 | 
			
		||||
            <div className="flex flex-col w-full lg:ml-2 mt-2 lg:mt-0">
 | 
			
		||||
                {/* Widevine Section */}
 | 
			
		||||
                <div className="border-2 border-yellow-500/50 flex flex-col w-full min-h-1/2 text-center rounded-2xl lg:p-4 p-2 overflow-y-auto">
 | 
			
		||||
          <h1 className="bg-black text-2xl font-bold text-white border-b-2 border-white p-2">Widevine CDMs</h1>
 | 
			
		||||
                    <h1 className="bg-black text-2xl font-bold text-white border-b-2 border-white p-2">
 | 
			
		||||
                        Widevine CDMs
 | 
			
		||||
                    </h1>
 | 
			
		||||
                    <div className="flex flex-col w-full grow p-2 bg-white/5 rounded-2xl mt-2 text-white text-left">
 | 
			
		||||
                        {wvList.length === 0 ? (
 | 
			
		||||
              <div className="text-white text-center font-bold">No Widevine CDMs uploaded.</div>
 | 
			
		||||
                            <div className="text-white text-center font-bold">
 | 
			
		||||
                                No Widevine CDMs uploaded.
 | 
			
		||||
                            </div>
 | 
			
		||||
                        ) : (
 | 
			
		||||
                            wvList.map((filename, i) => (
 | 
			
		||||
                                <div
 | 
			
		||||
                                    key={i}
 | 
			
		||||
                  className={`text-center font-bold text-white p-2 rounded ${i % 2 === 0 ? 'bg-black/30' : 'bg-black/60'}`}
 | 
			
		||||
                                    className={`text-center font-bold text-white p-2 rounded ${i % 2 === 0 ? "bg-black/30" : "bg-black/60"}`}
 | 
			
		||||
                                >
 | 
			
		||||
                                    {filename}
 | 
			
		||||
                                </div>
 | 
			
		||||
@ -217,27 +236,31 @@ function MyAccount() {
 | 
			
		||||
                        )}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <label className="bg-yellow-500 text-white w-full min-h-16 lg:min-h-16 mt-4 rounded-2xl flex items-center justify-center cursor-pointer">
 | 
			
		||||
            {uploading ? 'Uploading...' : 'Upload CDM'}
 | 
			
		||||
                        {uploading ? "Uploading..." : "Upload CDM"}
 | 
			
		||||
                        <input
 | 
			
		||||
                            type="file"
 | 
			
		||||
                            accept=".wvd"
 | 
			
		||||
                            hidden
 | 
			
		||||
              onChange={(e) => handleUpload(e, 'WV')}
 | 
			
		||||
                            onChange={(e) => handleUpload(e, "WV")}
 | 
			
		||||
                        />
 | 
			
		||||
                    </label>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                {/* Playready Section */}
 | 
			
		||||
                <div className="border-2 border-yellow-500/50 flex flex-col w-full min-h-1/2 text-center rounded-2xl p-2 mt-2 lg:mt-2 overflow-y-auto">
 | 
			
		||||
          <h1 className="text-2xl font-bold text-white border-b-2 border-white p-2 bg-black">Playready CDMs</h1>
 | 
			
		||||
                    <h1 className="text-2xl font-bold text-white border-b-2 border-white p-2 bg-black">
 | 
			
		||||
                        Playready CDMs
 | 
			
		||||
                    </h1>
 | 
			
		||||
                    <div className="flex flex-col w-full bg-white/5 grow rounded-2xl mt-2 text-white text-left p-2">
 | 
			
		||||
                        {prList.length === 0 ? (
 | 
			
		||||
              <div className="text-white text-center font-bold">No Playready CDMs uploaded.</div>
 | 
			
		||||
                            <div className="text-white text-center font-bold">
 | 
			
		||||
                                No Playready CDMs uploaded.
 | 
			
		||||
                            </div>
 | 
			
		||||
                        ) : (
 | 
			
		||||
                            prList.map((filename, i) => (
 | 
			
		||||
                                <div
 | 
			
		||||
                                    key={i}
 | 
			
		||||
                  className={`text-center font-bold text-white p-2 rounded ${i % 2 === 0 ? 'bg-black/30' : 'bg-black/60'}`}
 | 
			
		||||
                                    className={`text-center font-bold text-white p-2 rounded ${i % 2 === 0 ? "bg-black/30" : "bg-black/60"}`}
 | 
			
		||||
                                >
 | 
			
		||||
                                    {filename}
 | 
			
		||||
                                </div>
 | 
			
		||||
@ -245,12 +268,12 @@ function MyAccount() {
 | 
			
		||||
                        )}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <label className="bg-yellow-500 text-white w-full min-h-16 lg:min-h-16 mt-4 rounded-2xl flex items-center justify-center cursor-pointer">
 | 
			
		||||
            {uploading ? 'Uploading...' : 'Upload CDM'}
 | 
			
		||||
                        {uploading ? "Uploading..." : "Upload CDM"}
 | 
			
		||||
                        <input
 | 
			
		||||
                            type="file"
 | 
			
		||||
                            accept=".prd"
 | 
			
		||||
                            hidden
 | 
			
		||||
              onChange={(e) => handleUpload(e, 'PR')}
 | 
			
		||||
                            onChange={(e) => handleUpload(e, "PR")}
 | 
			
		||||
                        />
 | 
			
		||||
                    </label>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import React, { useState } from 'react';
 | 
			
		||||
import React, { useState } from "react";
 | 
			
		||||
 | 
			
		||||
function Register() {
 | 
			
		||||
  const [username, setUsername] = useState('');
 | 
			
		||||
  const [password, setPassword] = useState('');
 | 
			
		||||
  const [status, setStatus] = useState('');
 | 
			
		||||
    const [username, setUsername] = useState("");
 | 
			
		||||
    const [password, setPassword] = useState("");
 | 
			
		||||
    const [status, setStatus] = useState("");
 | 
			
		||||
 | 
			
		||||
    // Validation functions
 | 
			
		||||
    const validateUsername = (name) => /^[A-Za-z0-9_-]+$/.test(name);
 | 
			
		||||
@ -20,12 +20,12 @@ function Register() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
      const response = await fetch('/register', {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
            const response = await fetch("/register", {
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                headers: {
 | 
			
		||||
          'Content-Type': 'application/json'
 | 
			
		||||
                    "Content-Type": "application/json",
 | 
			
		||||
                },
 | 
			
		||||
        body: JSON.stringify({ username, password })
 | 
			
		||||
                body: JSON.stringify({ username, password }),
 | 
			
		||||
            });
 | 
			
		||||
            const data = await response.json();
 | 
			
		||||
            if (data.message) {
 | 
			
		||||
@ -34,7 +34,7 @@ function Register() {
 | 
			
		||||
                setStatus(data.error);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
      setStatus('An error occurred while registering.');
 | 
			
		||||
            setStatus("An error occurred while registering.");
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -49,13 +49,13 @@ function Register() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
      const response = await fetch('/login', {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
            const response = await fetch("/login", {
 | 
			
		||||
                method: "POST",
 | 
			
		||||
                headers: {
 | 
			
		||||
          'Content-Type': 'application/json'
 | 
			
		||||
                    "Content-Type": "application/json",
 | 
			
		||||
                },
 | 
			
		||||
        credentials: 'include', // Important to send cookies
 | 
			
		||||
        body: JSON.stringify({ username, password })
 | 
			
		||||
                credentials: "include", // Important to send cookies
 | 
			
		||||
                body: JSON.stringify({ username, password }),
 | 
			
		||||
            });
 | 
			
		||||
            const data = await response.json();
 | 
			
		||||
            if (data.message) {
 | 
			
		||||
@ -65,7 +65,7 @@ function Register() {
 | 
			
		||||
                setStatus(data.error);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
      setStatus('An error occurred while logging in.');
 | 
			
		||||
            setStatus("An error occurred while logging in.");
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -73,19 +73,23 @@ function Register() {
 | 
			
		||||
        <div className="flex flex-col w-full h-full items-center justify-center p-4">
 | 
			
		||||
            <div className="flex flex-col w-full h-full lg:w-1/2 lg:h-96 border-2 border-yellow-500/50 rounded-2xl p-4 overflow-x-auto justify-center items-center">
 | 
			
		||||
                <div className="flex flex-col w-full">
 | 
			
		||||
          <label htmlFor="username" className="text-lg font-bold mb-2 text-white">Username:</label>
 | 
			
		||||
                    <label htmlFor="username" className="text-lg font-bold mb-2 text-white">
 | 
			
		||||
                        Username:
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        value={username}
 | 
			
		||||
            onChange={e => setUsername(e.target.value)}
 | 
			
		||||
                        onChange={(e) => setUsername(e.target.value)}
 | 
			
		||||
                        placeholder="Username"
 | 
			
		||||
                        className="mb-4 p-2 border border-gray-300 rounded text-white bg-transparent"
 | 
			
		||||
                    />
 | 
			
		||||
          <label htmlFor="password" className="text-lg font-bold mb-2 text-white">Password:</label>
 | 
			
		||||
                    <label htmlFor="password" className="text-lg font-bold mb-2 text-white">
 | 
			
		||||
                        Password:
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                        type="password"
 | 
			
		||||
                        value={password}
 | 
			
		||||
            onChange={e => setPassword(e.target.value)}
 | 
			
		||||
                        onChange={(e) => setPassword(e.target.value)}
 | 
			
		||||
                        placeholder="Password"
 | 
			
		||||
                        className="mb-4 p-2 border border-gray-300 rounded text-white bg-transparent"
 | 
			
		||||
                    />
 | 
			
		||||
@ -104,11 +108,7 @@ function Register() {
 | 
			
		||||
                        Register
 | 
			
		||||
                    </button>
 | 
			
		||||
                </div>
 | 
			
		||||
        {status && (
 | 
			
		||||
          <p className="text-sm text-white mt-4 p-4">
 | 
			
		||||
            {status}
 | 
			
		||||
          </p>
 | 
			
		||||
        )}
 | 
			
		||||
                {status && <p className="text-sm text-white mt-4 p-4">{status}</p>}
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,12 @@
 | 
			
		||||
import React, { useState, useEffect, useRef } from 'react';
 | 
			
		||||
import shaka from 'shaka-player';
 | 
			
		||||
import { Helmet } from 'react-helmet'; // Import Helmet
 | 
			
		||||
import React, { useState, useEffect, useRef } from "react";
 | 
			
		||||
import shaka from "shaka-player";
 | 
			
		||||
import { Helmet } from "react-helmet"; // Import Helmet
 | 
			
		||||
 | 
			
		||||
function TestPlayer() {
 | 
			
		||||
  const [mpdUrl, setMpdUrl] = useState(''); // State to hold the MPD URL
 | 
			
		||||
  const [kids, setKids] = useState(''); // State to hold KIDs (separated by line breaks)
 | 
			
		||||
  const [keys, setKeys] = useState(''); // State to hold Keys (separated by line breaks)
 | 
			
		||||
  const [headers, setHeaders] = useState(''); // State to hold request headers
 | 
			
		||||
    const [mpdUrl, setMpdUrl] = useState(""); // State to hold the MPD URL
 | 
			
		||||
    const [kids, setKids] = useState(""); // State to hold KIDs (separated by line breaks)
 | 
			
		||||
    const [keys, setKeys] = useState(""); // State to hold Keys (separated by line breaks)
 | 
			
		||||
    const [headers, setHeaders] = useState(""); // State to hold request headers
 | 
			
		||||
 | 
			
		||||
    const videoRef = useRef(null); // Ref for the video element
 | 
			
		||||
    const playerRef = useRef(null); // Ref for Shaka Player instance
 | 
			
		||||
@ -38,8 +38,8 @@ function TestPlayer() {
 | 
			
		||||
                playerRef.current = player;
 | 
			
		||||
 | 
			
		||||
                // Add error listener
 | 
			
		||||
        player.addEventListener('error', (event) => {
 | 
			
		||||
          console.error('Error code', event.detail.code, 'object', event.detail);
 | 
			
		||||
                player.addEventListener("error", (event) => {
 | 
			
		||||
                    console.error("Error code", event.detail.code, "object", event.detail);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -78,13 +78,16 @@ function TestPlayer() {
 | 
			
		||||
            player.configure(config);
 | 
			
		||||
 | 
			
		||||
            // Load the video stream with MPD URL
 | 
			
		||||
      player.load(mpdUrl).then(() => {
 | 
			
		||||
        console.log('Video loaded');
 | 
			
		||||
      }).catch((error) => {
 | 
			
		||||
        console.error('Error loading the video', error);
 | 
			
		||||
            player
 | 
			
		||||
                .load(mpdUrl)
 | 
			
		||||
                .then(() => {
 | 
			
		||||
                    console.log("Video loaded");
 | 
			
		||||
                })
 | 
			
		||||
                .catch((error) => {
 | 
			
		||||
                    console.error("Error loading the video", error);
 | 
			
		||||
                });
 | 
			
		||||
        } else {
 | 
			
		||||
      console.error('MPD URL, KIDs, and Keys are required.');
 | 
			
		||||
            console.error("MPD URL, KIDs, and Keys are required.");
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -95,10 +98,10 @@ function TestPlayer() {
 | 
			
		||||
 | 
			
		||||
    // Helper function to parse headers from the textarea input
 | 
			
		||||
    const parseHeaders = (headersText) => {
 | 
			
		||||
    const headersArr = headersText.split('\n');
 | 
			
		||||
        const headersArr = headersText.split("\n");
 | 
			
		||||
        const headersObj = {};
 | 
			
		||||
        headersArr.forEach((line) => {
 | 
			
		||||
      const [key, value] = line.split(':');
 | 
			
		||||
            const [key, value] = line.split(":");
 | 
			
		||||
            if (key && value) {
 | 
			
		||||
                headersObj[key.trim()] = value.trim();
 | 
			
		||||
            }
 | 
			
		||||
@ -112,13 +115,7 @@ function TestPlayer() {
 | 
			
		||||
                <title>Test Player</title>
 | 
			
		||||
            </Helmet>
 | 
			
		||||
            <div className="w-full flex flex-col">
 | 
			
		||||
        <video
 | 
			
		||||
          ref={videoRef}
 | 
			
		||||
          width="100%"
 | 
			
		||||
          height="auto"
 | 
			
		||||
          controls
 | 
			
		||||
          className="h-96"
 | 
			
		||||
        />
 | 
			
		||||
                <video ref={videoRef} width="100%" height="auto" controls className="h-96" />
 | 
			
		||||
                <input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    value={mpdUrl}
 | 
			
		||||
@ -144,10 +141,7 @@ function TestPlayer() {
 | 
			
		||||
                    onChange={handleHeadersChange}
 | 
			
		||||
                    className="border-2 border-rose-700/50 mt-2 text-white p-1 overflow-y-auto rounded transition-all ease-in-out focus:outline-none focus:ring-2 focus:ring-rose-700/50 duration-200"
 | 
			
		||||
                />
 | 
			
		||||
        <button
 | 
			
		||||
          onClick={handleSubmit}
 | 
			
		||||
          className="mt-4 p-2 bg-blue-500 text-white rounded"
 | 
			
		||||
        >
 | 
			
		||||
                <button onClick={handleSubmit} className="mt-4 p-2 bg-blue-500 text-white rounded">
 | 
			
		||||
                    Submit
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
@ -1,35 +1,35 @@
 | 
			
		||||
import { useEffect, useState } from 'react';
 | 
			
		||||
import { NavLink } from 'react-router-dom';
 | 
			
		||||
import closeIcon from '../assets/icons/close.svg';
 | 
			
		||||
import homeIcon from '../assets/icons/home.svg';
 | 
			
		||||
import cacheIcon from '../assets/icons/cache.svg';
 | 
			
		||||
import apiIcon from '../assets/icons/api.svg';
 | 
			
		||||
import testPlayerIcon from '../assets/icons/testplayer.svg'; 
 | 
			
		||||
import accountIcon from '../assets/icons/account.svg'; 
 | 
			
		||||
import discordIcon from '../assets/icons/discord.svg';
 | 
			
		||||
import telegramIcon from '../assets/icons/telegram.svg';
 | 
			
		||||
import giteaIcon from '../assets/icons/gitea.svg';
 | 
			
		||||
import { useEffect, useState } from "react";
 | 
			
		||||
import { NavLink } from "react-router-dom";
 | 
			
		||||
import closeIcon from "../assets/icons/close.svg";
 | 
			
		||||
import homeIcon from "../assets/icons/home.svg";
 | 
			
		||||
import cacheIcon from "../assets/icons/cache.svg";
 | 
			
		||||
import apiIcon from "../assets/icons/api.svg";
 | 
			
		||||
import testPlayerIcon from "../assets/icons/testplayer.svg";
 | 
			
		||||
import accountIcon from "../assets/icons/account.svg";
 | 
			
		||||
import discordIcon from "../assets/icons/discord.svg";
 | 
			
		||||
import telegramIcon from "../assets/icons/telegram.svg";
 | 
			
		||||
import giteaIcon from "../assets/icons/gitea.svg";
 | 
			
		||||
 | 
			
		||||
function SideMenu({ isMenuOpen, setIsMenuOpen }) {
 | 
			
		||||
    const [externalLinks, setExternalLinks] = useState({
 | 
			
		||||
    discord: '#',
 | 
			
		||||
    telegram: '#',
 | 
			
		||||
    gitea: '#',
 | 
			
		||||
        discord: "#",
 | 
			
		||||
        telegram: "#",
 | 
			
		||||
        gitea: "#",
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
    fetch('/api/links')
 | 
			
		||||
        fetch("/api/links")
 | 
			
		||||
            .then((res) => res.json())
 | 
			
		||||
            .then((data) => setExternalLinks(data))
 | 
			
		||||
      .catch((err) => console.error('Failed to fetch links:', err));
 | 
			
		||||
            .catch((err) => console.error("Failed to fetch links:", err));
 | 
			
		||||
    }, []);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div
 | 
			
		||||
            className={`flex flex-col fixed top-0 left-0 w-full h-full bg-black transition-transform transform ${
 | 
			
		||||
        isMenuOpen ? 'translate-x-0' : '-translate-x-full'
 | 
			
		||||
                isMenuOpen ? "translate-x-0" : "-translate-x-full"
 | 
			
		||||
            } z-50`}
 | 
			
		||||
      style={{ transitionDuration: '0.3s' }}
 | 
			
		||||
            style={{ transitionDuration: "0.3s" }}
 | 
			
		||||
        >
 | 
			
		||||
            <div className="flex flex-col bg-gray-950/55 h-full">
 | 
			
		||||
                {/* Header */}
 | 
			
		||||
@ -43,7 +43,11 @@ function SideMenu({ isMenuOpen, setIsMenuOpen }) {
 | 
			
		||||
                            className="w-full h-full flex items-center justify-center"
 | 
			
		||||
                            onClick={() => setIsMenuOpen(false)}
 | 
			
		||||
                        >
 | 
			
		||||
              <img src={closeIcon} alt="Close" className="w-1/2 h-1/2 cursor-pointer" />
 | 
			
		||||
                            <img
 | 
			
		||||
                                src={closeIcon}
 | 
			
		||||
                                alt="Close"
 | 
			
		||||
                                className="w-1/2 h-1/2 cursor-pointer"
 | 
			
		||||
                            />
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
@ -56,8 +60,8 @@ function SideMenu({ isMenuOpen, setIsMenuOpen }) {
 | 
			
		||||
                            className={({ isActive }) =>
 | 
			
		||||
                                `flex flex-row items-center gap-3 p-3 border-l-4 ${
 | 
			
		||||
                                    isActive
 | 
			
		||||
                    ? 'border-l-sky-500/50 bg-black/50 text-white'
 | 
			
		||||
                    : 'border-transparent hover:border-l-sky-500/50 hover:bg-white/5 text-white/80'
 | 
			
		||||
                                        ? "border-l-sky-500/50 bg-black/50 text-white"
 | 
			
		||||
                                        : "border-transparent hover:border-l-sky-500/50 hover:bg-white/5 text-white/80"
 | 
			
		||||
                                }`
 | 
			
		||||
                            }
 | 
			
		||||
                            onClick={() => setIsMenuOpen(false)}
 | 
			
		||||
@ -71,8 +75,8 @@ function SideMenu({ isMenuOpen, setIsMenuOpen }) {
 | 
			
		||||
                            className={({ isActive }) =>
 | 
			
		||||
                                `flex flex-row items-center gap-3 p-3 border-l-4 ${
 | 
			
		||||
                                    isActive
 | 
			
		||||
                    ? 'border-l-emerald-500/50 bg-black/50 text-white'
 | 
			
		||||
                    : 'border-transparent hover:border-l-emerald-500/50 hover:bg-white/5 text-white/80'
 | 
			
		||||
                                        ? "border-l-emerald-500/50 bg-black/50 text-white"
 | 
			
		||||
                                        : "border-transparent hover:border-l-emerald-500/50 hover:bg-white/5 text-white/80"
 | 
			
		||||
                                }`
 | 
			
		||||
                            }
 | 
			
		||||
                            onClick={() => setIsMenuOpen(false)}
 | 
			
		||||
@ -86,8 +90,8 @@ function SideMenu({ isMenuOpen, setIsMenuOpen }) {
 | 
			
		||||
                            className={({ isActive }) =>
 | 
			
		||||
                                `flex flex-row items-center gap-3 p-3 border-l-4 ${
 | 
			
		||||
                                    isActive
 | 
			
		||||
                    ? 'border-l-indigo-500/50 bg-black/50 text-white'
 | 
			
		||||
                    : 'border-transparent hover:border-l-indigo-500/50 hover:bg-white/5 text-white/80'
 | 
			
		||||
                                        ? "border-l-indigo-500/50 bg-black/50 text-white"
 | 
			
		||||
                                        : "border-transparent hover:border-l-indigo-500/50 hover:bg-white/5 text-white/80"
 | 
			
		||||
                                }`
 | 
			
		||||
                            }
 | 
			
		||||
                            onClick={() => setIsMenuOpen(false)}
 | 
			
		||||
@ -101,8 +105,8 @@ function SideMenu({ isMenuOpen, setIsMenuOpen }) {
 | 
			
		||||
                            className={({ isActive }) =>
 | 
			
		||||
                                `flex flex-row items-center gap-3 p-3 border-l-4 ${
 | 
			
		||||
                                    isActive
 | 
			
		||||
                    ? 'border-l-rose-700/50 bg-black/50 text-white'
 | 
			
		||||
                    : 'border-transparent hover:border-l-rose-700/50 hover:bg-white/5 text-white/80'
 | 
			
		||||
                                        ? "border-l-rose-700/50 bg-black/50 text-white"
 | 
			
		||||
                                        : "border-transparent hover:border-l-rose-700/50 hover:bg-white/5 text-white/80"
 | 
			
		||||
                                }`
 | 
			
		||||
                            }
 | 
			
		||||
                            onClick={() => setIsMenuOpen(false)}
 | 
			
		||||
@ -119,8 +123,8 @@ function SideMenu({ isMenuOpen, setIsMenuOpen }) {
 | 
			
		||||
                            className={({ isActive }) =>
 | 
			
		||||
                                `flex flex-row items-center gap-3 p-3 border-l-4 ${
 | 
			
		||||
                                    isActive
 | 
			
		||||
                    ? 'border-l-yellow-500/50 bg-black/50 text-white'
 | 
			
		||||
                    : 'border-transparent hover:border-l-yellow-500/50 hover:bg-white/5 text-white/80'
 | 
			
		||||
                                        ? "border-l-yellow-500/50 bg-black/50 text-white"
 | 
			
		||||
                                        : "border-transparent hover:border-l-yellow-500/50 hover:bg-white/5 text-white/80"
 | 
			
		||||
                                }`
 | 
			
		||||
                            }
 | 
			
		||||
                            onClick={() => setIsMenuOpen(false)}
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,9 @@
 | 
			
		||||
 | 
			
		||||
details summary::-webkit-details-marker {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  details summary {
 | 
			
		||||
details summary {
 | 
			
		||||
    list-style: none;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,13 @@
 | 
			
		||||
import { StrictMode } from 'react'
 | 
			
		||||
import { createRoot } from 'react-dom/client'
 | 
			
		||||
import { BrowserRouter } from 'react-router-dom'
 | 
			
		||||
import './index.css'
 | 
			
		||||
import App from './App.jsx'
 | 
			
		||||
import { StrictMode } from "react";
 | 
			
		||||
import { createRoot } from "react-dom/client";
 | 
			
		||||
import { BrowserRouter } from "react-router-dom";
 | 
			
		||||
import "./index.css";
 | 
			
		||||
import App from "./App.jsx";
 | 
			
		||||
 | 
			
		||||
createRoot(document.getElementById('root')).render(
 | 
			
		||||
createRoot(document.getElementById("root")).render(
 | 
			
		||||
    <StrictMode>
 | 
			
		||||
        <BrowserRouter>
 | 
			
		||||
            <App />
 | 
			
		||||
        </BrowserRouter>
 | 
			
		||||
    </StrictMode>
 | 
			
		||||
)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { defineConfig } from 'vite'
 | 
			
		||||
import react from '@vitejs/plugin-react'
 | 
			
		||||
import tailwindcss from '@tailwindcss/vite'
 | 
			
		||||
import { defineConfig } from "vite";
 | 
			
		||||
import react from "@vitejs/plugin-react";
 | 
			
		||||
import tailwindcss from "@tailwindcss/vite";
 | 
			
		||||
 | 
			
		||||
// https://vite.dev/config/
 | 
			
		||||
export default defineConfig({
 | 
			
		||||
    plugins: [react(), tailwindcss()],
 | 
			
		||||
})
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user