Skip to content

Instantly share code, notes, and snippets.

@Baw-Appie
Last active January 14, 2026 07:49
Show Gist options
  • Select an option

  • Save Baw-Appie/4b5564461479aa70f40b12b120dbd082 to your computer and use it in GitHub Desktop.

Select an option

Save Baw-Appie/4b5564461479aa70f40b12b120dbd082 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Minelist Hosting Provider Checker
// @namespace http://tampermonkey.net/
// @version 0.2
// @description Displays detailed connection information for servers on Minelist.
// @author You
// @match https://minelist.kr/*
// @match https://mine.page/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=minelist.kr
// @require https://fastly.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.min.js
// @grant none
// ==/UserScript==
(() => {
'use strict';
const IP_REGEX = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/;
/**
* Observes a container for newly inserted elements and triggers a callback.
* @param {string} containerSelector - The selector for the container to observe.
* @param {string} elementSelector - The selector for the target elements to find within the container.
* @param {(element: HTMLElement) => void} callback - The function to call for each new element found.
*/
const onElementInserted = (containerSelector, elementSelector, callback) => {
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
if (mutation.addedNodes.length) {
$(mutation.addedNodes).find(elementSelector).each((i, el) => callback(el));
}
}
});
const target = $(containerSelector)[0];
if (target) {
observer.observe(target, { childList: true, subtree: true });
}
};
/**
* Checks if a server address is blacklisted.
* @param {string} serverAddress - The server address to check.
* @returns {boolean} - Always returns false in this version.
*/
const isBlacklisted = (serverAddress) => false;
/**
* Checks server address is from known hosting service
* @param {string} serverAddress - The server address to check.
* @returns {object} hostingInfo - The hosting service information
*/
const getHosting = (serverAddress) => {
const hostings = [
{ name: "Stella IT", logo: { light: "https://static.stella-it-usercontent.com/logo/logo_black.svg", dark: "https://static.stella-it-usercontent.com/logo/logo_white.svg" }, ips: ["141.11.195."] },
{ name: "SKH Systems", logo: { light: "https://iili.io/f8v9Kfj.png", dark: "https://iili.io/f8v9Kfj.png" }, ips: ["27.123.9.", "165.101.60.", "165.101.61."] },
{ name: "MCV.KR", logo: { light: "https://iili.io/f8vCOx4.md.png", dark: "https://iili.io/f8vndzv.md.png" }, ips: ["172.104.117."] },
]
for (const hosting of hostings) {
if (
Array.isArray(hosting.ips) &&
hosting.ips.some(prefix => serverAddress.startsWith(prefix))
) {
return hosting;
}
}
return null
}
/**
* Removes the trailing dot from a domain name if it exists.
* @param {string} serverAddress - The address to clean.
* @returns {string} - The cleaned address.
*/
const removeTrailingDot = (serverAddress) => serverAddress.endsWith('.') ? serverAddress.slice(0, -1) : serverAddress;
/**
* Queries the Google Public DNS API.
* @param {string} name - The name to resolve.
* @param {string} [type="A"] - The DNS record type to query.
* @returns {Promise<object>} - The DNS query result as a JSON object.
*/
const queryDNS = async (name, type = "A") => {
const response = await fetch(`https://dns.google/resolve?name=${name}&type=${type}`);
return response.json();
};
/**
* Fetches ASN (Autonomous System Number) information for a given IP.
* @param {string} ip - The IP address.
* @returns {Promise<object>} - The ASN information from ipinfo.io.
*/
const getAsInfo = async (ip) => {
const response = await fetch(`https://ipinfo.io/${ip}/json?token=app_test`);
return response.json();
};
/**
* Processes a DNS record to extract connection details.
* @param {object} record - A DNS record from the Google DNS API.
* @returns {Promise<string|null>} - A formatted string with connection details or null.
*/
const getHostingInformationHTML = (address) => {
const info = getHosting(address)
if(!info) return ""
const isDark = $("html").attr("data-bs-theme") == "dark"
return `
<img src="${isDark ? info.logo.dark : info.logo.light}" alt="${info.name}" style="display:block; max-width: 150px; margin: 10px auto;" />
`
}
const processDnsRecord = async (record) => {
const dataParts = record.data.split(" ");
let ip
let text = ""
if (dataParts.length > 1) {
// SRV Record (e.g., _minecraft._tcp.example.com)
const [, , port, target] = dataParts;
const cleanTarget = removeTrailingDot(target);
if (isBlacklisted(cleanTarget)) return `${cleanTarget}:${port}`;
const aRecord = await queryDNS(cleanTarget, "A");
ip = aRecord.Answer?.find(ans => ans.type === 1)?.data;
if (ip && IP_REGEX.test(ip)) {
const as = await getAsInfo(ip);
text += `${cleanTarget} - ${ip}:${port} [${as.org || 'N/A'}]`;
} else {
text += `${cleanTarget}:${port}`;
}
} else {
// A Record
ip = dataParts[0];
if (IP_REGEX.test(ip)) {
const as = await getAsInfo(ip);
text += `${ip} [${as.org || 'N/A'}]`;
}
}
return { text, ip };
};
/**
* Fetches and displays detailed server information under the server address element.
* @param {HTMLElement} element - The HTML element containing the server address.
*/
const addAddressElement = async (element) => {
const serverAddress = element.innerText.trim();
if (!serverAddress) return;
const [aRecords, srvRecords] = await Promise.all([
queryDNS(serverAddress, "A"),
queryDNS(`_minecraft._tcp.${serverAddress}`, "SRV"),
]);
const recordsToProcess = srvRecords.Answer || aRecords.Answer || [];
const results = (await Promise.all(recordsToProcess.map(processDnsRecord))).filter(Boolean);
if (results.length > 0) {
const resultHTML = `<ul style="margin:0; list-style-type: none; padding-left: 10px;">${results.map(v => `<li>${v.text}</li>`).join("")}</ul>`;
element.innerHTML = `${serverAddress}${resultHTML}`;
const badge = $(element).parent().parent().parent().next().children()
badge.html(badge.html() + results.map(v => getHostingInformationHTML(v.ip)).join(""))
}
};
console.log("===== Minelist Hosting Provider Checker Initialized =====");
// Process servers already on the page
// Process servers added dynamically (e.g., by search or page navigation)
$(".copyable.copyable-ip").each((i, el) => addAddressElement(el));
$("button[data-action='theme#toggle']").each((i, el) => $(el).on('click', () => location.reload()));
onElementInserted('body', '.copyable.copyable-ip', (el) => addAddressElement(el));
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment