Kostenloses Tool - Kein Konto erforderlich

Kostenloser M3U- & IPTV-Duplikat-Entferner

Bereinigen Sie Ihre M3U-, M3U8- oder IPTV-Playlist online, indem Sie doppelte Kanäle in Sekunden entfernen. Vergleich nach Name, URL oder beides. Laden Sie sofort eine saubere Datei herunter.

M3U-Datei hier ablegen

oder

.m3u und .m3u8 unterstützt - Lokal im Browser verarbeitet - Keine Uploads auf unsere Server

100% privat

Deine Datei verlässt deinen Browser nie. Alle Verarbeitung erfolgt lokal.

Flexible Übereinstimmung

Duplikate nach Stream-URL, Kanalname oder beidem gleichzeitig abgleichen. Behält das erste Vorkommen.

Sofort-Download

Laden Sie Ihre bereinigte M3U-Datei sofort herunter. Kein Warten, keine E-Mail, keine Registrierung erforderlich.

Mehr aus deiner Playlist herausholen?

Erstelle ein kostenloses M3U Maker Konto, um Kanäle zu filtern, Playlists zu erstellen und sie automatisch zu synchronisieren.

(function() { var zone = document.getElementById('uploadZone'); var fileInput = document.getElementById('fileInput'); var results = document.getElementById('results'); var resetBtn = document.getElementById('resetBtn'); var browseBtn = document.getElementById('browseBtn'); var reprocessBtn = document.getElementById('reprocessBtn'); var downloadBtn = document.getElementById('downloadBtn'); var matchUrl = document.getElementById('matchUrl'); var matchName = document.getElementById('matchName'); var parsedChannels = []; var originalHeader = '#EXTM3U'; var currentFilename = ''; 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 = ''; parsedChannels = []; }); reprocessBtn.addEventListener('click', function() { showResults(); }); downloadBtn.addEventListener('click', function() { downloadClean(); }); var loading = document.getElementById('loading'); function processFile(file) { currentFilename = file.name; zone.style.display = 'none'; loading.style.display = ''; var reader = new FileReader(); reader.onload = function(e) { parseM3U(e.target.result); }; reader.readAsText(file, 'UTF-8'); } function parseM3U(content) { var lines = content.split(/\r?\n/); parsedChannels = []; originalHeader = '#EXTM3U'; var i = 0; if (lines[0] && lines[0].trim().startsWith('#EXTM3U')) { originalHeader = lines[0].trim(); i = 1; } while (i < lines.length) { var line = lines[i].trim(); if (!line) { i++; continue; } if (line.startsWith('#EXTINF:')) { var extinf = line; var nameMatch = line.match(/,(.+)$/); var name = nameMatch ? nameMatch[1].trim() : ''; i++; while (i < lines.length && !lines[i].trim()) i++; var url = lines[i] ? lines[i].trim() : ''; if (url && !url.startsWith('#')) { parsedChannels.push({ extinf: extinf, name: name, url: url }); } } i++; } loading.style.display = 'none'; results.style.display = ''; document.getElementById('resultsFilename').textContent = currentFilename; showResults(); } function showResults() { var byUrl = matchUrl.checked; var byName = matchName.checked; if (!byUrl && !byName) { matchUrl.checked = true; byUrl = true; } var seenUrls = {}, seenNames = {}; var kept = [], dupes = []; parsedChannels.forEach(function(ch) { var isDupe = false; var dupeType = ''; if (byUrl && ch.url && seenUrls[ch.url]) { isDupe = true; dupeType = 'url'; } if (byName && ch.name && seenNames[ch.name.toLowerCase()]) { isDupe = true; dupeType = dupeType ? dupeType + '+name' : 'name'; } if (isDupe) { dupes.push({ ch: ch, type: dupeType }); } else { kept.push(ch); if (byUrl && ch.url) seenUrls[ch.url] = true; if (byName && ch.name) seenNames[ch.name.toLowerCase()] = true; } }); // Stats var statsRow = document.getElementById('statsRow'); statsRow.textContent = ''; [ { val: parsedChannels.length.toLocaleString(), label: 'Total channels', cls: '' }, { val: dupes.length, label: 'Duplicates found', cls: dupes.length > 0 ? 'tool-stat--warning' : '' }, { val: kept.length.toLocaleString(), label: 'Unique channels', cls: kept.length > 0 ? 'tool-stat--success' : '' }, { val: dupes.length > 0 ? Math.round(dupes.length / parsedChannels.length * 100) + '%' : '0%', label: 'Reduction', cls: '' } ].forEach(function(s) { var div = document.createElement('div'); div.className = 'tool-stat ' + s.cls; 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); statsRow.appendChild(div); }); // Dupes list var dupeSection = document.getElementById('dupeSection'); var nodupeMsg = document.getElementById('nodupeMsg'); var downloadBar = document.getElementById('downloadBar'); if (dupes.length > 0) { document.getElementById('dupeGroupHeader').textContent = 'Duplicate channels to be removed (' + dupes.length + ')'; var dupeList = document.getElementById('dupeList'); dupeList.textContent = ''; dupes.slice(0, 100).forEach(function(d) { var item = document.createElement('div'); item.className = 'tool-dupe-item'; var badge = document.createElement('span'); badge.className = 'tool-dupe-badge tool-dupe-badge--' + (d.type === 'url' ? 'url' : 'name'); badge.textContent = d.type === 'url' ? 'URL' : d.type === 'name' ? 'Name' : 'URL+Name'; item.appendChild(badge); var info = document.createElement('div'); info.className = 'tool-dupe-info'; var nameEl = document.createElement('div'); nameEl.className = 'tool-dupe-name'; nameEl.textContent = d.ch.name || '(no name)'; var urlEl = document.createElement('div'); urlEl.className = 'tool-dupe-url'; urlEl.textContent = d.ch.url; info.appendChild(nameEl); info.appendChild(urlEl); item.appendChild(info); dupeList.appendChild(item); }); if (dupes.length > 100) { var more = document.createElement('div'); more.className = 'tool-issue-more'; more.textContent = '… and ' + (dupes.length - 100) + ' more duplicates'; dupeList.appendChild(more); } dupeSection.style.display = ''; nodupeMsg.style.display = 'none'; document.getElementById('downloadInfo').textContent = kept.length.toLocaleString() + ' channels, ' + dupes.length + ' duplicates removed'; downloadBar.style.display = ''; downloadBtn._kept = kept; } else { dupeSection.style.display = 'none'; nodupeMsg.style.display = ''; downloadBar.style.display = 'none'; } } function downloadClean() { var kept = downloadBtn._kept; if (!kept) return; var lines = [originalHeader]; kept.forEach(function(ch) { lines.push(ch.extinf); lines.push(ch.url); lines.push(''); }); var blob = new Blob([lines.join('\n')], { type: 'audio/x-mpegurl' }); var a = document.createElement('a'); a.href = URL.createObjectURL(blob); var base = currentFilename.replace(/\.[^.]+$/, ''); a.download = base + '-cleaned.m3u'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(a.href); } })();