mirror of https://github.com/iptv-org/iptv
Update scripts
parent
74b3cff1d2
commit
02ec7e6f76
@ -1,53 +1,61 @@
|
||||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '@freearhey/core'
|
||||
import { Playlist, Subdivision, Region } from '../models'
|
||||
import { Playlist, Region, Stream } from '../models'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type RegionsGeneratorProps = {
|
||||
streams: Collection
|
||||
regions: Collection
|
||||
subdivisions: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class RegionsGenerator implements Generator {
|
||||
streams: Collection
|
||||
regions: Collection
|
||||
subdivisions: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, regions, subdivisions, logger }: RegionsGeneratorProps) {
|
||||
constructor({ streams, regions, logger }: RegionsGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.regions = regions
|
||||
this.subdivisions = subdivisions
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
const streams = this.streams
|
||||
.orderBy(stream => stream.getTitle())
|
||||
.filter(stream => stream.isSFW())
|
||||
.orderBy((stream: Stream) => stream.getTitle())
|
||||
.filter((stream: Stream) => stream.isSFW())
|
||||
|
||||
this.regions.forEach(async (region: Region) => {
|
||||
if (region.code === 'INT') return
|
||||
if (region.isWorldwide()) return
|
||||
|
||||
const regionSubdivisionsCodes = this.subdivisions
|
||||
.filter((subdivision: Subdivision) => region.countries.indexOf(subdivision.country) > -1)
|
||||
.map((subdivision: Subdivision) => `s/${subdivision.code}`)
|
||||
|
||||
const regionCodes = region.countries
|
||||
.map((code: string) => `c/${code}`)
|
||||
.concat(regionSubdivisionsCodes)
|
||||
.add(`r/${region.code}`)
|
||||
|
||||
const regionStreams = streams.filter(stream => stream.broadcastArea.intersects(regionCodes))
|
||||
const regionStreams = streams.filter((stream: Stream) => stream.isBroadcastInRegion(region))
|
||||
|
||||
const playlist = new Playlist(regionStreams, { public: true })
|
||||
const filepath = `regions/${region.code.toLowerCase()}.m3u`
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
this.logger.info(
|
||||
JSON.stringify({ type: 'region', filepath, count: playlist.streams.count() })
|
||||
)
|
||||
})
|
||||
|
||||
const internationalStreams = streams.filter((stream: Stream) => stream.isInternational())
|
||||
const internationalPlaylist = new Playlist(internationalStreams, { public: true })
|
||||
const internationalFilepath = 'regions/int.m3u'
|
||||
await this.storage.save(internationalFilepath, internationalPlaylist.toString())
|
||||
this.logger.info(
|
||||
JSON.stringify({
|
||||
type: 'region',
|
||||
filepath: internationalFilepath,
|
||||
count: internationalPlaylist.streams.count()
|
||||
})
|
||||
)
|
||||
|
||||
const undefinedStreams = streams.filter((stream: Stream) => !stream.hasBroadcastArea())
|
||||
const playlist = new Playlist(undefinedStreams, { public: true })
|
||||
const filepath = 'regions/undefined.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ type: 'region', filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
type BroadcastAreaProps = {
|
||||
code: string
|
||||
}
|
||||
|
||||
export class BroadcastArea {
|
||||
code: string
|
||||
|
||||
constructor(data: BroadcastAreaProps) {
|
||||
this.code = data.code
|
||||
}
|
||||
}
|
@ -1,20 +1,58 @@
|
||||
type CountryProps = {
|
||||
import { Collection, Dictionary } from '@freearhey/core'
|
||||
import { Region, Language } from '.'
|
||||
|
||||
type CountryData = {
|
||||
code: string
|
||||
name: string
|
||||
languages: string[]
|
||||
lang: string
|
||||
flag: string
|
||||
}
|
||||
|
||||
export class Country {
|
||||
code: string
|
||||
name: string
|
||||
languages: string[]
|
||||
flag: string
|
||||
languageCode: string
|
||||
language?: Language
|
||||
subdivisions?: Collection
|
||||
regions?: Collection
|
||||
|
||||
constructor(data: CountryData) {
|
||||
this.code = data.code
|
||||
this.name = data.name
|
||||
this.flag = data.flag
|
||||
this.languageCode = data.lang
|
||||
}
|
||||
|
||||
withSubdivisions(subdivisionsGroupedByCountryCode: Dictionary): this {
|
||||
this.subdivisions = subdivisionsGroupedByCountryCode.get(this.code) || new Collection()
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withRegions(regions: Collection): this {
|
||||
this.regions = regions.filter(
|
||||
(region: Region) => region.code !== 'INT' && region.includesCountryCode(this.code)
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withLanguage(languagesGroupedByCode: Dictionary): this {
|
||||
this.language = languagesGroupedByCode.get(this.languageCode)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
getLanguage(): Language | undefined {
|
||||
return this.language
|
||||
}
|
||||
|
||||
getRegions(): Collection {
|
||||
return this.regions || new Collection()
|
||||
}
|
||||
|
||||
constructor({ code, name, languages, flag }: CountryProps) {
|
||||
this.code = code
|
||||
this.name = name
|
||||
this.languages = languages
|
||||
this.flag = flag
|
||||
getSubdivisions(): Collection {
|
||||
return this.subdivisions || new Collection()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,196 @@
|
||||
import { Collection, Dictionary } from '@freearhey/core'
|
||||
import { Country, Language, Region, Channel, Subdivision } from './index'
|
||||
|
||||
type FeedData = {
|
||||
channel: string
|
||||
id: string
|
||||
name: string
|
||||
is_main: boolean
|
||||
broadcast_area: Collection
|
||||
languages: Collection
|
||||
timezones: Collection
|
||||
video_format: string
|
||||
}
|
||||
|
||||
export class Feed {
|
||||
channelId: string
|
||||
channel?: Channel
|
||||
id: string
|
||||
name: string
|
||||
isMain: boolean
|
||||
broadcastAreaCodes: Collection
|
||||
broadcastCountryCodes: Collection
|
||||
broadcastCountries?: Collection
|
||||
broadcastRegionCodes: Collection
|
||||
broadcastRegions?: Collection
|
||||
broadcastSubdivisionCodes: Collection
|
||||
broadcastSubdivisions?: Collection
|
||||
languageCodes: Collection
|
||||
languages?: Collection
|
||||
timezoneIds: Collection
|
||||
timezones?: Collection
|
||||
videoFormat: string
|
||||
|
||||
constructor(data: FeedData) {
|
||||
this.channelId = data.channel
|
||||
this.id = data.id
|
||||
this.name = data.name
|
||||
this.isMain = data.is_main
|
||||
this.broadcastAreaCodes = new Collection(data.broadcast_area)
|
||||
this.languageCodes = new Collection(data.languages)
|
||||
this.timezoneIds = new Collection(data.timezones)
|
||||
this.videoFormat = data.video_format
|
||||
this.broadcastCountryCodes = new Collection()
|
||||
this.broadcastRegionCodes = new Collection()
|
||||
this.broadcastSubdivisionCodes = new Collection()
|
||||
|
||||
this.broadcastAreaCodes.forEach((areaCode: string) => {
|
||||
const [type, code] = areaCode.split('/')
|
||||
|
||||
switch (type) {
|
||||
case 'c':
|
||||
this.broadcastCountryCodes.add(code)
|
||||
break
|
||||
case 'r':
|
||||
this.broadcastRegionCodes.add(code)
|
||||
break
|
||||
case 's':
|
||||
this.broadcastSubdivisionCodes.add(code)
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
withChannel(channelsGroupedById: Dictionary): this {
|
||||
this.channel = channelsGroupedById.get(this.channelId)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withLanguages(languagesGroupedByCode: Dictionary): this {
|
||||
this.languages = this.languageCodes
|
||||
.map((code: string) => languagesGroupedByCode.get(code))
|
||||
.filter(Boolean)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withTimezones(timezonesGroupedById: Dictionary): this {
|
||||
this.timezones = this.timezoneIds
|
||||
.map((id: string) => timezonesGroupedById.get(id))
|
||||
.filter(Boolean)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withBroadcastSubdivisions(subdivisionsGroupedByCode: Dictionary): this {
|
||||
this.broadcastSubdivisions = this.broadcastSubdivisionCodes.map((code: string) =>
|
||||
subdivisionsGroupedByCode.get(code)
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withBroadcastCountries(
|
||||
countriesGroupedByCode: Dictionary,
|
||||
regionsGroupedByCode: Dictionary,
|
||||
subdivisionsGroupedByCode: Dictionary
|
||||
): this {
|
||||
let broadcastCountries = new Collection()
|
||||
|
||||
if (this.isInternational()) {
|
||||
this.broadcastCountries = broadcastCountries
|
||||
return this
|
||||
}
|
||||
|
||||
this.broadcastCountryCodes.forEach((code: string) => {
|
||||
broadcastCountries.add(countriesGroupedByCode.get(code))
|
||||
})
|
||||
|
||||
this.broadcastRegionCodes.forEach((code: string) => {
|
||||
const region: Region = regionsGroupedByCode.get(code)
|
||||
broadcastCountries = broadcastCountries.concat(region.countryCodes)
|
||||
})
|
||||
|
||||
this.broadcastSubdivisionCodes.forEach((code: string) => {
|
||||
const subdivision: Subdivision = subdivisionsGroupedByCode.get(code)
|
||||
broadcastCountries.add(countriesGroupedByCode.get(subdivision.countryCode))
|
||||
})
|
||||
|
||||
this.broadcastCountries = broadcastCountries.uniq().filter(Boolean)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
withBroadcastRegions(regions: Collection, regionsGroupedByCode: Dictionary): this {
|
||||
if (!this.broadcastCountries) return this
|
||||
const countriesCodes = this.broadcastCountries.map((country: Country) => country.code)
|
||||
|
||||
const broadcastRegions = regions.filter((region: Region) =>
|
||||
region.countryCodes.intersects(countriesCodes)
|
||||
)
|
||||
|
||||
if (this.isInternational()) broadcastRegions.add(regionsGroupedByCode.get('INT'))
|
||||
|
||||
this.broadcastRegions = broadcastRegions
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
hasBroadcastArea(): boolean {
|
||||
return (
|
||||
this.isInternational() || (!!this.broadcastCountries && this.broadcastCountries.notEmpty())
|
||||
)
|
||||
}
|
||||
|
||||
getBroadcastCountries(): Collection {
|
||||
return this.broadcastCountries || new Collection()
|
||||
}
|
||||
|
||||
getBroadcastRegions(): Collection {
|
||||
return this.broadcastRegions || new Collection()
|
||||
}
|
||||
|
||||
getTimezones(): Collection {
|
||||
return this.timezones || new Collection()
|
||||
}
|
||||
|
||||
getLanguages(): Collection {
|
||||
return this.languages || new Collection()
|
||||
}
|
||||
|
||||
hasLanguages(): boolean {
|
||||
return !!this.languages && this.languages.notEmpty()
|
||||
}
|
||||
|
||||
hasLanguage(language: Language): boolean {
|
||||
return (
|
||||
!!this.languages &&
|
||||
this.languages.includes((_language: Language) => _language.code === language.code)
|
||||
)
|
||||
}
|
||||
|
||||
isInternational(): boolean {
|
||||
return this.broadcastAreaCodes.includes('r/INT')
|
||||
}
|
||||
|
||||
isBroadcastInSubdivision(subdivision: Subdivision): boolean {
|
||||
if (this.isInternational()) return false
|
||||
|
||||
return this.broadcastSubdivisionCodes.includes(subdivision.code)
|
||||
}
|
||||
|
||||
isBroadcastInCountry(country: Country): boolean {
|
||||
if (this.isInternational()) return false
|
||||
|
||||
return this.getBroadcastCountries().includes(
|
||||
(_country: Country) => _country.code === country.code
|
||||
)
|
||||
}
|
||||
|
||||
isBroadcastInRegion(region: Region): boolean {
|
||||
if (this.isInternational()) return false
|
||||
|
||||
return this.getBroadcastRegions().includes((_region: Region) => _region.code === region.code)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { Collection, Dictionary } from '@freearhey/core'
|
||||
|
||||
type TimezoneData = {
|
||||
id: string
|
||||
utc_offset: string
|
||||
countries: string[]
|
||||
}
|
||||
|
||||
export class Timezone {
|
||||
id: string
|
||||
utcOffset: string
|
||||
countryCodes: Collection
|
||||
countries?: Collection
|
||||
|
||||
constructor(data: TimezoneData) {
|
||||
this.id = data.id
|
||||
this.utcOffset = data.utc_offset
|
||||
this.countryCodes = new Collection(data.countries)
|
||||
}
|
||||
|
||||
withCountries(countriesGroupedByCode: Dictionary): this {
|
||||
this.countries = this.countryCodes.map((code: string) => countriesGroupedByCode.get(code))
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
getCountries(): Collection {
|
||||
return this.countries || new Collection()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue