Initial commit: StreamFlow IPTV platform
This commit is contained in:
commit
73a8ae9ffd
1240 changed files with 278451 additions and 0 deletions
94
backend/utils/m3uParser.js
Normal file
94
backend/utils/m3uParser.js
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
const axios = require('axios');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { db } = require('../database/db');
|
||||
const logger = require('./logger');
|
||||
|
||||
const parseM3U = async (source, playlistId, isFile = false) => {
|
||||
try {
|
||||
let content;
|
||||
|
||||
if (isFile) {
|
||||
content = fs.readFileSync(source, 'utf8');
|
||||
} else {
|
||||
const response = await axios.get(source, { timeout: 30000 });
|
||||
content = response.data;
|
||||
}
|
||||
|
||||
const lines = content.split('\n').map(line => line.trim());
|
||||
const channels = [];
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i].startsWith('#EXTINF:')) {
|
||||
const info = lines[i];
|
||||
const url = lines[i + 1];
|
||||
|
||||
if (!url || url.startsWith('#')) continue;
|
||||
|
||||
const nameMatch = info.match(/,(.+)$/);
|
||||
const name = nameMatch ? nameMatch[1].trim() : 'Unknown';
|
||||
|
||||
const tvgIdMatch = info.match(/tvg-id="([^"]*)"/);
|
||||
const tvgNameMatch = info.match(/tvg-name="([^"]*)"/);
|
||||
const tvgLogoMatch = info.match(/tvg-logo="([^"]*)"/);
|
||||
const groupTitleMatch = info.match(/group-title="([^"]*)"/);
|
||||
const languageMatch = info.match(/tvg-language="([^"]*)"/);
|
||||
const countryMatch = info.match(/tvg-country="([^"]*)"/);
|
||||
|
||||
const isRadio = info.toLowerCase().includes('radio') ||
|
||||
groupTitleMatch?.[1]?.toLowerCase().includes('radio') ||
|
||||
url.toLowerCase().includes('radio');
|
||||
|
||||
channels.push({
|
||||
playlistId,
|
||||
name,
|
||||
url,
|
||||
logo: tvgLogoMatch ? tvgLogoMatch[1] : null,
|
||||
groupName: groupTitleMatch ? groupTitleMatch[1] : 'Uncategorized',
|
||||
tvgId: tvgIdMatch ? tvgIdMatch[1] : null,
|
||||
tvgName: tvgNameMatch ? tvgNameMatch[1] : null,
|
||||
language: languageMatch ? languageMatch[1] : null,
|
||||
country: countryMatch ? countryMatch[1] : null,
|
||||
isRadio: isRadio ? 1 : 0
|
||||
});
|
||||
|
||||
i++; // Skip the URL line
|
||||
}
|
||||
}
|
||||
|
||||
// Insert channels in batches
|
||||
const batchSize = 100;
|
||||
for (let i = 0; i < channels.length; i += batchSize) {
|
||||
const batch = channels.slice(i, i + batchSize);
|
||||
const stmt = db.prepare(`
|
||||
INSERT INTO channels (playlist_id, name, url, logo, group_name, tvg_id, tvg_name, language, country, is_radio)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`);
|
||||
|
||||
for (const channel of batch) {
|
||||
stmt.run(
|
||||
channel.playlistId,
|
||||
channel.name,
|
||||
channel.url,
|
||||
channel.logo,
|
||||
channel.groupName,
|
||||
channel.tvgId,
|
||||
channel.tvgName,
|
||||
channel.language,
|
||||
channel.country,
|
||||
channel.isRadio
|
||||
);
|
||||
}
|
||||
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
logger.info(`Parsed ${channels.length} channels for playlist ${playlistId}`);
|
||||
return channels.length;
|
||||
} catch (error) {
|
||||
logger.error('M3U parsing error:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { parseM3U };
|
||||
Loading…
Add table
Add a link
Reference in a new issue