commit 08b110b285c63067e764d6813aa9ccee4489b8f1 Author: MCHost Date: Thu Jul 3 00:26:07 2025 -0400 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..37d7e73 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.env diff --git a/README.md b/README.md new file mode 100644 index 0000000..96e9417 --- /dev/null +++ b/README.md @@ -0,0 +1,112 @@ +# Minecraft Server Status Checker + +A web application to check the status of Minecraft Java and Bedrock Edition servers. Built with Node.js, Express, and Tailwind CSS, it provides a sleek, modern interface with particle animations and confetti effects for a delightful user experience. + +## Features + +- Check status for Minecraft Java and Bedrock Edition servers. +- Displays server details like version, player count, MOTD, and more. +- Responsive design with Tailwind CSS. +- Interactive particle background using tsParticles. +- Confetti celebration on successful server status checks. +- URL-based server checks for direct access. +- Environment variable support for configuration. + +## Prerequisites + +- [Node.js](https://nodejs.org/) (v16 or higher) +- [npm](https://www.npmjs.com/) (v7 or higher) +- Status check binaries (configured via environment variables) + +## Installation + +1. **Clone the repository**: + + ```bash + git clone https://git.ssh.surf/hypermc/status-check.git + cd status-check + ``` + +2. **Install dependencies**: + + ```bash + npm install + ``` + +3. **Set up environment variables**: + + Create a `.env` file in the root directory and configure the paths to your status check binaries: + + ```env + STATUS_CHECK_PATH=/path/to/java-status-check + GEYSER_STATUS_CHECK_PATH=/path/to/bedrock-status-check + ``` + + Ensure the binaries are executable and return JSON output as expected by the application. + +4. **Build CSS** (if modifying `style.css`): + + Ensure Tailwind CSS is set up. If you have `tailwindcss` installed globally: + + ```bash + npx tailwindcss -i public/css/style.css -o public/css/style.min.css --minify + ``` + + Alternatively, use the provided `style.min.css` for production. + +5. **Run the application**: + + ```bash + node status_site.js + ``` + + The server will start at `http://localhost:3066`. + +## Usage + +1. Open `http://localhost:3066` in your browser. +2. Select the server edition (Java or Bedrock). +3. Enter the connection string in the format `host:port` (e.g., `example.com:25565`). +4. Click "Check Status" to view the server status. +5. Alternatively, use a direct URL like `http://localhost:3066/java/example.com/25565` to check a server. + +## Project Structure + +``` +minecraft-server-status-checker/ +├── public/ +│ ├── css/ +│ │ ├── style.css # Tailwind CSS source +│ │ └── style.min.css # Minified CSS output +│ ├── js/ +│ │ └── app.js # Client-side JavaScript +│ ├── favicon/ # Favicon assets +│ └── index.html # Main HTML page +├── .env # Environment variables (not tracked) +├── status_site.js # Express server +├── package.json # Node.js dependencies +└── README.md # This file +``` + +## Dependencies + +- **Backend**: + - [express](https://expressjs.com/) - Web framework + - [dotenv](https://www.npmjs.com/package/dotenv) - Environment variable management + - [child_process](https://nodejs.org/api/child_process.html) - For executing status check binaries + +- **Frontend**: + - [Tailwind CSS](https://tailwindcss.com/) - Styling + - [tsParticles](https://particles.js.org/) - Particle animations + - [canvas-confetti](https://www.npmjs.com/package/canvas-confetti) - Confetti effects + +## Configuration + +The application relies on two environment variables: + +https://git.ssh.surf/hypermc/mc-status + +- `STATUS_CHECK_PATH`: Path to the Java Edition status check binary. +- `GEYSER_STATUS_CHECK_PATH`: Path to the Bedrock Edition status check binary. + +These binaries should accept `-host` and `-port` arguments and output JSON data. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..e69de29 diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..734d350 --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,50 @@ +@import "tailwindcss"; + +@keyframes pulse { + + 0%, + 100% { + transform: scale(1); + opacity: 0.7; + } + + 50% { + transform: scale(1.05); + opacity: 1; + } +} + +@keyframes slideIn { + from { + transform: translateY(-20px); + opacity: 0; + } + + to { + transform: translateY(0); + opacity: 1; + } +} + +.animate-pulse-custom { + animation: pulse 2s infinite; +} + +.animate-slide-in { + animation: slideIn 0.5s ease-out; +} + +.gradient-bg { + background: linear-gradient(135deg, #1e3a8a, #6b21a8, #be185d); +} + +.glass { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(10px); +} + +/* Ensure gradient text works across browsers */ +.bg-clip-text { + -webkit-background-clip: text; + background-clip: text; +} \ No newline at end of file diff --git a/public/css/style.min.css b/public/css/style.min.css new file mode 100644 index 0000000..7663e42 --- /dev/null +++ b/public/css/style.min.css @@ -0,0 +1,1319 @@ +/*! tailwindcss v4.1.11 | MIT License | https://tailwindcss.com */ +@layer properties; +@layer theme, base, components, utilities; +@layer theme { + :root, :host { + --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; + --color-red-400: oklch(70.4% 0.191 22.216); + --color-red-500: oklch(63.7% 0.237 25.331); + --color-red-600: oklch(57.7% 0.245 27.325); + --color-red-700: oklch(50.5% 0.213 27.518); + --color-yellow-600: oklch(68.1% 0.162 75.834); + --color-yellow-700: oklch(55.4% 0.135 66.442); + --color-green-400: oklch(79.2% 0.209 151.711); + --color-green-600: oklch(62.7% 0.194 149.214); + --color-green-700: oklch(52.7% 0.154 150.069); + --color-teal-600: oklch(60% 0.118 184.704); + --color-teal-700: oklch(51.1% 0.096 186.391); + --color-cyan-600: oklch(60.9% 0.126 221.723); + --color-cyan-700: oklch(52% 0.105 223.128); + --color-blue-400: oklch(70.7% 0.165 254.624); + --color-blue-500: oklch(62.3% 0.214 259.815); + --color-blue-600: oklch(54.6% 0.245 262.881); + --color-blue-700: oklch(48.8% 0.243 264.376); + --color-purple-600: oklch(55.8% 0.288 302.321); + --color-purple-700: oklch(49.6% 0.265 301.924); + --color-gray-100: oklch(96.7% 0.003 264.542); + --color-gray-200: oklch(92.8% 0.006 264.531); + --color-gray-300: oklch(87.2% 0.01 258.338); + --color-gray-400: oklch(70.7% 0.022 261.325); + --color-gray-500: oklch(55.1% 0.027 264.364); + --color-gray-600: oklch(44.6% 0.03 256.802); + --color-gray-700: oklch(37.3% 0.034 259.733); + --color-gray-800: oklch(27.8% 0.033 256.848); + --color-gray-900: oklch(21% 0.034 264.665); + --color-black: #000; + --color-white: #fff; + --spacing: 0.25rem; + --container-md: 28rem; + --container-lg: 32rem; + --container-xl: 36rem; + --container-7xl: 80rem; + --text-xs: 0.75rem; + --text-xs--line-height: calc(1 / 0.75); + --text-sm: 0.875rem; + --text-sm--line-height: calc(1.25 / 0.875); + --text-base: 1rem; + --text-base--line-height: calc(1.5 / 1); + --text-lg: 1.125rem; + --text-lg--line-height: calc(1.75 / 1.125); + --text-xl: 1.25rem; + --text-xl--line-height: calc(1.75 / 1.25); + --text-2xl: 1.5rem; + --text-2xl--line-height: calc(2 / 1.5); + --text-4xl: 2.25rem; + --text-4xl--line-height: calc(2.5 / 2.25); + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + --tracking-tight: -0.025em; + --leading-relaxed: 1.625; + --radius-md: 0.375rem; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + --radius-2xl: 1rem; + --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); + --animate-spin: spin 1s linear infinite; + --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + --blur-md: 12px; + --default-transition-duration: 150ms; + --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + --default-font-family: var(--font-sans); + --default-mono-font-family: var(--font-mono); + } +} +@layer base { + *, ::after, ::before, ::backdrop, ::file-selector-button { + box-sizing: border-box; + margin: 0; + padding: 0; + border: 0 solid; + } + html, :host { + line-height: 1.5; + -webkit-text-size-adjust: 100%; + tab-size: 4; + font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); + font-feature-settings: var(--default-font-feature-settings, normal); + font-variation-settings: var(--default-font-variation-settings, normal); + -webkit-tap-highlight-color: transparent; + } + hr { + height: 0; + color: inherit; + border-top-width: 1px; + } + abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + } + h1, h2, h3, h4, h5, h6 { + font-size: inherit; + font-weight: inherit; + } + a { + color: inherit; + -webkit-text-decoration: inherit; + text-decoration: inherit; + } + b, strong { + font-weight: bolder; + } + code, kbd, samp, pre { + font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); + font-feature-settings: var(--default-mono-font-feature-settings, normal); + font-variation-settings: var(--default-mono-font-variation-settings, normal); + font-size: 1em; + } + small { + font-size: 80%; + } + sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + sub { + bottom: -0.25em; + } + sup { + top: -0.5em; + } + table { + text-indent: 0; + border-color: inherit; + border-collapse: collapse; + } + :-moz-focusring { + outline: auto; + } + progress { + vertical-align: baseline; + } + summary { + display: list-item; + } + ol, ul, menu { + list-style: none; + } + img, svg, video, canvas, audio, iframe, embed, object { + display: block; + vertical-align: middle; + } + img, video { + max-width: 100%; + height: auto; + } + button, input, select, optgroup, textarea, ::file-selector-button { + font: inherit; + font-feature-settings: inherit; + font-variation-settings: inherit; + letter-spacing: inherit; + color: inherit; + border-radius: 0; + background-color: transparent; + opacity: 1; + } + :where(select:is([multiple], [size])) optgroup { + font-weight: bolder; + } + :where(select:is([multiple], [size])) optgroup option { + padding-inline-start: 20px; + } + ::file-selector-button { + margin-inline-end: 4px; + } + ::placeholder { + opacity: 1; + } + @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) { + ::placeholder { + color: currentcolor; + @supports (color: color-mix(in lab, red, red)) { + color: color-mix(in oklab, currentcolor 50%, transparent); + } + } + } + textarea { + resize: vertical; + } + ::-webkit-search-decoration { + -webkit-appearance: none; + } + ::-webkit-date-and-time-value { + min-height: 1lh; + text-align: inherit; + } + ::-webkit-datetime-edit { + display: inline-flex; + } + ::-webkit-datetime-edit-fields-wrapper { + padding: 0; + } + ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field { + padding-block: 0; + } + :-moz-ui-invalid { + box-shadow: none; + } + button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button { + appearance: button; + } + ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { + height: auto; + } + [hidden]:where(:not([hidden="until-found"])) { + display: none !important; + } +} +@layer utilities { + .collapse { + visibility: collapse; + } + .invisible { + visibility: hidden; + } + .visible { + visibility: visible; + } + .absolute { + position: absolute; + } + .fixed { + position: fixed; + } + .relative { + position: relative; + } + .static { + position: static; + } + .sticky { + position: sticky; + } + .inset-0 { + inset: calc(var(--spacing) * 0); + } + .z-0 { + z-index: 0; + } + .z-10 { + z-index: 10; + } + .z-50 { + z-index: 50; + } + .container { + width: 100%; + @media (width >= 40rem) { + max-width: 40rem; + } + @media (width >= 48rem) { + max-width: 48rem; + } + @media (width >= 64rem) { + max-width: 64rem; + } + @media (width >= 80rem) { + max-width: 80rem; + } + @media (width >= 96rem) { + max-width: 96rem; + } + } + .mx-auto { + margin-inline: auto; + } + .mt-1 { + margin-top: calc(var(--spacing) * 1); + } + .mt-2 { + margin-top: calc(var(--spacing) * 2); + } + .mt-4 { + margin-top: calc(var(--spacing) * 4); + } + .mt-8 { + margin-top: calc(var(--spacing) * 8); + } + .mr-2 { + margin-right: calc(var(--spacing) * 2); + } + .mb-1 { + margin-bottom: calc(var(--spacing) * 1); + } + .mb-2 { + margin-bottom: calc(var(--spacing) * 2); + } + .mb-3 { + margin-bottom: calc(var(--spacing) * 3); + } + .mb-4 { + margin-bottom: calc(var(--spacing) * 4); + } + .mb-6 { + margin-bottom: calc(var(--spacing) * 6); + } + .ml-2 { + margin-left: calc(var(--spacing) * 2); + } + .ml-4 { + margin-left: calc(var(--spacing) * 4); + } + .block { + display: block; + } + .contents { + display: contents; + } + .flex { + display: flex; + } + .grid { + display: grid; + } + .hidden { + display: none; + } + .inline { + display: inline; + } + .inline-block { + display: inline-block; + } + .table { + display: table; + } + .h-5 { + height: calc(var(--spacing) * 5); + } + .h-24 { + height: calc(var(--spacing) * 24); + } + .h-48 { + height: calc(var(--spacing) * 48); + } + .h-full { + height: 100%; + } + .max-h-\[95vh\] { + max-height: 95vh; + } + .max-h-\[calc\(95vh-10rem\)\] { + max-height: calc(95vh - 10rem); + } + .min-h-full { + min-height: 100%; + } + .min-h-screen { + min-height: 100vh; + } + .w-1\/3 { + width: calc(1/3 * 100%); + } + .w-2\/3 { + width: calc(2/3 * 100%); + } + .w-5 { + width: calc(var(--spacing) * 5); + } + .w-20 { + width: calc(var(--spacing) * 20); + } + .w-32 { + width: calc(var(--spacing) * 32); + } + .w-full { + width: 100%; + } + .max-w-7xl { + max-width: var(--container-7xl); + } + .max-w-\[95\%\] { + max-width: 95%; + } + .max-w-lg { + max-width: var(--container-lg); + } + .max-w-md { + max-width: var(--container-md); + } + .flex-1 { + flex: 1; + } + .flex-grow { + flex-grow: 1; + } + .grow { + flex-grow: 1; + } + .transform { + transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); + } + .animate-pulse { + animation: var(--animate-pulse); + } + .cursor-not-allowed { + cursor: not-allowed; + } + .resize { + resize: both; + } + .list-inside { + list-style-position: inside; + } + .list-decimal { + list-style-type: decimal; + } + .list-disc { + list-style-type: disc; + } + .grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); + } + .flex-col { + flex-direction: column; + } + .flex-wrap { + flex-wrap: wrap; + } + .items-baseline { + align-items: baseline; + } + .items-center { + align-items: center; + } + .justify-between { + justify-content: space-between; + } + .justify-center { + justify-content: center; + } + .justify-end { + justify-content: flex-end; + } + .justify-start { + justify-content: flex-start; + } + .gap-2 { + gap: calc(var(--spacing) * 2); + } + .gap-4 { + gap: calc(var(--spacing) * 4); + } + .gap-5 { + gap: calc(var(--spacing) * 5); + } + .gap-10 { + gap: calc(var(--spacing) * 10); + } + .gap-15 { + gap: calc(var(--spacing) * 15); + } + .gap-20 { + gap: calc(var(--spacing) * 20); + } + .space-y-1 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-y-2 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-y-4 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-y-6 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse))); + } + } + .space-x-1 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 1) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-x-reverse))); + } + } + .space-x-2 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 2) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-x-reverse))); + } + } + .space-x-4 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 4) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-x-reverse))); + } + } + .truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .overflow-hidden { + overflow: hidden; + } + .overflow-x-auto { + overflow-x: auto; + } + .overflow-x-hidden { + overflow-x: hidden; + } + .overflow-y-auto { + overflow-y: auto; + } + .rounded { + border-radius: 0.25rem; + } + .rounded-2xl { + border-radius: var(--radius-2xl); + } + .rounded-full { + border-radius: calc(infinity * 1px); + } + .rounded-lg { + border-radius: var(--radius-lg); + } + .rounded-md { + border-radius: var(--radius-md); + } + .rounded-xl { + border-radius: var(--radius-xl); + } + .border { + border-style: var(--tw-border-style); + border-width: 1px; + } + .border-t { + border-top-style: var(--tw-border-style); + border-top-width: 1px; + } + .border-b { + border-bottom-style: var(--tw-border-style); + border-bottom-width: 1px; + } + .border-gray-500 { + border-color: var(--color-gray-500); + } + .border-gray-600 { + border-color: var(--color-gray-600); + } + .bg-black { + background-color: var(--color-black); + } + .bg-blue-600 { + background-color: var(--color-blue-600); + } + .bg-cyan-600 { + background-color: var(--color-cyan-600); + } + .bg-gray-600 { + background-color: var(--color-gray-600); + } + .bg-gray-700 { + background-color: var(--color-gray-700); + } + .bg-gray-700\/50 { + background-color: color-mix(in srgb, oklch(37.3% 0.034 259.733) 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-gray-700) 50%, transparent); + } + } + .bg-gray-800 { + background-color: var(--color-gray-800); + } + .bg-gray-800\/50 { + background-color: color-mix(in srgb, oklch(27.8% 0.033 256.848) 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-gray-800) 50%, transparent); + } + } + .bg-gray-800\/80 { + background-color: color-mix(in srgb, oklch(27.8% 0.033 256.848) 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-gray-800) 80%, transparent); + } + } + .bg-gray-900 { + background-color: var(--color-gray-900); + } + .bg-green-600 { + background-color: var(--color-green-600); + } + .bg-purple-600 { + background-color: var(--color-purple-600); + } + .bg-red-600 { + background-color: var(--color-red-600); + } + .bg-teal-600 { + background-color: var(--color-teal-600); + } + .bg-white { + background-color: var(--color-white); + } + .bg-yellow-600 { + background-color: var(--color-yellow-600); + } + .p-2 { + padding: calc(var(--spacing) * 2); + } + .p-3 { + padding: calc(var(--spacing) * 3); + } + .p-4 { + padding: calc(var(--spacing) * 4); + } + .p-6 { + padding: calc(var(--spacing) * 6); + } + .p-8 { + padding: calc(var(--spacing) * 8); + } + .px-1 { + padding-inline: calc(var(--spacing) * 1); + } + .px-2 { + padding-inline: calc(var(--spacing) * 2); + } + .px-3 { + padding-inline: calc(var(--spacing) * 3); + } + .px-4 { + padding-inline: calc(var(--spacing) * 4); + } + .px-6 { + padding-inline: calc(var(--spacing) * 6); + } + .py-1 { + padding-block: calc(var(--spacing) * 1); + } + .py-2 { + padding-block: calc(var(--spacing) * 2); + } + .py-3 { + padding-block: calc(var(--spacing) * 3); + } + .py-4 { + padding-block: calc(var(--spacing) * 4); + } + .py-6 { + padding-block: calc(var(--spacing) * 6); + } + .py-12 { + padding-block: calc(var(--spacing) * 12); + } + .pb-2 { + padding-bottom: calc(var(--spacing) * 2); + } + .pl-6 { + padding-left: calc(var(--spacing) * 6); + } + .text-center { + text-align: center; + } + .text-2xl { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); + } + .text-4xl { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + .text-base { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + } + .text-lg { + font-size: var(--text-lg); + line-height: var(--tw-leading, var(--text-lg--line-height)); + } + .text-sm { + font-size: var(--text-sm); + line-height: var(--tw-leading, var(--text-sm--line-height)); + } + .text-xl { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); + } + .text-xs { + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } + .leading-relaxed { + --tw-leading: var(--leading-relaxed); + line-height: var(--leading-relaxed); + } + .font-bold { + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); + } + .font-medium { + --tw-font-weight: var(--font-weight-medium); + font-weight: var(--font-weight-medium); + } + .font-semibold { + --tw-font-weight: var(--font-weight-semibold); + font-weight: var(--font-weight-semibold); + } + .tracking-tight { + --tw-tracking: var(--tracking-tight); + letter-spacing: var(--tracking-tight); + } + .break-words { + overflow-wrap: break-word; + } + .break-all { + word-break: break-all; + } + .whitespace-pre-wrap { + white-space: pre-wrap; + } + .text-blue-400 { + color: var(--color-blue-400); + } + .text-gray-100 { + color: var(--color-gray-100); + } + .text-gray-200 { + color: var(--color-gray-200); + } + .text-gray-300 { + color: var(--color-gray-300); + } + .text-gray-400 { + color: var(--color-gray-400); + } + .text-green-400 { + color: var(--color-green-400); + } + .text-red-400 { + color: var(--color-red-400); + } + .text-red-500 { + color: var(--color-red-500); + } + .text-white { + color: var(--color-white); + } + .lowercase { + text-transform: lowercase; + } + .opacity-50 { + opacity: 50%; + } + .shadow-lg { + --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .shadow-md { + --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .shadow-sm { + --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .shadow-xl { + --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .ring-1 { + --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .ring-gray-600\/50 { + --tw-ring-color: color-mix(in srgb, oklch(44.6% 0.03 256.802) 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --tw-ring-color: color-mix(in oklab, var(--color-gray-600) 50%, transparent); + } + } + .ring-gray-700\/50 { + --tw-ring-color: color-mix(in srgb, oklch(37.3% 0.034 259.733) 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --tw-ring-color: color-mix(in oklab, var(--color-gray-700) 50%, transparent); + } + } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } + .blur { + --tw-blur: blur(8px); + filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); + } + .filter { + filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); + } + .backdrop-blur-md { + --tw-backdrop-blur: blur(var(--blur-md)); + -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,); + } + .transition { + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .transition-all { + transition-property: all; + transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); + transition-duration: var(--tw-duration, var(--default-transition-duration)); + } + .duration-200 { + --tw-duration: 200ms; + transition-duration: 200ms; + } + .duration-300 { + --tw-duration: 300ms; + transition-duration: 300ms; + } + .ease-in-out { + --tw-ease: var(--ease-in-out); + transition-timing-function: var(--ease-in-out); + } + .select-all { + -webkit-user-select: all; + user-select: all; + } + .hover\:bg-blue-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-blue-700); + } + } + } + .hover\:bg-cyan-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-cyan-700); + } + } + } + .hover\:bg-gray-600\/50 { + &:hover { + @media (hover: hover) { + background-color: color-mix(in srgb, oklch(44.6% 0.03 256.802) 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + background-color: color-mix(in oklab, var(--color-gray-600) 50%, transparent); + } + } + } + } + .hover\:bg-gray-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-gray-700); + } + } + } + .hover\:bg-green-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-green-700); + } + } + } + .hover\:bg-purple-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-purple-700); + } + } + } + .hover\:bg-red-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-red-700); + } + } + } + .hover\:bg-teal-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-teal-700); + } + } + } + .hover\:bg-yellow-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-yellow-700); + } + } + } + .hover\:text-blue-500 { + &:hover { + @media (hover: hover) { + color: var(--color-blue-500); + } + } + } + .hover\:text-red-700 { + &:hover { + @media (hover: hover) { + color: var(--color-red-700); + } + } + } + .hover\:text-white { + &:hover { + @media (hover: hover) { + color: var(--color-white); + } + } + } + .hover\:underline { + &:hover { + @media (hover: hover) { + text-decoration-line: underline; + } + } + } + .hover\:shadow-lg { + &:hover { + @media (hover: hover) { + --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + } + } + .focus\:border-blue-500 { + &:focus { + border-color: var(--color-blue-500); + } + } + .focus\:ring-blue-500 { + &:focus { + --tw-ring-color: var(--color-blue-500); + } + } + .sm\:w-\[90\%\] { + @media (width >= 40rem) { + width: 90%; + } + } + .sm\:p-4 { + @media (width >= 40rem) { + padding: calc(var(--spacing) * 4); + } + } + .sm\:px-6 { + @media (width >= 40rem) { + padding-inline: calc(var(--spacing) * 6); + } + } + .md\:w-\[85\%\] { + @media (width >= 48rem) { + width: 85%; + } + } + .md\:grid-cols-2 { + @media (width >= 48rem) { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + .md\:grid-cols-3 { + @media (width >= 48rem) { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + } + .lg\:w-\[80\%\] { + @media (width >= 64rem) { + width: 80%; + } + } + .lg\:px-8 { + @media (width >= 64rem) { + padding-inline: calc(var(--spacing) * 8); + } + } +} +@keyframes pulse { + 0%, 100% { + transform: scale(1); + opacity: 0.7; + } + 50% { + transform: scale(1.05); + opacity: 1; + } +} +@keyframes slideIn { + from { + transform: translateY(-20px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} +.animate-pulse-custom { + animation: pulse 2s infinite; +} +.animate-slide-in { + animation: slideIn 0.5s ease-out; +} +.gradient-bg { + background: linear-gradient(135deg, #1e3a8a, #6b21a8, #be185d); +} +.glass { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(10px); +} +.bg-clip-text { + -webkit-background-clip: text; + background-clip: text; +} +@property --tw-rotate-x { + syntax: "*"; + inherits: false; +} +@property --tw-rotate-y { + syntax: "*"; + inherits: false; +} +@property --tw-rotate-z { + syntax: "*"; + inherits: false; +} +@property --tw-skew-x { + syntax: "*"; + inherits: false; +} +@property --tw-skew-y { + syntax: "*"; + inherits: false; +} +@property --tw-space-y-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-space-x-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} +@property --tw-border-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-leading { + syntax: "*"; + inherits: false; +} +@property --tw-font-weight { + syntax: "*"; + inherits: false; +} +@property --tw-tracking { + syntax: "*"; + inherits: false; +} +@property --tw-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-inset-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-inset-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-inset-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-ring-color { + syntax: "*"; + inherits: false; +} +@property --tw-ring-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-inset-ring-color { + syntax: "*"; + inherits: false; +} +@property --tw-inset-ring-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-ring-inset { + syntax: "*"; + inherits: false; +} +@property --tw-ring-offset-width { + syntax: ""; + inherits: false; + initial-value: 0px; +} +@property --tw-ring-offset-color { + syntax: "*"; + inherits: false; + initial-value: #fff; +} +@property --tw-ring-offset-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; +} +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} +@property --tw-blur { + syntax: "*"; + inherits: false; +} +@property --tw-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-invert { + syntax: "*"; + inherits: false; +} +@property --tw-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-sepia { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow-color { + syntax: "*"; + inherits: false; +} +@property --tw-drop-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; +} +@property --tw-drop-shadow-size { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-blur { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-brightness { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-contrast { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-grayscale { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-hue-rotate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-invert { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-opacity { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-saturate { + syntax: "*"; + inherits: false; +} +@property --tw-backdrop-sepia { + syntax: "*"; + inherits: false; +} +@property --tw-duration { + syntax: "*"; + inherits: false; +} +@property --tw-ease { + syntax: "*"; + inherits: false; +} +@keyframes spin { + to { + transform: rotate(360deg); + } +} +@keyframes pulse { + 50% { + opacity: 0.5; + } +} +@layer properties { + @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { + *, ::before, ::after, ::backdrop { + --tw-rotate-x: initial; + --tw-rotate-y: initial; + --tw-rotate-z: initial; + --tw-skew-x: initial; + --tw-skew-y: initial; + --tw-space-y-reverse: 0; + --tw-space-x-reverse: 0; + --tw-border-style: solid; + --tw-leading: initial; + --tw-font-weight: initial; + --tw-tracking: initial; + --tw-shadow: 0 0 #0000; + --tw-shadow-color: initial; + --tw-shadow-alpha: 100%; + --tw-inset-shadow: 0 0 #0000; + --tw-inset-shadow-color: initial; + --tw-inset-shadow-alpha: 100%; + --tw-ring-color: initial; + --tw-ring-shadow: 0 0 #0000; + --tw-inset-ring-color: initial; + --tw-inset-ring-shadow: 0 0 #0000; + --tw-ring-inset: initial; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-outline-style: solid; + --tw-blur: initial; + --tw-brightness: initial; + --tw-contrast: initial; + --tw-grayscale: initial; + --tw-hue-rotate: initial; + --tw-invert: initial; + --tw-opacity: initial; + --tw-saturate: initial; + --tw-sepia: initial; + --tw-drop-shadow: initial; + --tw-drop-shadow-color: initial; + --tw-drop-shadow-alpha: 100%; + --tw-drop-shadow-size: initial; + --tw-backdrop-blur: initial; + --tw-backdrop-brightness: initial; + --tw-backdrop-contrast: initial; + --tw-backdrop-grayscale: initial; + --tw-backdrop-hue-rotate: initial; + --tw-backdrop-invert: initial; + --tw-backdrop-opacity: initial; + --tw-backdrop-saturate: initial; + --tw-backdrop-sepia: initial; + --tw-duration: initial; + --tw-ease: initial; + } + } +} diff --git a/public/favicon/android-chrome-192x192.png b/public/favicon/android-chrome-192x192.png new file mode 100644 index 0000000..05020e6 Binary files /dev/null and b/public/favicon/android-chrome-192x192.png differ diff --git a/public/favicon/android-chrome-512x512.png b/public/favicon/android-chrome-512x512.png new file mode 100644 index 0000000..96b37b8 Binary files /dev/null and b/public/favicon/android-chrome-512x512.png differ diff --git a/public/favicon/apple-touch-icon.png b/public/favicon/apple-touch-icon.png new file mode 100644 index 0000000..69e2782 Binary files /dev/null and b/public/favicon/apple-touch-icon.png differ diff --git a/public/favicon/favicon-16x16.png b/public/favicon/favicon-16x16.png new file mode 100644 index 0000000..97690c0 Binary files /dev/null and b/public/favicon/favicon-16x16.png differ diff --git a/public/favicon/favicon-32x32.png b/public/favicon/favicon-32x32.png new file mode 100644 index 0000000..48c3683 Binary files /dev/null and b/public/favicon/favicon-32x32.png differ diff --git a/public/favicon/favicon.ico b/public/favicon/favicon.ico new file mode 100644 index 0000000..b570dd9 Binary files /dev/null and b/public/favicon/favicon.ico differ diff --git a/public/favicon/site.webmanifest b/public/favicon/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/public/favicon/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..9c80145 --- /dev/null +++ b/public/index.html @@ -0,0 +1,63 @@ + + + + + + + Minecraft Server Status Checker + + + + + + + + + + +
+
+
+

+ My-MC Server Status Check +

+
+
+
+
+
+
+ + +
+
+ + +
+ +
+ +
+
+
+
+

© 2025 Minecraft Server Status Checker

+
+
+ + + + diff --git a/public/js/app.js b/public/js/app.js new file mode 100644 index 0000000..71ef037 --- /dev/null +++ b/public/js/app.js @@ -0,0 +1,105 @@ + // Initialize tsParticles + tsParticles.load("particles-js", { + particles: { + number: { value: 50, density: { enable: true, value_area: 800 } }, + color: { value: ["#60a5fa", "#a855f7", "#ec4899"] }, + shape: { type: "circle" }, + opacity: { value: 0.5, random: true }, + size: { value: 3, random: true }, + move: { enable: true, speed: 0.5, direction: "none", random: true, out_mode: "out" }, + }, + interactivity: { + events: { onhover: { enable: true, mode: "repulse" }, onclick: { enable: true, mode: "push" } }, + modes: { repulse: { distance: 100, duration: 0.4 }, push: { particles_nb: 4 } }, + }, + retina_detect: true +}); + +// Confetti function +function launchConfetti() { + confetti({ + particleCount: 100, + spread: 70, + origin: { y: 0.6 }, + colors: ['#60a5fa', '#a855f7', '#ec4899'] + }); +} + +// Form submission handler +document.getElementById('serverForm').addEventListener('submit', async (e) => { + e.preventDefault(); + const edition = document.getElementById('edition').value; + const connection = document.getElementById('connection').value; + const [host, port] = connection.split(':'); + + if (!host || !port) { + alert('Please enter a valid connection string (host:port)'); + return; + } + + const statusResult = document.getElementById('statusResult'); + const statusContent = document.getElementById('statusContent'); + statusResult.classList.add('hidden'); + statusContent.innerHTML = '

Checking...

'; + + try { + const response = await fetch(`/${edition}/${host}/${port}`); + if (!response.ok) throw new Error('Request failed'); + const result = await response.json(); + + statusResult.classList.remove('hidden'); + if (result.isOnline) { + launchConfetti(); + const { data } = result; + const statusData = {}; + + if (edition === 'java') { + if (data.version?.name?.clean) statusData['Version'] = data.version.name.clean; + if (data.version?.protocol) statusData['Protocol'] = data.version.protocol; + if (data.players?.online != null) statusData['Players Online'] = data.players.online; + if (data.players?.max != null) statusData['Max Players'] = data.players.max; + if (data.motd?.clean) statusData['MOTD'] = data.motd.clean; + if (data.favicon) statusData['Favicon'] = 'Present'; + if (data.srv_record) statusData['SRV Record'] = JSON.stringify(data.srv_record); + if (data.mods) statusData['Mods'] = JSON.stringify(data.mods); + } else { + if (data.version) statusData['Version'] = data.version; + if (data.protocol_version) statusData['Protocol'] = data.protocol_version; + if (data.online_players != null) statusData['Players Online'] = data.online_players; + if (data.max_players != null) statusData['Max Players'] = data.max_players; + if (data.motd) statusData['MOTD'] = data.motd.clean; + if (data.gamemode) statusData['Gamemode'] = data.gamemode; + if (data.server_id) statusData['Server ID'] = data.server_id; + } + + statusContent.innerHTML = ` +

Status: Online

+ ${Object.entries(statusData).map(([key, value]) => ` +

${key}: ${value}

+ `).join('')} + `; + } else { + statusContent.innerHTML = ` +

Status: Offline

+

Error: Server is not reachable

+ `; + } + } catch (error) { + statusResult.classList.remove('hidden'); + statusContent.innerHTML = ` +

Status: Error

+

Error: An error occurred while checking the server status

+ `; + } +}); + +// Handle URL-based checks +const path = window.location.pathname.split('/'); +if (path[1] && path[2] && path[3]) { + const edition = path[1]; + const host = path[2]; + const port = path[3]; + document.getElementById('edition').value = edition; + document.getElementById('connection').value = `${host}:${port}`; + document.getElementById('serverForm').dispatchEvent(new Event('submit')); +} \ No newline at end of file diff --git a/status-site.js b/status-site.js new file mode 100644 index 0000000..ebd9e76 --- /dev/null +++ b/status-site.js @@ -0,0 +1,67 @@ +const express = require('express'); +const { promisify } = require('util'); +const { exec } = require('child_process'); +const app = express(); +const port = 3066; +require('dotenv').config(); + +const execPromise = promisify(exec); + +async function checkConnectionStatus(hostname, port) { + try { + const command = `${process.env.STATUS_CHECK_PATH} -host ${hostname} -port ${port}`; + const { stdout, stderr } = await execPromise(command); + if (stderr) { + return { isOnline: false, error: stderr }; + } + const data = JSON.parse(stdout); + return { isOnline: true, data }; + } catch (error) { + return { isOnline: false, error: error.message }; + } +} + +async function checkGeyserStatus(hostname, port) { + try { + const command = `${process.env.GEYSER_STATUS_CHECK_PATH} -host ${hostname} -port ${port}`; + const { stdout, stderr } = await execPromise(command); + if (stderr) { + return { isOnline: false, error: stderr }; + } + const data = JSON.parse(stdout); + return { isOnline: true, data }; + } catch (error) { + return { isOnline: false, error: error.message }; + } +} + +app.use(express.static('public')); + +app.get('/', (req, res) => { + res.sendFile(__dirname + '/public/index.html'); +}); + +app.get('/java/:host/:port', async (req, res) => { + const { host, port } = req.params; + try { + const result = await checkConnectionStatus(host, port); + res.json(result); + } catch (error) { + res.status(500).json({ isOnline: false, error: `Server error: ${error.message}` }); + } +}); + +app.get('/bedrock/:host/:port', async (req, res) => { + const { host, port } = req.params; + try { + const result = await checkGeyserStatus(host, port); + console.log(result) + res.json(result); + } catch (error) { + res.status(500).json({ isOnline: false, error: `Server error: ${error.message}` }); + } +}); + +app.listen(port, () => { + console.log(`Server running at http://localhost:${port}`); +}); \ No newline at end of file