أداة مجانية - لا يلزم حساب

أداة التحقق المجانية من قوائم تشغيل M3U و IPTV

تحقق من قائمة تشغيل M3U أو M3U8 أو IPTV الخاصة بك عبر الإنترنت. يكتشف الأخطاء والعناوين المفقودة وعناوين URL غير الصالحة والقنوات المكررة فوراً.

اسحب وأفلت ملف M3U هنا

أو

يدعم .m3u و.m3u8 - المعالجة محلياً في متصفحك - لا يُرفع أبداً إلى خوادمنا

100% خاص

ملفك لا يغادر متصفحك أبداً. جميع المعالجة محلية.

نتائج فورية

التحقق في أجزاء من الثانية، حتى لقوائم التشغيل الكبيرة.

تقرير مفصل

يتحقق من غياب ترويسة #EXTM3U وعناوين URL غير الصالحة وسمات group-title المفقودة والقنوات المكررة.

هل تريد فعل المزيد مع قائمة التشغيل؟

أنشئ حساباً مجانياً في M3U Maker لتصفية القنوات وإنشاء قوائم تشغيل مخصصة.

(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'); 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 = ''; }); var loading = document.getElementById('loading'); function processFile(file) { zone.style.display = 'none'; loading.style.display = ''; var reader = new FileReader(); reader.onload = function(e) { validateM3U(e.target.result, file.name); }; reader.readAsText(file, 'UTF-8'); } function validateM3U(content, filename) { var lines = content.split(/\r?\n/); var errors = [], warnings = []; var channelCount = 0; var urls = {}, names = {}; var i = 0; if (lines[0] && lines[0].trim().startsWith('#EXTM3U')) { i = 1; } else { errors.push({ line: 1, msg: 'Missing #EXTM3U header on line 1' }); } while (i < lines.length) { var line = lines[i].trim(); if (!line || line === '#EXTM3U') { i++; continue; } if (line.startsWith('#EXTINF:')) { channelCount++; var lineNum = i + 1; var nameMatch = line.match(/,(.+)$/); var name = nameMatch ? nameMatch[1].trim() : ''; if (!name) { warnings.push({ line: lineNum, msg: 'Channel #' + channelCount + ': missing name after comma in #EXTINF' }); } if (line.indexOf('group-title') === -1) { warnings.push({ line: lineNum, msg: 'Channel #' + channelCount + (name ? ' "' + name + '"' : '') + ': missing group-title attribute' }); } if (name) { var lname = name.toLowerCase(); if (names[lname] !== undefined) { warnings.push({ line: lineNum, msg: 'Duplicate channel name: "' + name + '" (also on line ' + names[lname] + ')' }); } else { names[lname] = lineNum; } } i++; while (i < lines.length && !lines[i].trim()) i++; var urlLine = lines[i] ? lines[i].trim() : ''; var urlLineNum = i + 1; if (!urlLine || urlLine.startsWith('#')) { errors.push({ line: lineNum, msg: 'Channel #' + channelCount + (name ? ' "' + name + '"' : '') + ': no stream URL found after #EXTINF' }); } else { if (!/^(https?|rtsp|rtp|udp|igmp|mms|rtmp):\/\//i.test(urlLine)) { warnings.push({ line: urlLineNum, msg: 'Channel #' + channelCount + (name ? ' "' + name + '"' : '') + ': unusual URL format' }); } if (urls[urlLine] !== undefined) { warnings.push({ line: urlLineNum, msg: 'Duplicate stream URL for "' + name + '" (also on line ' + urls[urlLine] + ')' }); } else { urls[urlLine] = urlLineNum; } } } i++; } showResults(filename, channelCount, errors, warnings); } function showResults(filename, channelCount, errors, warnings) { document.getElementById('resultsFilename').textContent = filename; var statsRow = document.getElementById('statsRow'); var dupeCount = warnings.filter(function(w) { return w.msg.indexOf('Duplicate') === 0; }).length; statsRow.textContent = ''; [ { val: channelCount.toLocaleString(), label: 'Channels', cls: '' }, { val: errors.length, label: 'Errors', cls: errors.length > 0 ? 'tool-stat--error' : '' }, { val: warnings.length, label: 'Warnings', cls: warnings.length > 0 ? 'tool-stat--warning' : '' }, { val: dupeCount, label: 'Duplicates', 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); }); var total = errors.length * 3 + warnings.length; var score = Math.max(0, Math.min(100, Math.round(100 - (total / Math.max(channelCount, 1)) * 200))); var scoreColor = score >= 80 ? 'var(--accent-success)' : score >= 50 ? 'var(--accent-warning)' : 'var(--accent-danger)'; document.getElementById('scoreText').textContent = score + '/100 - ' + (score >= 80 ? 'Good' : score >= 50 ? 'Fair' : 'Poor'); var fill = document.getElementById('scoreFill'); fill.style.width = '0%'; setTimeout(function() { fill.style.width = score + '%'; fill.style.background = scoreColor; }, 50); var issueList = document.getElementById('issueList'); issueList.textContent = ''; function renderGroup(items, type) { if (!items.length) return; var group = document.createElement('div'); group.className = 'tool-issue-group'; var header = document.createElement('div'); header.className = 'tool-issue-group-header tool-issue--' + type; header.textContent = (type === 'error' ? 'Errors' : 'Warnings') + ' (' + items.length + ')'; group.appendChild(header); var list = document.createElement('div'); list.className = 'tool-issue-list'; items.slice(0, 50).forEach(function(issue) { var item = document.createElement('div'); item.className = 'tool-issue-item'; var lineSpan = document.createElement('span'); lineSpan.className = 'tool-issue-line'; lineSpan.textContent = 'L' + issue.line; var msgSpan = document.createElement('span'); msgSpan.className = 'tool-issue-msg'; msgSpan.textContent = issue.msg; item.appendChild(lineSpan); item.appendChild(msgSpan); list.appendChild(item); }); if (items.length > 50) { var more = document.createElement('div'); more.className = 'tool-issue-more'; more.textContent = '… and ' + (items.length - 50) + ' more ' + type + 's'; list.appendChild(more); } group.appendChild(list); issueList.appendChild(group); } renderGroup(errors, 'error'); renderGroup(warnings, 'warning'); document.getElementById('successMsg').style.display = (errors.length + warnings.length === 0) ? '' : 'none'; loading.style.display = 'none'; results.style.display = ''; } })();