Playlist Format Converter
Convert your playlist files between M3U and PLS formats. Paste your playlist content or upload a file, select the formats, and convert!
Warning: File extension not recognized. Attempting auto-detection.
'; } }; reader.onerror = function() { resultArea.style.display = 'block'; resultArea.innerHTML = 'Error reading file.
'; inputPlaylistContent.value = ''; }; reader.readAsText(file); } /** * Initiates the playlist conversion process. */ function initiateConversion() { const inputContent = document.getElementById('inputPlaylistContent').value.trim(); const inputFormatSelect = document.getElementById('inputFormatSelect'); const outputFormatSelect = document.getElementById('outputFormatSelect'); const outputPlaylistContent = document.getElementById('outputPlaylistContent'); const resultArea = document.getElementById('resultArea'); const downloadPdfButton = document.getElementById('downloadPdfButton'); if (!inputContent) { resultArea.style.display = 'block'; resultArea.innerHTML = 'Please paste playlist content or upload a file.
'; downloadPdfButton.style.display = 'none'; return; } let inputFormat = inputFormatSelect.value; const outputFormat = outputFormatSelect.value; // Auto-detect input format if selected if (inputFormat === 'auto') { if (inputContent.startsWith('#EXTM3U')) { inputFormat = 'm3u'; } else if (inputContent.startsWith('')) { inputFormat = 'pls'; } else { resultArea.style.display = 'block'; resultArea.innerHTML = 'Could not auto-detect input format. Please select it manually.
'; downloadPdfButton.style.display = 'none'; return; } inputFormatSelect.value = inputFormat; // Update dropdown to detected format } let convertedContent = ''; let errorMessage = ''; if (inputFormat === outputFormat) { errorMessage = 'Input and Output formats are the same. No conversion needed.'; convertedContent = inputContent; // Just copy content } else if (inputFormat === 'm3u' && outputFormat === 'pls') { convertedContent = convertM3uToPls(inputContent); } else if (inputFormat === 'pls' && outputFormat === 'm3u') { convertedContent = convertPlsToM3u(inputContent); } else { errorMessage = `Unsupported conversion: ${inputFormat.toUpperCase()} to ${outputFormat.toUpperCase()}.`; } if (errorMessage) { resultArea.style.display = 'block'; resultArea.innerHTML = `${errorMessage}
`; outputPlaylistContent.value = ''; downloadPdfButton.style.display = 'none'; } else { outputPlaylistContent.value = convertedContent; resultArea.style.display = 'block'; resultArea.innerHTML = `Conversion successful! Download the .${outputFormat} file below.
`; downloadConvertedFile(convertedContent, `converted_playlist.${outputFormat}`); downloadPdfButton.style.display = 'block'; // Store data for PDF report resultArea.dataset.originalFormat = inputFormat; resultArea.dataset.convertedFormat = outputFormat; resultArea.dataset.originalContentPreview = inputContent.substring(0, 500) + (inputContent.length > 500 ? '...' : ''); resultArea.dataset.convertedContentPreview = convertedContent.substring(0, 500) + (convertedContent.length > 500 ? '...' : ''); } } /** * Converts M3U playlist content to PLS format. * Basic M3U: #EXTINF:duration,title\npath * Basic PLS: \nFileX=path\nTitleX=title\nLengthX=duration */ function convertM3uToPls(m3uContent) { const lines = m3uContent.split('\n').map(line => line.trim()).filter(line => line.length > 0); let plsLines = ['', 'NumberOfEntries=0', 'Version=2']; let entryCount = 0; for (let i = 0; i < lines.length; i++) { if (lines[i].startsWith('#EXTINF:')) { entryCount++; const infoParts = lines[i].substring('#EXTINF:'.length).split(','); const duration = infoParts[0]; const title = infoParts.slice(1).join(','); // Title might contain commas const filePath = lines[++i]; // Next line is the file path if (filePath) { plsLines.push(`File${entryCount}=${filePath}`); plsLines.push(`Title${entryCount}=${title}`); plsLines.push(`Length${entryCount}=${duration}`); } } else if (!lines[i].startsWith('#')) { // Handle simple M3U (just file paths) entryCount++; plsLines.push(`File${entryCount}=${lines[i]}`); plsLines.push(`Title${entryCount}=${lines[i].split('/').pop().split('\\').pop()}`); // Derive title from filename plsLines.push(`Length${entryCount}=-1`); // Unknown length } } // Update NumberOfEntries plsLines[1] = `NumberOfEntries=${entryCount}`; return plsLines.join('\n'); } /** * Converts PLS playlist content to M3U format. */ function convertPlsToM3u(plsContent) { const lines = plsContent.split('\n').map(line => line.trim()).filter(line => line.length > 0); let m3uLines = ['#EXTM3U']; const entries = {}; let maxEntryNum = 0; lines.forEach(line => { const parts = line.split('='); if (parts.length < 2) return; const key = parts[0].trim(); const value = parts.slice(1).join('=').trim(); // Value might contain '=' const match = key.match(/(File|Title|Length)(\d+)/i); if (match) { const type = match[1].toLowerCase(); const num = parseInt(match[2], 10); if (!entries[num]) { entries[num] = { file: '', title: '', length: -1 }; } entries[num][type] = value; if (num > maxEntryNum) maxEntryNum = num; } }); for (let i = 1; i <= maxEntryNum; i++) { const entry = entries[i]; if (entry && entry.file) { const duration = entry.length !== -1 ? entry.length : 0; // Use 0 for unknown length in M3U const title = entry.title || entry.file.split('/').pop().split('\\').pop(); // Fallback title m3uLines.push(`#EXTINF:${duration},${title}`); m3uLines.push(entry.file); } } return m3uLines.join('\n'); } /** * Triggers the download of the converted playlist file. * @param {string} content The content of the file to download. * @param {string} filename The desired filename including extension. */ function downloadConvertedFile(content, filename) { const blob = new Blob([content], { type: 'text/plain;charset=utf-8;' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } /** * Clears all input/output fields and hides results/PDF button. */ function clearAll() { document.getElementById('inputPlaylistContent').value = ''; document.getElementById('outputPlaylistContent').value = ''; document.getElementById('fileUpload').value = ''; // Clear file input document.getElementById('inputFormatSelect').value = 'auto'; // Reset format selection document.getElementById('outputFormatSelect').value = 'm3u'; const resultArea = document.getElementById('resultArea'); const downloadPdfButton = document.getElementById('downloadPdfButton'); resultArea.style.display = 'none'; resultArea.innerHTML = ''; // Clear stored data for PDF delete resultArea.dataset.originalFormat; delete resultArea.dataset.convertedFormat; delete resultArea.dataset.originalContentPreview; delete resultArea.dataset.convertedContentPreview; downloadPdfButton.style.display = 'none'; } /** * Generates a PDF summary of the conversion. */ function generatePdf() { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { console.error('jsPDF library not loaded. Cannot generate PDF.'); const resultArea = document.getElementById('resultArea'); if (resultArea) { resultArea.innerHTML = 'PDF generation failed. Library not loaded.
'; } return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); const resultArea = document.getElementById('resultArea'); // Retrieve stored data for PDF const originalFormat = resultArea.dataset.originalFormat || 'N/A'; const convertedFormat = resultArea.dataset.convertedFormat || 'N/A'; const originalContentPreview = resultArea.dataset.originalContentPreview || 'No content provided.'; const convertedContentPreview = resultArea.dataset.convertedContentPreview || 'No content converted.'; const generationDate = new Date().toLocaleString(); let yOffset = 20; // Title doc.setFontSize(24); doc.setTextColor(44, 62, 80); doc.text("Playlist Conversion Report", 105, yOffset, { align: 'center' }); yOffset += 20; // Summary details doc.setFontSize(14); doc.setTextColor(51, 51, 51); doc.text(`Conversion Date: ${generationDate}`, 20, yOffset); yOffset += 10; doc.text(`Original Format: ${originalFormat.toUpperCase()}`, 20, yOffset); yOffset += 10; doc.text(`Converted To: ${convertedFormat.toUpperCase()}`, 20, yOffset); yOffset += 20; // Original Content Preview doc.setFontSize(12); doc.text("Original Content Preview (first 500 chars):", 20, yOffset); yOffset += 10; const originalPreviewLines = doc.splitTextToSize(originalContentPreview, 170); doc.text(originalPreviewLines, 20, yOffset); yOffset += (originalPreviewLines.length * 7) + 15; // Converted Content Preview if (yOffset > 250) { // Check for page break doc.addPage(); yOffset = 20; } doc.setFontSize(12); doc.text("Converted Content Preview (first 500 chars):", 20, yOffset); yOffset += 10; const convertedPreviewLines = doc.splitTextToSize(convertedContentPreview, 170); doc.text(convertedPreviewLines, 20, yOffset); yOffset += (convertedPreviewLines.length * 7) + 15; // Footer doc.setFontSize(9); doc.setTextColor(150, 150, 150); doc.text(`Report Generated by Playlist Converter Tool`, 20, doc.internal.pageSize.height - 15); doc.save("Playlist_Conversion_Summary.pdf"); }