UNPKG

iptv-checker

Version:

Node.js CLI tool for checking links in IPTV playlists

137 lines (114 loc) 3.87 kB
import { HttpErrorParser } from './HttpErrorParser.js' import { SocksProxyAgent } from 'socks-proxy-agent' import { ProxyParser } from './ProxyParser.js' import { normalizeUrl } from './utils.js' import { TESTING } from '../constants.js' import axiosRetry from 'axios-retry' import errors from '../errors.js' import axios from 'axios' import https from 'https' export class StreamLoader { constructor({ logger, config, cache }) { this.cache = cache this.config = config this.logger = logger this.httpErrorParser = new HttpErrorParser() this.cancelToken = axios.CancelToken this.logger.debug('StreamLoader.constructor') const client = axios.create({ method: 'GET', timeout: this.config.timeout, maxContentLength: 100 * 1024, httpsAgent: new https.Agent({ rejectUnauthorized: false }), validateStatus: function (status) { return (status >= 200 && status < 400) || status === 405 } }) axiosRetry(client, { retries: this.config.retry, retryDelay: this.config.delay ? () => this.config.delay : axiosRetry.exponentialDelay, onRetry: retryCount => { this.logger.debug(`axiosRetry.retryCount: ${retryCount}`) } }) this.client = client } async load(item) { this.logger.debug('StreamLoader.load') this.logger.debug('item.url') this.logger.debug(item.url) if (!/^(http|https)/.test(item.url)) return Promise.resolve() const timeout = item.timeout || this.config.timeout let source = this.cancelToken.source() let options = { timeout, headers: {}, cancelToken: source.token } if (!TESTING) { setTimeout(() => { source.cancel('timeout') }, timeout) } const userAgent = item.http && item.http['user-agent'] ? item.http['user-agent'] : this.config.userAgent if (userAgent) { options.headers['User-Agent'] = userAgent } const referer = item.http && item.http.referrer ? item.http.referrer : this.config.httpReferer if (referer) { options.headers['Referer'] = referer } if (this.config.proxy) { const parser = new ProxyParser() const proxy = parser.parse(this.config.proxy) if ( proxy.protocol && ['socks', 'socks5', 'socks5h', 'socks4', 'socks4a'].includes(String(proxy.protocol)) ) { const socksProxyAgent = new SocksProxyAgent(this.config.proxy) options = { ...options, ...{ httpAgent: socksProxyAgent, httpsAgent: socksProxyAgent } } } else { options = { ...options, ...{ proxy } } } } try { const response = await this.client(item.url, options) const responseUrl = response.request.res.responseUrl const itemUrlNorm = normalizeUrl(item.url) const responseUrlNorm = normalizeUrl(responseUrl) this.logger.debug('itemUrlNorm') this.logger.debug(itemUrlNorm) this.logger.debug('responseUrl') this.logger.debug(responseUrl) this.logger.debug('responseUrlNorm') this.logger.debug(responseUrlNorm) this.logger.debug('response.status') this.logger.debug(response.status) this.logger.debug('response.data') this.logger.debug(response.data) if (itemUrlNorm !== responseUrlNorm && this.cache.has(responseUrlNorm)) { return Promise.reject({ ok: false, code: 'DUPLICATE', message: `Duplicate` }) } else { this.cache.add(responseUrlNorm) } return response } catch (err) { this.logger.debug(err.stack) const code = this.httpErrorParser.parse(err) if (code === 'HTTP_MAX_CONTENT_LENGTH_EXCEEDED') { return Promise.resolve() } return Promise.reject({ ok: false, code, message: errors[code] }) } } }