├── .gitignore ├── .npmignore ├── terminal.png ├── tsconfig.json ├── package.json ├── README.md ├── bin └── mc-status └── src └── index.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /lib 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /src 2 | /terminal.png 3 | tsconfig.json 4 | -------------------------------------------------------------------------------- /terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/janispritzkau/mc-server-status/HEAD/terminal.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "module": "commonjs", 5 | "lib": ["esnext"], 6 | "strict": true, 7 | "declaration": true, 8 | "outDir": "lib" 9 | }, 10 | "include": [ 11 | "src" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mc-server-status", 3 | "version": "2.0.2", 4 | "description": "Fetch the status of a Minecraft server.", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "scripts": { 8 | "prepare": "tsc" 9 | }, 10 | "bin": { 11 | "mc-status": "./bin/mc-status" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/janispritzkau/mc-server-status.git" 16 | }, 17 | "keywords": [ 18 | "minecraft", 19 | "status", 20 | "server" 21 | ], 22 | "author": "Janis Pritzkau ", 23 | "license": "MIT", 24 | "dependencies": { 25 | "mc-chat-format": "^1.2.1", 26 | "mcproto": "^0.8.2" 27 | }, 28 | "devDependencies": { 29 | "@types/node": "^12.12.59", 30 | "typescript": "^4.0.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minecraft Server Status 2 | 3 | [![npm](https://img.shields.io/npm/v/mc-server-status.svg)](https://www.npmjs.com/package/mc-server-status) 4 | [![downloads](https://img.shields.io/npm/dm/mc-server-status.svg)](https://www.npmjs.com/package/mc-server-status) 5 | 6 | A small utility and library for getting the description, player count 7 | and ping of a Minecraft server. 8 | 9 | ## Usage 10 | 11 | ```bash 12 | mc-status 2b2t.org 13 | # with port 14 | mc-status localhost 25565 15 | 16 | # output json 17 | mc-status --json
18 | ``` 19 | 20 | ![Terminal output](https://gitlab.com/janispritzkau/mc-status/raw/master/terminal.png) 21 | 22 | You can also use it as a library: 23 | 24 | ```js 25 | const { getStatus } = require("mc-server-status") 26 | 27 | const status = await getStatus("2b2t.org") 28 | console.log(status) 29 | ``` 30 | -------------------------------------------------------------------------------- /bin/mc-status: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const chat = require("mc-chat-format") 3 | const { getStatus } = require("../lib") 4 | 5 | async function main() { 6 | let useJson = false, args = [] 7 | for (const arg of process.argv.slice(2)) { 8 | if (arg == "--json") useJson = true 9 | else if (!arg.startsWith("-")) args.push(arg) 10 | } 11 | 12 | if (args.length < 1) return console.error("Please specify a valid server address") 13 | 14 | const host = args[0] 15 | const port = parseInt(args[1]) 16 | 17 | let status 18 | try { 19 | status = await getStatus(host, port) 20 | } catch (err) { 21 | const match = err.message.match(/ECONNREFUSED (.+)/) 22 | if (match) { 23 | console.error(`Could not connect to ${match[1]}`) 24 | } else { 25 | console.error(err.message) 26 | } 27 | return 28 | } 29 | 30 | if (useJson) return console.log(JSON.stringify(status, null, 2)) 31 | 32 | console.log("\n" + chat.format(status.description, { useAnsiCodes: true }) + "\n") 33 | console.log(`\x1b[1mVersion: \x1b[0m ${status.version.name} (${status.version.protocol})`) 34 | console.log(`\x1b[1mPlayers: \x1b[0m ${status.players.online}/${status.players.max}`) 35 | console.log(`\x1b[1mFavicon: \x1b[0m ${ 36 | status.favicon ? `yes, ${status.favicon.length} bytes` : "no" 37 | }`) 38 | console.log(`\x1b[1mPing: \x1b[0m ${status.ping} ms\n`) 39 | } 40 | 41 | main().catch(console.error) 42 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Client, PacketWriter, State } from "mcproto" 2 | 3 | export interface Status { 4 | version: { 5 | name: string 6 | protocol: number 7 | } 8 | players: { 9 | max: number 10 | online: number 11 | } 12 | description: string 13 | favicon?: string 14 | ping?: number 15 | } 16 | 17 | export interface StatusOptions { 18 | /** @default true */ 19 | checkPing?: boolean 20 | /** @default 5000 // ms */ 21 | timeout?: number 22 | /** @default 736 // 1.16.1 */ 23 | protocol?: number 24 | } 25 | 26 | const defaultOptions: Partial = { 27 | checkPing: true, 28 | timeout: 5000, 29 | protocol: 736 30 | } 31 | 32 | export async function getStatus(host: string, port?: number | null, options?: StatusOptions): Promise { 33 | options = { ...defaultOptions, ...options } 34 | 35 | const client = await Client.connect(host, port, { 36 | connectTimeout: options.timeout, 37 | timeout: options.timeout 38 | }) 39 | 40 | client.send(new PacketWriter(0x0).writeVarInt(options.protocol!) 41 | .writeString(host).writeUInt16(client.socket.remotePort!) 42 | .writeVarInt(State.Status)) 43 | 44 | client.send(new PacketWriter(0x0)) 45 | 46 | const status: Status = (await client.nextPacket()).readJSON() 47 | 48 | if (options.checkPing) { 49 | client.send(new PacketWriter(0x1).write(Buffer.alloc(8))) 50 | const start = Date.now() 51 | 52 | await client.nextPacket(0x1) 53 | status.ping = Date.now() - start 54 | } 55 | 56 | client.end() 57 | 58 | return status 59 | } 60 | --------------------------------------------------------------------------------