mirror of
https://github.com/iptv-org/iptv
synced 2026-09-11 06:17:08 -04:00
Update scripts
This commit is contained in:
+6
-1
@@ -14,6 +14,7 @@ const data = {
|
|||||||
feedsKeyByStreamId: new Dictionary<sdk.Models.Feed>(),
|
feedsKeyByStreamId: new Dictionary<sdk.Models.Feed>(),
|
||||||
feedsGroupedByChannel: new Dictionary<sdk.Models.Feed[]>(),
|
feedsGroupedByChannel: new Dictionary<sdk.Models.Feed[]>(),
|
||||||
blocklistRecordsGroupedByChannel: new Dictionary<sdk.Models.BlocklistRecord[]>(),
|
blocklistRecordsGroupedByChannel: new Dictionary<sdk.Models.BlocklistRecord[]>(),
|
||||||
|
guidesGroupedByStreamId: new Dictionary<sdk.Models.Guide[]>(),
|
||||||
categories: new Collection<sdk.Models.Category>(),
|
categories: new Collection<sdk.Models.Category>(),
|
||||||
countries: new Collection<sdk.Models.Country>(),
|
countries: new Collection<sdk.Models.Country>(),
|
||||||
subdivisions: new Collection<sdk.Models.Subdivision>(),
|
subdivisions: new Collection<sdk.Models.Subdivision>(),
|
||||||
@@ -37,7 +38,8 @@ async function loadData() {
|
|||||||
subdivisions,
|
subdivisions,
|
||||||
cities,
|
cities,
|
||||||
regions,
|
regions,
|
||||||
blocklist
|
blocklist,
|
||||||
|
guides
|
||||||
} = dataManager.getProcessedData()
|
} = dataManager.getProcessedData()
|
||||||
|
|
||||||
const searchableData = channels.map((channel: sdk.Models.Channel) => channel.getSearchable())
|
const searchableData = channels.map((channel: sdk.Models.Channel) => channel.getSearchable())
|
||||||
@@ -57,6 +59,9 @@ async function loadData() {
|
|||||||
data.blocklistRecordsGroupedByChannel = blocklist.groupBy(
|
data.blocklistRecordsGroupedByChannel = blocklist.groupBy(
|
||||||
(blocklistRecord: sdk.Models.BlocklistRecord) => blocklistRecord.channel
|
(blocklistRecord: sdk.Models.BlocklistRecord) => blocklistRecord.channel
|
||||||
)
|
)
|
||||||
|
data.guidesGroupedByStreamId = guides
|
||||||
|
.filter((guide: sdk.Models.Guide) => !!guide.sources.length)
|
||||||
|
.groupBy((guide: sdk.Models.Guide) => guide.getStreamId())
|
||||||
data.categories = categories
|
data.categories = categories
|
||||||
data.countries = countries
|
data.countries = countries
|
||||||
data.subdivisions = subdivisions
|
data.subdivisions = subdivisions
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { Storage } from '@freearhey/storage-js'
|
|||||||
import { STREAMS_DIR } from '../../constants'
|
import { STREAMS_DIR } from '../../constants'
|
||||||
import { PlaylistParser } from '../../core'
|
import { PlaylistParser } from '../../core'
|
||||||
import { getStreamInfo } from '../../utils'
|
import { getStreamInfo } from '../../utils'
|
||||||
|
import { loadData, data } from '../../api'
|
||||||
import cliProgress from 'cli-progress'
|
import cliProgress from 'cli-progress'
|
||||||
import { loadData } from '../../api'
|
|
||||||
import { eachLimit } from 'async'
|
import { eachLimit } from 'async'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import os from 'node:os'
|
import os from 'node:os'
|
||||||
@@ -44,6 +44,10 @@ async function main() {
|
|||||||
let files = program.args.length ? program.args : await streamsStorage.list('**/*.m3u')
|
let files = program.args.length ? program.args : await streamsStorage.list('**/*.m3u')
|
||||||
files = files.map((filepath: string) => path.basename(filepath))
|
files = files.map((filepath: string) => path.basename(filepath))
|
||||||
let streams = await parser.parse(files)
|
let streams = await parser.parse(files)
|
||||||
|
streams = streams.map((stream: Stream) => {
|
||||||
|
stream.setGuides(data.guidesGroupedByStreamId.get(stream.getId()))
|
||||||
|
return stream
|
||||||
|
})
|
||||||
|
|
||||||
logger.info(`found ${streams.count()} streams`)
|
logger.info(`found ${streams.count()} streams`)
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ async function main() {
|
|||||||
})
|
})
|
||||||
const files = await streamsStorage.list('**/*.m3u')
|
const files = await streamsStorage.list('**/*.m3u')
|
||||||
let streams = await parser.parse(files)
|
let streams = await parser.parse(files)
|
||||||
|
streams = streams.map((stream: Stream) => {
|
||||||
|
stream.setGuides(data.guidesGroupedByStreamId.get(stream.getId()))
|
||||||
|
return stream
|
||||||
|
})
|
||||||
const totalStreams = streams.count()
|
const totalStreams = streams.count()
|
||||||
logger.info(`found ${totalStreams} streams`)
|
logger.info(`found ${totalStreams} streams`)
|
||||||
|
|
||||||
@@ -62,32 +66,16 @@ async function main() {
|
|||||||
await new LanguagesGenerator({ streams, logFile }).generate()
|
await new LanguagesGenerator({ streams, logFile }).generate()
|
||||||
|
|
||||||
logger.info('generating countries/...')
|
logger.info('generating countries/...')
|
||||||
await new CountriesGenerator({
|
await new CountriesGenerator({ countries, streams, logFile }).generate()
|
||||||
countries,
|
|
||||||
streams,
|
|
||||||
logFile
|
|
||||||
}).generate()
|
|
||||||
|
|
||||||
logger.info('generating subdivisions/...')
|
logger.info('generating subdivisions/...')
|
||||||
await new SubdivisionsGenerator({
|
await new SubdivisionsGenerator({ subdivisions, streams, logFile }).generate()
|
||||||
subdivisions,
|
|
||||||
streams,
|
|
||||||
logFile
|
|
||||||
}).generate()
|
|
||||||
|
|
||||||
logger.info('generating cities/...')
|
logger.info('generating cities/...')
|
||||||
await new CitiesGenerator({
|
await new CitiesGenerator({ cities, streams, logFile }).generate()
|
||||||
cities,
|
|
||||||
streams,
|
|
||||||
logFile
|
|
||||||
}).generate()
|
|
||||||
|
|
||||||
logger.info('generating regions/...')
|
logger.info('generating regions/...')
|
||||||
await new RegionsGenerator({
|
await new RegionsGenerator({ streams, regions, logFile }).generate()
|
||||||
streams,
|
|
||||||
regions,
|
|
||||||
logFile
|
|
||||||
}).generate()
|
|
||||||
|
|
||||||
logger.info('generating sources/...')
|
logger.info('generating sources/...')
|
||||||
await new SourcesGenerator({ streams, logFile }).generate()
|
await new SourcesGenerator({ streams, logFile }).generate()
|
||||||
@@ -99,10 +87,7 @@ async function main() {
|
|||||||
await new IndexCategoryGenerator({ streams, logFile }).generate()
|
await new IndexCategoryGenerator({ streams, logFile }).generate()
|
||||||
|
|
||||||
logger.info('generating index.country.m3u...')
|
logger.info('generating index.country.m3u...')
|
||||||
await new IndexCountryGenerator({
|
await new IndexCountryGenerator({ streams, logFile }).generate()
|
||||||
streams,
|
|
||||||
logFile
|
|
||||||
}).generate()
|
|
||||||
|
|
||||||
logger.info('generating index.language.m3u...')
|
logger.info('generating index.language.m3u...')
|
||||||
await new IndexLanguageGenerator({ streams, logFile }).generate()
|
await new IndexLanguageGenerator({ streams, logFile }).generate()
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ async function loadStreams() {
|
|||||||
const files = await streamsStorage.list('**/*.m3u')
|
const files = await streamsStorage.list('**/*.m3u')
|
||||||
|
|
||||||
streams = await parser.parse(files)
|
streams = await parser.parse(files)
|
||||||
|
streams = streams.map((stream: Stream) => {
|
||||||
|
stream.setGuides(apiData.guidesGroupedByStreamId.get(stream.getId()))
|
||||||
|
return stream
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processIssues(issues: Collection<Issue>) {
|
async function processIssues(issues: Collection<Issue>) {
|
||||||
@@ -132,7 +136,7 @@ async function removeStream(issue: Issue) {
|
|||||||
if (changed) {
|
if (changed) {
|
||||||
processedIssues.add(issue)
|
processedIssues.add(issue)
|
||||||
} else {
|
} else {
|
||||||
log.error(`None of the URLs specified in the request were found in the playlists`)
|
log.error('None of the URLs specified in the request were found in the playlists')
|
||||||
skippedIssues.add(issue)
|
skippedIssues.add(issue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,6 +166,8 @@ async function editStream(issue: Issue) {
|
|||||||
|
|
||||||
stream.updateWithIssue(data)
|
stream.updateWithIssue(data)
|
||||||
|
|
||||||
|
stream.setGuides(apiData.guidesGroupedByStreamId.get(stream.getId()))
|
||||||
|
|
||||||
const errors = new Collection<Error>()
|
const errors = new Collection<Error>()
|
||||||
errors.concat(stream.validate())
|
errors.concat(stream.validate())
|
||||||
if (errors.isNotEmpty()) {
|
if (errors.isNotEmpty()) {
|
||||||
@@ -260,6 +266,8 @@ async function addStream(issue: Issue) {
|
|||||||
|
|
||||||
stream.updateTitle().updateFilepath()
|
stream.updateTitle().updateFilepath()
|
||||||
|
|
||||||
|
stream.setGuides(apiData.guidesGroupedByStreamId.get(stream.getId()))
|
||||||
|
|
||||||
streams.add(stream)
|
streams.add(stream)
|
||||||
|
|
||||||
const errors = new Collection<Error>()
|
const errors = new Collection<Error>()
|
||||||
|
|||||||
@@ -1,26 +1,65 @@
|
|||||||
import { Collection } from '@freearhey/core'
|
import { Collection } from '@freearhey/core'
|
||||||
|
import * as sdk from '@iptv-org/sdk'
|
||||||
import { Stream } from '../models'
|
import { Stream } from '../models'
|
||||||
|
|
||||||
type PlaylistOptions = {
|
type PlaylistOptions = {
|
||||||
public: boolean
|
public?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Playlist {
|
export class Playlist {
|
||||||
streams: Collection<Stream>
|
streams: Collection<Stream>
|
||||||
options: {
|
public: boolean
|
||||||
public: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(streams: Collection<Stream>, options?: PlaylistOptions) {
|
constructor(streams: Collection<Stream>, options?: PlaylistOptions) {
|
||||||
this.streams = streams
|
this.streams = streams
|
||||||
this.options = options || { public: false }
|
this.public = options?.public === true
|
||||||
|
}
|
||||||
|
|
||||||
|
getGuides(): Collection<sdk.Models.Guide> {
|
||||||
|
const guides = new Collection<sdk.Models.Guide>()
|
||||||
|
|
||||||
|
this.streams.forEach(stream => {
|
||||||
|
guides.concat(stream.getGuides())
|
||||||
|
})
|
||||||
|
|
||||||
|
return guides
|
||||||
|
}
|
||||||
|
|
||||||
|
getGuideUrls(): Collection<string> {
|
||||||
|
function byFormat(source: sdk.Types.GuideSource) {
|
||||||
|
if (source.format === 'GZIP') return 2
|
||||||
|
if (source.format === 'XML') return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const urls = new Collection<string>()
|
||||||
|
|
||||||
|
this.getGuides().forEach((guide: sdk.Models.Guide) => {
|
||||||
|
const sources = new Collection(guide.sources)
|
||||||
|
|
||||||
|
const source = sources
|
||||||
|
.filter((source: sdk.Types.GuideSource) => ['GZIP', 'XML'].includes(source.format))
|
||||||
|
.sortBy([byFormat], ['desc'])
|
||||||
|
.first()
|
||||||
|
|
||||||
|
if (source) urls.add(source.url)
|
||||||
|
})
|
||||||
|
|
||||||
|
return urls.uniq()
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
let output = '#EXTM3U\r\n'
|
let output = '#EXTM3U'
|
||||||
|
|
||||||
|
const guideUrls = this.getGuideUrls()
|
||||||
|
if (guideUrls.count()) {
|
||||||
|
output += ` x-tvg-url="${guideUrls.join(',')}"`
|
||||||
|
}
|
||||||
|
|
||||||
|
output += '\r\n'
|
||||||
|
|
||||||
this.streams.forEach((stream: Stream) => {
|
this.streams.forEach((stream: Stream) => {
|
||||||
output += stream.toString(this.options) + '\r\n'
|
output += stream.toString({ public: this.public }) + '\r\n'
|
||||||
})
|
})
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|||||||
@@ -13,6 +13,15 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
removed: boolean = false
|
removed: boolean = false
|
||||||
tvgId?: string
|
tvgId?: string
|
||||||
statusCode?: string
|
statusCode?: string
|
||||||
|
guides = new Collection<sdk.Models.Guide>()
|
||||||
|
|
||||||
|
setGuides(guides?: sdk.Models.Guide[]) {
|
||||||
|
this.guides = new Collection(guides)
|
||||||
|
}
|
||||||
|
|
||||||
|
getGuides(): Collection<sdk.Models.Guide> {
|
||||||
|
return this.guides
|
||||||
|
}
|
||||||
|
|
||||||
validate(): Collection<Error> {
|
validate(): Collection<Error> {
|
||||||
const errors = new Collection<Error>()
|
const errors = new Collection<Error>()
|
||||||
@@ -80,12 +89,12 @@ export class Stream extends sdk.Models.Stream {
|
|||||||
quality: quality || null,
|
quality: quality || null,
|
||||||
url: data.url,
|
url: data.url,
|
||||||
referrer: data.http.referrer || null,
|
referrer: data.http.referrer || null,
|
||||||
user_agent: data.http['user-agent'] || null
|
user_agent: data.http['user-agent'] || null,
|
||||||
|
label: label || null
|
||||||
})
|
})
|
||||||
|
|
||||||
stream.tvgId = data.tvg.id
|
stream.tvgId = data.tvg.id
|
||||||
stream.line = data.line
|
stream.line = data.line
|
||||||
stream.label = label || null
|
|
||||||
|
|
||||||
return stream
|
return stream
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user