iptv-database/scripts/db/update.js

205 lines
5 KiB
JavaScript
Raw Normal View History

2023-04-08 20:38:21 -04:00
const { csv, file } = require('../core')
const channelScheme = require('../db/schemes/channels')
const { Octokit } = require('@octokit/core')
const { paginateRest } = require('@octokit/plugin-paginate-rest')
const CustomOctokit = Octokit.plugin(paginateRest)
const _ = require('lodash')
const octokit = new CustomOctokit({
auth: process.env.GITHUB_TOKEN
})
const DATA_DIR = process.env.DATA_DIR || './data'
const OWNER = 'iptv-org'
const REPO = 'database'
2023-04-11 06:44:42 -04:00
let channels = []
let processedIssues = []
2023-04-08 20:38:21 -04:00
async function main() {
try {
const filepath = `${DATA_DIR}/channels.csv`
2023-04-11 06:44:42 -04:00
channels = await csv.fromFile(filepath)
2023-04-08 20:38:21 -04:00
2023-04-23 16:30:06 -04:00
await removeChannels()
2023-04-11 06:44:42 -04:00
await editChannels()
await addChannels()
2023-04-08 20:38:21 -04:00
channels = _.orderBy(channels, [channels => channels.id.toLowerCase()], ['asc'])
await csv.save(filepath, channels)
2023-04-08 21:49:53 -04:00
const output = processedIssues.map(issue => `closes #${issue.number}`).join(', ')
2023-04-08 20:41:50 -04:00
console.log(`OUTPUT=${output}`)
2023-04-08 20:38:21 -04:00
} catch (err) {
console.log(err.message)
}
}
main()
2023-04-23 16:30:06 -04:00
async function removeChannels() {
const issues = await fetchIssues('channels:remove,approved')
issues.map(parseIssue).forEach(({ issue, channel }) => {
if (!channel) {
updateIssue(issue, { labels: ['channels:remove', 'rejected:invalid'] })
return
}
const index = _.findIndex(channels, { id: channel.id })
if (index < 0) {
updateIssue(issue, { labels: ['channels:remove', 'rejected:wrong_id'] })
return
}
channels.splice(index, 1)
processedIssues.push(issue)
})
}
2023-04-11 06:44:42 -04:00
async function editChannels() {
const issues = await fetchIssues('channels:edit,approved')
issues.map(parseIssue).forEach(({ issue, channel }) => {
if (!channel) {
updateIssue(issue, { labels: ['channels:edit', 'rejected:invalid'] })
return
}
const index = _.findIndex(channels, { id: channel.id })
if (!index) {
2023-04-23 16:30:06 -04:00
updateIssue(issue, { labels: ['channels:edit', 'rejected:wrong_id'] })
2023-04-11 06:44:42 -04:00
return
}
const found = channels[index]
for (let prop in channel) {
if (channel[prop] !== undefined) {
found[prop] = channel[prop]
}
}
2023-04-23 15:44:04 -04:00
found.id = generateChannelId(found.name, found.country)
2023-04-11 06:44:42 -04:00
channels.splice(index, 1, found)
processedIssues.push(issue)
})
}
async function addChannels() {
const issues = await fetchIssues('channels:add,approved')
issues.map(parseIssue).forEach(({ issue, channel }) => {
if (!channel) {
updateIssue(issue, { labels: ['channels:add', 'rejected:invalid'] })
return
}
const found = channels.find(c => c.id === channel.id)
if (found) {
updateIssue(issue, { labels: ['channels:add', 'rejected:duplicate'] })
return
}
channels.push(channel)
processedIssues.push(issue)
})
}
2023-04-08 20:38:21 -04:00
async function fetchIssues(labels) {
const issues = await octokit.paginate('GET /repos/{owner}/{repo}/issues', {
owner: OWNER,
repo: REPO,
per_page: 100,
labels,
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
})
return issues
}
async function updateIssue(issue, { labels }) {
await octokit.request('PATCH /repos/{owner}/{repo}/issues/{issue_number}', {
owner: OWNER,
repo: REPO,
issue_number: issue.number,
labels,
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
})
}
function parseIssue(issue) {
const buffer = {}
const channel = {}
const fields = {
2023-04-11 06:44:42 -04:00
'Channel ID (required)': 'id',
2023-04-08 20:38:21 -04:00
'Channel Name': 'name',
2023-04-11 06:44:42 -04:00
'Alternative Names': 'alt_names',
2023-04-08 20:52:55 -04:00
'Alternative Names (optional)': 'alt_names',
2023-04-11 06:44:42 -04:00
Network: 'network',
2023-04-08 20:38:21 -04:00
'Network (optional)': 'network',
2023-04-11 06:44:42 -04:00
Owners: 'owners',
2023-04-08 20:38:21 -04:00
'Owners (optional)': 'owners',
Country: 'country',
2023-04-11 06:44:42 -04:00
Subdivision: 'subdivision',
2023-04-08 20:38:21 -04:00
'Subdivision (optional)': 'subdivision',
2023-04-11 06:44:42 -04:00
City: 'city',
2023-04-08 20:38:21 -04:00
'City (optional)': 'city',
'Broadcast Area': 'broadcast_area',
Languages: 'languages',
2023-04-11 06:44:42 -04:00
Categories: 'categories',
2023-04-08 20:38:21 -04:00
'Categories (optional)': 'categories',
NSFW: 'is_nsfw',
2023-04-11 06:44:42 -04:00
Launched: 'launched',
2023-04-08 20:38:21 -04:00
'Launched (optional)': 'launched',
2023-04-11 06:44:42 -04:00
Closed: 'closed',
2023-04-08 20:38:21 -04:00
'Closed (optional)': 'closed',
2023-04-11 06:44:42 -04:00
'Replaced By': 'replaced_by',
2023-04-08 20:38:21 -04:00
'Replaced By (optional)': 'replaced_by',
2023-04-11 06:44:42 -04:00
Website: 'website',
2023-04-08 20:38:21 -04:00
'Website (optional)': 'website',
Logo: 'logo'
}
2023-05-24 12:23:02 -04:00
const matches = issue.body.match(/### ([^\r\n]+)\s+([^\r\n]+)/g)
2023-04-08 20:38:21 -04:00
if (!matches) return { issue, channel: null }
matches.forEach(item => {
2023-05-24 12:23:02 -04:00
const [, fieldLabel, value] = item.match(/### ([^\r\n]+)\s+([^\r\n]+)/)
2023-04-08 20:38:21 -04:00
const field = fields[fieldLabel]
if (!field) return
buffer[field] = value === '_No response_' ? undefined : value.trim()
})
for (let field of Object.keys(channelScheme)) {
channel[field] = buffer[field]
}
2023-04-11 06:44:42 -04:00
if (!channel.id) {
channel.id = generateChannelId(channel.name, channel.country)
}
2023-04-08 20:38:21 -04:00
return { issue, channel }
}
function generateChannelId(name, country) {
if (name && country) {
const slug = name
.replace(/\+/gi, 'Plus')
.replace(/^@/gi, 'At')
.replace(/[^a-z\d]+/gi, '')
country = country.toLowerCase()
return `${slug}.${country}`
}
return null
}