mirror of
https://github.com/iptv-org/iptv.git
synced 2025-05-11 17:40:03 -04:00
Update scripts
This commit is contained in:
parent
8a83f23243
commit
f1d2add19a
98 changed files with 2423 additions and 1499 deletions
|
@ -1,18 +0,0 @@
|
|||
const api = require('../core/api')
|
||||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
await api.categories.load()
|
||||
const categories = await api.categories.all()
|
||||
|
||||
const output = []
|
||||
for (const category of categories) {
|
||||
let items = _.filter(streams, { categories: [{ id: category.id }] })
|
||||
output.push({ filepath: `categories/${category.id}.m3u`, items })
|
||||
}
|
||||
|
||||
let items = _.filter(streams, stream => !stream.categories.length)
|
||||
output.push({ filepath: 'categories/undefined.m3u', items })
|
||||
|
||||
return output
|
||||
}
|
55
scripts/generators/categoriesGenerator.ts
Normal file
55
scripts/generators/categoriesGenerator.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '../core'
|
||||
import { Stream, Category, Playlist } from '../models'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type CategoriesGeneratorProps = {
|
||||
streams: Collection
|
||||
categories: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class CategoriesGenerator implements Generator {
|
||||
streams: Collection
|
||||
categories: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, categories, logger }: CategoriesGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.categories = categories
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate() {
|
||||
const streams = this.streams.orderBy([(stream: Stream) => stream.getTitle()])
|
||||
|
||||
this.categories.forEach(async (category: Category) => {
|
||||
let categoryStreams = streams
|
||||
.filter((stream: Stream) => stream.hasCategory(category))
|
||||
.map((stream: Stream) => {
|
||||
const groupTitle = stream.categories
|
||||
? stream.categories
|
||||
.map((category: Category) => category.name)
|
||||
.sort()
|
||||
.join(';')
|
||||
: ''
|
||||
stream.groupTitle = groupTitle
|
||||
|
||||
return stream
|
||||
})
|
||||
|
||||
const playlist = new Playlist(categoryStreams, { public: true })
|
||||
const filepath = `categories/${category.id}.m3u`
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
})
|
||||
|
||||
const undefinedStreams = streams.filter((stream: Stream) => stream.noCategories())
|
||||
const playlist = new Playlist(undefinedStreams, { public: true })
|
||||
const filepath = `categories/undefined.m3u`
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
const api = require('../core/api')
|
||||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, stream => stream.is_nsfw === false)
|
||||
|
||||
await api.countries.load()
|
||||
const countries = await api.countries.all()
|
||||
await api.regions.load()
|
||||
let regions = await api.regions.all()
|
||||
regions = regions.filter(r => r.code !== 'INT')
|
||||
await api.subdivisions.load()
|
||||
const subdivisions = await api.subdivisions.all()
|
||||
|
||||
let output = []
|
||||
for (const country of countries) {
|
||||
let countryRegionCodes = _.filter(regions, { countries: [country.code] }).map(
|
||||
r => `r/${r.code}`
|
||||
)
|
||||
const countrySubdivisions = _.filter(subdivisions, { country: country.code })
|
||||
const countryAreaCodes = countryRegionCodes.concat(countrySubdivisions.map(s => `s/${s.code}`))
|
||||
countryAreaCodes.push(`c/${country.code}`)
|
||||
|
||||
let items = _.filter(streams, stream => {
|
||||
return _.intersection(stream.broadcast_area, countryAreaCodes).length
|
||||
})
|
||||
|
||||
output.push({ filepath: `countries/${country.code.toLowerCase()}.m3u`, items })
|
||||
|
||||
for (let subdivision of countrySubdivisions) {
|
||||
let subdivisionItems = _.filter(streams, stream => {
|
||||
return stream.broadcast_area.includes(`s/${subdivision.code}`)
|
||||
})
|
||||
|
||||
if (subdivisionItems.length) {
|
||||
output.push({
|
||||
filepath: `subdivisions/${subdivision.code.toLowerCase()}.m3u`,
|
||||
items: subdivisionItems
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let intItems = _.filter(streams, stream => stream.broadcast_area.includes('r/INT'))
|
||||
output.push({
|
||||
filepath: `countries/int.m3u`,
|
||||
items: intItems
|
||||
})
|
||||
|
||||
output = output.filter(f => f.items.length > 0)
|
||||
|
||||
return output
|
||||
}
|
85
scripts/generators/countriesGenerator.ts
Normal file
85
scripts/generators/countriesGenerator.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '../core'
|
||||
import { Country, Region, Subdivision, Stream, Playlist } from '../models'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type CountriesGeneratorProps = {
|
||||
streams: Collection
|
||||
regions: Collection
|
||||
subdivisions: Collection
|
||||
countries: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class CountriesGenerator implements Generator {
|
||||
streams: Collection
|
||||
countries: Collection
|
||||
regions: Collection
|
||||
subdivisions: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, countries, regions, subdivisions, logger }: CountriesGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.countries = countries
|
||||
this.regions = regions
|
||||
this.subdivisions = subdivisions
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
let streams = this.streams
|
||||
.orderBy([stream => stream.getTitle()])
|
||||
.filter((stream: Stream) => stream.isSFW())
|
||||
let regions = this.regions.filter((region: Region) => region.code !== 'INT')
|
||||
|
||||
this.countries.forEach(async (country: Country) => {
|
||||
const countrySubdivisions = this.subdivisions.filter(
|
||||
(subdivision: Subdivision) => subdivision.country === country.code
|
||||
)
|
||||
|
||||
const countrySubdivisionsCodes = countrySubdivisions.map(
|
||||
(subdivision: Subdivision) => `s/${subdivision.code}`
|
||||
)
|
||||
|
||||
const countryAreaCodes = regions
|
||||
.filter((region: Region) => region.countries.includes(country.code))
|
||||
.map((region: Region) => `r/${region.code}`)
|
||||
.concat(countrySubdivisionsCodes)
|
||||
.add(`c/${country.code}`)
|
||||
|
||||
const countryStreams = streams.filter(stream =>
|
||||
stream.broadcastArea.intersects(countryAreaCodes)
|
||||
)
|
||||
|
||||
if (countryStreams.isEmpty()) return
|
||||
|
||||
const playlist = new Playlist(countryStreams, { public: true })
|
||||
const filepath = `countries/${country.code.toLowerCase()}.m3u`
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
|
||||
countrySubdivisions.forEach(async (subdivision: Subdivision) => {
|
||||
const subdivisionStreams = streams.filter(stream =>
|
||||
stream.broadcastArea.includes(`s/${subdivision.code}`)
|
||||
)
|
||||
|
||||
if (subdivisionStreams.isEmpty()) return
|
||||
|
||||
const playlist = new Playlist(subdivisionStreams, { public: true })
|
||||
const filepath = `subdivisions/${subdivision.code.toLowerCase()}.m3u`
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
})
|
||||
})
|
||||
|
||||
const internationalStreams = streams.filter(stream => stream.isInternational())
|
||||
if (internationalStreams.notEmpty()) {
|
||||
const playlist = new Playlist(internationalStreams, { public: true })
|
||||
const filepath = `countries/int.m3u`
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
}
|
||||
}
|
3
scripts/generators/generator.ts
Normal file
3
scripts/generators/generator.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export interface Generator {
|
||||
generate(): Promise<void>
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
exports.categories = require('./categories')
|
||||
exports.countries = require('./countries')
|
||||
exports.languages = require('./languages')
|
||||
exports.regions = require('./regions')
|
||||
exports.index_m3u = require('./index_m3u')
|
||||
exports.index_nsfw_m3u = require('./index_nsfw_m3u')
|
||||
exports.index_category_m3u = require('./index_category_m3u')
|
||||
exports.index_country_m3u = require('./index_country_m3u')
|
||||
exports.index_language_m3u = require('./index_language_m3u')
|
||||
exports.index_region_m3u = require('./index_region_m3u')
|
10
scripts/generators/index.ts
Normal file
10
scripts/generators/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
export * from './categoriesGenerator'
|
||||
export * from './countriesGenerator'
|
||||
export * from './languagesGenerator'
|
||||
export * from './regionsGenerator'
|
||||
export * from './indexGenerator'
|
||||
export * from './indexNsfwGenerator'
|
||||
export * from './indexCategoryGenerator'
|
||||
export * from './indexCountryGenerator'
|
||||
export * from './indexLanguageGenerator'
|
||||
export * from './indexRegionGenerator'
|
53
scripts/generators/indexCategoryGenerator.ts
Normal file
53
scripts/generators/indexCategoryGenerator.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '../core'
|
||||
import { Stream, Playlist, Category } from '../models'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type IndexCategoryGeneratorProps = {
|
||||
streams: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class IndexCategoryGenerator implements Generator {
|
||||
streams: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, logger }: IndexCategoryGeneratorProps) {
|
||||
this.streams = streams
|
||||
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())
|
||||
|
||||
let groupedStreams = new Collection()
|
||||
streams.forEach((stream: Stream) => {
|
||||
if (stream.noCategories()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'Undefined'
|
||||
groupedStreams.add(streamClone)
|
||||
return
|
||||
}
|
||||
|
||||
stream.categories.forEach((category: Category) => {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = category.name
|
||||
groupedStreams.push(streamClone)
|
||||
})
|
||||
})
|
||||
|
||||
groupedStreams = groupedStreams.orderBy(stream => {
|
||||
if (stream.groupTitle === 'Undefined') return 'ZZ'
|
||||
return stream.groupTitle
|
||||
})
|
||||
|
||||
const playlist = new Playlist(groupedStreams, { public: true })
|
||||
const filepath = 'index.category.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
}
|
104
scripts/generators/indexCountryGenerator.ts
Normal file
104
scripts/generators/indexCountryGenerator.ts
Normal file
|
@ -0,0 +1,104 @@
|
|||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '../core'
|
||||
import { Stream, Playlist, Country, Subdivision, Region } from '../models'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type IndexCountryGeneratorProps = {
|
||||
streams: Collection
|
||||
regions: Collection
|
||||
countries: Collection
|
||||
subdivisions: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class IndexCountryGenerator implements Generator {
|
||||
streams: Collection
|
||||
countries: Collection
|
||||
regions: Collection
|
||||
subdivisions: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, regions, countries, subdivisions, logger }: IndexCountryGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.countries = countries
|
||||
this.regions = regions
|
||||
this.subdivisions = subdivisions
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
let groupedStreams = new Collection()
|
||||
|
||||
this.streams
|
||||
.orderBy(stream => stream.getTitle())
|
||||
.filter(stream => stream.isSFW())
|
||||
.forEach(stream => {
|
||||
if (stream.noBroadcastArea()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'Undefined'
|
||||
groupedStreams.add(streamClone)
|
||||
return
|
||||
}
|
||||
|
||||
if (stream.isInternational()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'International'
|
||||
groupedStreams.add(streamClone)
|
||||
}
|
||||
|
||||
this.getStreamBroadcastCountries(stream).forEach((country: Country) => {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = country.name
|
||||
groupedStreams.add(streamClone)
|
||||
})
|
||||
})
|
||||
|
||||
groupedStreams = groupedStreams.orderBy((stream: Stream) => {
|
||||
if (stream.groupTitle === 'International') return 'ZZ'
|
||||
if (stream.groupTitle === 'Undefined') return 'ZZZ'
|
||||
|
||||
return stream.groupTitle
|
||||
})
|
||||
|
||||
const playlist = new Playlist(groupedStreams, { public: true })
|
||||
const filepath = 'index.country.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
|
||||
getStreamBroadcastCountries(stream: Stream) {
|
||||
const groupedRegions = this.regions.keyBy((region: Region) => region.code)
|
||||
const groupedCountries = this.countries.keyBy((country: Country) => country.code)
|
||||
const groupedSubdivisions = this.subdivisions.keyBy(
|
||||
(subdivision: Subdivision) => subdivision.code
|
||||
)
|
||||
|
||||
let broadcastCountries = new Collection()
|
||||
|
||||
stream.broadcastArea.forEach(broadcastAreaCode => {
|
||||
const [type, code] = broadcastAreaCode.split('/')
|
||||
switch (type) {
|
||||
case 'c':
|
||||
broadcastCountries.add(code)
|
||||
break
|
||||
case 'r':
|
||||
if (code !== 'INT' && groupedRegions.has(code)) {
|
||||
broadcastCountries = broadcastCountries.concat(groupedRegions.get(code).countries)
|
||||
}
|
||||
break
|
||||
case 's':
|
||||
if (groupedSubdivisions.has(code)) {
|
||||
broadcastCountries.add(groupedSubdivisions.get(code).country)
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
return broadcastCountries
|
||||
.uniq()
|
||||
.map(code => groupedCountries.get(code))
|
||||
.filter(Boolean)
|
||||
}
|
||||
}
|
32
scripts/generators/indexGenerator.ts
Normal file
32
scripts/generators/indexGenerator.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { Collection, Logger, Storage } from '../core'
|
||||
import { Stream, Playlist } from '../models'
|
||||
import { Generator } from './generator'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type IndexGeneratorProps = {
|
||||
streams: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class IndexGenerator implements Generator {
|
||||
streams: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, logger }: IndexGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
const sfwStreams = this.streams
|
||||
.orderBy(stream => stream.getTitle())
|
||||
.filter((stream: Stream) => stream.isSFW())
|
||||
|
||||
const playlist = new Playlist(sfwStreams, { public: true })
|
||||
const filepath = 'index.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
}
|
52
scripts/generators/indexLanguageGenerator.ts
Normal file
52
scripts/generators/indexLanguageGenerator.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '../core'
|
||||
import { Stream, Playlist, Language } from '../models'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type IndexLanguageGeneratorProps = {
|
||||
streams: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class IndexLanguageGenerator implements Generator {
|
||||
streams: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, logger }: IndexLanguageGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
let groupedStreams = new Collection()
|
||||
this.streams
|
||||
.orderBy(stream => stream.getTitle())
|
||||
.filter(stream => stream.isSFW())
|
||||
.forEach(stream => {
|
||||
if (stream.noLanguages()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'Undefined'
|
||||
groupedStreams.add(streamClone)
|
||||
return
|
||||
}
|
||||
|
||||
stream.languages.forEach((language: Language) => {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = language.name
|
||||
groupedStreams.add(streamClone)
|
||||
})
|
||||
})
|
||||
|
||||
groupedStreams = groupedStreams.orderBy((stream: Stream) => {
|
||||
if (stream.groupTitle === 'Undefined') return 'ZZ'
|
||||
return stream.groupTitle
|
||||
})
|
||||
|
||||
const playlist = new Playlist(groupedStreams, { public: true })
|
||||
const filepath = 'index.language.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
}
|
30
scripts/generators/indexNsfwGenerator.ts
Normal file
30
scripts/generators/indexNsfwGenerator.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { Collection, Logger, Storage } from '../core'
|
||||
import { Stream, Playlist } from '../models'
|
||||
import { Generator } from './generator'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type IndexNsfwGeneratorProps = {
|
||||
streams: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class IndexNsfwGenerator implements Generator {
|
||||
streams: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, logger }: IndexNsfwGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
const allStreams = this.streams.orderBy((stream: Stream) => stream.getTitle())
|
||||
|
||||
const playlist = new Playlist(allStreams, { public: true })
|
||||
const filepath = 'index.nsfw.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
}
|
83
scripts/generators/indexRegionGenerator.ts
Normal file
83
scripts/generators/indexRegionGenerator.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '../core'
|
||||
import { Stream, Playlist, Region } from '../models'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type IndexRegionGeneratorProps = {
|
||||
streams: Collection
|
||||
regions: Collection
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export class IndexRegionGenerator implements Generator {
|
||||
streams: Collection
|
||||
regions: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, regions, logger }: IndexRegionGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.regions = regions
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
let groupedStreams = new Collection()
|
||||
this.streams
|
||||
.orderBy((stream: Stream) => stream.getTitle())
|
||||
.filter((stream: Stream) => stream.isSFW())
|
||||
.forEach((stream: Stream) => {
|
||||
if (stream.noBroadcastArea()) {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = 'Undefined'
|
||||
groupedStreams.push(streamClone)
|
||||
return
|
||||
}
|
||||
|
||||
this.getStreamRegions(stream).forEach((region: Region) => {
|
||||
const streamClone = stream.clone()
|
||||
streamClone.groupTitle = region.name
|
||||
groupedStreams.push(streamClone)
|
||||
})
|
||||
})
|
||||
|
||||
groupedStreams = groupedStreams.orderBy((stream: Stream) => {
|
||||
if (stream.groupTitle === 'Undefined') return 'ZZ'
|
||||
return stream.groupTitle
|
||||
})
|
||||
|
||||
const playlist = new Playlist(groupedStreams, { public: true })
|
||||
const filepath = 'index.region.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
|
||||
getStreamRegions(stream: Stream) {
|
||||
let streamRegions = new Collection()
|
||||
stream.broadcastArea.forEach(broadcastAreaCode => {
|
||||
const [type, code] = broadcastAreaCode.split('/')
|
||||
switch (type) {
|
||||
case 'r':
|
||||
const groupedRegions = this.regions.keyBy((region: Region) => region.code)
|
||||
streamRegions.add(groupedRegions.get(code))
|
||||
break
|
||||
case 's':
|
||||
const [countryCode] = code.split('-')
|
||||
const subdivisionRegions = this.regions.filter((region: Region) =>
|
||||
region.countries.includes(countryCode)
|
||||
)
|
||||
streamRegions = streamRegions.concat(subdivisionRegions)
|
||||
break
|
||||
case 'c':
|
||||
const countryRegions = this.regions.filter((region: Region) =>
|
||||
region.countries.includes(code)
|
||||
)
|
||||
streamRegions = streamRegions.concat(countryRegions)
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
return streamRegions
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, stream => stream.is_nsfw === false)
|
||||
|
||||
let items = []
|
||||
streams.forEach(stream => {
|
||||
if (!stream.categories.length) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = 'Undefined'
|
||||
items.push(item)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
stream.categories
|
||||
.filter(c => c)
|
||||
.forEach(category => {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = category.name
|
||||
items.push(item)
|
||||
})
|
||||
})
|
||||
|
||||
items = _.sortBy(items, item => {
|
||||
if (item.group_title === 'Undefined') return ''
|
||||
|
||||
return item.group_title
|
||||
})
|
||||
|
||||
return { filepath: 'index.category.m3u', items }
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
const api = require('../core/api')
|
||||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, stream => stream.is_nsfw === false)
|
||||
|
||||
await api.regions.load()
|
||||
let regions = await api.regions.all()
|
||||
regions = _.keyBy(regions, 'code')
|
||||
|
||||
await api.countries.load()
|
||||
let countries = await api.countries.all()
|
||||
countries = _.keyBy(countries, 'code')
|
||||
|
||||
await api.subdivisions.load()
|
||||
let subdivisions = await api.subdivisions.all()
|
||||
subdivisions = _.keyBy(subdivisions, 'code')
|
||||
|
||||
let items = []
|
||||
streams.forEach(stream => {
|
||||
if (!stream.broadcast_area.length) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = 'Undefined'
|
||||
items.push(item)
|
||||
return
|
||||
}
|
||||
|
||||
if (stream.broadcast_area.includes('r/INT')) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = 'International'
|
||||
items.push(item)
|
||||
}
|
||||
|
||||
const broadcastCountries = getBroadcastCountries(stream, { countries, regions, subdivisions })
|
||||
broadcastCountries.forEach(country => {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = country.name
|
||||
items.push(item)
|
||||
})
|
||||
})
|
||||
|
||||
items = sortByGroupTitle(items)
|
||||
|
||||
return { filepath: 'index.country.m3u', items }
|
||||
}
|
||||
|
||||
function getBroadcastCountries(stream, { countries, regions, subdivisions }) {
|
||||
let codes = stream.broadcast_area.reduce((acc, item) => {
|
||||
const [type, code] = item.split('/')
|
||||
switch (type) {
|
||||
case 'c':
|
||||
acc.push(code)
|
||||
break
|
||||
case 'r':
|
||||
if (code !== 'INT' && regions[code]) {
|
||||
acc = acc.concat(regions[code].countries)
|
||||
}
|
||||
break
|
||||
case 's':
|
||||
if (subdivisions[code]) {
|
||||
acc.push(subdivisions[code].country)
|
||||
}
|
||||
break
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
|
||||
codes = _.uniq(codes)
|
||||
|
||||
return codes.map(code => countries[code]).filter(c => c)
|
||||
}
|
||||
|
||||
function sortByGroupTitle(items) {
|
||||
return _.sortBy(items, item => {
|
||||
if (item.group_title === 'International') return '[' // ASCII character 91
|
||||
if (item.group_title === 'Undefined') return ']' // ASCII character 93
|
||||
|
||||
return item.group_title
|
||||
})
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, stream => stream.is_nsfw === false)
|
||||
|
||||
let items = []
|
||||
streams.forEach(stream => {
|
||||
if (!stream.languages.length) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = 'Undefined'
|
||||
items.push(item)
|
||||
return
|
||||
}
|
||||
|
||||
stream.languages.forEach(language => {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = language.name
|
||||
items.push(item)
|
||||
})
|
||||
})
|
||||
|
||||
items = _.sortBy(items, i => {
|
||||
if (i.group_title === 'Undefined') return ''
|
||||
|
||||
return i.group_title
|
||||
})
|
||||
|
||||
return { filepath: 'index.language.m3u', items }
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
const api = require('../core/api')
|
||||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, stream => stream.is_nsfw === false)
|
||||
return { filepath: 'index.m3u', items: streams }
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
const api = require('../core/api')
|
||||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
return { filepath: 'index.nsfw.m3u', items: streams }
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
const api = require('../core/api')
|
||||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, stream => stream.is_nsfw === false)
|
||||
|
||||
await api.regions.load()
|
||||
let regions = await api.regions.all()
|
||||
regions = _.keyBy(regions, 'code')
|
||||
|
||||
let items = []
|
||||
streams.forEach(stream => {
|
||||
if (!stream.broadcast_area.length) {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = 'Undefined'
|
||||
items.push(item)
|
||||
return
|
||||
}
|
||||
|
||||
getChannelRegions(stream, { regions }).forEach(region => {
|
||||
const item = _.cloneDeep(stream)
|
||||
item.group_title = region.name
|
||||
items.push(item)
|
||||
})
|
||||
})
|
||||
|
||||
items = _.sortBy(items, i => {
|
||||
if (i.group_title === 'Undefined') return ''
|
||||
|
||||
return i.group_title
|
||||
})
|
||||
|
||||
return { filepath: 'index.region.m3u', items }
|
||||
}
|
||||
|
||||
function getChannelRegions(stream, { regions }) {
|
||||
return stream.broadcast_area
|
||||
.reduce((acc, item) => {
|
||||
const [type, code] = item.split('/')
|
||||
switch (type) {
|
||||
case 'r':
|
||||
acc.push(regions[code])
|
||||
break
|
||||
case 's':
|
||||
const [c] = code.split('-')
|
||||
const r1 = _.filter(regions, { countries: [c] })
|
||||
acc = acc.concat(r1)
|
||||
break
|
||||
case 'c':
|
||||
const r2 = _.filter(regions, { countries: [code] })
|
||||
acc = acc.concat(r2)
|
||||
break
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
.filter(i => i)
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, stream => stream.is_nsfw === false)
|
||||
|
||||
let languages = []
|
||||
streams.forEach(stream => {
|
||||
languages = languages.concat(stream.languages)
|
||||
})
|
||||
languages = _.uniqBy(languages, 'code')
|
||||
languages = _.sortBy(languages, 'name')
|
||||
|
||||
const output = []
|
||||
for (const language of languages) {
|
||||
let items = _.filter(streams, { languages: [{ code: language.code }] })
|
||||
if (items.length) {
|
||||
output.push({ filepath: `languages/${language.code}.m3u`, items })
|
||||
}
|
||||
}
|
||||
|
||||
let items = _.filter(streams, stream => !stream.languages.length)
|
||||
output.push({ filepath: 'languages/undefined.m3u', items })
|
||||
|
||||
return output
|
||||
}
|
50
scripts/generators/languagesGenerator.ts
Normal file
50
scripts/generators/languagesGenerator.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '../core'
|
||||
import { Playlist, Language, Stream } from '../models'
|
||||
import { PUBLIC_DIR } from '../constants'
|
||||
|
||||
type LanguagesGeneratorProps = { streams: Collection; logger: Logger }
|
||||
|
||||
export class LanguagesGenerator implements Generator {
|
||||
streams: Collection
|
||||
storage: Storage
|
||||
logger: Logger
|
||||
|
||||
constructor({ streams, logger }: LanguagesGeneratorProps) {
|
||||
this.streams = streams
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
let streams = this.streams.orderBy(stream => stream.getTitle()).filter(stream => stream.isSFW())
|
||||
|
||||
let languages = new Collection()
|
||||
streams.forEach((stream: Stream) => {
|
||||
languages = languages.concat(stream.languages)
|
||||
})
|
||||
|
||||
languages
|
||||
.uniqBy((language: Language) => language.code)
|
||||
.orderBy((language: Language) => language.name)
|
||||
.forEach(async (language: Language) => {
|
||||
const languageStreams = streams.filter(stream => stream.hasLanguage(language))
|
||||
|
||||
if (languageStreams.isEmpty()) return
|
||||
|
||||
const playlist = new Playlist(languageStreams, { public: true })
|
||||
const filepath = `languages/${language.code}.m3u`
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
})
|
||||
|
||||
const undefinedStreams = streams.filter(stream => stream.noLanguages())
|
||||
|
||||
if (undefinedStreams.isEmpty()) return
|
||||
|
||||
const playlist = new Playlist(undefinedStreams, { public: true })
|
||||
const filepath = 'languages/undefined.m3u'
|
||||
await this.storage.save(filepath, playlist.toString())
|
||||
this.logger.info(JSON.stringify({ filepath, count: playlist.streams.count() }))
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
const api = require('../core/api')
|
||||
const _ = require('lodash')
|
||||
|
||||
module.exports = async function (streams = []) {
|
||||
streams = _.filter(streams, stream => stream.is_nsfw === false)
|
||||
|
||||
await api.regions.load()
|
||||
const regions = await api.regions.all()
|
||||
|
||||
await api.subdivisions.load()
|
||||
const subdivisions = await api.subdivisions.all()
|
||||
|
||||
const output = []
|
||||
for (const region of regions) {
|
||||
if (region.code === 'INT') continue
|
||||
|
||||
const regionCountries = region.countries
|
||||
let areaCodes = regionCountries.map(code => `c/${code}`)
|
||||
|
||||
const regionSubdivisions = _.filter(
|
||||
subdivisions,
|
||||
s => regionCountries.indexOf(s.country) > -1
|
||||
).map(s => `s/${s.code}`)
|
||||
areaCodes = areaCodes.concat(regionSubdivisions)
|
||||
|
||||
areaCodes.push(`r/${region.code}`)
|
||||
|
||||
let items = _.filter(streams, stream => _.intersection(stream.broadcast_area, areaCodes).length)
|
||||
output.push({ filepath: `regions/${region.code.toLowerCase()}.m3u`, items })
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
51
scripts/generators/regionsGenerator.ts
Normal file
51
scripts/generators/regionsGenerator.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { Generator } from './generator'
|
||||
import { Collection, Storage, Logger } from '../core'
|
||||
import { Playlist, Subdivision, Region } 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) {
|
||||
this.streams = streams
|
||||
this.regions = regions
|
||||
this.subdivisions = subdivisions
|
||||
this.storage = new Storage(PUBLIC_DIR)
|
||||
this.logger = logger
|
||||
}
|
||||
|
||||
async generate(): Promise<void> {
|
||||
let streams = this.streams.orderBy(stream => stream.getTitle()).filter(stream => stream.isSFW())
|
||||
|
||||
this.regions.forEach(async (region: Region) => {
|
||||
if (region.code === 'INT') 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 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() }))
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue