mirror of
https://github.com/iptv-org/database.git
synced 2025-05-10 11:40:01 -04:00
451 lines
13 KiB
TypeScript
451 lines
13 KiB
TypeScript
import { CSV, IssueLoader, CSVParser, Issue, IssueData } from '../core'
|
|
import { Channel, Blocked, Feed } from '../models'
|
|
import { DATA_DIR } from '../constants'
|
|
import { Storage, Collection } from '@freearhey/core'
|
|
import { createChannelId, createFeedId } from '../utils'
|
|
|
|
let blocklist = new Collection()
|
|
let channels = new Collection()
|
|
let feeds = new Collection()
|
|
let issues = new Collection()
|
|
const processedIssues = new Collection()
|
|
|
|
async function main() {
|
|
const dataStorage = new Storage(DATA_DIR)
|
|
const parser = new CSVParser()
|
|
const loader = new IssueLoader()
|
|
|
|
issues = await loader.load()
|
|
|
|
const channelsCSV = await dataStorage.load('channels.csv')
|
|
channels = (await parser.parse(channelsCSV)).map(data => new Channel(data))
|
|
|
|
const feedsCSV = await dataStorage.load('feeds.csv')
|
|
feeds = (await parser.parse(feedsCSV)).map(data => new Feed(data))
|
|
|
|
const blocklistCSV = await dataStorage.load('blocklist.csv')
|
|
blocklist = (await parser.parse(blocklistCSV)).map(data => new Blocked(data))
|
|
|
|
await removeFeeds()
|
|
await removeChannels()
|
|
await editFeeds()
|
|
await editChannels()
|
|
await addFeeds()
|
|
await addChannels()
|
|
await blockChannels()
|
|
await unblockChannels()
|
|
|
|
channels = channels.sortBy(channel => channel.id.toLowerCase())
|
|
const channelsOutput = new CSV({ items: channels }).toString()
|
|
await dataStorage.save('channels.csv', channelsOutput)
|
|
|
|
feeds = feeds.sortBy(feed => `${feed.channel}@${feed.id}`.toLowerCase())
|
|
const feedsOutput = new CSV({ items: feeds }).toString()
|
|
await dataStorage.save('feeds.csv', feedsOutput)
|
|
|
|
blocklist = blocklist.sortBy(blocked => blocked.channel.toLowerCase())
|
|
const blocklistOutput = new CSV({ items: blocklist }).toString()
|
|
await dataStorage.save('blocklist.csv', blocklistOutput)
|
|
|
|
const output = processedIssues.map((issue: Issue) => `closes #${issue.number}`).join(', ')
|
|
process.stdout.write(`OUTPUT=${output}`)
|
|
}
|
|
|
|
main()
|
|
|
|
async function removeFeeds() {
|
|
const requests = issues.filter(
|
|
issue => issue.labels.includes('feeds:remove') && issue.labels.includes('approved')
|
|
)
|
|
|
|
requests.forEach((issue: Issue) => {
|
|
if (issue.data.missing('channel_id') || issue.data.missing('feed_id')) return
|
|
|
|
const found = feeds.first(
|
|
(feed: Feed) =>
|
|
feed.channel === issue.data.getString('channel_id') &&
|
|
feed.id === issue.data.getString('feed_id')
|
|
)
|
|
if (!found) return
|
|
|
|
feeds.remove((feed: Feed) => feed.channel === found.channel && feed.id === found.id)
|
|
|
|
onFeedRemoval(found.channel, found.id)
|
|
|
|
processedIssues.push(issue)
|
|
})
|
|
}
|
|
|
|
async function editFeeds() {
|
|
const requests = issues.filter(
|
|
issue => issue.labels.includes('feeds:edit') && issue.labels.includes('approved')
|
|
)
|
|
|
|
requests.forEach((issue: Issue) => {
|
|
const data: IssueData = issue.data
|
|
if (data.missing('channel_id') || data.missing('feed_id')) return
|
|
|
|
const found: Feed = feeds.first(
|
|
(feed: Feed) =>
|
|
feed.channel === data.getString('channel_id') && feed.id === data.getString('feed_id')
|
|
)
|
|
if (!found) return
|
|
|
|
let channelId: string | undefined = found.channel
|
|
let feedId: string | undefined = found.id
|
|
if (data.has('feed_name')) {
|
|
const name = data.getString('feed_name') || found.name
|
|
if (name) {
|
|
feedId = createFeedId(name)
|
|
if (feedId) onFeedIdChange(found.channel, found.id, feedId)
|
|
}
|
|
}
|
|
|
|
if (data.has('is_main')) {
|
|
const isMain = data.getBoolean('is_main') || false
|
|
if (isMain) onFeedNewMain(channelId, feedId)
|
|
}
|
|
|
|
if (!feedId || !channelId) return
|
|
|
|
const updated = new Feed({
|
|
channel: channelId,
|
|
id: feedId,
|
|
name: data.getString('feed_name'),
|
|
is_main: data.getBoolean('is_main'),
|
|
broadcast_area: data.getArray('broadcast_area'),
|
|
timezones: data.getArray('timezones'),
|
|
languages: data.getArray('languages'),
|
|
video_format: data.getString('video_format'),
|
|
launched: data.getString('launched'),
|
|
closed: data.getString('closed'),
|
|
replaced_by: data.getString('replaced_by')
|
|
})
|
|
|
|
found.merge(updated)
|
|
|
|
processedIssues.push(issue)
|
|
})
|
|
}
|
|
|
|
async function addFeeds() {
|
|
const requests = issues.filter(
|
|
issue => issue.labels.includes('feeds:add') && issue.labels.includes('approved')
|
|
)
|
|
|
|
requests.forEach((issue: Issue) => {
|
|
const data: IssueData = issue.data
|
|
|
|
if (
|
|
data.missing('channel_id') ||
|
|
data.missing('feed_name') ||
|
|
data.missing('is_main') ||
|
|
data.missing('broadcast_area') ||
|
|
data.missing('timezones') ||
|
|
data.missing('languages') ||
|
|
data.missing('video_format')
|
|
)
|
|
return
|
|
|
|
const channelId = data.getString('channel_id')
|
|
const feedName = data.getString('feed_name') || 'SD'
|
|
const feedId = createFeedId(feedName)
|
|
if (!channelId || !feedId) return
|
|
|
|
const found: Feed = feeds.first(
|
|
(feed: Feed) => feed.channel === channelId && feed.id === feedId
|
|
)
|
|
if (found) return
|
|
|
|
const isMain = data.getBoolean('is_main') || false
|
|
if (isMain) onFeedNewMain(channelId, feedId)
|
|
|
|
feeds.push(
|
|
new Feed({
|
|
channel: channelId,
|
|
id: feedId,
|
|
name: feedName,
|
|
is_main: data.getBoolean('is_main'),
|
|
broadcast_area: data.getArray('broadcast_area'),
|
|
timezones: data.getArray('timezones'),
|
|
languages: data.getArray('languages'),
|
|
video_format: data.getString('video_format'),
|
|
launched: data.getString('launched'),
|
|
closed: data.getString('closed'),
|
|
replaced_by: data.getString('replaced_by')
|
|
})
|
|
)
|
|
|
|
processedIssues.push(issue)
|
|
})
|
|
}
|
|
|
|
async function removeChannels() {
|
|
const requests = issues.filter(
|
|
issue => issue.labels.includes('channels:remove') && issue.labels.includes('approved')
|
|
)
|
|
|
|
requests.forEach((issue: Issue) => {
|
|
if (issue.data.missing('channel_id')) return
|
|
|
|
const found = channels.first(
|
|
(channel: Channel) => channel.id === issue.data.getString('channel_id')
|
|
)
|
|
if (!found) return
|
|
|
|
channels.remove((channel: Channel) => channel.id === found.id)
|
|
|
|
onChannelRemoval(found.id)
|
|
|
|
processedIssues.push(issue)
|
|
})
|
|
}
|
|
|
|
async function editChannels() {
|
|
const requests = issues.filter(
|
|
issue => issue.labels.includes('channels:edit') && issue.labels.includes('approved')
|
|
)
|
|
|
|
requests.forEach((issue: Issue) => {
|
|
const data: IssueData = issue.data
|
|
if (data.missing('channel_id')) return
|
|
|
|
const found: Channel = channels.first(
|
|
(channel: Channel) => channel.id === data.getString('channel_id')
|
|
)
|
|
if (!found) return
|
|
|
|
let channelId: string | undefined = found.id
|
|
if (data.has('channel_name') || data.has('country')) {
|
|
const name = data.getString('channel_name') || found.name
|
|
const country = data.getString('country') || found.country
|
|
if (name && country) {
|
|
channelId = createChannelId(name, country)
|
|
if (channelId) onChannelIdChange(found.id, channelId)
|
|
}
|
|
}
|
|
|
|
if (!channelId) return
|
|
|
|
const updated = new Channel({
|
|
id: channelId,
|
|
name: data.getString('channel_name'),
|
|
alt_names: data.getArray('alt_names'),
|
|
network: data.getString('network'),
|
|
owners: data.getArray('owners'),
|
|
country: data.getString('country'),
|
|
subdivision: data.getString('subdivision'),
|
|
city: data.getString('city'),
|
|
broadcast_area: data.getArray('broadcast_area'),
|
|
languages: data.getArray('languages'),
|
|
categories: data.getArray('categories'),
|
|
is_nsfw: data.getBoolean('is_nsfw'),
|
|
launched: data.getString('launched'),
|
|
closed: data.getString('closed'),
|
|
replaced_by: data.getString('replaced_by'),
|
|
website: data.getString('website'),
|
|
logo: data.getString('logo')
|
|
})
|
|
|
|
found.merge(updated)
|
|
|
|
processedIssues.push(issue)
|
|
})
|
|
}
|
|
|
|
async function addChannels() {
|
|
const requests = issues.filter(
|
|
issue => issue.labels.includes('channels:add') && issue.labels.includes('approved')
|
|
)
|
|
|
|
requests.forEach((issue: Issue) => {
|
|
const data: IssueData = issue.data
|
|
|
|
if (
|
|
data.missing('channel_name') ||
|
|
data.missing('country') ||
|
|
data.missing('is_nsfw') ||
|
|
data.missing('logo') ||
|
|
data.missing('feed_name') ||
|
|
data.missing('broadcast_area') ||
|
|
data.missing('timezones') ||
|
|
data.missing('languages') ||
|
|
data.missing('video_format')
|
|
)
|
|
return
|
|
|
|
const channelId = createChannelId(data.getString('channel_name'), data.getString('country'))
|
|
if (!channelId) return
|
|
|
|
const found: Channel = channels.first((channel: Channel) => channel.id === channelId)
|
|
if (found) return
|
|
|
|
channels.push(
|
|
new Channel({
|
|
id: channelId,
|
|
name: data.getString('channel_name'),
|
|
alt_names: data.getArray('alt_names'),
|
|
network: data.getString('network'),
|
|
owners: data.getArray('owners'),
|
|
country: data.getString('country'),
|
|
subdivision: data.getString('subdivision'),
|
|
city: data.getString('city'),
|
|
broadcast_area: data.getArray('broadcast_area'),
|
|
languages: data.getArray('languages'),
|
|
categories: data.getArray('categories'),
|
|
is_nsfw: data.getBoolean('is_nsfw'),
|
|
launched: data.getString('launched'),
|
|
closed: data.getString('closed'),
|
|
replaced_by: data.getString('replaced_by'),
|
|
website: data.getString('website'),
|
|
logo: data.getString('logo')
|
|
})
|
|
)
|
|
|
|
const feedName = data.getString('feed_name') || 'SD'
|
|
|
|
feeds.push(
|
|
new Feed({
|
|
channel: channelId,
|
|
id: createFeedId(feedName),
|
|
name: feedName,
|
|
is_main: true,
|
|
broadcast_area: data.getArray('broadcast_area'),
|
|
timezones: data.getArray('timezones'),
|
|
languages: data.getArray('languages'),
|
|
video_format: data.getString('video_format'),
|
|
launched: data.getString('launched'),
|
|
closed: data.getString('closed'),
|
|
replaced_by: data.getString('replaced_by')
|
|
})
|
|
)
|
|
|
|
processedIssues.push(issue)
|
|
})
|
|
}
|
|
|
|
async function unblockChannels() {
|
|
const requests = issues.filter(
|
|
issue => issue.labels.includes('blocklist:remove') && issue.labels.includes('approved')
|
|
)
|
|
|
|
requests.forEach((issue: Issue) => {
|
|
const data = issue.data
|
|
if (data.missing('channel_id')) return
|
|
|
|
const found: Blocked = blocklist.first(
|
|
(blocked: Blocked) => blocked.channel === data.getString('channel_id')
|
|
)
|
|
if (!found) return
|
|
|
|
blocklist.remove((blocked: Blocked) => blocked.channel === found.channel)
|
|
|
|
processedIssues.push(issue)
|
|
})
|
|
}
|
|
|
|
async function blockChannels() {
|
|
const requests = issues.filter(
|
|
issue => issue.labels.includes('blocklist:add') && issue.labels.includes('approved')
|
|
)
|
|
|
|
requests.forEach((issue: Issue) => {
|
|
const data = issue.data
|
|
if (data.missing('channel_id')) return
|
|
|
|
const found: Blocked = blocklist.first(
|
|
(blocked: Blocked) => blocked.channel === data.getString('channel_id')
|
|
)
|
|
if (found) return
|
|
|
|
const channel = data.getString('channel_id')
|
|
const reason = data.getString('reason')?.toLowerCase()
|
|
const ref = data.getString('ref')
|
|
if (!channel || !reason || !ref) return
|
|
|
|
blocklist.push(
|
|
new Blocked({
|
|
channel,
|
|
reason,
|
|
ref
|
|
})
|
|
)
|
|
|
|
processedIssues.push(issue)
|
|
})
|
|
}
|
|
|
|
function onFeedIdChange(channelId: string, feedId: string, newFeedId: string) {
|
|
channels.forEach((channel: Channel) => {
|
|
if (channel.replaced_by && channel.replaced_by === `${channelId}@${feedId}`) {
|
|
channel.replaced_by = `${channelId}@${newFeedId}`
|
|
}
|
|
})
|
|
|
|
feeds.forEach((feed: Feed) => {
|
|
if (feed.replaced_by && feed.replaced_by === `${channelId}@${feedId}`) {
|
|
feed.replaced_by = `${channelId}@${newFeedId}`
|
|
}
|
|
})
|
|
}
|
|
|
|
function onFeedNewMain(channelId: string, feedId: string) {
|
|
feeds.forEach((feed: Feed) => {
|
|
if (feed.channel === channelId && feed.id !== feedId && feed.is_main === true) {
|
|
feed.is_main = false
|
|
}
|
|
})
|
|
}
|
|
|
|
function onFeedRemoval(channelId: string, feedId: string) {
|
|
channels.forEach((channel: Channel) => {
|
|
if (channel.replaced_by && channel.replaced_by === `${channelId}@${feedId}`) {
|
|
channel.replaced_by = ''
|
|
}
|
|
})
|
|
|
|
feeds.forEach((feed: Feed) => {
|
|
if (feed.replaced_by && feed.replaced_by === `${channelId}@${feedId}`) {
|
|
feed.replaced_by = ''
|
|
}
|
|
})
|
|
}
|
|
|
|
function onChannelIdChange(channelId: string, newChannelId: string) {
|
|
channels.forEach((channel: Channel) => {
|
|
if (channel.replaced_by && channel.replaced_by.includes(channelId)) {
|
|
channel.replaced_by = channel.replaced_by.replace(channelId, newChannelId)
|
|
}
|
|
})
|
|
|
|
feeds.forEach((feed: Feed) => {
|
|
if (feed.channel === channelId) {
|
|
feed.channel = newChannelId
|
|
}
|
|
|
|
if (feed.replaced_by && feed.replaced_by.includes(channelId)) {
|
|
feed.replaced_by = feed.replaced_by.replace(channelId, newChannelId)
|
|
}
|
|
})
|
|
|
|
blocklist.forEach((blocked: Blocked) => {
|
|
if (blocked.channel === channelId) {
|
|
blocked.channel = newChannelId
|
|
}
|
|
})
|
|
}
|
|
|
|
function onChannelRemoval(channelId: string) {
|
|
channels.forEach((channel: Channel) => {
|
|
if (channel.replaced_by && channel.replaced_by.includes(channelId)) {
|
|
channel.replaced_by = ''
|
|
}
|
|
})
|
|
|
|
feeds.remove((feed: Feed) => feed.channel === channelId)
|
|
feeds.forEach((feed: Feed) => {
|
|
if (feed.replaced_by && feed.replaced_by.includes(channelId)) {
|
|
feed.replaced_by = ''
|
|
}
|
|
})
|
|
}
|