mirror of
https://github.com/iptv-org/epg.git
synced 2025-05-10 00:50:09 -04:00
Merge pull request #1203 from iptv-org/create-status-md
Create STATUS.md
This commit is contained in:
commit
bf94743137
17 changed files with 259 additions and 81 deletions
2
.github/workflows/_update-readme.yml
vendored
2
.github/workflows/_update-readme.yml
vendored
|
@ -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
53
.github/workflows/_update-status.yml
vendored
Normal 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
8
.readme/_sites.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
<table>
|
||||
<thead>
|
||||
<tr><th align="left">Site</th><th align="left">Status </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>
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"build": "README.md",
|
||||
"files": ["./.readme/template.md"]
|
||||
}
|
4
.readme/readme.json
Normal file
4
.readme/readme.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"build": "README.md",
|
||||
"files": ["./.readme/readme.md"]
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
# EPG
|
||||
|
||||
EPG (Electronic Program Guide) for thousands of TV channels collected from different sources.
|
||||
|
||||
## Usage
|
||||
|
||||
To load a program guide, all you need to do is copy the link to one or more of the guides from the list below and paste it into your favorite player.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
#include "./.readme/_countries.md"
|
||||
|
||||
All guides also have a compressed and JSON version. To download them, simply change the extension from `.xml` to `.xml.gz` or `.json` respectively.
|
||||
|
||||
## Contribution
|
||||
|
||||
If you find a bug or want to contribute to the code or documentation, you can help by submitting an [issue](https://github.com/iptv-org/epg/issues) or a [pull request](https://github.com/iptv-org/epg/pulls).
|
||||
# EPG
|
||||
|
||||
EPG (Electronic Program Guide) for thousands of TV channels collected from different sources.
|
||||
|
||||
## Usage
|
||||
|
||||
To load a program guide, all you need to do is copy the link to one or more of the guides from the list below and paste it into your favorite player.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
#include "./.readme/_countries.md"
|
||||
|
||||
All guides also have a compressed and JSON version. To download them, simply change the extension from `.xml` to `.xml.gz` or `.json` respectively.
|
||||
|
||||
## Contribution
|
||||
|
||||
If you find a bug or want to contribute to the code or documentation, you can help by submitting an [issue](https://github.com/iptv-org/epg/issues) or a [pull request](https://github.com/iptv-org/epg/pulls).
|
4
.readme/status.json
Normal file
4
.readme/status.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"build": "STATUS.md",
|
||||
"files": ["./.readme/status.md"]
|
||||
}
|
4
.readme/status.md
Normal file
4
.readme/status.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Status
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
#include "./.readme/_sites.md"
|
|
@ -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,
|
||||
|
|
|
@ -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} ${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 ',
|
||||
'Channels',
|
||||
'EPG',
|
||||
'Status '
|
||||
'EPG'
|
||||
])
|
||||
|
||||
await file.create('./.readme/_countries.md', output)
|
||||
|
|
52
scripts/commands/status/update.js
Normal file
52
scripts/commands/status/update.js
Normal 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 '
|
||||
])
|
||||
|
||||
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)
|
||||
}
|
|
@ -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} ${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
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
# EPG
|
||||
|
||||
EPG (Electronic Program Guide) for thousands of TV channels collected from different sources.
|
||||
|
||||
## Usage
|
||||
|
||||
To load a program guide, all you need to do is copy the link to one or more of the guides from the list below and paste it into your favorite player.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Country </th><th>Channels</th><th>EPG</th><th>Status </th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td valign="top" rowspan="2">🇨🇦 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>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
All guides also have a compressed and JSON version. To download them, simply change the extension from `.xml` to `.xml.gz` or `.json` respectively.
|
||||
|
||||
## Contribution
|
||||
|
||||
If you find a bug or want to contribute to the code or documentation, you can help by submitting an [issue](https://github.com/iptv-org/epg/issues) or a [pull request](https://github.com/iptv-org/epg/pulls).
|
||||
# EPG
|
||||
|
||||
EPG (Electronic Program Guide) for thousands of TV channels collected from different sources.
|
||||
|
||||
## Usage
|
||||
|
||||
To load a program guide, all you need to do is copy the link to one or more of the guides from the list below and paste it into your favorite player.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th align="left">Country </th><th align="left">Channels</th><th align="left">EPG</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td valign="top" rowspan="2">🇨🇦 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>
|
||||
|
||||
All guides also have a compressed and JSON version. To download them, simply change the extension from `.xml` to `.xml.gz` or `.json` respectively.
|
||||
|
||||
## Contribution
|
||||
|
||||
If you find a bug or want to contribute to the code or documentation, you can help by submitting an [issue](https://github.com/iptv-org/epg/issues) or a [pull request](https://github.com/iptv-org/epg/pulls).
|
||||
|
|
11
tests/__data__/expected/_status.md
Normal file
11
tests/__data__/expected/_status.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Status
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th align="left">Site</th><th align="left">Status </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>
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"build" : "tests/__data__/output/readme.md",
|
||||
"files" : ["./.readme/template.md"]
|
||||
"files" : ["./.readme/readme.md"]
|
||||
}
|
4
tests/__data__/input/status.json
Normal file
4
tests/__data__/input/status.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"build" : "tests/__data__/output/status.md",
|
||||
"files" : ["./.readme/status.md"]
|
||||
}
|
26
tests/commands/status/update.test.js
Normal file
26
tests/commands/status/update.test.js
Normal 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)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue