From e07e71d324f6a09af99d1eb967645155d3fa4b98 Mon Sep 17 00:00:00 2001 From: SpaceMonkey <> Date: Sat, 1 Mar 2025 23:46:36 +0000 Subject: [PATCH] no message --- .forgejo/scripts/countries.js | 173 ++++++++++++++++++---------------- .forgejo/scripts/sort-m3u.js | 118 +++++++++++++---------- 2 files changed, 160 insertions(+), 131 deletions(-) diff --git a/.forgejo/scripts/countries.js b/.forgejo/scripts/countries.js index ac60a0e..b58fa84 100644 --- a/.forgejo/scripts/countries.js +++ b/.forgejo/scripts/countries.js @@ -2,93 +2,108 @@ const fs = require('fs'); const path = require('path'); function splitByGroup(filePath) { - const content = fs.readFileSync(filePath, 'utf8'); - const lines = content.split('\n'); + const content = fs.readFileSync(filePath, 'utf8'); + const lines = content.split('\n'); + + // Create groups directory if it doesn't exist + const groupsDir = path.join(path.dirname(filePath), 'countries'); + if (!fs.existsSync(groupsDir)) { + fs.mkdirSync(groupsDir); + } + + // Get existing country files + const existingFiles = fs.readdirSync(groupsDir) + .filter(file => file.endsWith('.m3u')) + .map(file => file.toLowerCase()); + + const groups = {}; + + // First line should be #EXTM3U + const header = lines[0]; + if (!header.startsWith('#EXTM3U')) { + throw new Error('Invalid M3U file: Missing #EXTM3U header'); + } + + // Process the file line by line to handle multi-line entries + let currentGroupTitle = null; + let currentEntry = []; + let isInEntry = false; + + for (let i = 1; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line) continue; - // Create groups directory if it doesn't exist - const groupsDir = path.join(path.dirname(filePath), 'countries'); - if (!fs.existsSync(groupsDir)) { - fs.mkdirSync(groupsDir); - } - - // Get existing country files - const existingFiles = fs.readdirSync(groupsDir) - .filter(file => file.endsWith('.m3u')) - .map(file => file.toLowerCase()); - - const groups = {}; - let currentExtinf = null; - - // First line should be #EXTM3U - const header = lines[0]; - if (!header.startsWith('#EXTM3U')) { - throw new Error('Invalid M3U file: Missing #EXTM3U header'); - } - - // Process each line - lines.forEach(line => { - line = line.trim(); - if (!line) return; + if (line.startsWith('#EXTINF')) { + // Start of a new entry + isInEntry = true; + currentEntry = [line]; + + // Extract the group title + const groupMatch = line.match(/group-title="([^"]*)"/); + currentGroupTitle = groupMatch ? groupMatch[1] : 'Unknown'; + + // Initialize the group if it doesn't exist + if (!groups[currentGroupTitle]) { + groups[currentGroupTitle] = ['#EXTM3U']; + } + } else if (isInEntry) { + // Add the line to the current entry + currentEntry.push(line); + + // If this is a URL line (doesn't start with #), this completes the entry + if (!line.startsWith('#')) { + // Add all lines of the entry to the appropriate group + groups[currentGroupTitle].push(...currentEntry); - if (line.startsWith('#EXTINF')) { - currentExtinf = line; - const groupMatch = line.match(/group-title="([^"]*)"/); - const groupTitle = groupMatch ? groupMatch[1] : 'Unknown'; - - if (!groups[groupTitle]) { - groups[groupTitle] = ['#EXTM3U']; - } - groups[groupTitle].push(line); - } else if (currentExtinf && !line.startsWith('#')) { - // This is a URL line - const groupMatch = currentExtinf.match(/group-title="([^"]*)"/); - const groupTitle = groupMatch ? groupMatch[1] : 'Unknown'; - groups[groupTitle].push(line); - currentExtinf = null; - } - }); - - // Get list of current group files that should exist - const currentGroupFiles = Object.keys(groups).map(groupTitle => - `${groupTitle.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.m3u` - ); - - // Remove files for groups that no longer exist - existingFiles.forEach(existingFile => { - if (!currentGroupFiles.includes(existingFile)) { - const fileToRemove = path.join(groupsDir, existingFile); - fs.unlinkSync(fileToRemove); - console.log(`Removed obsolete group playlist: ${existingFile}`); - } - }); - - // Write each group to a separate file - Object.entries(groups).forEach(([groupTitle, groupLines]) => { - const safeGroupTitle = groupTitle.replace(/[^a-z0-9]/gi, '_').toLowerCase(); - const groupFilePath = path.join(groupsDir, `${safeGroupTitle}.m3u`); - fs.writeFileSync(groupFilePath, groupLines.join('\n') + '\n'); - console.log(`Created/updated group playlist: ${groupFilePath}`); - }); - - // Create a summary of the split - const summary = Object.entries(groups).map(([group, lines]) => { - const channelCount = (lines.length - 1) / 2; // Subtract header and divide by 2 (EXTINF + URL) - return `${group}: ${channelCount} channels`; - }); - - console.log('\nPlaylist split summary:'); - console.log(summary.join('\n')); + // Reset for the next entry + isInEntry = false; + currentEntry = []; + } + } + } + + // Get list of current group files that should exist + const currentGroupFiles = Object.keys(groups).map(groupTitle => + `${groupTitle.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.m3u` + ); + + // Remove files for groups that no longer exist + existingFiles.forEach(existingFile => { + if (!currentGroupFiles.includes(existingFile)) { + const fileToRemove = path.join(groupsDir, existingFile); + fs.unlinkSync(fileToRemove); + console.log(`Removed obsolete group playlist: ${existingFile}`); + } + }); + + // Write each group to a separate file + Object.entries(groups).forEach(([groupTitle, groupLines]) => { + const safeGroupTitle = groupTitle.replace(/[^a-z0-9]/gi, '_').toLowerCase(); + const groupFilePath = path.join(groupsDir, `${safeGroupTitle}.m3u`); + fs.writeFileSync(groupFilePath, groupLines.join('\n') + '\n'); + console.log(`Created/updated group playlist: ${groupFilePath}`); + }); + + // Create a summary of the split + // Count entries properly by counting #EXTINF lines + const summary = Object.entries(groups).map(([group, lines]) => { + const channelCount = lines.filter(line => line.startsWith('#EXTINF')).length; + return `${group}: ${channelCount} channels`; + }); + + console.log('\nPlaylist split summary:'); + console.log(summary.join('\n')); } const filePath = process.argv[2]; if (!filePath) { - console.error('Please provide the path to mystique.m3u'); - process.exit(1); + console.error('Please provide the path to mystique.m3u'); + process.exit(1); } try { - splitByGroup(filePath); + splitByGroup(filePath); } catch (error) { - console.error('Error splitting mystique.m3u:', error.message); - process.exit(1); + console.error('Error splitting mystique.m3u:', error.message); + process.exit(1); } \ No newline at end of file diff --git a/.forgejo/scripts/sort-m3u.js b/.forgejo/scripts/sort-m3u.js index 70d0eef..39c8417 100644 --- a/.forgejo/scripts/sort-m3u.js +++ b/.forgejo/scripts/sort-m3u.js @@ -1,67 +1,81 @@ const fs = require('fs'); function sortM3uByGroupTitle(filePath) { - // Read the file - const content = fs.readFileSync(filePath, 'utf8'); - const lines = content.split('\n'); + // Read the file + const content = fs.readFileSync(filePath, 'utf8'); + const lines = content.split('\n'); + + // First line should be #EXTM3U + const header = lines[0]; + if (!header.startsWith('#EXTM3U')) { + throw new Error('Invalid M3U file: Missing #EXTM3U header'); + } + + // Group the entries + const entries = []; + let currentEntry = []; + + for (let i = 1; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line) continue; - // First line should be #EXTM3U - const header = lines[0]; - if (!header.startsWith('#EXTM3U')) { - throw new Error('Invalid M3U file: Missing #EXTM3U header'); - } - - // Group the entries - const entries = []; - let currentEntry = []; - - for (let i = 1; i < lines.length; i++) { - const line = lines[i].trim(); - if (!line) continue; - - if (line.startsWith('#EXTINF')) { - if (currentEntry.length === 2) { - entries.push(currentEntry); - } - currentEntry = [line]; - } else if (currentEntry.length === 1) { - currentEntry.push(line); - } - } - - // Add the last entry if exists - if (currentEntry.length === 2) { + if (line.startsWith('#EXTINF')) { + // If we have a previous entry that's complete (has a URL), add it + if (currentEntry.length > 0 && !currentEntry[currentEntry.length - 1].startsWith('#')) { entries.push(currentEntry); + currentEntry = []; + } + + // Start a new entry + currentEntry = [line]; + } else if (line.startsWith('#')) { + // This is another directive line (like #EXTVLCOPT), add it to the current entry + if (currentEntry.length > 0) { + currentEntry.push(line); + } + } else { + // This is a URL line, add it to complete the current entry + if (currentEntry.length > 0) { + currentEntry.push(line); + entries.push(currentEntry); + currentEntry = []; + } } - - // Sort entries by group-title - entries.sort((a, b) => { - const groupTitleA = (a[0].match(/group-title="([^"]*)"/) || [])[1] || ''; - const groupTitleB = (b[0].match(/group-title="([^"]*)"/) || [])[1] || ''; - return groupTitleA.localeCompare(groupTitleB); - }); - - // Rebuild the file content - const sortedContent = [ - header, - ...entries.flatMap(entry => entry) - ].join('\n'); - - // Write back to file - fs.writeFileSync(filePath, sortedContent); - console.log('M3U file has been sorted by group-title'); + } + + // Add the last entry if complete + if (currentEntry.length > 0 && !currentEntry[currentEntry.length - 1].startsWith('#')) { + entries.push(currentEntry); + } + + // Sort entries by group-title + entries.sort((a, b) => { + const groupTitleA = (a[0].match(/group-title="([^"]*)"/) || [])[1] || ''; + const groupTitleB = (b[0].match(/group-title="([^"]*)"/) || [])[1] || ''; + return groupTitleA.localeCompare(groupTitleB); + }); + + // Rebuild the file content + const sortedContent = [ + header, + ...entries.flatMap(entry => entry) + ].join('\n'); + + // Write back to file + fs.writeFileSync(filePath, sortedContent); + console.log('M3U file has been sorted by group-title'); } // Get file path from command line argument const filePath = process.argv[2]; if (!filePath) { - console.error('Please provide a file path'); - process.exit(1); + console.error('Please provide a file path'); + process.exit(1); } try { - sortM3uByGroupTitle(filePath); + sortM3uByGroupTitle(filePath); } catch (error) { - console.error('Error:', error.message); - process.exit(1); -} + console.error('Error:', error.message); + process.exit(1); +} \ No newline at end of file