Merge pull request #1203 from iptv-org/create-status-md

Create STATUS.md
This commit is contained in:
Aleksandr Statciuk 2022-10-22 04:48:13 +03:00 committed by GitHub
commit bf94743137
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 259 additions and 81 deletions

View file

@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: echo "BRANCH_NAME=$(date +'bot/auto-update-%s')" >> $GITHUB_OUTPUT
- run: echo "BRANCH_NAME=$(date +'bot/update-readme-%s')" >> $GITHUB_OUTPUT
id: create-branch-name
- run: git config user.name 'iptv-bot[bot]'
- run: git config user.email '84861620+iptv-bot[bot]@users.noreply.github.com'

53
.github/workflows/_update-status.yml vendored Normal file
View file

@ -0,0 +1,53 @@
name: _update-status
on:
workflow_dispatch:
schedule:
- cron: '0 9 * * *'
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: echo "BRANCH_NAME=$(date +'bot/update-status-%s')" >> $GITHUB_OUTPUT
id: create-branch-name
- run: git config user.name 'iptv-bot[bot]'
- run: git config user.email '84861620+iptv-bot[bot]@users.noreply.github.com'
- run: git checkout -b ${{ steps.create-branch-name.outputs.BRANCH_NAME }}
- uses: actions/setup-node@v3
if: ${{ !env.ACT }}
with:
node-version: 16
cache: 'npm'
- run: npm install
- run: npm run status:update
- name: Commit Changes
if: ${{ !env.ACT }}
run: |
git add STATUS.md
git commit -m "[Bot] Update STATUS.md"
git status
git push -u origin ${{ steps.create-branch-name.outputs.BRANCH_NAME }}
- uses: tibdex/github-app-token@v1
if: ${{ !env.ACT }}
id: create-app-token
with:
app_id: ${{ secrets.APP_ID }}
private_key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: repo-sync/pull-request@v2
if: ${{ !env.ACT && github.ref == 'refs/heads/master' }}
id: pull-request
with:
github_token: ${{ steps.create-app-token.outputs.token }}
source_branch: ${{ steps.create-branch-name.outputs.BRANCH_NAME }}
destination_branch: 'master'
pr_title: '[Bot] Update STATUS.md'
pr_body: |
This pull request is created via [update-status][1] workflow.
[1]: https://github.com/iptv-org/epg/actions/runs/${{ github.run_id }}
- uses: juliangruber/merge-pull-request-action@v1
if: ${{ !env.ACT && github.ref == 'refs/heads/master' }}
with:
github-token: ${{ secrets.PAT }}
number: ${{ steps.pull-request.outputs.pr_number }}
method: squash

8
.readme/_sites.md Normal file
View file

@ -0,0 +1,8 @@
<table>
<thead>
<tr><th align="left">Site</th><th align="left">Status&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th></tr>
</thead>
<tbody>
<tr><td valign="top" rowspan="1">example.com</td><td nowrap><a href="https://github.com/iptv-org/epg/actions/workflows/example.com.yml"><img src="https://github.com/iptv-org/epg/actions/workflows/example.com.yml/badge.svg" alt="example.com" style="max-width: 100%;"></a></td></tr>
</tbody>
</table>

View file

@ -1,4 +0,0 @@
{
"build": "README.md",
"files": ["./.readme/template.md"]
}

4
.readme/readme.json Normal file
View file

@ -0,0 +1,4 @@
{
"build": "README.md",
"files": ["./.readme/readme.md"]
}

4
.readme/status.json Normal file
View file

@ -0,0 +1,4 @@
{
"build": "STATUS.md",
"files": ["./.readme/status.md"]
}

4
.readme/status.md Normal file
View file

@ -0,0 +1,4 @@
# Status
<!-- prettier-ignore -->
#include "./.readme/_sites.md"

View file

@ -12,6 +12,7 @@
"api:update": "node scripts/commands/api/update.js",
"api:load": "mkdir -p scripts/data && curl -L -o scripts/data/channels.json https://iptv-org.github.io/api/channels.json && curl -L -o scripts/data/countries.json https://iptv-org.github.io/api/countries.json",
"readme:update": "node scripts/commands/readme/update.js",
"status:update": "node scripts/commands/status/update.js",
"lint": "npx eslint ./scripts/**/*.js",
"test": "TZ=Pacific/Nauru npx jest --runInBand",
"test:commands": "npx jest --runInBand -- commands",
@ -19,6 +20,7 @@
"act:test": "act workflow_dispatch -W .github/workflows/_test.yml",
"act:check": "act workflow_dispatch -W .github/workflows/_check.yml",
"act:update-readme": "act workflow_dispatch -W .github/workflows/_update-readme.yml",
"act:update-status": "act workflow_dispatch -W .github/workflows/_update-status.yml",
"act:update-api": "act workflow_dispatch -W .github/workflows/_update-api.yml"
},
"private": true,

View file

@ -5,7 +5,7 @@ const _ = require('lodash')
const CHANNELS_PATH = process.env.CHANNELS_PATH || 'sites/**/*.channels.xml'
const options = program
.option('-c, --config <config>', 'Set path to config file', '.readme/config.json')
.option('-c, --config <config>', 'Set path to config file', '.readme/readme.json')
.parse(process.argv)
.opts()
@ -46,28 +46,30 @@ main()
async function generateCountriesTable(items = []) {
logger.info('generating countries table...')
let rows = []
let data = []
for (const item of items) {
const country = api.countries.find({ code: item.code.toUpperCase() })
if (!country) continue
rows.push({
flag: country.flag,
name: country.name,
channels: item.count,
epg: `<code>https://iptv-org.github.io/epg/guides/${item.group}.epg.xml</code>`,
status: `<a href="https://github.com/iptv-org/epg/actions/workflows/${item.site}.yml"><img src="https://github.com/iptv-org/epg/actions/workflows/${item.site}.yml/badge.svg" alt="${item.site}" style="max-width: 100%;"></a>`
})
data.push([
country.name,
`${country.flag}&nbsp;${country.name}`,
item.count,
`<code>https://iptv-org.github.io/epg/guides/${item.group}.epg.xml</code>`
])
}
rows = _.orderBy(rows, ['name', 'channels'], ['asc', 'desc'])
rows = _.groupBy(rows, 'name')
data = _.orderBy(data, [item => item[0], item => item[2]], ['asc', 'desc'])
data = data.map(i => {
i.shift()
return i
})
data = Object.values(_.groupBy(data, item => item[0]))
const output = table.create(rows, [
const output = table.create(data, [
'Country&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
'Channels',
'EPG',
'Status&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'
'EPG'
])
await file.create('./.readme/_countries.md', output)

View file

@ -0,0 +1,52 @@
const { file, markdown, logger, table } = require('../../core')
const { program } = require('commander')
const _ = require('lodash')
const CONFIGS_PATH = process.env.CONFIGS_PATH || 'sites/**/*.config.js'
const options = program
.option('-c, --config <config>', 'Set path to config file', '.readme/status.json')
.parse(process.argv)
.opts()
async function main() {
let data = []
const files = await file.list(CONFIGS_PATH).catch(console.error)
for (const filepath of files) {
try {
const { site, ignore } = require(file.resolve(filepath))
if (ignore) continue
data.push([
site,
`<a href="https://github.com/iptv-org/epg/actions/workflows/${site}.yml"><img src="https://github.com/iptv-org/epg/actions/workflows/${site}.yml/badge.svg" alt="${site}" style="max-width: 100%;"></a>`
])
} catch (err) {
console.error(err)
continue
}
}
data = Object.values(_.groupBy(data, item => item[0]))
const output = table.create(data, [
'Site',
'Status&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'
])
await file.create('./.readme/_sites.md', output)
await updateMarkdown()
}
main()
async function updateMarkdown() {
logger.info('updating status.md...')
const config = require(file.resolve(options.config))
await file.createDir(file.dirname(config.build))
await markdown.compile(options.config)
}

View file

@ -1,35 +1,47 @@
const table = {}
table.create = function (data, cols) {
let output = '<table>\n'
let output = '<table>\r\n'
output += ' <thead>\n <tr>'
output += ' <thead>\r\n <tr>'
for (let column of cols) {
output += `<th>${column}</th>`
output += `<th align="left">${column}</th>`
}
output += '</tr>\n </thead>\n'
output += '</tr>\r\n </thead>\r\n'
output += ' <tbody>\n'
for (let groupId in data) {
const group = data[groupId]
for (let [i, item] of group.entries()) {
const rowspan = group.length > 1 ? ` rowspan="${group.length}"` : ''
output += ' <tr>'
if (i === 0) {
const name = item.flag ? `${item.flag}&nbsp;${item.name}` : item.name
output += `<td valign="top"${rowspan}>${name}</td>`
}
output += `<td align="right">${item.channels}</td>`
output += `<td nowrap>${item.epg}</td>`
output += `<td>${item.status}</td>`
output += '</tr>\n'
}
}
output += ' </tbody>\n'
output += ' <tbody>\r\n'
output += getHTMLRows(data)
output += ' </tbody>\r\n'
output += '</table>'
return output
}
function getHTMLRows(data) {
let output = ''
for (let group of data) {
let rowspan = group.length
for (let [j, row] of group.entries()) {
output += ' <tr>'
for (let [i, value] of row.entries()) {
if (i === 0 && j === 0) {
output += `<td valign="top" rowspan="${rowspan}">${value}</td>`
} else if (i > 0) {
if (typeof value === 'number') {
output += `<td align="right" nowrap>${value}</td>`
} else {
output += `<td nowrap>${value}</td>`
}
}
}
output += '</tr>\r\n'
}
}
return output
}
function getSpan() {}
module.exports = table

View file

@ -9,11 +9,11 @@ To load a program guide, all you need to do is copy the link to one or more of t
<!-- prettier-ignore -->
<table>
<thead>
<tr><th>Country&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th><th>Channels</th><th>EPG</th><th>Status&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th></tr>
<tr><th align="left">Country&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th><th align="left">Channels</th><th align="left">EPG</th></tr>
</thead>
<tbody>
<tr><td valign="top" rowspan="2">🇨🇦&nbsp;Canada</td><td align="right">2</td><td nowrap><code>https://iptv-org.github.io/epg/guides/ca-en/example.com.epg.xml</code></td><td><a href="https://github.com/iptv-org/epg/actions/workflows/example.com.yml"><img src="https://github.com/iptv-org/epg/actions/workflows/example.com.yml/badge.svg" alt="example.com" style="max-width: 100%;"></a></td></tr>
<tr><td align="right">1</td><td nowrap><code>https://iptv-org.github.io/epg/guides/ca-ru/example.com.epg.xml</code></td><td><a href="https://github.com/iptv-org/epg/actions/workflows/example.com.yml"><img src="https://github.com/iptv-org/epg/actions/workflows/example.com.yml/badge.svg" alt="example.com" style="max-width: 100%;"></a></td></tr>
<tr><td valign="top" rowspan="2">🇨🇦&nbsp;Canada</td><td align="right" nowrap>2</td><td nowrap><code>https://iptv-org.github.io/epg/guides/ca-en/example.com.epg.xml</code></td></tr>
<tr><td align="right" nowrap>1</td><td nowrap><code>https://iptv-org.github.io/epg/guides/ca-ru/example.com.epg.xml</code></td></tr>
</tbody>
</table>

View file

@ -0,0 +1,11 @@
# Status
<!-- prettier-ignore -->
<table>
<thead>
<tr><th align="left">Site</th><th align="left">Status&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th></tr>
</thead>
<tbody>
<tr><td valign="top" rowspan="1">example.com</td><td nowrap><a href="https://github.com/iptv-org/epg/actions/workflows/example.com.yml"><img src="https://github.com/iptv-org/epg/actions/workflows/example.com.yml/badge.svg" alt="example.com" style="max-width: 100%;"></a></td></tr>
</tbody>
</table>

View file

@ -1,4 +1,4 @@
{
"build" : "tests/__data__/output/readme.md",
"files" : ["./.readme/template.md"]
"files" : ["./.readme/readme.md"]
}

View file

@ -0,0 +1,4 @@
{
"build" : "tests/__data__/output/status.md",
"files" : ["./.readme/status.md"]
}

View file

@ -0,0 +1,26 @@
const { execSync } = require('child_process')
const fs = require('fs-extra')
const path = require('path')
beforeEach(() => {
fs.emptyDirSync('tests/__data__/output')
const stdout = execSync(
'CONFIGS_PATH=tests/__data__/input/sites/example.com.config.js DATA_DIR=tests/__data__/input/data npm run status:update -- --config=tests/__data__/input/status.json',
{ encoding: 'utf8' }
)
})
it('can update status.md', () => {
expect(content('tests/__data__/output/status.md')).toBe(
content('tests/__data__/expected/_status.md')
)
})
function content(filepath) {
const data = fs.readFileSync(path.resolve(filepath), {
encoding: 'utf8'
})
return JSON.stringify(data)
}