iptv/scripts/commands/playlist/cleaner.js

91 lines
2.5 KiB
JavaScript

const { file, parser, logger, checker, m3u } = require('../../core')
const { program } = require('commander')
program
.argument('[filepath]', 'Path to file to validate')
.option('-t, --timeout <timeout>', 'Set timeout for each request', parser.parseNumber, 60000)
.option('-d, --delay <delay>', 'Set delay for each request', parser.parseNumber, 0)
.option('--debug', 'Enable debug mode')
.parse(process.argv)
const options = program.opts()
async function main() {
const files = program.args.length ? program.args : await file.list('streams/*.m3u')
for (const filepath of files) {
if (!filepath.endsWith('.m3u')) continue
logger.info(`${filepath}`)
const playlist = await parser.parsePlaylist(filepath)
const before = playlist.items.length
for (const stream of playlist.items) {
if (options.debug) logger.info(stream.url)
const [_, status] = stream.raw.match(/status="([a-z]+)"/) || [null, null]
stream.status = status
if (status === 'error' && /^(http|https)/.test(stream.url) && !/\[.*\]$/.test(stream.name)) {
const result = await checkStream(stream)
const newStatus = parseStatus(result.error)
if (status === newStatus) {
stream.remove = true
logger.info(`removed "${stream.name}"`)
}
}
}
const items = playlist.items
.filter(i => !i.remove)
.map(item => ({
attrs: {
'tvg-id': item.tvg.id,
status: item.status,
'user-agent': item.http['user-agent'] || undefined
},
title: item.name,
url: item.url,
vlcOpts: {
'http-referrer': item.http.referrer || undefined,
'http-user-agent': item.http['user-agent'] || undefined
}
}))
if (before !== items.length) {
const output = m3u.create(items)
await file.create(filepath, output)
logger.info(`saved`)
}
}
}
main()
async function checkStream(item) {
const config = {
timeout: options.timeout,
delay: options.delay,
debug: options.debug
}
const request = {
url: item.url,
http: {
referrer: item.http.referrer,
'user-agent': item.http['user-agent']
}
}
return checker.check(request, config)
}
function parseStatus(error) {
if (!error) return 'online'
switch (error) {
case 'Operation timed out':
return 'timeout'
case 'Server returned 403 Forbidden (access denied)':
return 'blocked'
default:
return 'error'
}
}