Mjet falas - Nuk kërkohet llogari

Analizues falas i listave M3U & IPTV

Analizoni listën tuaj M3U, M3U8 ose IPTV online. Pasqyrë e plotë: numri i kanaleve për grup, statistikat e cilësisë (4K/HD/SD), shpërndarjen e protokolleve dhe pikët e shëndetit të meta-të dhënave.

Tërhiqni dhe lëshoni skedarin tuaj M3U këtu

ose

.m3u dhe .m3u8 të mbështetur - Procesuar lokalisht në shfletuesin tuaj - Nuk ngarkohet kurrë në serverët tanë

100% privat

Skedari juaj nuk largohet kurrë nga shfletuesi juaj. I gjithë procesimi ekzekutohet lokalisht - asgjë nuk dërgohet në serverët tanë.

E menjëhershme dhe e detajuar

Ndarja e cilësisë, statistikat e protokollit, rezultati i shëndetit të metadata dhe renditja e plotë e grupeve - të gjitha në sekonda.

Mbështetje për skedarë të mëdhenj

Trajton lista të vogla dhe të mëdha njëlloj - testuar në skedarë me mbi 50.000 kanale.

Dëshironi të bëni më shumë me listën tuaj?

Krijoni një llogari falas M3U Maker për të filtruar kanalet, krijuar lista të personalizuara dhe mbajtur ato të sinkronizuara automatikisht me skedarin burimor.

(function() { var zone = document.getElementById('uploadZone'); var fileInput = document.getElementById('fileInput'); var loading = document.getElementById('loading'); var results = document.getElementById('results'); var resetBtn = document.getElementById('resetBtn'); var browseBtn = document.getElementById('browseBtn'); browseBtn.addEventListener('click', function(e) { e.stopPropagation(); fileInput.click(); }); zone.addEventListener('click', function() { fileInput.click(); }); zone.addEventListener('dragover', function(e) { e.preventDefault(); zone.classList.add('drag-over'); }); zone.addEventListener('dragleave', function() { zone.classList.remove('drag-over'); }); zone.addEventListener('drop', function(e) { e.preventDefault(); zone.classList.remove('drag-over'); if (e.dataTransfer.files[0]) processFile(e.dataTransfer.files[0]); }); fileInput.addEventListener('change', function() { if (fileInput.files[0]) processFile(fileInput.files[0]); }); resetBtn.addEventListener('click', function() { results.style.display = 'none'; loading.style.display = 'none'; zone.style.display = ''; fileInput.value = ''; }); function processFile(file) { zone.style.display = 'none'; loading.style.display = ''; document.getElementById('resultsFilename').textContent = file.name; var reader = new FileReader(); reader.onload = function(e) { setTimeout(function() { analyzeM3U(e.target.result); }, 30); }; reader.readAsText(file, 'UTF-8'); } function analyzeM3U(content) { var lines = content.split(/\r?\n/); var channels = 0, groups = {}, noGroup = 0; var quality = { '4K': 0, 'FHD': 0, 'HD': 0, 'SD': 0 }; var protocols = {}; var hasLogo = 0, hasGroup = 0, hasTvgId = 0, hasName = 0; var i = lines[0] && lines[0].trim().startsWith('#EXTM3U') ? 1 : 0; while (i < lines.length) { var line = lines[i].trim(); if (!line) { i++; continue; } if (line.startsWith('#EXTINF:')) { channels++; // Name var nameMatch = line.match(/,(.+)$/); var name = nameMatch ? nameMatch[1].trim() : ''; if (name) hasName++; // Group var groupMatch = line.match(/group-title="([^"]*)"/i); var group = groupMatch ? groupMatch[1].trim() : ''; if (group) { hasGroup++; groups[group] = (groups[group] || 0) + 1; } else { noGroup++; } // Logo if (/tvg-logo="[^"]+"/i.test(line)) hasLogo++; // tvg-id if (/tvg-id="[^"]+"/i.test(line)) hasTvgId++; // Quality from name var uname = name.toUpperCase(); if (/\b(4K|UHD|2160P)\b/.test(uname)) quality['4K']++; else if (/\b(FHD|1080[PI]|FULLHD)\b/.test(uname)) quality['FHD']++; else if (/\b(HD|720[PI])\b/.test(uname)) quality['HD']++; else quality['SD']++; // URL on next line i++; while (i < lines.length && !lines[i].trim()) i++; var url = lines[i] ? lines[i].trim() : ''; if (url && !url.startsWith('#')) { var protoMatch = url.match(/^([a-z][a-z0-9+\-.]*):\/\//i); var proto = protoMatch ? protoMatch[1].toLowerCase() : 'other'; protocols[proto] = (protocols[proto] || 0) + 1; } } i++; } showResults(channels, groups, noGroup, quality, protocols, hasLogo, hasGroup, hasTvgId, hasName); } function pct(val, total) { return total > 0 ? Math.round(val / total * 100) : 0; } function showResults(channels, groups, noGroup, quality, protocols, hasLogo, hasGroup, hasTvgId, hasName) { var groupCount = Object.keys(groups).length + (noGroup > 0 ? 1 : 0); // Summary stats var statsEl = document.getElementById('summaryStats'); statsEl.textContent = ''; [ { val: channels.toLocaleString(), label: 'Total channels' }, { val: groupCount, label: 'Groups' }, { val: pct(quality['4K'] + quality['FHD'] + quality['HD'], channels) + '%', label: 'HD or better' }, { val: pct(hasLogo, channels) + '%', label: 'Has logo' }, { val: pct(hasGroup, channels) + '%', label: 'Has group' } ].forEach(function(s) { var div = document.createElement('div'); div.className = 'tool-stat'; var val = document.createElement('span'); val.className = 'tool-stat-value'; val.textContent = s.val; var lbl = document.createElement('span'); lbl.className = 'tool-stat-label'; lbl.textContent = s.label; div.appendChild(val); div.appendChild(lbl); statsEl.appendChild(div); }); // Quality bars var qualityData = [ { label: '4K / UHD', count: quality['4K'], color: 'var(--accent-secondary)' }, { label: 'Full HD (1080p)', count: quality['FHD'], color: 'var(--accent-primary)' }, { label: 'HD (720p)', count: quality['HD'], color: '#00b894' }, { label: 'SD / Unknown', count: quality['SD'], color: 'var(--text-muted)' } ]; renderBars('qualityBars', qualityData, channels); // Protocol bars var protoData = Object.entries(protocols) .sort(function(a, b) { return b[1] - a[1]; }) .map(function(e) { return { label: e[0], count: e[1], color: 'var(--accent-primary)' }; }); renderBars('protocolBars', protoData, channels); // Metadata bars var metaData = [ { label: 'Has channel name', count: hasName, color: 'var(--accent-primary)' }, { label: 'Has group-title', count: hasGroup, color: 'var(--accent-primary)' }, { label: 'Has tvg-logo', count: hasLogo, color: 'var(--accent-primary)' }, { label: 'Has tvg-id', count: hasTvgId, color: 'var(--accent-primary)' } ]; renderBars('metaBars', metaData, channels); // Groups list var sortedGroups = Object.entries(groups).sort(function(a, b) { return b[1] - a[1]; }); if (noGroup > 0) sortedGroups.push(['(no group)', noGroup]); var maxCount = sortedGroups.length > 0 ? sortedGroups[0][1] : 1; document.getElementById('groupsCount').textContent = groupCount + ' groups'; var groupsList = document.getElementById('groupsList'); groupsList.textContent = ''; var showAll = false; var limit = 15; function renderGroups(all) { groupsList.textContent = ''; var toShow = all ? sortedGroups : sortedGroups.slice(0, limit); toShow.forEach(function(g) { var item = document.createElement('div'); item.className = 'analyzer-group-item'; var label = document.createElement('div'); label.className = 'analyzer-group-label'; var name = document.createElement('span'); name.className = 'analyzer-group-name'; name.textContent = g[0]; var count = document.createElement('span'); count.className = 'analyzer-group-count'; count.textContent = g[1].toLocaleString(); label.appendChild(name); label.appendChild(count); var barWrap = document.createElement('div'); barWrap.className = 'analyzer-group-bar-wrap'; var bar = document.createElement('div'); bar.className = 'analyzer-group-bar'; bar.style.width = '0%'; barWrap.appendChild(bar); setTimeout(function() { bar.style.width = Math.round(g[1] / maxCount * 100) + '%'; }, 50); item.appendChild(label); item.appendChild(barWrap); groupsList.appendChild(item); }); } renderGroups(false); var moreEl = document.getElementById('groupsMore'); if (sortedGroups.length > limit) { moreEl.style.display = ''; var remaining = sortedGroups.length - limit; var btn = document.createElement('button'); btn.className = 'btn btn-ghost btn-sm'; btn.textContent = 'Show all ' + sortedGroups.length + ' groups'; btn.addEventListener('click', function() { renderGroups(true); moreEl.style.display = 'none'; }); moreEl.textContent = ''; moreEl.appendChild(btn); } else { moreEl.style.display = 'none'; } loading.style.display = 'none'; results.style.display = ''; } function renderBars(containerId, data, total) { var container = document.getElementById(containerId); container.textContent = ''; var max = data.reduce(function(m, d) { return Math.max(m, d.count); }, 1); data.forEach(function(d) { if (d.count === 0) return; var item = document.createElement('div'); item.className = 'analyzer-bar-item'; var header = document.createElement('div'); header.className = 'analyzer-bar-header'; var lbl = document.createElement('span'); lbl.className = 'analyzer-bar-label'; lbl.textContent = d.label; var cnt = document.createElement('span'); cnt.className = 'analyzer-bar-count'; cnt.textContent = d.count.toLocaleString() + ' (' + pct(d.count, total) + '%)'; header.appendChild(lbl); header.appendChild(cnt); var barWrap = document.createElement('div'); barWrap.className = 'analyzer-bar-wrap'; var bar = document.createElement('div'); bar.className = 'analyzer-bar-fill'; bar.style.width = '0%'; bar.style.background = d.color; barWrap.appendChild(bar); setTimeout(function(b, w) { b.style.width = w + '%'; }.bind(null, bar, Math.round(d.count / max * 100)), 50); item.appendChild(header); item.appendChild(barWrap); container.appendChild(item); }); } })();