2
.github/workflows/_load.yml
vendored
2
.github/workflows/_load.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
with:
|
||||
name: database
|
||||
path: scripts/database
|
||||
- run: npm run guides:update
|
||||
- run: npm run guides:update_legacy
|
||||
- uses: tibdex/github-app-token@v1
|
||||
if: ${{ !env.ACT }}
|
||||
id: create-deploy-token
|
||||
|
||||
34
.github/workflows/_update-api.yml
vendored
34
.github/workflows/_update-api.yml
vendored
@@ -1,34 +0,0 @@
|
||||
name: _update-api
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 9 * * *'
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
if: ${{ !env.ACT }}
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- run: npm run api:update
|
||||
- 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: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
if: ${{ !env.ACT && github.ref == 'refs/heads/master' }}
|
||||
with:
|
||||
repository-name: iptv-org/api
|
||||
branch: gh-pages
|
||||
folder: .api
|
||||
token: ${{ steps.create-app-token.outputs.token }}
|
||||
git-config-name: iptv-bot[bot]
|
||||
git-config-email: 84861620+iptv-bot[bot]@users.noreply.github.com
|
||||
commit-message: '[Bot] Deploy to GitHub Pages'
|
||||
clean: false
|
||||
53
.github/workflows/_update-status.yml
vendored
53
.github/workflows/_update-status.yml
vendored
@@ -1,53 +0,0 @@
|
||||
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
|
||||
@@ -1,4 +1,4 @@
|
||||
name: _update-readme
|
||||
name: _update
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: echo "BRANCH_NAME=$(date +'bot/update-readme-%s')" >> $GITHUB_OUTPUT
|
||||
- run: echo "BRANCH_NAME=$(date +'bot/auto-update-%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'
|
||||
@@ -18,22 +18,54 @@ jobs:
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- run: npm run api:load
|
||||
- run: npm run readme:update
|
||||
- name: Commit Changes
|
||||
if: ${{ !env.ACT }}
|
||||
run: |
|
||||
git add README.md
|
||||
git commit -m "[Bot] Update README.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 }}
|
||||
- run: npm install
|
||||
- run: npm run api:load
|
||||
- if: ${{ !env.ACT }}
|
||||
run: GITHUB_TOKEN=${{ steps.create-app-token.outputs.token }} npm run programs:load
|
||||
- run: npm run guides:update
|
||||
- uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
if: ${{ !env.ACT && github.ref == 'refs/heads/master' }}
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: .gh-pages
|
||||
token: ${{ steps.create-deploy-token.outputs.token }}
|
||||
git-config-name: iptv-bot[bot]
|
||||
git-config-email: 84861620+iptv-bot[bot]@users.noreply.github.com
|
||||
commit-message: '[Bot] Update guides'
|
||||
clean: false
|
||||
force: false
|
||||
- run: npm run api:update
|
||||
- uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
if: ${{ !env.ACT && github.ref == 'refs/heads/master' }}
|
||||
with:
|
||||
repository-name: iptv-org/api
|
||||
branch: gh-pages
|
||||
folder: .api
|
||||
token: ${{ steps.create-app-token.outputs.token }}
|
||||
git-config-name: iptv-bot[bot]
|
||||
git-config-email: 84861620+iptv-bot[bot]@users.noreply.github.com
|
||||
commit-message: '[Bot] Deploy to iptv-org/api'
|
||||
clean: false
|
||||
- run: npm run readme:update
|
||||
- if: ${{ !env.ACT }}
|
||||
run: |
|
||||
git add README.md
|
||||
git commit -m "[Bot] Update README.md"
|
||||
git status
|
||||
git push -u origin ${{ steps.create-branch-name.outputs.BRANCH_NAME }}
|
||||
- run: npm run status:update
|
||||
- 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: repo-sync/pull-request@v2
|
||||
if: ${{ !env.ACT && github.ref == 'refs/heads/master' }}
|
||||
id: pull-request
|
||||
@@ -43,7 +75,7 @@ jobs:
|
||||
destination_branch: 'master'
|
||||
pr_title: '[Bot] Update README.md'
|
||||
pr_body: |
|
||||
This pull request is created via [update-readme][1] workflow.
|
||||
This pull request is created via [update][1] workflow.
|
||||
|
||||
[1]: https://github.com/iptv-org/epg/actions/runs/${{ github.run_id }}
|
||||
- uses: juliangruber/merge-pull-request-action@v1
|
||||
3
.readme/.gitignore
vendored
3
.readme/.gitignore
vendored
@@ -1,3 +1,2 @@
|
||||
_ca-provinces.md
|
||||
_countries.md
|
||||
_us-states.md
|
||||
_sites.md
|
||||
259
package-lock.json
generated
259
package-lock.json
generated
@@ -8,6 +8,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alex_neo/jest-expect-message": "^1.0.5",
|
||||
"@octokit/core": "^4.1.0",
|
||||
"axios": "^0.21.1",
|
||||
"chalk": "^4.1.2",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
@@ -22,6 +23,7 @@
|
||||
"iconv-lite": "^0.4.24",
|
||||
"inquirer": "^8.2.0",
|
||||
"jest": "^27.3.1",
|
||||
"langs": "^2.0.0",
|
||||
"libxmljs2": "^0.30.1",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-include": "^0.4.3",
|
||||
@@ -35,6 +37,7 @@
|
||||
"srcset": "^4.0.0",
|
||||
"tabletojson": "^2.0.7",
|
||||
"transliteration": "^2.2.0",
|
||||
"unzipit": "^1.4.0",
|
||||
"wildcard-match": "^5.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -967,6 +970,102 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz",
|
||||
"integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz",
|
||||
"integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^3.0.0",
|
||||
"@octokit/graphql": "^5.0.0",
|
||||
"@octokit/request": "^6.0.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz",
|
||||
"integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz",
|
||||
"integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^6.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
|
||||
"integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw=="
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
|
||||
"integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^7.0.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz",
|
||||
"integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
|
||||
"integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@seald-io/binary-search-tree": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.2.tgz",
|
||||
@@ -1495,6 +1594,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
@@ -2144,6 +2248,11 @@
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
|
||||
@@ -3374,6 +3483,14 @@
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-potential-custom-element-name": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
||||
@@ -4233,6 +4350,11 @@
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
|
||||
},
|
||||
"node_modules/langs": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/langs/-/langs-2.0.0.tgz",
|
||||
"integrity": "sha512-v4pxOBEQVN1WBTfB1crhTtxzNLZU9HPWgadlwzWKISJtt6Ku/CnpBrwVy+jFv8StjxsPfwPFzO0CMwdZLJ0/BA=="
|
||||
},
|
||||
"node_modules/leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
@@ -5840,6 +5962,11 @@
|
||||
"is-typedarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
@@ -5848,6 +5975,17 @@
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unzipit": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/unzipit/-/unzipit-1.4.0.tgz",
|
||||
"integrity": "sha512-hjoB8j1igXJgmxqaAvqkIW+faKTpG9cPK6QvkBhNCyd8OPWqODXTBVqTEmZbz62K5J/dX4Xa8lTa0NRikQwSjQ==",
|
||||
"dependencies": {
|
||||
"uzip-module": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@@ -5862,6 +6000,11 @@
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"node_modules/uzip-module": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uzip-module/-/uzip-module-1.0.3.tgz",
|
||||
"integrity": "sha512-AMqwWZaknLM77G+VPYNZLEruMGWGzyigPK3/Whg99B3S6vGHuqsyl5ZrOv1UUF3paGK1U6PM0cnayioaryg/fA=="
|
||||
},
|
||||
"node_modules/v8-compile-cache": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
|
||||
@@ -6846,6 +6989,84 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/auth-token": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz",
|
||||
"integrity": "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==",
|
||||
"requires": {
|
||||
"@octokit/types": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz",
|
||||
"integrity": "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==",
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^3.0.0",
|
||||
"@octokit/graphql": "^5.0.0",
|
||||
"@octokit/request": "^6.0.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz",
|
||||
"integrity": "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz",
|
||||
"integrity": "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==",
|
||||
"requires": {
|
||||
"@octokit/request": "^6.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
|
||||
"integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw=="
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
|
||||
"integrity": "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==",
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^7.0.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"@octokit/types": "^8.0.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz",
|
||||
"integrity": "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==",
|
||||
"requires": {
|
||||
"@octokit/types": "^8.0.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
|
||||
"integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^14.0.0"
|
||||
}
|
||||
},
|
||||
"@seald-io/binary-search-tree": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.2.tgz",
|
||||
@@ -7270,6 +7491,11 @@
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
@@ -7760,6 +7986,11 @@
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
|
||||
},
|
||||
"deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
|
||||
@@ -8634,6 +8865,11 @@
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||
},
|
||||
"is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
},
|
||||
"is-potential-custom-element-name": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
||||
@@ -9293,6 +9529,11 @@
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
|
||||
},
|
||||
"langs": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/langs/-/langs-2.0.0.tgz",
|
||||
"integrity": "sha512-v4pxOBEQVN1WBTfB1crhTtxzNLZU9HPWgadlwzWKISJtt6Ku/CnpBrwVy+jFv8StjxsPfwPFzO0CMwdZLJ0/BA=="
|
||||
},
|
||||
"leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
@@ -10496,11 +10737,24 @@
|
||||
"is-typedarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
},
|
||||
"universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
|
||||
},
|
||||
"unzipit": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/unzipit/-/unzipit-1.4.0.tgz",
|
||||
"integrity": "sha512-hjoB8j1igXJgmxqaAvqkIW+faKTpG9cPK6QvkBhNCyd8OPWqODXTBVqTEmZbz62K5J/dX4Xa8lTa0NRikQwSjQ==",
|
||||
"requires": {
|
||||
"uzip-module": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@@ -10515,6 +10769,11 @@
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"uzip-module": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/uzip-module/-/uzip-module-1.0.3.tgz",
|
||||
"integrity": "sha512-AMqwWZaknLM77G+VPYNZLEruMGWGzyigPK3/Whg99B3S6vGHuqsyl5ZrOv1UUF3paGK1U6PM0cnayioaryg/fA=="
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
"channels:editor": "node scripts/commands/channels/editor.js",
|
||||
"queue:create": "node scripts/commands/queue/create.js",
|
||||
"cluster:load": "node scripts/commands/cluster/load.js",
|
||||
"programs:load": "node scripts/commands/programs/load.js",
|
||||
"programs:save": "node scripts/commands/programs/save.js",
|
||||
"guides:update": "node scripts/commands/guides/update.js",
|
||||
"guides:update": "NODE_OPTIONS=--max-old-space-size=4096 node scripts/commands/guides/update.js",
|
||||
"guides:update_legacy": "node scripts/commands/guides/update_legacy.js",
|
||||
"api:load": "./scripts/commands/api/load.sh",
|
||||
"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",
|
||||
@@ -34,6 +36,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@alex_neo/jest-expect-message": "^1.0.5",
|
||||
"@octokit/core": "^4.1.0",
|
||||
"axios": "^0.21.1",
|
||||
"chalk": "^4.1.2",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
@@ -48,6 +51,7 @@
|
||||
"iconv-lite": "^0.4.24",
|
||||
"inquirer": "^8.2.0",
|
||||
"jest": "^27.3.1",
|
||||
"langs": "^2.0.0",
|
||||
"libxmljs2": "^0.30.1",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-include": "^0.4.3",
|
||||
@@ -61,6 +65,7 @@
|
||||
"srcset": "^4.0.0",
|
||||
"tabletojson": "^2.0.7",
|
||||
"transliteration": "^2.2.0",
|
||||
"unzipit": "^1.4.0",
|
||||
"wildcard-match": "^5.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
6
scripts/.gitignore
vendored
6
scripts/.gitignore
vendored
@@ -1,3 +1,3 @@
|
||||
database/
|
||||
logs/
|
||||
data/
|
||||
/database/
|
||||
/logs/
|
||||
/data/
|
||||
7
scripts/commands/api/load.sh
Executable file
7
scripts/commands/api/load.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
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
|
||||
curl -L -o scripts/data/regions.json https://iptv-org.github.io/api/regions.json
|
||||
curl -L -o scripts/data/subdivisions.json https://iptv-org.github.io/api/subdivisions.json
|
||||
@@ -2,35 +2,22 @@ const { file, parser, logger } = require('../../core')
|
||||
const { program } = require('commander')
|
||||
const _ = require('lodash')
|
||||
|
||||
const CHANNELS_PATH = process.env.CHANNELS_PATH || 'sites/**/*.channels.xml'
|
||||
const LOGS_DIR = process.env.LOGS_DIR || 'scripts/logs'
|
||||
const OUTPUT_DIR = process.env.OUTPUT_DIR || '.api'
|
||||
|
||||
async function main() {
|
||||
let guides = []
|
||||
|
||||
const files = await file.list(CHANNELS_PATH).catch(console.error)
|
||||
for (const filepath of files) {
|
||||
try {
|
||||
const { site, channels } = await parser.parseChannels(filepath)
|
||||
const dir = file.dirname(filepath)
|
||||
const config = require(file.resolve(`${dir}/${site}.config.js`))
|
||||
if (config.ignore) continue
|
||||
const logPath = `${LOGS_DIR}/guides/update.log`
|
||||
const results = await parser.parseLogs(logPath)
|
||||
|
||||
const filename = file.basename(filepath)
|
||||
const [__, suffix] = filename.match(/\_(.*)\.channels\.xml$/) || [null, null]
|
||||
|
||||
for (const channel of channels) {
|
||||
guides.push({
|
||||
channel: channel.id,
|
||||
site: channel.site,
|
||||
lang: channel.lang,
|
||||
url: `https://iptv-org.github.io/epg/guides/${suffix}/${site}.epg.xml.gz`
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
continue
|
||||
}
|
||||
for (const result of results) {
|
||||
guides.push({
|
||||
channel: result.channel,
|
||||
site: result.site,
|
||||
lang: result.lang,
|
||||
url: `https://iptv-org.github.io/epg/guides/${result.filename}.xml.gz`
|
||||
})
|
||||
}
|
||||
|
||||
guides = _.sortBy(guides, 'channel')
|
||||
|
||||
@@ -1,84 +1,139 @@
|
||||
const { db, logger, file, zip } = require('../../core')
|
||||
const { db, api, logger, file, zip } = require('../../core')
|
||||
const { generateXMLTV, Program, Channel } = require('epg-grabber')
|
||||
const _ = require('lodash')
|
||||
const langs = require('langs')
|
||||
|
||||
const PUBLIC_DIR = process.env.PUBLIC_DIR || '.gh-pages'
|
||||
const LOGS_DIR = process.env.LOGS_DIR || 'scripts/logs'
|
||||
const CURR_DATE = process.env.CURR_DATE || new Date()
|
||||
|
||||
const logPath = `${LOGS_DIR}/guides/update.log`
|
||||
|
||||
async function main() {
|
||||
logger.info(`Generating guides/...`)
|
||||
logger.info(`starting...`)
|
||||
|
||||
logger.info('Loading "database/programs.db"...')
|
||||
logger.info('loading API data...')
|
||||
await api.countries.load()
|
||||
await api.channels.load()
|
||||
await api.regions.load()
|
||||
await api.subdivisions.load()
|
||||
|
||||
let countries = await api.countries.all()
|
||||
let api_channels = await api.channels.all()
|
||||
|
||||
let channels_dic = {}
|
||||
api_channels.forEach(channel => {
|
||||
channels_dic[channel.id] = channel
|
||||
})
|
||||
|
||||
let api_regions = await api.regions.all()
|
||||
let api_subdivisions = await api.subdivisions.all()
|
||||
|
||||
logger.info('loading database/programs.db...')
|
||||
await db.programs.load()
|
||||
let db_programs = await db.programs.find({})
|
||||
db_programs = db_programs
|
||||
.map(p => {
|
||||
if (p.titles.length) {
|
||||
p.lang = p.titles[0].lang
|
||||
return p
|
||||
}
|
||||
return null
|
||||
})
|
||||
.filter(Boolean)
|
||||
logger.info(`found ${db_programs.length} programs`)
|
||||
|
||||
let total = 0
|
||||
const grouped = groupByGroup(await loadQueue())
|
||||
for (const key in grouped) {
|
||||
let channels = {}
|
||||
let programs = []
|
||||
for (const item of grouped[key]) {
|
||||
if (item.error) continue
|
||||
logger.info(`creating ${logPath}...`)
|
||||
await file.create(logPath)
|
||||
|
||||
const itemPrograms = await loadProgramsForItem(item)
|
||||
programs = programs.concat(itemPrograms)
|
||||
for (let country of countries) {
|
||||
let countryBroadcastCode = `c/${country.code}`
|
||||
let countryRegions = api_regions
|
||||
.filter(r => r.countries.includes(country.code))
|
||||
.map(r => `r/${r.code}`)
|
||||
let countrySubdivisions = api_subdivisions
|
||||
.filter(s => s.country === country.code)
|
||||
.map(s => `s/${s.code}`)
|
||||
let broadcastCodes = [countryBroadcastCode, ...countryRegions, ...countrySubdivisions]
|
||||
|
||||
if (channels[item.channel.id]) continue
|
||||
channels[item.channel.id] = new Channel(item.channel)
|
||||
let countryChannels = api_channels.filter(
|
||||
c => _.intersection(c.broadcast_area, broadcastCodes).length
|
||||
)
|
||||
countryChannels = countryChannels.map(c => c.id)
|
||||
|
||||
let countryPrograms = db_programs.filter(p => countryChannels.includes(p.channel))
|
||||
let langGroups = _.groupBy(countryPrograms, 'lang')
|
||||
|
||||
for (let langCode of country.languages) {
|
||||
const lang = convertLangCode(langCode, '3', '1')
|
||||
if (!lang) continue
|
||||
|
||||
let langPrograms = langGroups[lang]
|
||||
if (!langPrograms || !langPrograms.length) continue
|
||||
|
||||
let programs = []
|
||||
let channelGroups = _.groupBy(langPrograms, 'channel')
|
||||
for (let groupedPrograms of Object.values(channelGroups)) {
|
||||
let channelPrograms = getChannelPrograms(groupedPrograms)
|
||||
if (!channelPrograms.length) continue
|
||||
|
||||
programs = programs.concat(channelPrograms)
|
||||
}
|
||||
programs = _.sortBy(programs, ['channel', 'start'])
|
||||
programs = programs.map(p => new Program(p, new Channel(channels_dic[p.channel])))
|
||||
let channels = programs.map(p => {
|
||||
let c = channels_dic[p.channel]
|
||||
c.site = p.site
|
||||
c.lang = lang
|
||||
|
||||
return new Channel(c)
|
||||
})
|
||||
channels = _.sortBy(channels, 'id')
|
||||
channels = _.uniqBy(channels, 'id')
|
||||
|
||||
const filename = `${country.code.toLowerCase()}_${lang}`
|
||||
const xmlFilepath = `${PUBLIC_DIR}/guides/${filename}.xml`
|
||||
const gzFilepath = `${PUBLIC_DIR}/guides/${filename}.xml.gz`
|
||||
const jsonFilepath = `${PUBLIC_DIR}/guides/${filename}.json`
|
||||
logger.info(`creating ${xmlFilepath}...`)
|
||||
const xmltv = generateXMLTV({
|
||||
channels,
|
||||
programs,
|
||||
date: CURR_DATE
|
||||
})
|
||||
await file.create(xmlFilepath, xmltv)
|
||||
logger.info(`creating ${gzFilepath}...`)
|
||||
const compressed = await zip.compress(xmltv)
|
||||
await file.create(gzFilepath, compressed)
|
||||
logger.info(`creating ${jsonFilepath}...`)
|
||||
await file.create(jsonFilepath, JSON.stringify({ channels, programs }))
|
||||
|
||||
for (let channel of channels) {
|
||||
let result = {
|
||||
country: country.code,
|
||||
lang,
|
||||
site: channel.site,
|
||||
channel: channel.id,
|
||||
filename
|
||||
}
|
||||
|
||||
await file.append(logPath, JSON.stringify(result) + '\r\n')
|
||||
}
|
||||
}
|
||||
programs = _.sortBy(programs, ['channel', 'start'])
|
||||
programs = programs.map(p => new Program(p, channels[p.channel]))
|
||||
programs = _.uniqBy(programs, p => p.channel + p.start)
|
||||
total += programs.length
|
||||
channels = Object.values(channels)
|
||||
channels = _.sortBy(channels, 'id')
|
||||
|
||||
const xmlFilepath = `${PUBLIC_DIR}/guides/${key}.epg.xml`
|
||||
const gzFilepath = `${PUBLIC_DIR}/guides/${key}.epg.xml.gz`
|
||||
const jsonFilepath = `${PUBLIC_DIR}/guides/${key}.epg.json`
|
||||
logger.info(`Creating "${xmlFilepath}"...`)
|
||||
const xmltv = generateXMLTV({ channels, programs, date: CURR_DATE })
|
||||
await file.create(xmlFilepath, xmltv)
|
||||
logger.info(`Creating "${gzFilepath}"...`)
|
||||
const compressed = await zip.compress(xmltv)
|
||||
await file.create(gzFilepath, compressed)
|
||||
logger.info(`Creating "${jsonFilepath}"...`)
|
||||
await file.create(jsonFilepath, JSON.stringify({ channels, programs }))
|
||||
}
|
||||
|
||||
if (!total) {
|
||||
logger.error('\nError: No programs found')
|
||||
process.exit(1)
|
||||
} else {
|
||||
logger.info(`Done`)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
function groupByGroup(items = []) {
|
||||
const groups = {}
|
||||
function convertLangCode(code, from, to) {
|
||||
let found = langs.where(from, code)
|
||||
|
||||
items.forEach(item => {
|
||||
item.groups.forEach(key => {
|
||||
if (!groups[key]) {
|
||||
groups[key] = []
|
||||
}
|
||||
|
||||
groups[key].push(item)
|
||||
})
|
||||
})
|
||||
|
||||
return groups
|
||||
return found ? found[to] : null
|
||||
}
|
||||
|
||||
async function loadQueue() {
|
||||
logger.info('Loading queue...')
|
||||
function getChannelPrograms(programs) {
|
||||
let groups = _.groupBy(programs, 'site')
|
||||
groups = Object.values(groups)
|
||||
|
||||
await db.queue.load()
|
||||
|
||||
return await db.queue.find({}).sort({ xmltv_id: 1 })
|
||||
}
|
||||
|
||||
async function loadProgramsForItem(item) {
|
||||
return await db.programs.find({ _qid: item._id }).sort({ channel: 1, start: 1 })
|
||||
return groups[0]
|
||||
}
|
||||
|
||||
84
scripts/commands/guides/update_legacy.js
Normal file
84
scripts/commands/guides/update_legacy.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const { db, logger, file, zip } = require('../../core')
|
||||
const { generateXMLTV, Program, Channel } = require('epg-grabber')
|
||||
const _ = require('lodash')
|
||||
|
||||
const PUBLIC_DIR = process.env.PUBLIC_DIR || '.gh-pages'
|
||||
const CURR_DATE = process.env.CURR_DATE || new Date()
|
||||
|
||||
async function main() {
|
||||
logger.info(`Generating guides/...`)
|
||||
|
||||
logger.info('Loading "database/programs.db"...')
|
||||
await db.programs.load()
|
||||
|
||||
let total = 0
|
||||
const grouped = groupByGroup(await loadQueue())
|
||||
for (const key in grouped) {
|
||||
let channels = {}
|
||||
let programs = []
|
||||
for (const item of grouped[key]) {
|
||||
if (item.error) continue
|
||||
|
||||
const itemPrograms = await loadProgramsForItem(item)
|
||||
programs = programs.concat(itemPrograms)
|
||||
|
||||
if (channels[item.channel.id]) continue
|
||||
channels[item.channel.id] = new Channel(item.channel)
|
||||
}
|
||||
programs = _.sortBy(programs, ['channel', 'start'])
|
||||
programs = programs.map(p => new Program(p, channels[p.channel]))
|
||||
programs = _.uniqBy(programs, p => p.channel + p.start)
|
||||
total += programs.length
|
||||
channels = Object.values(channels)
|
||||
channels = _.sortBy(channels, 'id')
|
||||
|
||||
const xmlFilepath = `${PUBLIC_DIR}/guides/${key}.epg.xml`
|
||||
const gzFilepath = `${PUBLIC_DIR}/guides/${key}.epg.xml.gz`
|
||||
const jsonFilepath = `${PUBLIC_DIR}/guides/${key}.epg.json`
|
||||
logger.info(`Creating "${xmlFilepath}"...`)
|
||||
const xmltv = generateXMLTV({ channels, programs, date: CURR_DATE })
|
||||
await file.create(xmlFilepath, xmltv)
|
||||
logger.info(`Creating "${gzFilepath}"...`)
|
||||
const compressed = await zip.compress(xmltv)
|
||||
await file.create(gzFilepath, compressed)
|
||||
logger.info(`Creating "${jsonFilepath}"...`)
|
||||
await file.create(jsonFilepath, JSON.stringify({ channels, programs }))
|
||||
}
|
||||
|
||||
if (!total) {
|
||||
logger.error('\nError: No programs found')
|
||||
process.exit(1)
|
||||
} else {
|
||||
logger.info(`Done`)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
function groupByGroup(items = []) {
|
||||
const groups = {}
|
||||
|
||||
items.forEach(item => {
|
||||
item.groups.forEach(key => {
|
||||
if (!groups[key]) {
|
||||
groups[key] = []
|
||||
}
|
||||
|
||||
groups[key].push(item)
|
||||
})
|
||||
})
|
||||
|
||||
return groups
|
||||
}
|
||||
|
||||
async function loadQueue() {
|
||||
logger.info('Loading queue...')
|
||||
|
||||
await db.queue.load()
|
||||
|
||||
return await db.queue.find({}).sort({ xmltv_id: 1 })
|
||||
}
|
||||
|
||||
async function loadProgramsForItem(item) {
|
||||
return await db.programs.find({ _qid: item._id }).sort({ channel: 1, start: 1 })
|
||||
}
|
||||
110
scripts/commands/programs/load.js
Normal file
110
scripts/commands/programs/load.js
Normal file
@@ -0,0 +1,110 @@
|
||||
const { Octokit } = require('@octokit/core')
|
||||
const dayjs = require('dayjs')
|
||||
const isToday = require('dayjs/plugin/isToday')
|
||||
const utc = require('dayjs/plugin/utc')
|
||||
const unzipit = require('unzipit')
|
||||
const { file, logger } = require('../../core')
|
||||
|
||||
dayjs.extend(isToday)
|
||||
dayjs.extend(utc)
|
||||
|
||||
const DB_DIR = process.env.DB_DIR || './scripts/database'
|
||||
const dbPath = `${DB_DIR}/programs.db`
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: process.env.GITHUB_TOKEN
|
||||
})
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
let workflows = await getWorkflows()
|
||||
logger.info(`found ${workflows.length} workflows\r\n`)
|
||||
|
||||
await file.create(dbPath)
|
||||
const total = workflows.length
|
||||
for (let [i, workflow] of workflows.entries()) {
|
||||
logger.info(`[${i + 1}/${total}] ${workflow.name}`)
|
||||
const run = await getWorkflowRun(workflow)
|
||||
if (!run) continue
|
||||
|
||||
let artifact = await getRunArtifacts(run)
|
||||
|
||||
const buffer = await downloadArtifact(artifact)
|
||||
await file.append(dbPath, buffer)
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err.message)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
async function downloadArtifact(artifact) {
|
||||
let results = await octokit.request(
|
||||
'GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format}',
|
||||
{
|
||||
owner: 'iptv-org',
|
||||
repo: 'epg',
|
||||
artifact_id: artifact.id,
|
||||
archive_format: 'zip'
|
||||
}
|
||||
)
|
||||
|
||||
const { entries } = await unzipit.unzip(results.data)
|
||||
|
||||
const arrayBuffer = await entries['programs.db'].arrayBuffer()
|
||||
|
||||
return toString(arrayBuffer)
|
||||
}
|
||||
|
||||
async function getRunArtifacts(run) {
|
||||
let results = await octokit.request('GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts', {
|
||||
owner: 'iptv-org',
|
||||
repo: 'epg',
|
||||
run_id: run.id
|
||||
})
|
||||
|
||||
return results.data.artifacts.find(a => a.name === 'database')
|
||||
}
|
||||
|
||||
async function getWorkflowRun(workflow) {
|
||||
let today = dayjs.utc().format('YYYY-MM-DD')
|
||||
let results = await octokit.request(
|
||||
'GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs',
|
||||
{
|
||||
owner: 'iptv-org',
|
||||
repo: 'epg',
|
||||
workflow_id: workflow.id,
|
||||
status: 'success',
|
||||
created: `>=${today}`
|
||||
}
|
||||
)
|
||||
|
||||
return results.data.workflow_runs.find(
|
||||
r => r.event === 'schedule' || r.event === 'workflow_dispatch'
|
||||
)
|
||||
}
|
||||
|
||||
async function getWorkflows() {
|
||||
let workflows = []
|
||||
for (let page of [1, 2, 3]) {
|
||||
try {
|
||||
let results = await octokit.request('GET /repos/{owner}/{repo}/actions/workflows', {
|
||||
owner: 'iptv-org',
|
||||
repo: 'epg',
|
||||
per_page: 100,
|
||||
page
|
||||
})
|
||||
|
||||
workflows = workflows.concat(results.data.workflows)
|
||||
} catch (err) {
|
||||
console.log(err.message)
|
||||
}
|
||||
}
|
||||
|
||||
return workflows.filter(w => !/^_/.test(w.name) && w.name !== 'pages-build-deployment')
|
||||
}
|
||||
|
||||
function toString(arrayBuffer) {
|
||||
return new TextDecoder().decode(arrayBuffer)
|
||||
}
|
||||
@@ -14,7 +14,6 @@ const options = program
|
||||
.opts()
|
||||
|
||||
const CHANNELS_PATH = process.env.CHANNELS_PATH || 'sites/**/*.channels.xml'
|
||||
const LOGS_DIR = process.env.LOGS_DIR || 'scripts/logs'
|
||||
|
||||
async function main() {
|
||||
logger.info('Starting...')
|
||||
|
||||
@@ -2,7 +2,7 @@ const { file, markdown, parser, logger, api, table } = require('../../core')
|
||||
const { program } = require('commander')
|
||||
const _ = require('lodash')
|
||||
|
||||
const CHANNELS_PATH = process.env.CHANNELS_PATH || 'sites/**/*.channels.xml'
|
||||
const LOGS_DIR = process.env.LOGS_DIR || 'scripts/logs'
|
||||
|
||||
const options = program
|
||||
.option('-c, --config <config>', 'Set path to config file', '.readme/readme.json')
|
||||
@@ -10,52 +10,34 @@ const options = program
|
||||
.opts()
|
||||
|
||||
async function main() {
|
||||
const items = []
|
||||
|
||||
await api.countries.load().catch(console.error)
|
||||
const files = await file.list(CHANNELS_PATH).catch(console.error)
|
||||
for (const filepath of files) {
|
||||
try {
|
||||
const { site, channels } = await parser.parseChannels(filepath)
|
||||
const dir = file.dirname(filepath)
|
||||
const config = require(file.resolve(`${dir}/${site}.config.js`))
|
||||
if (config.ignore) continue
|
||||
|
||||
const filename = file.basename(filepath)
|
||||
const [__, suffix] = filename.match(/\_(.*)\.channels\.xml$/) || [null, null]
|
||||
const [code] = suffix.split('-')
|
||||
|
||||
items.push({
|
||||
code,
|
||||
site,
|
||||
count: channels.length,
|
||||
group: `${suffix}/${site}`
|
||||
})
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
continue
|
||||
const logPath = `${LOGS_DIR}/guides/update.log`
|
||||
const results = await parser.parseLogs(logPath)
|
||||
const files = results.reduce((acc, curr) => {
|
||||
if (acc[curr.filename]) {
|
||||
acc[curr.filename].channels++
|
||||
} else {
|
||||
acc[curr.filename] = {
|
||||
country: curr.country,
|
||||
channels: 1,
|
||||
filename: curr.filename
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await generateCountriesTable(items)
|
||||
await updateReadme()
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
async function generateCountriesTable(items = []) {
|
||||
logger.info('generating countries table...')
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
let data = []
|
||||
for (const item of items) {
|
||||
const country = api.countries.find({ code: item.code.toUpperCase() })
|
||||
for (const filename in files) {
|
||||
const item = files[filename]
|
||||
const country = api.countries.find({ code: item.country })
|
||||
if (!country) continue
|
||||
|
||||
data.push([
|
||||
country.name,
|
||||
`${country.flag} ${country.name}`,
|
||||
item.count,
|
||||
`<code>https://iptv-org.github.io/epg/guides/${item.group}.epg.xml</code>`
|
||||
item.channels,
|
||||
`<code>https://iptv-org.github.io/epg/guides/${filename}.xml</code>`
|
||||
])
|
||||
}
|
||||
|
||||
@@ -73,8 +55,12 @@ async function generateCountriesTable(items = []) {
|
||||
])
|
||||
|
||||
await file.create('./.readme/_countries.md', output)
|
||||
|
||||
await updateReadme()
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
async function updateReadme() {
|
||||
logger.info('updating readme.md...')
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ class API {
|
||||
const api = {}
|
||||
|
||||
api.channels = new API(`${DATA_DIR}/channels.json`)
|
||||
api.regions = new API(`${DATA_DIR}/regions.json`)
|
||||
api.countries = new API(`${DATA_DIR}/countries.json`)
|
||||
api.subdivisions = new API(`${DATA_DIR}/subdivisions.json`)
|
||||
|
||||
|
||||
@@ -10,4 +10,10 @@ logger.config({
|
||||
displayBadge: false
|
||||
})
|
||||
|
||||
logger.memoryUsage = function () {
|
||||
const used = process.memoryUsage().heapUsed / 1024 / 1024
|
||||
|
||||
logger.info(`memory: ${Math.round(used * 100) / 100} MB`)
|
||||
}
|
||||
|
||||
module.exports = logger
|
||||
|
||||
@@ -12,8 +12,9 @@ To load a program guide, all you need to do is copy the link to one or more of t
|
||||
<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>
|
||||
<tr><td valign="top" rowspan="2">🇨🇦 Canada</td><td align="right" nowrap>5</td><td nowrap><code>https://iptv-org.github.io/epg/guides/ca_fr.xml</code></td></tr>
|
||||
<tr><td align="right" nowrap>2</td><td nowrap><code>https://iptv-org.github.io/epg/guides/ca_en.xml</code></td></tr>
|
||||
<tr><td valign="top" rowspan="1">🇩🇰 Denmark</td><td align="right" nowrap>1</td><td nowrap><code>https://iptv-org.github.io/epg/guides/dk_da.xml</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"channel":"CNNInternationalEurope.us","site":"example.com","lang":"en","url":"https://iptv-org.github.io/epg/guides/ca-en/example.com.epg.xml.gz"},{"channel":"CNNInternationalEurope.us","site":"example.com","lang":"ru","url":"https://iptv-org.github.io/epg/guides/ca-ru/example.com.epg.xml.gz"},{"channel":"CNNInternationalEurope2.us","site":"example.com","lang":"en","url":"https://iptv-org.github.io/epg/guides/ca-en/example.com.epg.xml.gz"}]
|
||||
[{"channel":"6eren.dk","site":"allente.se","lang":"da","url":"https://iptv-org.github.io/epg/guides/dk_da.xml.gz"},{"channel":"ABCSpark.ca","site":"tvhebdo.com","lang":"fr","url":"https://iptv-org.github.io/epg/guides/ca_fr.xml.gz"},{"channel":"BBCEarthCanada.ca","site":"tvhebdo.com","lang":"fr","url":"https://iptv-org.github.io/epg/guides/ca_fr.xml.gz"},{"channel":"CFMTDT.ca","site":"tvhebdo.com","lang":"fr","url":"https://iptv-org.github.io/epg/guides/ca_fr.xml.gz"},{"channel":"CFMTDT.ca","site":"tvhebdo.com","lang":"en","url":"https://iptv-org.github.io/epg/guides/ca_en.xml.gz"},{"channel":"CanalVie.ca","site":"tvhebdo.com","lang":"fr","url":"https://iptv-org.github.io/epg/guides/ca_fr.xml.gz"},{"channel":"CanalVie.ca","site":"tvhebdo.com","lang":"en","url":"https://iptv-org.github.io/epg/guides/ca_en.xml.gz"},{"channel":"beINSportsCanada.ca","site":"tvhebdo.com","lang":"fr","url":"https://iptv-org.github.io/epg/guides/ca_fr.xml.gz"}]
|
||||
1
tests/__data__/expected/guides/dk_da.json
Normal file
1
tests/__data__/expected/guides/dk_da.json
Normal file
@@ -0,0 +1 @@
|
||||
{"channels":[{"id":"6eren.dk","name":"6'eren","site":"allente.se","lang":"da","logo":"https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png","url":"https://allente.se"}],"programs":[{"site":"allente.se","channel":"6eren.dk","titles":[{"value":"Diners, Drive-Ins and Dives","lang":"da"}],"sub_titles":[],"descriptions":[{"value":"Underholdning","lang":"da"}],"icon":{"src":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/487/2022-10-24/se.cs.6eren.event.B_0254194276971024040000.jpg?size=2560x1440"},"episodeNumbers":[{"system":"xmltv_ns","value":"23.5.0/1"},{"system":"onscreen","value":"S24E06"}],"date":null,"start":1666584000000,"stop":1666585500000,"urls":[],"ratings":[],"categories":[{"value":"series","lang":"da"}],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[]}]}
|
||||
4
tests/__data__/expected/guides/dk_da.xml
Normal file
4
tests/__data__/expected/guides/dk_da.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?><tv date="20221020">
|
||||
<channel id="6eren.dk"><display-name>6'eren</display-name><icon src="https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png"/><url>https://allente.se</url></channel>
|
||||
<programme start="20221024040000 +0000" stop="20221024042500 +0000" channel="6eren.dk"><title lang="da">Diners, Drive-Ins and Dives</title><desc lang="da">Underholdning</desc><category lang="da">series</category><icon src="https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/487/2022-10-24/se.cs.6eren.event.B_0254194276971024040000.jpg?size=2560x1440"/><episode-num system="xmltv_ns">23.5.0/1</episode-num><episode-num system="onscreen">S24E06</episode-num></programme>
|
||||
</tv>
|
||||
BIN
tests/__data__/expected/guides/dk_da.xml.gz
Normal file
BIN
tests/__data__/expected/guides/dk_da.xml.gz
Normal file
Binary file not shown.
@@ -1,6 +1 @@
|
||||
{"group":"us/directv.com","count":0,"status":1}
|
||||
{"group":"fr/chaines-tv.orange.fr","count":1,"status":0}
|
||||
{"group":"bh/chaines-tv.orange.fr","count":1,"status":0}
|
||||
{"group":"ge/magticom.ge","count":0,"status":1}
|
||||
{"group":"ru/yandex.ru","count":0,"status":1}
|
||||
{"group":"zw/dstv.com","count":1,"status":0}
|
||||
{"country":"DK","lang":"da","site":"allente.se","channel":"6eren.dk","filename":"dk_da"}
|
||||
|
||||
@@ -51,5 +51,6 @@
|
||||
"categories": [],
|
||||
"is_nsfw": false,
|
||||
"logo": "https://rndcdn.dstv.com/dstvcms/2020/08/31/M-Net_Movies_2_Logo_4-3_lightbackground_xlrg.png"
|
||||
}
|
||||
},
|
||||
{"id":"6eren.dk","name":"6'eren","alt_names":[],"network":null,"owners":["Warner Bros. Discovery EMEA"],"country":"DK","subdivision":null,"city":null,"broadcast_area":["c/DK"],"languages":["dan"],"categories":[],"is_nsfw":false,"launched":"2009-01-01","closed":null,"replaced_by":null,"website":"http://www.6-eren.dk/","logo":"https://upload.wikimedia.org/wikipedia/commons/6/64/6%27eren_2015.png"}
|
||||
]
|
||||
File diff suppressed because one or more lines are too long
1
tests/__data__/input/data/regions.json
Normal file
1
tests/__data__/input/data/regions.json
Normal file
File diff suppressed because one or more lines are too long
@@ -1,4 +1 @@
|
||||
{"titles":[{"lang":"fr","value":"World Sport"}],"descriptions":[{"lang":"fr","value":"Все о главных спортивных событиях мира. Обзоры самых важных спортивных событий, аналитика, мнения экспертов."}],"sub_titles":[],"urls":[],"categories":[],"icon":{},"episodeNumbers":[],"date":null,"ratings":[],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"channel":"CNNInternationalEurope.us","start":1641825900000,"stop":1641826800000,"site":"chaines-tv.orange.fr","_qid":"0Wefq0oMR3feCcuY","_id":"12AJc0GeEJE9p4c3"}
|
||||
{"titles":[{"lang":"fr","value":"Connecting Africa. 114-я серия"}],"descriptions":[{"lang":"fr","value":"114-я серия. Проект, рассказывающий о людях и компаниях, которые совершают революцию в африканском бизнесе, и о тех, кто объединяет континент, выступая за свободную торговлю в Африке."}],"sub_titles":[],"urls":[],"categories":[],"icon":{},"episodeNumbers":[],"date":null,"ratings":[],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"channel":"CNNInternationalEurope.us","start":1641843900000,"stop":1641844800000,"site":"chaines-tv.orange.fr","_qid":"0Wefq0oMR3feCcuY","_id":"1dxcT34nyxzOlxBL"}
|
||||
{"titles":[{"lang":"en","value":"Robin Hood"}],"descriptions":[],"sub_titles":[],"urls":[],"categories":[],"icon":{},"episodeNumbers":[{"system":"xmltv_ns","value":"8.256.0/1"},{"system":"onscreen","value":"S09E257"}],"date":null,"ratings":[],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"channel":"MNetMovies2.za","start":1641822300000,"stop":1641829200000,"site":"dstv.com","_qid":"1lnhXpN7g0ER5XwN","_id":"1AoKArQw6MxP6pVU"}
|
||||
{"titles":[{"lang":"en","value":"Robin Hood"}],"descriptions":[],"sub_titles":[],"urls":[],"categories":[],"icon":{},"episodeNumbers":[{"system":"xmltv_ns","value":"8.256.0/1"},{"system":"onscreen","value":"S09E257"}],"date":null,"ratings":[],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"channel":"MNetMovies2.za","start":1641822300000,"stop":1641829200000,"site":"dstv.com","_qid":"1lnhXpN7g0ER5XwN","_id":"12oKArQw6MxP6pVU"}
|
||||
{"site":"allente.se","channel":"6eren.dk","titles":[{"value":"Diners, Drive-Ins and Dives","lang":"da"}],"sub_titles":[],"descriptions":[{"value":"Underholdning","lang":"da"}],"icon":{"src":"https://viasatps.api.comspace.se/PS/channeldate/image/viasat.ps/487/2022-10-24/se.cs.6eren.event.B_0254194276971024040000.jpg?size=2560x1440"},"episodeNumbers":[{"system":"xmltv_ns","value":"23.5.0/1"},{"system":"onscreen","value":"S24E06"}],"date":null,"start":1666584000000,"stop":1666585500000,"urls":[],"ratings":[],"categories":[{"value":"series","lang":"da"}],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"_qid":"f6cxSM73LfZ8TdYz","_id":"HxsrTRTFj1z05TAK"}
|
||||
@@ -0,0 +1,4 @@
|
||||
{"titles":[{"lang":"fr","value":"World Sport"}],"descriptions":[{"lang":"fr","value":"Все о главных спортивных событиях мира. Обзоры самых важных спортивных событий, аналитика, мнения экспертов."}],"sub_titles":[],"urls":[],"categories":[],"icon":{},"episodeNumbers":[],"date":null,"ratings":[],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"channel":"CNNInternationalEurope.us","start":1641825900000,"stop":1641826800000,"site":"chaines-tv.orange.fr","_qid":"0Wefq0oMR3feCcuY","_id":"12AJc0GeEJE9p4c3"}
|
||||
{"titles":[{"lang":"fr","value":"Connecting Africa. 114-я серия"}],"descriptions":[{"lang":"fr","value":"114-я серия. Проект, рассказывающий о людях и компаниях, которые совершают революцию в африканском бизнесе, и о тех, кто объединяет континент, выступая за свободную торговлю в Африке."}],"sub_titles":[],"urls":[],"categories":[],"icon":{},"episodeNumbers":[],"date":null,"ratings":[],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"channel":"CNNInternationalEurope.us","start":1641843900000,"stop":1641844800000,"site":"chaines-tv.orange.fr","_qid":"0Wefq0oMR3feCcuY","_id":"1dxcT34nyxzOlxBL"}
|
||||
{"titles":[{"lang":"en","value":"Robin Hood"}],"descriptions":[],"sub_titles":[],"urls":[],"categories":[],"icon":{},"episodeNumbers":[{"system":"xmltv_ns","value":"8.256.0/1"},{"system":"onscreen","value":"S09E257"}],"date":null,"ratings":[],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"channel":"MNetMovies2.za","start":1641822300000,"stop":1641829200000,"site":"dstv.com","_qid":"1lnhXpN7g0ER5XwN","_id":"1AoKArQw6MxP6pVU"}
|
||||
{"titles":[{"lang":"en","value":"Robin Hood"}],"descriptions":[],"sub_titles":[],"urls":[],"categories":[],"icon":{},"episodeNumbers":[{"system":"xmltv_ns","value":"8.256.0/1"},{"system":"onscreen","value":"S09E257"}],"date":null,"ratings":[],"directors":[],"actors":[],"writers":[],"adapters":[],"producers":[],"composers":[],"editors":[],"presenters":[],"commentators":[],"guests":[],"channel":"MNetMovies2.za","start":1641822300000,"stop":1641829200000,"site":"dstv.com","_qid":"1lnhXpN7g0ER5XwN","_id":"12oKArQw6MxP6pVU"}
|
||||
@@ -1,7 +1,8 @@
|
||||
{"group":"us/magticom.ge","count":74,"status":0}
|
||||
{"group":"za/dstv.com","count":1,"status":0}
|
||||
{"group":"us-pr/tvtv.us","count":14,"status":0}
|
||||
{"group":"us-pr/gatotv.com","count":7,"status":1}
|
||||
{"group":"us-pr/directv.com","count":0,"status":0}
|
||||
{"group":"ca-nl/tvtv.us","count":1,"status":0}
|
||||
{"group":"us/tvtv.us","count":372,"status":0}
|
||||
{"country":"DK","lang":"da","site":"allente.se","channel":"6eren.dk","filename":"dk_da"}
|
||||
{"country":"CA","lang":"fr","site":"tvhebdo.com","channel":"ABCSpark.ca","filename":"ca_fr"}
|
||||
{"country":"CA","lang":"fr","site":"tvhebdo.com","channel":"BBCEarthCanada.ca","filename":"ca_fr"}
|
||||
{"country":"CA","lang":"fr","site":"tvhebdo.com","channel":"beINSportsCanada.ca","filename":"ca_fr"}
|
||||
{"country":"CA","lang":"fr","site":"tvhebdo.com","channel":"CanalVie.ca","filename":"ca_fr"}
|
||||
{"country":"CA","lang":"fr","site":"tvhebdo.com","channel":"CFMTDT.ca","filename":"ca_fr"}
|
||||
{"country":"CA","lang":"en","site":"tvhebdo.com","channel":"CanalVie.ca","filename":"ca_en"}
|
||||
{"country":"CA","lang":"en","site":"tvhebdo.com","channel":"CFMTDT.ca","filename":"ca_en"}
|
||||
@@ -6,7 +6,7 @@ beforeEach(() => {
|
||||
fs.emptyDirSync('tests/__data__/output')
|
||||
|
||||
const stdout = execSync(
|
||||
'CHANNELS_PATH=tests/__data__/input/sites/example.com_ca-*.channels.xml OUTPUT_DIR=tests/__data__/output/api npm run api:update',
|
||||
'LOGS_DIR=tests/__data__/input/logs OUTPUT_DIR=tests/__data__/output/api npm run api:update',
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
})
|
||||
|
||||
@@ -6,23 +6,19 @@ const glob = require('glob')
|
||||
beforeEach(() => {
|
||||
fs.emptyDirSync('tests/__data__/output')
|
||||
fs.copyFileSync(
|
||||
'tests/__data__/input/database/update-guides/queue.db',
|
||||
'tests/__data__/output/queue.db'
|
||||
'tests/__data__/input/database/update-guides/programs.db',
|
||||
'tests/__data__/output/programs.db'
|
||||
)
|
||||
|
||||
const stdout = execSync(
|
||||
'DB_DIR=tests/__data__/output LOGS_DIR=tests/__data__/output/logs DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output CURR_DATE=2022-10-20 npm run guides:update',
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
})
|
||||
|
||||
it('can generate /guides', () => {
|
||||
fs.copyFileSync(
|
||||
'tests/__data__/input/database/update-guides/programs.db',
|
||||
'tests/__data__/output/programs.db'
|
||||
)
|
||||
const stdout = execSync(
|
||||
'DB_DIR=tests/__data__/output DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output CURR_DATE=2022-05-05 npm run guides:update',
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
|
||||
const uncompressed = glob
|
||||
.sync('tests/__data__/expected/guides/**/*.epg.xml')
|
||||
.sync('tests/__data__/expected/guides/*.xml')
|
||||
.map(f => f.replace('tests/__data__/expected/', ''))
|
||||
|
||||
uncompressed.forEach(filepath => {
|
||||
@@ -30,7 +26,7 @@ it('can generate /guides', () => {
|
||||
})
|
||||
|
||||
const compressed = glob
|
||||
.sync('tests/__data__/expected/guides/**/*.epg.xml.gz')
|
||||
.sync('tests/__data__/expected/guides/*.xml.gz')
|
||||
.map(f => f.replace('tests/__data__/expected/', ''))
|
||||
|
||||
compressed.forEach(filepath => {
|
||||
@@ -38,29 +34,16 @@ it('can generate /guides', () => {
|
||||
})
|
||||
|
||||
const json = glob
|
||||
.sync('tests/__data__/expected/guides/**/*.json')
|
||||
.sync('tests/__data__/expected/guides/*.json')
|
||||
.map(f => f.replace('tests/__data__/expected/', ''))
|
||||
|
||||
json.forEach(filepath => {
|
||||
expect(content(`output/${filepath}`), filepath).toBe(content(`expected/${filepath}`))
|
||||
})
|
||||
})
|
||||
|
||||
it('will terminate process if programs not found', () => {
|
||||
fs.copyFileSync(
|
||||
'tests/__data__/input/database/update-guides/no-programs.db',
|
||||
'tests/__data__/output/programs.db'
|
||||
expect(content('output/logs/guides/update.log')).toEqual(
|
||||
content('expected/logs/guides/update.log')
|
||||
)
|
||||
try {
|
||||
const stdout = execSync(
|
||||
'DB_DIR=tests/__data__/output DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output npm run guides:update',
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
process.exit(1)
|
||||
} catch (err) {
|
||||
expect(err.status).toBe(1)
|
||||
expect(err.stdout.includes('Error: No programs found')).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
function content(filepath) {
|
||||
|
||||
70
tests/commands/guides/update_legacy.test.js
Normal file
70
tests/commands/guides/update_legacy.test.js
Normal file
@@ -0,0 +1,70 @@
|
||||
const { execSync } = require('child_process')
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const glob = require('glob')
|
||||
|
||||
beforeEach(() => {
|
||||
fs.emptyDirSync('tests/__data__/output')
|
||||
fs.copyFileSync(
|
||||
'tests/__data__/input/database/update-guides_legacy/queue.db',
|
||||
'tests/__data__/output/queue.db'
|
||||
)
|
||||
})
|
||||
|
||||
it('can generate /guides', () => {
|
||||
fs.copyFileSync(
|
||||
'tests/__data__/input/database/update-guides_legacy/programs.db',
|
||||
'tests/__data__/output/programs.db'
|
||||
)
|
||||
const stdout = execSync(
|
||||
'DB_DIR=tests/__data__/output DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output CURR_DATE=2022-05-05 npm run guides:update_legacy',
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
|
||||
const uncompressed = glob
|
||||
.sync('tests/__data__/expected/guides/!()/*.epg.xml')
|
||||
.map(f => f.replace('tests/__data__/expected/', ''))
|
||||
|
||||
uncompressed.forEach(filepath => {
|
||||
expect(content(`output/${filepath}`), filepath).toBe(content(`expected/${filepath}`))
|
||||
})
|
||||
|
||||
const compressed = glob
|
||||
.sync('tests/__data__/expected/guides/!()/*.epg.xml.gz')
|
||||
.map(f => f.replace('tests/__data__/expected/', ''))
|
||||
|
||||
compressed.forEach(filepath => {
|
||||
expect(content(`output/${filepath}`), filepath).toBe(content(`expected/${filepath}`))
|
||||
})
|
||||
|
||||
const json = glob
|
||||
.sync('tests/__data__/expected/guides/!()/*.json')
|
||||
.map(f => f.replace('tests/__data__/expected/', ''))
|
||||
|
||||
json.forEach(filepath => {
|
||||
expect(content(`output/${filepath}`), filepath).toBe(content(`expected/${filepath}`))
|
||||
})
|
||||
})
|
||||
|
||||
it('will terminate process if programs not found', () => {
|
||||
fs.copyFileSync(
|
||||
'tests/__data__/input/database/update-guides_legacy/no-programs.db',
|
||||
'tests/__data__/output/programs.db'
|
||||
)
|
||||
try {
|
||||
const stdout = execSync(
|
||||
'DB_DIR=tests/__data__/output DATA_DIR=tests/__data__/input/data PUBLIC_DIR=tests/__data__/output npm run guides:update_legacy',
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
process.exit(1)
|
||||
} catch (err) {
|
||||
expect(err.status).toBe(1)
|
||||
expect(err.stdout.includes('Error: No programs found')).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
function content(filepath) {
|
||||
return fs.readFileSync(`tests/__data__/${filepath}`, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
}
|
||||
@@ -6,7 +6,7 @@ beforeEach(() => {
|
||||
fs.emptyDirSync('tests/__data__/output')
|
||||
|
||||
const stdout = execSync(
|
||||
'DB_DIR=tests/__data__/output/database LOGS_DIR=tests/__data__/output/logs CHANNELS_PATH=tests/__data__/input/sites/example.com_ca-*.channels.xml npm run queue:create -- --max-clusters=1 --days=2',
|
||||
'DB_DIR=tests/__data__/output/database CHANNELS_PATH=tests/__data__/input/sites/example.com_ca-*.channels.xml npm run queue:create -- --max-clusters=1 --days=2',
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ beforeEach(() => {
|
||||
fs.emptyDirSync('tests/__data__/output')
|
||||
|
||||
const stdout = execSync(
|
||||
'CHANNELS_PATH=tests/__data__/input/sites/example.com_ca-*.channels.xml DATA_DIR=tests/__data__/input/data npm run readme:update -- --config=tests/__data__/input/readme.json',
|
||||
'LOGS_DIR=tests/__data__/input/logs DATA_DIR=tests/__data__/input/data npm run readme:update -- --config=tests/__data__/input/readme.json',
|
||||
{ encoding: 'utf8' }
|
||||
)
|
||||
})
|
||||
|
||||
108
yarn.lock
108
yarn.lock
@@ -565,6 +565,77 @@
|
||||
"semver" "^7.3.5"
|
||||
"tar" "^6.1.11"
|
||||
|
||||
"@octokit/auth-token@^3.0.0":
|
||||
"integrity" "sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q=="
|
||||
"resolved" "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.2.tgz"
|
||||
"version" "3.0.2"
|
||||
dependencies:
|
||||
"@octokit/types" "^8.0.0"
|
||||
|
||||
"@octokit/core@^4.1.0":
|
||||
"integrity" "sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ=="
|
||||
"resolved" "https://registry.npmjs.org/@octokit/core/-/core-4.1.0.tgz"
|
||||
"version" "4.1.0"
|
||||
dependencies:
|
||||
"@octokit/auth-token" "^3.0.0"
|
||||
"@octokit/graphql" "^5.0.0"
|
||||
"@octokit/request" "^6.0.0"
|
||||
"@octokit/request-error" "^3.0.0"
|
||||
"@octokit/types" "^8.0.0"
|
||||
"before-after-hook" "^2.2.0"
|
||||
"universal-user-agent" "^6.0.0"
|
||||
|
||||
"@octokit/endpoint@^7.0.0":
|
||||
"integrity" "sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw=="
|
||||
"resolved" "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.3.tgz"
|
||||
"version" "7.0.3"
|
||||
dependencies:
|
||||
"@octokit/types" "^8.0.0"
|
||||
"is-plain-object" "^5.0.0"
|
||||
"universal-user-agent" "^6.0.0"
|
||||
|
||||
"@octokit/graphql@^5.0.0":
|
||||
"integrity" "sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A=="
|
||||
"resolved" "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.4.tgz"
|
||||
"version" "5.0.4"
|
||||
dependencies:
|
||||
"@octokit/request" "^6.0.0"
|
||||
"@octokit/types" "^8.0.0"
|
||||
"universal-user-agent" "^6.0.0"
|
||||
|
||||
"@octokit/openapi-types@^14.0.0":
|
||||
"integrity" "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw=="
|
||||
"resolved" "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz"
|
||||
"version" "14.0.0"
|
||||
|
||||
"@octokit/request-error@^3.0.0":
|
||||
"integrity" "sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg=="
|
||||
"resolved" "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.2.tgz"
|
||||
"version" "3.0.2"
|
||||
dependencies:
|
||||
"@octokit/types" "^8.0.0"
|
||||
"deprecation" "^2.0.0"
|
||||
"once" "^1.4.0"
|
||||
|
||||
"@octokit/request@^6.0.0":
|
||||
"integrity" "sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw=="
|
||||
"resolved" "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz"
|
||||
"version" "6.2.2"
|
||||
dependencies:
|
||||
"@octokit/endpoint" "^7.0.0"
|
||||
"@octokit/request-error" "^3.0.0"
|
||||
"@octokit/types" "^8.0.0"
|
||||
"is-plain-object" "^5.0.0"
|
||||
"node-fetch" "^2.6.7"
|
||||
"universal-user-agent" "^6.0.0"
|
||||
|
||||
"@octokit/types@^8.0.0":
|
||||
"integrity" "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg=="
|
||||
"resolved" "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz"
|
||||
"version" "8.0.0"
|
||||
dependencies:
|
||||
"@octokit/openapi-types" "^14.0.0"
|
||||
|
||||
"@seald-io/binary-search-tree@^1.0.2":
|
||||
"integrity" "sha512-+pYGvPFAk7wUR+ONMOlc6A+LUN4kOCFwyPLjyaeS7wVibADPHWYJNYsNtyIAwjF1AXQkuaXElnIc4XjKt55QZA=="
|
||||
"resolved" "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.2.tgz"
|
||||
@@ -973,6 +1044,11 @@
|
||||
"resolved" "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
|
||||
"version" "1.5.1"
|
||||
|
||||
"before-after-hook@^2.2.0":
|
||||
"integrity" "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
"resolved" "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz"
|
||||
"version" "2.2.3"
|
||||
|
||||
"bindings@~1.5.0":
|
||||
"integrity" "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="
|
||||
"resolved" "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz"
|
||||
@@ -1446,6 +1522,11 @@
|
||||
"resolved" "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz"
|
||||
"version" "1.0.0"
|
||||
|
||||
"deprecation@^2.0.0":
|
||||
"integrity" "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
"resolved" "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz"
|
||||
"version" "2.3.1"
|
||||
|
||||
"detect-libc@^2.0.0":
|
||||
"integrity" "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w=="
|
||||
"resolved" "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz"
|
||||
@@ -2213,6 +2294,11 @@
|
||||
"resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
|
||||
"version" "7.0.0"
|
||||
|
||||
"is-plain-object@^5.0.0":
|
||||
"integrity" "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
"resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz"
|
||||
"version" "5.0.0"
|
||||
|
||||
"is-potential-custom-element-name@^1.0.1":
|
||||
"integrity" "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
|
||||
"resolved" "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz"
|
||||
@@ -2805,6 +2891,11 @@
|
||||
"resolved" "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz"
|
||||
"version" "2.0.0"
|
||||
|
||||
"langs@^2.0.0":
|
||||
"integrity" "sha512-v4pxOBEQVN1WBTfB1crhTtxzNLZU9HPWgadlwzWKISJtt6Ku/CnpBrwVy+jFv8StjxsPfwPFzO0CMwdZLJ0/BA=="
|
||||
"resolved" "https://registry.npmjs.org/langs/-/langs-2.0.0.tgz"
|
||||
"version" "2.0.0"
|
||||
|
||||
"leven@^3.1.0":
|
||||
"integrity" "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="
|
||||
"resolved" "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz"
|
||||
@@ -3894,6 +3985,11 @@
|
||||
dependencies:
|
||||
"is-typedarray" "^1.0.0"
|
||||
|
||||
"universal-user-agent@^6.0.0":
|
||||
"integrity" "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
|
||||
"resolved" "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz"
|
||||
"version" "6.0.0"
|
||||
|
||||
"universalify@^0.1.2":
|
||||
"integrity" "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
|
||||
"resolved" "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz"
|
||||
@@ -3904,6 +4000,13 @@
|
||||
"resolved" "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz"
|
||||
"version" "2.0.0"
|
||||
|
||||
"unzipit@^1.4.0":
|
||||
"integrity" "sha512-hjoB8j1igXJgmxqaAvqkIW+faKTpG9cPK6QvkBhNCyd8OPWqODXTBVqTEmZbz62K5J/dX4Xa8lTa0NRikQwSjQ=="
|
||||
"resolved" "https://registry.npmjs.org/unzipit/-/unzipit-1.4.0.tgz"
|
||||
"version" "1.4.0"
|
||||
dependencies:
|
||||
"uzip-module" "^1.0.2"
|
||||
|
||||
"uri-js@^4.2.2":
|
||||
"integrity" "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="
|
||||
"resolved" "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
|
||||
@@ -3916,6 +4019,11 @@
|
||||
"resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
||||
"version" "1.0.2"
|
||||
|
||||
"uzip-module@^1.0.2":
|
||||
"integrity" "sha512-AMqwWZaknLM77G+VPYNZLEruMGWGzyigPK3/Whg99B3S6vGHuqsyl5ZrOv1UUF3paGK1U6PM0cnayioaryg/fA=="
|
||||
"resolved" "https://registry.npmjs.org/uzip-module/-/uzip-module-1.0.3.tgz"
|
||||
"version" "1.0.3"
|
||||
|
||||
"v8-compile-cache@^2.0.3":
|
||||
"integrity" "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA=="
|
||||
"resolved" "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
|
||||
|
||||
Reference in New Issue
Block a user