mirror of
https://github.com/iptv-org/iptv
synced 2026-03-21 19:31:01 -04:00
update tests & replace ffprobe -> mediainfo.js
This commit is contained in:
@@ -5,21 +5,16 @@ import { Stream } from '../../models'
|
||||
import { program } from 'commander'
|
||||
import { eachLimit } from 'async-es'
|
||||
import chalk from 'chalk'
|
||||
import child_process from 'node:child_process'
|
||||
import os from 'node:os'
|
||||
import dns from 'node:dns'
|
||||
import type { DataLoaderData } from '../../types/dataLoader'
|
||||
import type { DataProcessorData } from '../../types/dataProcessor'
|
||||
|
||||
const cpus = os.cpus()
|
||||
|
||||
const LIVE_UPDATE_INTERVAL = 5000
|
||||
const LIVE_UPDATE_MAX_STREAMS = 100
|
||||
|
||||
let errors = 0
|
||||
let warnings = 0
|
||||
const results = {}
|
||||
let interval
|
||||
const results: { [key: string]: string } = {}
|
||||
let interval: string | number | NodeJS.Timeout | undefined
|
||||
let streams = new Collection()
|
||||
let isLiveUpdateEnabled = true
|
||||
|
||||
@@ -28,8 +23,8 @@ program
|
||||
.option(
|
||||
'-p, --parallel <number>',
|
||||
'Batch size of streams to test concurrently',
|
||||
cpus.length,
|
||||
(value: string) => parseInt(value)
|
||||
(value: string) => parseInt(value),
|
||||
10
|
||||
)
|
||||
.option('-x, --proxy <url>', 'Use the specified proxy')
|
||||
.parse(process.argv)
|
||||
@@ -40,24 +35,6 @@ const logger = new Logger()
|
||||
const tester = new StreamTester()
|
||||
|
||||
async function main() {
|
||||
if (await isOffline()) {
|
||||
logger.error(chalk.red('Internet connection is required for the script to work'))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
child_process.execSync('ffprobe -version', { stdio: 'ignore' })
|
||||
} catch {
|
||||
logger.error(
|
||||
chalk.red(
|
||||
'For the script to work, the "ffprobe" library must be installed (https://ffmpeg.org/download.html)'
|
||||
)
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
logger.info('loading data from api...')
|
||||
const processor = new DataProcessor()
|
||||
const dataStorage = new Storage(DATA_DIR)
|
||||
@@ -158,7 +135,7 @@ function drawTable() {
|
||||
}
|
||||
}
|
||||
|
||||
function onFinish(error) {
|
||||
function onFinish(error: any) {
|
||||
clearInterval(interval)
|
||||
|
||||
if (error) {
|
||||
@@ -181,11 +158,3 @@ function onFinish(error) {
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
async function isOffline() {
|
||||
return new Promise((resolve, reject) => {
|
||||
dns.lookup('info.cern.ch', err => {
|
||||
if (err) resolve(true)
|
||||
reject(false)
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
@@ -1,27 +1,83 @@
|
||||
import { Stream } from '../models'
|
||||
import { IPTVChecker } from 'iptv-checker'
|
||||
import { TESTING } from '../constants'
|
||||
import MediainfoFactory from 'mediainfo.js'
|
||||
|
||||
export class StreamTester {
|
||||
checker: IPTVChecker
|
||||
|
||||
constructor() {
|
||||
this.checker = new IPTVChecker()
|
||||
}
|
||||
constructor() {}
|
||||
|
||||
async test(stream: Stream) {
|
||||
if (TESTING) {
|
||||
const results = (await import('../../tests/__data__/input/playlist_test/results.js')).default
|
||||
|
||||
return results[stream.url]
|
||||
return results[stream.url as keyof typeof results]
|
||||
} else {
|
||||
return this.checker.checkStream({
|
||||
url: stream.url,
|
||||
http: {
|
||||
referrer: stream.getReferrer(),
|
||||
'user-agent': stream.getUserAgent()
|
||||
try {
|
||||
const controller = new AbortController()
|
||||
const timeout = 10000
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
||||
|
||||
const res = await fetch(stream.url, {
|
||||
signal: controller.signal,
|
||||
headers: {
|
||||
'User-Agent': stream.getUserAgent() || 'Mozilla/5.0',
|
||||
Referer: stream.getReferrer()
|
||||
}
|
||||
})
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (!res.ok) {
|
||||
return {
|
||||
status: {
|
||||
ok: false,
|
||||
code: `HTTP_${res.status}`
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const mediainfo = await MediainfoFactory({ format: 'object' })
|
||||
const buffer = await res.arrayBuffer()
|
||||
const result = await mediainfo.analyzeData(
|
||||
() => buffer.byteLength,
|
||||
(size: any, offset: number | undefined) =>
|
||||
Buffer.from(buffer).subarray(offset, offset + size)
|
||||
)
|
||||
|
||||
if (result && result.media && result.media.track.length > 0) {
|
||||
return {
|
||||
status: {
|
||||
ok: true,
|
||||
code: 'OK'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
status: {
|
||||
ok: false,
|
||||
code: 'NO_VIDEO'
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
let code = 'UNKNOWN_ERROR'
|
||||
if (error.name === 'AbortError') {
|
||||
code = 'TIMEOUT'
|
||||
} else if (error.cause) {
|
||||
const cause = error.cause as Error & { code?: string }
|
||||
if (cause.code) {
|
||||
code = cause.code
|
||||
} else {
|
||||
code = cause.name
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
status: {
|
||||
ok: false,
|
||||
code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user