Aplikasi/Dashboard cek inet Ping ke DNS

 

Berikut aku tuliskan source code untuk membuat tamlilan dashboard cek ping ke DSN Publik google, cloudfire, dan DNS Bersama. Copy dan simpan file ini kemudian buka pakai browser, atau bisa pakai web server. Berikut source codenya : 

<?php
// ============================================
// SUPER FAST MONITOR + WORLD CLOCK + POPUP
// ============================================

date_default_timezone_set('UTC');

// WORLD CLOCK DATA
$cities = [
    ['Jakarta', 'Asia/Jakarta', '🇮🇩', 'WIB (UTC+7)'],
    ['Makassar', 'Asia/Makassar', '🇮🇩', 'WITA (UTC+8)'],
    ['Jayapura', 'Asia/Jayapura', '🇮🇩', 'WIT (UTC+9)'],
    ['Tokyo', 'Asia/Tokyo', '🇯🇵', 'JST (UTC+9)'],
    ['Dubai', 'Asia/Dubai', '🇦🇪', 'GST (UTC+4)'],
    ['London', 'Europe/London', '🇬🇧', 'GMT/BST'],
    ['New York', 'America/New_York', '🇺🇸', 'EST/EDT'],
];

// KONFIGURASI SERVER
$servers = [
    //['Proxmox VE', '192.168.1.100', [8006, 8443], 'Data Center'],
    //['Web Server', '192.168.1.101', [80, 443], 'Data Center'],
    //['Database MySQL', '192.168.1.102', [3306], 'Data Center'],
    //['Database PostgreSQL', '192.168.1.102', [5432], 'Data Center'],
    //['Router Mikrotik', '192.168.1.1', [22, 80], 'Network'],
    ['Google DNS', '8.8.8.8', [53], 'External'],
    ['Google DNS', '8.8.4.4', [53], 'External'],
    ['Cloudflare DNS', '1.1.1.1', [53], 'External'],
    ['DNS Bersama APJII', '103.88.88.88', [53], 'External'],
    //['DNS Bersama APJII', '103.88.88.89', [53], 'External'],
    ['DNS Bersama APJII', '203.119.13.77', [53], 'External'],
    ['DNS Bersama APJII', '203.119.13.78', [53], 'External'],
];

// FUNGSI PING CEPAT
function fastPing($ip) {
    $os = strtoupper(substr(PHP_OS, 0, 3));
    if ($os === 'WIN') {
        $cmd = "ping -n 1 -w 500 $ip 2>nul";
    } else {
        $cmd = "ping -c 1 -W 1 $ip 2>/dev/null";
    }
    $output = [];
    $return = 0;
    exec($cmd, $output, $return);
    
    $time = 0;
    foreach ($output as $line) {
        if (preg_match('/time[= <](\d+\.?\d*)/i', $line, $m)) {
            $time = round($m[1]);
            break;
        }
    }
    
    return [
        'online' => ($return === 0),
        'time' => $time
    ];
}

// FUNGSI CEK PORT CEPAT
function fastPortCheck($ip, $port) {
    $conn = @fsockopen($ip, $port, $errno, $errstr, 0.5);
    if ($conn) {
        fclose($conn);
        return true;
    }
    return false;
}

// PROSES SEMUA SERVER
$results = [];
foreach ($servers as $srv) {
    $ping = fastPing($srv[1]);
    
    $portsStatus = [];
    if ($ping['online']) {
        foreach ($srv[2] as $port) {
            $portsStatus[$port] = fastPortCheck($srv[1], $port);
        }
    } else {
        foreach ($srv[2] as $port) {
            $portsStatus[$port] = false;
        }
    }
    
    $results[] = [
        'name' => $srv[0],
        'ip' => $srv[1],
        'ports' => $srv[2],
        'loc' => $srv[3],
        'ping' => $ping,
        'ports_status' => $portsStatus
    ];
}

// STATISTIK
$total = count($results);
$pingOnline = count(array_filter($results, fn($r) => $r['ping']['online']));
$totalPorts = 0;
$openPorts = 0;
foreach ($results as $r) {
    foreach ($r['ports_status'] as $status) {
        $totalPorts++;
        if ($status) $openPorts++;
    }
}
$uptime = $total > 0 ? round(($pingOnline / $total) * 100) : 0;
?>

<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="refresh" content="10">
    <title>⚡ SUPER FAST Monitor | World Clock</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        :root {
            --bg: #0a0e1a;
            --card: #0f1622;
            --card-header: #0c111c;
            --border: #2a2f3f;
            --text: #e0e0e0;
            --text-muted: #888;
            --green: #2ecc71;
            --green-bg: #1a3a2a;
            --red: #e74c3c;
            --red-bg: #3a1a1a;
            --blue: #3498db;
            --yellow: #f39c12;
            --orange: #e67e22;
        }
        
        body.light {
            --bg: #f0f2f5;
            --card: #ffffff;
            --card-header: #f8f9fa;
            --border: #e0e0e0;
            --text: #1a1a2e;
            --green: #27ae60;
            --green-bg: #d5f4e6;
            --red: #e74c3c;
            --red-bg: #fee;
            --blue: #2980b9;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: var(--bg);
            padding: 16px;
            color: var(--text);
            transition: background 0.2s, color 0.2s;
        }
        
        .container {
            max-width: 1400px;
            margin: 0 auto;
        }
        
        /* Header */
        .header {
            background: var(--card);
            padding: 20px 24px;
            border-radius: 16px;
            margin-bottom: 20px;
            border: 1px solid var(--border);
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-wrap: wrap;
            gap: 15px;
        }
        
        .header h1 {
            font-size: 1.6rem;
            margin-bottom: 5px;
        }
        
        .header p {
            font-size: 0.8rem;
            opacity: 0.7;
        }
        
        .speed-badge {
            background: var(--green);
            color: #000;
            padding: 4px 12px;
            border-radius: 20px;
            font-size: 0.7rem;
            font-weight: bold;
        }
        
        /* Theme Toggle */
        .theme-toggle {
            background: var(--bg);
            border: 1px solid var(--border);
            border-radius: 50px;
            padding: 4px;
            display: flex;
            gap: 4px;
        }
        
        .theme-opt {
            padding: 6px 18px;
            border-radius: 40px;
            cursor: pointer;
            font-size: 0.8rem;
            transition: 0.2s;
        }
        
        .theme-opt.active {
            background: var(--blue);
            color: white;
        }
        
        /* WORLD CLOCK */
        .world-clock {
            background: var(--card);
            border-radius: 12px;
            margin-bottom: 20px;
            border: 1px solid var(--border);
            overflow: hidden;
        }
        
        .clock-header {
            background: var(--card-header);
            padding: 6px 12px;
            border-bottom: 1px solid var(--border);
            font-weight: bold;
            font-size: 0.7rem;
        }
        
        .clock-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
            gap: 1px;
            background: var(--border);
        }
        
        .clock-card {
            background: var(--card);
            padding: 6px 8px;
            text-align: center;
            transition: 0.2s;
        }
        
        .clock-card:hover {
            background: var(--card-header);
        }
        
        .city-name {
            font-size: 0.6rem;
            font-weight: 600;
            margin-bottom: 3px;
            color: var(--blue);
        }
        
        .city-time {
            font-size: 0.85rem;
            font-weight: 700;
            font-family: monospace;
            letter-spacing: 0.5px;
        }
        
        .city-date {
            font-size: 0.5rem;
            opacity: 0.6;
            margin-top: 2px;
        }
        
        .city-offset {
            font-size: 0.45rem;
            opacity: 0.5;
            margin-top: 2px;
        }
        
        /* Stats */
        .stats {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
            gap: 14px;
            margin-bottom: 20px;
        }
        
        .stat-card {
            background: var(--card);
            padding: 16px;
            border-radius: 14px;
            text-align: center;
            border: 1px solid var(--border);
            transition: 0.2s;
        }
        
        .stat-card:hover {
            transform: translateY(-2px);
            border-color: var(--green);
        }
        
        .stat-value {
            font-size: 1.8rem;
            font-weight: 700;
        }
        
        .stat-label {
            font-size: 0.7rem;
            opacity: 0.7;
            margin-top: 5px;
        }
        
        .text-green { color: var(--green); }
        .text-red { color: var(--red); }
        .text-blue { color: var(--blue); }
        .text-yellow { color: var(--yellow); }
        
        /* Controls */
        .controls {
            background: var(--card);
            padding: 12px 18px;
            border-radius: 14px;
            margin-bottom: 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-wrap: wrap;
            gap: 12px;
            border: 1px solid var(--border);
        }
        
        .btn {
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--border);
            padding: 8px 20px;
            border-radius: 10px;
            cursor: pointer;
            font-size: 0.85rem;
            transition: 0.2s;
        }
        
        .btn:hover {
            background: var(--border);
            transform: translateY(-1px);
        }
        
        .search-wrapper {
            position: relative;
            flex: 1;
            max-width: 280px;
        }
        
        .search-input {
            width: 100%;
            padding: 8px 12px 8px 35px;
            background: var(--bg);
            border: 1px solid var(--border);
            border-radius: 10px;
            color: var(--text);
            font-size: 0.85rem;
        }
        
        .search-input:focus {
            outline: none;
            border-color: var(--blue);
        }
        
        .search-icon {
            position: absolute;
            left: 12px;
            top: 50%;
            transform: translateY(-50%);
            opacity: 0.6;
        }
        
        .auto-info {
            font-size: 0.7rem;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .live-dot {
            width: 8px;
            height: 8px;
            background: var(--green);
            border-radius: 50%;
            animation: pulse 1.5s infinite;
        }
        
        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.3; }
        }
        
        /* Server Grid */
        .grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
            gap: 16px;
        }
        
        .card {
            background: var(--card);
            border-radius: 14px;
            overflow: hidden;
            border: 1px solid var(--border);
            transition: all 0.2s;
        }
        
        .card:hover {
            transform: translateY(-3px);
            border-color: var(--green);
            box-shadow: 0 8px 20px rgba(0,0,0,0.2);
        }
        
        .card-header {
            padding: 14px 16px;
            background: var(--card-header);
            border-bottom: 1px solid var(--border);
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .server-name {
            font-weight: 700;
            font-size: 1rem;
        }
        
        .server-ip {
            font-family: monospace;
            font-size: 0.7rem;
            opacity: 0.6;
            margin-top: 4px;
        }
        
        .ping-badge {
            padding: 4px 12px;
            border-radius: 20px;
            font-size: 0.7rem;
            font-weight: 600;
        }
        
        .ping-on {
            background: var(--green-bg);
            color: var(--green);
            border: 1px solid var(--green);
        }
        
        .ping-off {
            background: var(--red-bg);
            color: var(--red);
            border: 1px solid var(--red);
        }
        
        .card-body {
            padding: 14px 16px;
        }
        
        .ping-info {
            background: var(--bg);
            padding: 8px 12px;
            border-radius: 10px;
            margin-bottom: 14px;
            display: flex;
            justify-content: space-between;
            font-size: 0.8rem;
        }
        
        .port-list {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            margin-bottom: 12px;
        }
        
        .port-item {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            padding: 4px 10px;
            border-radius: 8px;
            font-size: 0.7rem;
            font-family: monospace;
            font-weight: 500;
        }
        
        .port-open {
            background: var(--green-bg);
            color: var(--green);
            border: 1px solid var(--green);
        }
        
        .port-closed {
            background: var(--red-bg);
            color: var(--red);
            border: 1px solid var(--red);
        }
        
        .loc-info {
            margin-top: 12px;
            padding-top: 10px;
            border-top: 1px solid var(--border);
            font-size: 0.7rem;
            opacity: 0.6;
            display: flex;
            align-items: center;
            gap: 6px;
        }
        
        .no-result {
            text-align: center;
            padding: 40px;
            background: var(--card);
            border-radius: 14px;
            border: 1px solid var(--border);
            grid-column: 1 / -1;
        }
        
        .footer {
            text-align: center;
            margin-top: 24px;
            padding: 14px;
            background: var(--card);
            border-radius: 12px;
            font-size: 0.7rem;
            opacity: 0.8;
            border: 1px solid var(--border);
        }
        
        /* Toast Notification */
        .toast-notification {
            position: fixed;
            top: 20px;
            right: 20px;
            background: var(--card);
            border-left: 4px solid var(--red);
            border-radius: 8px;
            padding: 12px 16px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            z-index: 1001;
            animation: slideIn 0.3s ease-out;
            max-width: 350px;
        }
        
        @keyframes slideIn {
            from {
                transform: translateX(100%);
                opacity: 0;
            }
            to {
                transform: translateX(0);
                opacity: 1;
            }
        }
        
        .toast-title {
            font-weight: bold;
            color: var(--red);
            margin-bottom: 5px;
        }
        
        .toast-message {
            font-size: 0.8rem;
        }
        
        .toast-close {
            float: right;
            cursor: pointer;
            opacity: 0.6;
        }
        
        .toast-close:hover {
            opacity: 1;
        }
        
        /* Loading */
        .loading {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0,0,0,0.7);
            display: none;
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }
        
        .spinner {
            width: 40px;
            height: 40px;
            border: 3px solid var(--border);
            border-top-color: var(--green);
            border-radius: 50%;
            animation: spin 0.5s linear infinite;
        }
        
        @keyframes spin {
            to { transform: rotate(360deg); }
        }
        
        @media (max-width: 700px) {
            body { padding: 10px; }
            .grid { grid-template-columns: 1fr; }
            .controls { flex-direction: column; align-items: stretch; }
            .search-wrapper { max-width: 100%; }
            .stats { grid-template-columns: repeat(2, 1fr); }
            .header { flex-direction: column; text-align: center; }
            .clock-grid { grid-template-columns: repeat(2, 1fr); }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <div>
                <h1>⚡ Web DNS Monitoring</h1>
                <p>Ping + Port Check | Timeout 0.5 detik | Refresh 10 detik</p>
            </div>
            <div style="display: flex; gap: 12px; align-items: center;">
                <span class="speed-badge">🚀 SPEED MODE</span>
                <div class="theme-toggle">
                    <div class="theme-opt" id="darkBtn" onclick="setTheme('dark')">🌙 Dark</div>
                    <div class="theme-opt" id="lightBtn" onclick="setTheme('light')">☀️ Light</div>
                </div>
            </div>
        </div>
        
        <!-- WORLD CLOCK -->
        <div class="world-clock">
            <div class="clock-header">
                🌍 WORLD CLOCK | Global Time Zones
            </div>
            <div class="clock-grid" id="worldClockGrid">
                <?php foreach ($cities as $city): 
                    $time = new DateTime('now', new DateTimeZone($city[1]));
                ?>
                <div class="clock-card">
                    <div class="city-name"><?php echo $city[2]; ?> <?php echo $city[0]; ?></div>
                    <div class="city-time"><?php echo $time->format('H:i:s'); ?></div>
                    <div class="city-date"><?php echo $time->format('d/m'); ?></div>
                    <div class="city-offset"><?php echo $city[3]; ?></div>
                </div>
                <?php endforeach; ?>
            </div>
        </div>
        
        <!-- Stats -->
        <div class="stats">
            <div class="stat-card">
                <div class="stat-value"><?php echo $total; ?></div>
                <div class="stat-label">Total Server</div>
            </div>
            <div class="stat-card">
                <div class="stat-value text-green"><?php echo $pingOnline; ?></div>
                <div class="stat-label">Online</div>
            </div>
            <div class="stat-card">
                <div class="stat-value text-red"><?php echo $total - $pingOnline; ?></div>
                <div class="stat-label">Offline</div>
            </div>
            <div class="stat-card">
                <div class="stat-value text-blue"><?php echo $openPorts; ?>/<?php echo $totalPorts; ?></div>
                <div class="stat-label">Port Terbuka</div>
            </div>
            <div class="stat-card">
                <div class="stat-value text-yellow"><?php echo $uptime; ?>%</div>
                <div class="stat-label">Uptime Rate</div>
            </div>
        </div>
        
        <!-- Controls -->
        <div class="controls">
            <button class="btn" onclick="manualRefresh()">🔄 Refresh Sekarang</button>
            <div class="search-wrapper">
                <span class="search-icon">🔍</span>
                <input type="text" class="search-input" id="searchInput" placeholder="Cari server atau IP..." onkeyup="filterServers()">
            </div>
            <div class="auto-info">
                <span class="live-dot"></span>
                <span>Auto refresh <span id="countdown">10</span> detik</span>
                <span>| ⏱️ Timeout: 0.5s</span>
            </div>
        </div>
        
        <!-- Server Grid -->
        <div class="grid" id="serverGrid">
            <?php foreach ($results as $srv): ?>
            <div class="card" data-name="<?php echo strtolower(htmlspecialchars($srv['name'])); ?>" data-ip="<?php echo htmlspecialchars($srv['ip']); ?>">
                <div class="card-header">
                    <div>
                        <div class="server-name"><?php echo htmlspecialchars($srv['name']); ?></div>
                        <div class="server-ip"><?php echo htmlspecialchars($srv['ip']); ?></div>
                    </div>
                    <div class="ping-badge <?php echo $srv['ping']['online'] ? 'ping-on' : 'ping-off'; ?>">
                        <?php echo $srv['ping']['online'] ? '✓ PING' : '✗ PING'; ?>
                    </div>
                </div>
                <div class="card-body">
                    <div class="ping-info">
                        <span>📡 Response Time</span>
                        <span class="<?php echo $srv['ping']['online'] ? 'text-green' : 'text-red'; ?>">
                            <?php echo $srv['ping']['online'] ? ($srv['ping']['time'] > 0 ? $srv['ping']['time'] . ' ms' : '&lt;1 ms') : 'Timeout'; ?>
                        </span>
                    </div>
                    
                    <div class="port-list">
                        <?php foreach ($srv['ports'] as $port): ?>
                        <?php $isOpen = $srv['ports_status'][$port] ?? false; ?>
                        <div class="port-item <?php echo $isOpen ? 'port-open' : 'port-closed'; ?>">
                            <span><?php echo $port; ?></span>
                            <span><?php echo $isOpen ? '✓' : '✗'; ?></span>
                        </div>
                        <?php endforeach; ?>
                    </div>
                    
                    <div class="loc-info">
                        <span>📍</span> <?php echo htmlspecialchars($srv['loc']); ?>
                    </div>
                </div>
            </div>
            <?php endforeach; ?>
        </div>
        
        <div class="footer">
            <span>⚡ Super Fast Mode: Ping 1x (0.5 detik) | Port scan 0.5 detik | Skip scan jika ping offline</span>
            <span style="display: block; margin-top: 5px;">🕐 Your time: <span id="clientTime">--:--:--</span></span>
            <span style="display: block; margin-top: 5px;"><a href="https://nurohman.my.id" target="_blank"><b>https://nurohman.my.id</b></a></span>
        </div>
    </div>
    
    <div class="loading" id="loading">
        <div class="spinner"></div>
    </div>
    
    <script>
        // ========== WORLD CLOCK REAL TIME ==========
        function updateWorldClocks() {
            const now = new Date();
            const utc = now.getTime() + (now.getTimezoneOffset() * 60000);
            
            const cities = [
                { id: 'jakarta', offset: 7 },
                { id: 'makassar', offset: 8 },
                { id: 'jayapura', offset: 9 },
                { id: 'tokyo', offset: 9 },
                { id: 'dubai', offset: 4 },
                { id: 'london', offset: 0 },
                { id: 'ny', offset: -5 }
            ];
            
            // Update London dengan DST
            const londonDate = new Date(utc);
            const year = londonDate.getFullYear();
            const dstStart = new Date(year, 2, 31 - ((year * 5 + 4) % 7));
            const dstEnd = new Date(year, 9, 31 - ((year * 5 + 1) % 7));
            const isLondonDST = (londonDate >= dstStart && londonDate < dstEnd);
            const londonOffset = isLondonDST ? 1 : 0;
            
            // Update New York dengan DST
            const nyDSTStart = new Date(year, 2, 8 + ((14 - (year * 5 + 4) % 7) % 7));
            const nyDSTEnd = new Date(year, 10, 1 + ((14 - (year * 5 + 1) % 7) % 7));
            const isNYDST = (londonDate >= nyDSTStart && londonDate < nyDSTEnd);
            const nyOffset = isNYDST ? -4 : -5;
            
            const offsets = {
                jakarta: 7,
                makassar: 8,
                jayapura: 9,
                tokyo: 9,
                dubai: 4,
                london: londonOffset,
                ny: nyOffset
            };
            
            for (const [city, offset] of Object.entries(offsets)) {
                const cityTime = new Date(utc + (offset * 3600000));
                const timeStr = cityTime.toLocaleTimeString('id-ID', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
                const dateStr = cityTime.toLocaleDateString('id-ID', { day: '2-digit', month: '2-digit' });
                
                const timeEl = document.getElementById(`time-${city}`);
                const dateEl = document.getElementById(`date-${city}`);
                if (timeEl) timeEl.innerHTML = timeStr;
                if (dateEl) dateEl.innerHTML = dateStr;
            }
        }
        
        // Set ID untuk setiap kota
        document.querySelectorAll('.clock-card').forEach((card, idx) => {
            const cities = ['jakarta', 'makassar', 'jayapura', 'tokyo', 'dubai', 'london', 'ny'];
            const timeSpan = card.querySelector('.city-time');
            const dateSpan = card.querySelector('.city-date');
            if (timeSpan) timeSpan.id = `time-${cities[idx]}`;
            if (dateSpan) dateSpan.id = `date-${cities[idx]}`;
        });
        
        // Update world clock setiap detik
        setInterval(updateWorldClocks, 1000);
        updateWorldClocks();
        
        // ========== PENCARIAN SERVER ==========
        function filterServers() {
            const keyword = document.getElementById('searchInput').value.toLowerCase().trim();
            const cards = document.querySelectorAll('.card');
            let hasVisible = false;
            
            cards.forEach(card => {
                const name = card.getAttribute('data-name');
                const ip = card.getAttribute('data-ip');
                const match = keyword === '' || name.includes(keyword) || ip.includes(keyword);
                
                if (match) {
                    card.style.display = '';
                    hasVisible = true;
                } else {
                    card.style.display = 'none';
                }
            });
            
            let noResult = document.getElementById('noResultMsg');
            if (!hasVisible && keyword !== '') {
                if (!noResult) {
                    noResult = document.createElement('div');
                    noResult.id = 'noResultMsg';
                    noResult.className = 'no-result';
                    document.getElementById('serverGrid').appendChild(noResult);
                }
                noResult.innerHTML = '🔍 Tidak ada server yang cocok dengan "' + keyword + '"';
                noResult.style.display = '';
            } else if (noResult) {
                noResult.style.display = 'none';
            }
        }
        
        // ========== REFRESH MANUAL ==========
        function manualRefresh() {
            document.getElementById('loading').style.display = 'flex';
            setTimeout(() => location.reload(), 200);
        }
        
        // ========== THEME DARK/LIGHT ==========
        function setTheme(theme) {
            const body = document.body;
            const darkBtn = document.getElementById('darkBtn');
            const lightBtn = document.getElementById('lightBtn');
            
            if (theme === 'dark') {
                body.classList.remove('light');
                darkBtn.classList.add('active');
                lightBtn.classList.remove('active');
                localStorage.setItem('theme', 'dark');
            } else {
                body.classList.add('light');
                lightBtn.classList.add('active');
                darkBtn.classList.remove('active');
                localStorage.setItem('theme', 'light');
            }
        }
        
        // ========== LOAD SAVED THEME ==========
        const savedTheme = localStorage.getItem('theme');
        if (savedTheme === 'light') setTheme('light');
        else setTheme('dark');
        
        // ========== AUTO REFRESH COUNTDOWN ==========
        let countdown = 11;
        const countdownEl = document.getElementById('countdown');
        
        if (countdownEl) countdownEl.textContent = countdown - 1;
        
        const timer = setInterval(() => {
            countdown--;
            if (countdownEl) countdownEl.textContent = countdown;
            if (countdown <= 0) {
                clearInterval(timer);
                location.reload();
            }
        }, 1000);
        
        // ========== JAM CLIENT ==========
        function updateClientTime() {
            const now = new Date();
            const hours = String(now.getHours()).padStart(2, '0');
            const minutes = String(now.getMinutes()).padStart(2, '0');
            const seconds = String(now.getSeconds()).padStart(2, '0');
            const clientTimeSpan = document.getElementById('clientTime');
            if (clientTimeSpan) {
                clientTimeSpan.innerHTML = `${hours}:${minutes}:${seconds}`;
            }
        }
        setInterval(updateClientTime, 1000);
        updateClientTime();
        
        // ========== NOTIFIKASI POPUP ==========
        function getOfflineServers() {
            const cards = document.querySelectorAll('.card');
            let offline = [];
            cards.forEach(card => {
                const pingBadge = card.querySelector('.ping-badge');
                const serverName = card.querySelector('.server-name').innerText;
                if (pingBadge && pingBadge.classList.contains('ping-off')) {
                    offline.push(serverName);
                }
            });
            return offline;
        }
        
        function showToastNotification(offlineServers) {
            const oldToast = document.querySelector('.toast-notification');
            if (oldToast) oldToast.remove();
            
            const toast = document.createElement('div');
            toast.className = 'toast-notification';
            toast.innerHTML = `
                <div class="toast-close" onclick="this.parentElement.remove()">✕</div>
                <div class="toast-title">🚨 SERVER OFFLINE!</div>
                <div class="toast-message">
                    ${offlineServers.length} server tidak merespon ping:<br>
                    <strong>${offlineServers.join(', ')}</strong>
                </div>
            `;
            document.body.appendChild(toast);
            
            setTimeout(() => {
                if (toast) toast.remove();
            }, 5000);
        }
        
        function showAlertPopup() {
            const offlineServers = getOfflineServers();
            
            if (offlineServers.length > 0) {
                alert(`⚠️ PERINGATAN!\n\n${offlineServers.length} Server OFFLINE:\n${offlineServers.join('\n')}`);
                showToastNotification(offlineServers);
                
                if (Notification.permission === 'granted') {
                    new Notification('🚨 Server Down Alert!', {
                        body: `${offlineServers.length} server offline: ${offlineServers.join(', ')}`,
                        icon: 'https://cdn-icons-png.flaticon.com/512/561/561127.png'
                    });
                }
            }
        }
        
        if (Notification.permission === 'default') {
            Notification.requestPermission();
        }
        
        setTimeout(() => {
            showAlertPopup();
        }, 1000);
        
        // ========== ENTER KEY ==========
        const searchInput = document.getElementById('searchInput');
        if (searchInput) {
            searchInput.addEventListener('keypress', function(e) {
                if (e.key === 'Enter') manualRefresh();
            });
        }
        
        console.log('⚡ SUPER FAST Monitor + World Clock Ready!');
    </script>
</body>
</html>

Post a Comment

0 Comments

MY POST

Aplikasi/Dashboard cek inet Ping ke DNS