2025-03-15 07:31:10 +03:00
|
|
|
import { Stream } from '../models'
|
|
|
|
|
import { TESTING } from '../constants'
|
2025-09-03 06:18:10 +03:00
|
|
|
import mediaInfoFactory from 'mediainfo.js'
|
2025-03-15 07:31:10 +03:00
|
|
|
|
|
|
|
|
export class StreamTester {
|
2025-09-02 17:00:50 +00:00
|
|
|
constructor() {}
|
2025-03-15 07:31:10 +03:00
|
|
|
|
|
|
|
|
async test(stream: Stream) {
|
|
|
|
|
if (TESTING) {
|
2025-03-29 11:39:46 +03:00
|
|
|
const results = (await import('../../tests/__data__/input/playlist_test/results.js')).default
|
2025-03-15 07:31:10 +03:00
|
|
|
|
2025-09-02 17:00:50 +00:00
|
|
|
return results[stream.url as keyof typeof results]
|
2025-03-15 07:31:10 +03:00
|
|
|
} else {
|
2025-09-02 17:00:50 +00:00
|
|
|
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}`
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 06:18:10 +03:00
|
|
|
const mediainfo = await mediaInfoFactory({ format: 'object' })
|
2025-09-02 17:00:50 +00:00
|
|
|
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
|
|
|
|
|
}
|
2025-03-15 07:31:10 +03:00
|
|
|
}
|
2025-09-02 17:00:50 +00:00
|
|
|
}
|
2025-03-15 07:31:10 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|