mirror of
https://github.com/iptv-org/iptv
synced 2025-12-16 02:16:47 -05:00
Update scripts
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { PlaylistParser, StreamTester, CliTable } from '../../core'
|
import { PlaylistParser, StreamTester, CliTable } from '../../core'
|
||||||
import type { TestResult } from '../../core/streamTester'
|
import type { StreamTesterResult } from '../../core/streamTester'
|
||||||
import { ROOT_DIR, STREAMS_DIR } from '../../constants'
|
import { ROOT_DIR, STREAMS_DIR } from '../../constants'
|
||||||
import { Logger, Collection } from '@freearhey/core'
|
import { Logger, Collection } from '@freearhey/core'
|
||||||
import { program, OptionValues } from 'commander'
|
import { program, OptionValues } from 'commander'
|
||||||
@@ -92,10 +92,10 @@ async function runTest(stream: Stream) {
|
|||||||
const key = stream.getUniqKey()
|
const key = stream.getUniqKey()
|
||||||
results[key] = chalk.white('LOADING...')
|
results[key] = chalk.white('LOADING...')
|
||||||
|
|
||||||
const result: TestResult = await tester.test(stream)
|
const result: StreamTesterResult = await tester.test(stream)
|
||||||
|
|
||||||
let status = ''
|
let status = ''
|
||||||
const errorStatusCodes = ['ENOTFOUND', 'HTTP_404_NOT_FOUND']
|
const errorStatusCodes = ['ENOTFOUND', 'HTTP_404_NOT_FOUND', 'HTTP_404_UNKONWN_ERROR']
|
||||||
if (result.status.ok) status = chalk.green('OK')
|
if (result.status.ok) status = chalk.green('OK')
|
||||||
else if (errorStatusCodes.includes(result.status.code)) {
|
else if (errorStatusCodes.includes(result.status.code)) {
|
||||||
status = chalk.red(result.status.code)
|
status = chalk.red(result.status.code)
|
||||||
@@ -144,7 +144,7 @@ function drawTable() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onFinish(error: Error) {
|
function onFinish(error: Error | null | undefined) {
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ async function removeStreams({
|
|||||||
|
|
||||||
requests.forEach((issue: Issue) => {
|
requests.forEach((issue: Issue) => {
|
||||||
const data = issue.data
|
const data = issue.data
|
||||||
if (data.missing('streamUrl')) return
|
if (data.missing('stream_url')) return
|
||||||
|
|
||||||
const streamUrls = data.getString('streamUrl') || ''
|
const streamUrls = data.getString('stream_url') || ''
|
||||||
|
|
||||||
let changed = false
|
let changed = false
|
||||||
streamUrls
|
streamUrls
|
||||||
@@ -104,14 +104,14 @@ async function editStreams({
|
|||||||
requests.forEach((issue: Issue) => {
|
requests.forEach((issue: Issue) => {
|
||||||
const data = issue.data
|
const data = issue.data
|
||||||
|
|
||||||
if (data.missing('streamUrl')) return
|
if (data.missing('stream_url')) return
|
||||||
|
|
||||||
const stream: Stream = streams.first(
|
const stream: Stream = streams.first(
|
||||||
(_stream: Stream) => _stream.url === data.getString('streamUrl')
|
(_stream: Stream) => _stream.url === data.getString('stream_url')
|
||||||
)
|
)
|
||||||
if (!stream) return
|
if (!stream) return
|
||||||
|
|
||||||
const streamId = data.getString('streamId') || ''
|
const streamId = data.getString('stream_id') || ''
|
||||||
const [channelId, feedId] = streamId.split('@')
|
const [channelId, feedId] = streamId.split('@')
|
||||||
|
|
||||||
if (channelId) {
|
if (channelId) {
|
||||||
@@ -138,12 +138,12 @@ async function addStreams({
|
|||||||
)
|
)
|
||||||
requests.forEach((issue: Issue) => {
|
requests.forEach((issue: Issue) => {
|
||||||
const data = issue.data
|
const data = issue.data
|
||||||
if (data.missing('streamId') || data.missing('streamUrl')) return
|
if (data.missing('stream_id') || data.missing('stream_url')) return
|
||||||
if (streams.includes((_stream: Stream) => _stream.url === data.getString('streamUrl'))) return
|
if (streams.includes((_stream: Stream) => _stream.url === data.getString('stream_url'))) return
|
||||||
const streamUrl = data.getString('streamUrl') || ''
|
const streamUrl = data.getString('stream_url') || ''
|
||||||
if (!isURI(streamUrl)) return
|
if (!isURI(streamUrl)) return
|
||||||
|
|
||||||
const streamId = data.getString('streamId') || ''
|
const streamId = data.getString('stream_id') || ''
|
||||||
const [channelId, feedId] = streamId.split('@')
|
const [channelId, feedId] = streamId.split('@')
|
||||||
|
|
||||||
const channel: sdk.Models.Channel | undefined = apiData.channelsKeyById.get(channelId)
|
const channel: sdk.Models.Channel | undefined = apiData.channelsKeyById.get(channelId)
|
||||||
@@ -151,9 +151,8 @@ async function addStreams({
|
|||||||
|
|
||||||
const label = data.getString('label') || ''
|
const label = data.getString('label') || ''
|
||||||
const quality = data.getString('quality') || null
|
const quality = data.getString('quality') || null
|
||||||
const httpUserAgent = data.getString('httpUserAgent') || null
|
const httpUserAgent = data.getString('http_user_agent') || null
|
||||||
const httpReferrer = data.getString('httpReferrer') || null
|
const httpReferrer = data.getString('http_referrer') || null
|
||||||
const directives = data.getArray('directives') || []
|
|
||||||
|
|
||||||
const stream = new Stream({
|
const stream = new Stream({
|
||||||
channel: channelId,
|
channel: channelId,
|
||||||
@@ -166,7 +165,7 @@ async function addStreams({
|
|||||||
})
|
})
|
||||||
|
|
||||||
stream.label = label
|
stream.label = label
|
||||||
stream.setDirectives(directives).updateTitle().updateFilepath()
|
stream.updateTitle().updateFilepath()
|
||||||
|
|
||||||
streams.add(stream)
|
streams.add(stream)
|
||||||
processedIssues.add(issue.number)
|
processedIssues.add(issue.number)
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ async function main() {
|
|||||||
const streams = await parser.parse(files)
|
const streams = await parser.parse(files)
|
||||||
logger.info(`found ${streams.count()} streams`)
|
logger.info(`found ${streams.count()} streams`)
|
||||||
|
|
||||||
let errors = new Collection()
|
const errors = new Collection()
|
||||||
let warnings = new Collection()
|
const warnings = new Collection()
|
||||||
const streamsGroupedByFilepath = streams.groupBy((stream: Stream) => stream.getFilepath())
|
const streamsGroupedByFilepath = streams.groupBy((stream: Stream) => stream.getFilepath())
|
||||||
for (const filepath of streamsGroupedByFilepath.keys()) {
|
for (const filepath of streamsGroupedByFilepath.keys()) {
|
||||||
const streams = streamsGroupedByFilepath.get(filepath)
|
const streams = streamsGroupedByFilepath.get(filepath)
|
||||||
@@ -97,8 +97,10 @@ async function main() {
|
|||||||
console.log(` ${chalk.gray(position)}${status}${logItem.message}`)
|
console.log(` ${chalk.gray(position)}${status}${logItem.message}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
errors = errors.concat(log.filter((logItem: LogItem) => logItem.type === 'error'))
|
log.forEach((logItem: LogItem) => {
|
||||||
warnings = warnings.concat(log.filter((logItem: LogItem) => logItem.type === 'warning'))
|
if (logItem.type === 'error') errors.add(logItem)
|
||||||
|
else if (logItem.type === 'warning') warnings.add(logItem)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ async function main() {
|
|||||||
issue.labels.find((label: string) => label === 'streams:remove')
|
issue.labels.find((label: string) => label === 'streams:remove')
|
||||||
)
|
)
|
||||||
removeRequests.forEach((issue: Issue) => {
|
removeRequests.forEach((issue: Issue) => {
|
||||||
const streamUrls = issue.data.getArray('streamUrl') || []
|
const streamUrls = issue.data.getArray('stream_url') || []
|
||||||
|
|
||||||
if (!streamUrls.length) {
|
if (!streamUrls.length) {
|
||||||
const result = {
|
const result = {
|
||||||
@@ -82,8 +82,8 @@ async function main() {
|
|||||||
const addRequests = issues.filter(issue => issue.labels.includes('streams:add'))
|
const addRequests = issues.filter(issue => issue.labels.includes('streams:add'))
|
||||||
const addRequestsBuffer = new Dictionary()
|
const addRequestsBuffer = new Dictionary()
|
||||||
addRequests.forEach((issue: Issue) => {
|
addRequests.forEach((issue: Issue) => {
|
||||||
const streamId = issue.data.getString('streamId') || ''
|
const streamId = issue.data.getString('stream_id') || ''
|
||||||
const streamUrl = issue.data.getString('streamUrl') || ''
|
const streamUrl = issue.data.getString('stream_url') || ''
|
||||||
const [channelId] = streamId.split('@')
|
const [channelId] = streamId.split('@')
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
@@ -114,8 +114,8 @@ async function main() {
|
|||||||
issue.labels.find((label: string) => label === 'streams:edit')
|
issue.labels.find((label: string) => label === 'streams:edit')
|
||||||
)
|
)
|
||||||
editRequests.forEach((issue: Issue) => {
|
editRequests.forEach((issue: Issue) => {
|
||||||
const streamId = issue.data.getString('streamId') || ''
|
const streamId = issue.data.getString('stream_id') || ''
|
||||||
const streamUrl = issue.data.getString('streamUrl') || ''
|
const streamUrl = issue.data.getString('stream_url') || ''
|
||||||
const [channelId] = streamId.split('@')
|
const [channelId] = streamId.split('@')
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
@@ -140,7 +140,7 @@ async function main() {
|
|||||||
)
|
)
|
||||||
const channelSearchRequestsBuffer = new Dictionary()
|
const channelSearchRequestsBuffer = new Dictionary()
|
||||||
channelSearchRequests.forEach((issue: Issue) => {
|
channelSearchRequests.forEach((issue: Issue) => {
|
||||||
const streamId = issue.data.getString('streamId') || issue.data.getString('channelId') || ''
|
const streamId = issue.data.getString('stream_id') || issue.data.getString('channel_id') || ''
|
||||||
const [channelId, feedId] = streamId.split('@')
|
const [channelId, feedId] = streamId.split('@')
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
|
|||||||
@@ -3,20 +3,18 @@ import { IssueData } from './issueData'
|
|||||||
import { Issue } from '../models'
|
import { Issue } from '../models'
|
||||||
|
|
||||||
const FIELDS = new Dictionary({
|
const FIELDS = new Dictionary({
|
||||||
'Stream ID': 'streamId',
|
'Stream ID': 'stream_id',
|
||||||
'Channel ID': 'channelId',
|
'Channel ID': 'channel_id',
|
||||||
'Feed ID': 'feedId',
|
'Feed ID': 'feed_id',
|
||||||
'Stream URL': 'streamUrl',
|
'Stream URL': 'stream_url',
|
||||||
'New Stream URL': 'newStreamUrl',
|
|
||||||
Label: 'label',
|
Label: 'label',
|
||||||
Quality: 'quality',
|
Quality: 'quality',
|
||||||
'HTTP User-Agent': 'httpUserAgent',
|
'HTTP User-Agent': 'http_user_agent',
|
||||||
'HTTP User Agent': 'httpUserAgent',
|
'HTTP User Agent': 'http_user_agent',
|
||||||
'HTTP Referrer': 'httpReferrer',
|
'HTTP Referrer': 'http_referrer',
|
||||||
'What happened to the stream?': 'reason',
|
'What happened to the stream?': 'reason',
|
||||||
Reason: 'reason',
|
Reason: 'reason',
|
||||||
Notes: 'notes',
|
Notes: 'notes'
|
||||||
Directives: 'directives'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export class IssueParser {
|
export class IssueParser {
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ export class PlaylistParser {
|
|||||||
for (const filepath of files) {
|
for (const filepath of files) {
|
||||||
if (!this.storage.existsSync(filepath)) continue
|
if (!this.storage.existsSync(filepath)) continue
|
||||||
const _parsed: Collection<Stream> = await this.parseFile(filepath)
|
const _parsed: Collection<Stream> = await this.parseFile(filepath)
|
||||||
parsed.concat(_parsed)
|
_parsed.forEach((item: Stream) => {
|
||||||
|
parsed.add(item)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsed
|
return parsed
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ export class LanguagesGenerator implements Generator {
|
|||||||
|
|
||||||
const languages = new Collection<sdk.Models.Language>()
|
const languages = new Collection<sdk.Models.Language>()
|
||||||
streams.forEach((stream: Stream) => {
|
streams.forEach((stream: Stream) => {
|
||||||
languages.concat(stream.getLanguages())
|
stream.getLanguages().forEach((language: sdk.Models.Language) => {
|
||||||
|
languages.add(language)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
languages
|
languages
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { data } from '../api'
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
export class Stream extends sdk.Models.Stream {
|
export class Stream extends sdk.Models.Stream {
|
||||||
directives: Collection<string>
|
|
||||||
filepath?: string
|
filepath?: string
|
||||||
line?: number
|
line?: number
|
||||||
groupTitle: string = 'Undefined'
|
groupTitle: string = 'Undefined'
|
||||||
@@ -19,18 +18,14 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
const data = {
|
const data = {
|
||||||
label: issueData.getString('label'),
|
label: issueData.getString('label'),
|
||||||
quality: issueData.getString('quality'),
|
quality: issueData.getString('quality'),
|
||||||
httpUserAgent: issueData.getString('httpUserAgent'),
|
httpUserAgent: issueData.getString('http_user_agent'),
|
||||||
httpReferrer: issueData.getString('httpReferrer'),
|
httpReferrer: issueData.getString('http_referrer')
|
||||||
newStreamUrl: issueData.getString('newStreamUrl'),
|
|
||||||
directives: issueData.getArray('directives')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.label !== undefined) this.label = data.label
|
if (data.label !== undefined) this.label = data.label
|
||||||
if (data.quality !== undefined) this.quality = data.quality
|
if (data.quality !== undefined) this.quality = data.quality
|
||||||
if (data.httpUserAgent !== undefined) this.user_agent = data.httpUserAgent
|
if (data.httpUserAgent !== undefined) this.user_agent = data.httpUserAgent
|
||||||
if (data.httpReferrer !== undefined) this.referrer = data.httpReferrer
|
if (data.httpReferrer !== undefined) this.referrer = data.httpReferrer
|
||||||
if (data.newStreamUrl !== undefined) this.url = data.newStreamUrl
|
|
||||||
if (data.directives !== undefined) this.setDirectives(data.directives)
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -54,24 +49,6 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
return { title, label, quality }
|
return { title, label, quality }
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDirectives(string: string): Collection<string> {
|
|
||||||
const directives = new Collection<string>()
|
|
||||||
|
|
||||||
if (!string) return directives
|
|
||||||
|
|
||||||
const supportedDirectives = ['#EXTVLCOPT', '#KODIPROP']
|
|
||||||
const lines = string.split('\r\n')
|
|
||||||
const regex = new RegExp(`^${supportedDirectives.join('|')}`, 'i')
|
|
||||||
|
|
||||||
lines.forEach((line: string) => {
|
|
||||||
if (regex.test(line)) {
|
|
||||||
directives.add(line.trim())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return directives
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.name) throw new Error('"name" property is required')
|
if (!data.name) throw new Error('"name" property is required')
|
||||||
if (!data.url) throw new Error('"url" property is required')
|
if (!data.url) throw new Error('"url" property is required')
|
||||||
|
|
||||||
@@ -91,7 +68,6 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
stream.tvgId = data.tvg.id
|
stream.tvgId = data.tvg.id
|
||||||
stream.line = data.line
|
stream.line = data.line
|
||||||
stream.label = label || null
|
stream.label = label || null
|
||||||
stream.directives = parseDirectives(data.raw)
|
|
||||||
|
|
||||||
return stream
|
return stream
|
||||||
}
|
}
|
||||||
@@ -235,7 +211,9 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
.intersects(new Collection<string>(region.countries))
|
.intersects(new Collection<string>(region.countries))
|
||||||
.isNotEmpty()
|
.isNotEmpty()
|
||||||
)
|
)
|
||||||
regions.concat(relatedRegions)
|
relatedRegions.forEach(region => {
|
||||||
|
regions.add(region)
|
||||||
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'country': {
|
case 'country': {
|
||||||
@@ -246,7 +224,9 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
(code: string) => code === country.code
|
(code: string) => code === country.code
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
regions.concat(countryRegions)
|
countryRegions.forEach(region => {
|
||||||
|
regions.add(region)
|
||||||
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'subdivision': {
|
case 'subdivision': {
|
||||||
@@ -257,7 +237,9 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
(code: string) => code === subdivision.country
|
(code: string) => code === subdivision.country
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
regions.concat(subdivisionRegions)
|
subdivisionRegions.forEach(region => {
|
||||||
|
regions.add(region)
|
||||||
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'city': {
|
case 'city': {
|
||||||
@@ -268,7 +250,9 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
(code: string) => code === city.country
|
(code: string) => code === city.country
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
regions.concat(cityRegions)
|
cityRegions.forEach(region => {
|
||||||
|
regions.add(region)
|
||||||
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,14 +290,6 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
return !!found
|
return !!found
|
||||||
}
|
}
|
||||||
|
|
||||||
setDirectives(directives: string[]): this {
|
|
||||||
this.directives = new Collection(directives).filter((directive: string) =>
|
|
||||||
/^(#KODIPROP|#EXTVLCOPT)/.test(directive)
|
|
||||||
)
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
updateTvgId(): this {
|
updateTvgId(): this {
|
||||||
if (!this.channel) return this
|
if (!this.channel) return this
|
||||||
if (this.feed) {
|
if (this.feed) {
|
||||||
@@ -418,20 +394,16 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
output += ` tvg-logo="${this.getTvgLogo()}" group-title="${this.groupTitle}"`
|
output += ` tvg-logo="${this.getTvgLogo()}" group-title="${this.groupTitle}"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output += `,${this.getFullTitle()}`
|
||||||
|
|
||||||
if (this.referrer) {
|
if (this.referrer) {
|
||||||
output += ` http-referrer="${this.referrer}"`
|
output += `\r\n#EXTVLCOPT:http-referrer=${this.referrer}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.user_agent) {
|
if (this.user_agent) {
|
||||||
output += ` http-user-agent="${this.user_agent}"`
|
output += `\r\n#EXTVLCOPT:http-user-agent=${this.user_agent}`
|
||||||
}
|
}
|
||||||
|
|
||||||
output += `,${this.getFullTitle()}`
|
|
||||||
|
|
||||||
this.directives.forEach((prop: string) => {
|
|
||||||
output += `\r\n${prop}`
|
|
||||||
})
|
|
||||||
|
|
||||||
output += `\r\n${this.url}`
|
output += `\r\n${this.url}`
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|||||||
Reference in New Issue
Block a user