Merge pull request #1212 from iptv-org/patch-2022.10.4

Patch 2022.10.4
This commit is contained in:
Aleksandr Statciuk
2022-10-26 20:37:36 +03:00
committed by GitHub
37 changed files with 893 additions and 1785 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -1,3 +1,2 @@
_ca-provinces.md
_countries.md
_us-states.md
_sites.md

259
package-lock.json generated
View File

@@ -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",

View File

@@ -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
View File

@@ -1,3 +1,3 @@
database/
logs/
data/
/database/
/logs/
/data/

7
scripts/commands/api/load.sh Executable file
View 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

View File

@@ -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')

View File

@@ -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]
}

View 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 })
}

View 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)
}

View File

@@ -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...')

View File

@@ -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}&nbsp;${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...')

View File

@@ -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`)

View File

@@ -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

View File

@@ -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&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th><th align="left">Channels</th><th align="left">EPG</th></tr>
</thead>
<tbody>
<tr><td valign="top" rowspan="2">🇨🇦&nbsp;Canada</td><td align="right" 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">🇨🇦&nbsp;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">🇩🇰&nbsp;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>

View File

@@ -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"}]

View 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":[]}]}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?><tv date="20221020">
<channel id="6eren.dk"><display-name>6&apos;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>

Binary file not shown.

View File

@@ -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"}

View File

@@ -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

File diff suppressed because one or more lines are too long

View File

@@ -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"}

View File

@@ -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"}

View File

@@ -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"}

View File

@@ -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' }
)
})

View File

@@ -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) {

View 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'
})
}

View File

@@ -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' }
)
})

View File

@@ -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
View File

@@ -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"