diff --git a/.github/workflows/_update-readme.yml b/.github/workflows/_update-readme.yml index 07f643da..41893691 100644 --- a/.github/workflows/_update-readme.yml +++ b/.github/workflows/_update-readme.yml @@ -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' diff --git a/.github/workflows/_update-status.yml b/.github/workflows/_update-status.yml new file mode 100644 index 00000000..c7f67177 --- /dev/null +++ b/.github/workflows/_update-status.yml @@ -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 diff --git a/.readme/_sites.md b/.readme/_sites.md new file mode 100644 index 00000000..b28b5063 --- /dev/null +++ b/.readme/_sites.md @@ -0,0 +1,8 @@ + + + + + + + +
SiteStatus                                                   
example.comexample.com
\ No newline at end of file diff --git a/.readme/config.json b/.readme/config.json deleted file mode 100644 index 88556a84..00000000 --- a/.readme/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "build": "README.md", - "files": ["./.readme/template.md"] -} diff --git a/.readme/readme.json b/.readme/readme.json new file mode 100644 index 00000000..db539a62 --- /dev/null +++ b/.readme/readme.json @@ -0,0 +1,4 @@ +{ + "build": "README.md", + "files": ["./.readme/readme.md"] +} diff --git a/.readme/template.md b/.readme/readme.md similarity index 97% rename from .readme/template.md rename to .readme/readme.md index a73700cb..2cd9f24a 100644 --- a/.readme/template.md +++ b/.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. - - -#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. + + +#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). diff --git a/.readme/status.json b/.readme/status.json new file mode 100644 index 00000000..1505b3a8 --- /dev/null +++ b/.readme/status.json @@ -0,0 +1,4 @@ +{ + "build": "STATUS.md", + "files": ["./.readme/status.md"] +} \ No newline at end of file diff --git a/.readme/status.md b/.readme/status.md new file mode 100644 index 00000000..3ee20ea5 --- /dev/null +++ b/.readme/status.md @@ -0,0 +1,4 @@ +# Status + + +#include "./.readme/_sites.md" diff --git a/package.json b/package.json index 4c643c29..d29da832 100644 --- a/package.json +++ b/package.json @@ -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, diff --git a/scripts/commands/readme/update.js b/scripts/commands/readme/update.js index 18f47c52..4ce5da4f 100644 --- a/scripts/commands/readme/update.js +++ b/scripts/commands/readme/update.js @@ -5,7 +5,7 @@ const _ = require('lodash') const CHANNELS_PATH = process.env.CHANNELS_PATH || 'sites/**/*.channels.xml' const options = program - .option('-c, --config ', 'Set path to config file', '.readme/config.json') + .option('-c, --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: `https://iptv-org.github.io/epg/guides/${item.group}.epg.xml`, - status: `${item.site}` - }) + data.push([ + country.name, + `${country.flag} ${country.name}`, + item.count, + `https://iptv-org.github.io/epg/guides/${item.group}.epg.xml` + ]) } - 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) diff --git a/scripts/commands/status/update.js b/scripts/commands/status/update.js new file mode 100644 index 00000000..9e3abdba --- /dev/null +++ b/scripts/commands/status/update.js @@ -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 ', '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, + `${site}` + ]) + } 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) +} diff --git a/scripts/core/table.js b/scripts/core/table.js index f9315f1e..0c5d363f 100644 --- a/scripts/core/table.js +++ b/scripts/core/table.js @@ -1,35 +1,47 @@ const table = {} table.create = function (data, cols) { - let output = '\n' + let output = '
\r\n' - output += ' \n ' + output += ' \r\n ' for (let column of cols) { - output += `` + output += `` } - output += '\n \n' + output += '\r\n \r\n' - output += ' \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 += ' ' - if (i === 0) { - const name = item.flag ? `${item.flag} ${item.name}` : item.name - output += `` - } - output += `` - output += `` - output += `` - output += '\n' - } - } - output += ' \n' + output += ' \r\n' + output += getHTMLRows(data) + output += ' \r\n' output += '
${column}${column}
${name}${item.channels}${item.epg}${item.status}
' return output } +function getHTMLRows(data) { + let output = '' + for (let group of data) { + let rowspan = group.length + for (let [j, row] of group.entries()) { + output += ' ' + for (let [i, value] of row.entries()) { + if (i === 0 && j === 0) { + output += `${value}` + } else if (i > 0) { + if (typeof value === 'number') { + output += `${value}` + } else { + output += `${value}` + } + } + } + output += '\r\n' + } + } + + return output +} + +function getSpan() {} + module.exports = table diff --git a/tests/__data__/expected/_readme.md b/tests/__data__/expected/_readme.md index 79027d19..5afa948d 100644 --- a/tests/__data__/expected/_readme.md +++ b/tests/__data__/expected/_readme.md @@ -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. - - - - - - - - - - -
Country                         ChannelsEPGStatus                                                   
🇨🇦 Canada2https://iptv-org.github.io/epg/guides/ca-en/example.com.epg.xmlexample.com
1https://iptv-org.github.io/epg/guides/ca-ru/example.com.epg.xmlexample.com
- -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. + + + + + + + + + + +
Country                         ChannelsEPG
🇨🇦 Canada2https://iptv-org.github.io/epg/guides/ca-en/example.com.epg.xml
1https://iptv-org.github.io/epg/guides/ca-ru/example.com.epg.xml
+ +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). diff --git a/tests/__data__/expected/_status.md b/tests/__data__/expected/_status.md new file mode 100644 index 00000000..25e8e613 --- /dev/null +++ b/tests/__data__/expected/_status.md @@ -0,0 +1,11 @@ +# Status + + + + + + + + + +
SiteStatus                                                   
example.comexample.com
diff --git a/tests/__data__/input/readme.json b/tests/__data__/input/readme.json index d226f0e6..fc3d3668 100644 --- a/tests/__data__/input/readme.json +++ b/tests/__data__/input/readme.json @@ -1,4 +1,4 @@ { "build" : "tests/__data__/output/readme.md", - "files" : ["./.readme/template.md"] + "files" : ["./.readme/readme.md"] } \ No newline at end of file diff --git a/tests/__data__/input/status.json b/tests/__data__/input/status.json new file mode 100644 index 00000000..02392960 --- /dev/null +++ b/tests/__data__/input/status.json @@ -0,0 +1,4 @@ +{ + "build" : "tests/__data__/output/status.md", + "files" : ["./.readme/status.md"] +} \ No newline at end of file diff --git a/tests/commands/status/update.test.js b/tests/commands/status/update.test.js new file mode 100644 index 00000000..568869b8 --- /dev/null +++ b/tests/commands/status/update.test.js @@ -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) +}