Merge pull request #2653 from iptv-org/patch-2025.01.7

This commit is contained in:
Alstruit 2025-01-31 22:58:53 -06:00 committed by GitHub
commit f7e1c1558c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 311 additions and 90 deletions

View file

@ -3,6 +3,5 @@
channels_changed="$(git diff --staged --name-only --diff-filter=ACMR -- 'sites/**/*.channels.xml' | sed 's| |\\ |g')" channels_changed="$(git diff --staged --name-only --diff-filter=ACMR -- 'sites/**/*.channels.xml' | sed 's| |\\ |g')"
if [ ! -z "$channels_changed" ]; then if [ ! -z "$channels_changed" ]; then
echo "npx eslint $channels_changed"
npm run channels:lint -- $channels_changed npm run channels:lint -- $channels_changed
fi fi

7
.husky/channels_validate.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
channels_changed="$(git diff --staged --name-only --diff-filter=ACMR -- 'sites/**/*.channels.xml' | sed 's| |\\ |g')"
if [ ! -z "$channels_changed" ]; then
npm run channels:validate -- $channels_changed
fi

View file

@ -1,2 +1,3 @@
.husky/check_scripts.sh .husky/scripts_lint.sh
.husky/check_channels.sh .husky/channels_lint.sh
.husky/channels_validate.sh

View file

@ -3,6 +3,5 @@
scripts_changed="$(git diff --staged --name-only --diff-filter=ACMR -- 'tests/**/*.ts' 'tests/**/*.js' 'scripts/**/*.ts' 'scripts/**/*.mts' 'scripts/**/*.js' 'sites/**/*.js' 'sites/**/*.ts' | sed 's| |\\ |g')" scripts_changed="$(git diff --staged --name-only --diff-filter=ACMR -- 'tests/**/*.ts' 'tests/**/*.js' 'scripts/**/*.ts' 'scripts/**/*.mts' 'scripts/**/*.js' 'sites/**/*.js' 'sites/**/*.ts' | sed 's| |\\ |g')"
if [ ! -z "$scripts_changed" ]; then if [ ! -z "$scripts_changed" ]; then
echo "npx eslint $scripts_changed"
npx eslint $scripts_changed npx eslint $scripts_changed
fi fi

View file

@ -58,6 +58,7 @@ Options:
-l, --lang <code> Filter channels by language (ISO 639-2 code) -l, --lang <code> Filter channels by language (ISO 639-2 code)
-t, --timeout <milliseconds> Override the default timeout for each request -t, --timeout <milliseconds> Override the default timeout for each request
-d, --delay <milliseconds> Override the default delay between request -d, --delay <milliseconds> Override the default delay between request
-x, --proxy <url> Use the specified proxy (example: "socks5://username:password@127.0.0.1:1234")
--days <days> Override the number of days for which the program will be loaded --days <days> Override the number of days for which the program will be loaded
(defaults to the value from the site config) (defaults to the value from the site config)
--maxConnections <number> Limit on the number of concurrent requests (default: 1) --maxConnections <number> Limit on the number of concurrent requests (default: 1)

147
package-lock.json generated
View file

@ -11,8 +11,8 @@
"@alex_neo/jest-expect-message": "^1.0.5", "@alex_neo/jest-expect-message": "^1.0.5",
"@eslint/eslintrc": "^3.2.0", "@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.17.0", "@eslint/js": "^9.17.0",
"@freearhey/core": "^0.5.0", "@freearhey/core": "^0.5.1",
"@ntlab/sfetch": "^1.0.0", "@ntlab/sfetch": "^1.2.0",
"@octokit/core": "^6.1.3", "@octokit/core": "^6.1.3",
"@octokit/plugin-paginate-rest": "^11.3.6", "@octokit/plugin-paginate-rest": "^11.3.6",
"@octokit/plugin-rest-endpoint-methods": "^13.2.6", "@octokit/plugin-rest-endpoint-methods": "^13.2.6",
@ -38,7 +38,7 @@
"csv-parser": "^3.0.0", "csv-parser": "^3.0.0",
"cwait": "^1.1.2", "cwait": "^1.1.2",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"epg-grabber": "^0.37.4", "epg-grabber": "^0.38.0",
"epg-parser": "^0.3.1", "epg-parser": "^0.3.1",
"eslint": "^9.17.0", "eslint": "^9.17.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
@ -69,6 +69,7 @@
"serve": "^14.2.4", "serve": "^14.2.4",
"signale": "^1.4.0", "signale": "^1.4.0",
"skip-postinstall": "^1.0.0", "skip-postinstall": "^1.0.0",
"socks-proxy-agent": "^8.0.5",
"srcset": "^4.0.0", "srcset": "^4.0.0",
"table2array": "^0.0.2", "table2array": "^0.0.2",
"tabletojson": "^2.0.7", "tabletojson": "^2.0.7",
@ -1203,9 +1204,9 @@
} }
}, },
"node_modules/@freearhey/core": { "node_modules/@freearhey/core": {
"version": "0.5.0", "version": "0.5.1",
"resolved": "https://registry.npmjs.org/@freearhey/core/-/core-0.5.0.tgz", "resolved": "https://registry.npmjs.org/@freearhey/core/-/core-0.5.1.tgz",
"integrity": "sha512-FcA5Pv9RvFvLYAwNmD/2vlSR49Rx+kihJ+xbIUgIACHY6lBUptfbNznm00DQoUyWRJG/cfT3dkYCwIxSUsdP+w==", "integrity": "sha512-UDKIOyrtcUXaiAeIvjNFTI6DlempiOQaRB83CqHNF1VPRHNBiNhGhERWyInHE2cjLp/cc0CA/IykOYS39kBK7Q==",
"dependencies": { "dependencies": {
"@types/fs-extra": "^11.0.2", "@types/fs-extra": "^11.0.2",
"@types/lodash": "^4.14.198", "@types/lodash": "^4.14.198",
@ -1863,9 +1864,9 @@
} }
}, },
"node_modules/@ntlab/sfetch": { "node_modules/@ntlab/sfetch": {
"version": "1.0.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ntlab/sfetch/-/sfetch-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@ntlab/sfetch/-/sfetch-1.2.0.tgz",
"integrity": "sha512-AWrC43z1TncvB7S7dl9Wn8xZpCqdKFBfXqaN3BXPfJeS3gxV9Fm86eAsW95YdXTOgPWbCC/GAgVuXi6Aot6DkQ==", "integrity": "sha512-9SE4NnqWo8l6mG0rnAkgng6ozSamIpF3EC+GOTQGGa6eAC0tNJvzrylMz6YRjjEGH6mOfn7ZBAuKj5WIZUul6A==",
"dependencies": { "dependencies": {
"axios": "^1.7.9" "axios": "^1.7.9"
} }
@ -4192,9 +4193,9 @@
} }
}, },
"node_modules/epg-grabber": { "node_modules/epg-grabber": {
"version": "0.37.4", "version": "0.38.0",
"resolved": "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.37.4.tgz", "resolved": "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.38.0.tgz",
"integrity": "sha512-PS104bH9tHRa9kivSwx47AKMkfHwKy51XQTx+GO6sIXvIp2Z4LBpwMEXGcfPoAsdIGxgs2Wrl0dZ/QGL+7x6YQ==", "integrity": "sha512-jbwTgi6G7e+zrb2oNC0C7mcQYoRkFnvhXCurexeICaEy4avRB6WS5rD/yfqYoiqaXOM3x1BNBpCKFYoS7Ob5YA==",
"dependencies": { "dependencies": {
"axios": "^1.6.1", "axios": "^1.6.1",
"axios-cache-interceptor": "^0.10.3", "axios-cache-interceptor": "^0.10.3",
@ -4209,6 +4210,7 @@
"http-cookie-agent": "^6.0.8", "http-cookie-agent": "^6.0.8",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"node-gzip": "^1.1.2", "node-gzip": "^1.1.2",
"socks-proxy-agent": "^8.0.5",
"tough-cookie": "^5.0.0", "tough-cookie": "^5.0.0",
"winston": "^3.3.3", "winston": "^3.3.3",
"xml-js": "^1.6.11" "xml-js": "^1.6.11"
@ -5247,6 +5249,23 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/ip-address": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
"dependencies": {
"jsbn": "1.1.0",
"sprintf-js": "^1.1.3"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/ip-address/node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
},
"node_modules/is-arrayish": { "node_modules/is-arrayish": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@ -6141,6 +6160,11 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/jsbn": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
},
"node_modules/jsesc": { "node_modules/jsesc": {
"version": "2.5.2", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@ -7641,6 +7665,41 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/socks": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
"integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
"dependencies": {
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
},
"engines": {
"node": ">= 10.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/socks-proxy-agent": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
"integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
"dependencies": {
"agent-base": "^7.1.2",
"debug": "^4.3.4",
"socks": "^2.8.3"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@ -9172,9 +9231,9 @@
} }
}, },
"@freearhey/core": { "@freearhey/core": {
"version": "0.5.0", "version": "0.5.1",
"resolved": "https://registry.npmjs.org/@freearhey/core/-/core-0.5.0.tgz", "resolved": "https://registry.npmjs.org/@freearhey/core/-/core-0.5.1.tgz",
"integrity": "sha512-FcA5Pv9RvFvLYAwNmD/2vlSR49Rx+kihJ+xbIUgIACHY6lBUptfbNznm00DQoUyWRJG/cfT3dkYCwIxSUsdP+w==", "integrity": "sha512-UDKIOyrtcUXaiAeIvjNFTI6DlempiOQaRB83CqHNF1VPRHNBiNhGhERWyInHE2cjLp/cc0CA/IykOYS39kBK7Q==",
"requires": { "requires": {
"@types/fs-extra": "^11.0.2", "@types/fs-extra": "^11.0.2",
"@types/lodash": "^4.14.198", "@types/lodash": "^4.14.198",
@ -9661,9 +9720,9 @@
} }
}, },
"@ntlab/sfetch": { "@ntlab/sfetch": {
"version": "1.0.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ntlab/sfetch/-/sfetch-1.0.0.tgz", "resolved": "https://registry.npmjs.org/@ntlab/sfetch/-/sfetch-1.2.0.tgz",
"integrity": "sha512-AWrC43z1TncvB7S7dl9Wn8xZpCqdKFBfXqaN3BXPfJeS3gxV9Fm86eAsW95YdXTOgPWbCC/GAgVuXi6Aot6DkQ==", "integrity": "sha512-9SE4NnqWo8l6mG0rnAkgng6ozSamIpF3EC+GOTQGGa6eAC0tNJvzrylMz6YRjjEGH6mOfn7ZBAuKj5WIZUul6A==",
"requires": { "requires": {
"axios": "^1.7.9" "axios": "^1.7.9"
} }
@ -11280,9 +11339,9 @@
"integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
}, },
"epg-grabber": { "epg-grabber": {
"version": "0.37.4", "version": "0.38.0",
"resolved": "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.37.4.tgz", "resolved": "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.38.0.tgz",
"integrity": "sha512-PS104bH9tHRa9kivSwx47AKMkfHwKy51XQTx+GO6sIXvIp2Z4LBpwMEXGcfPoAsdIGxgs2Wrl0dZ/QGL+7x6YQ==", "integrity": "sha512-jbwTgi6G7e+zrb2oNC0C7mcQYoRkFnvhXCurexeICaEy4avRB6WS5rD/yfqYoiqaXOM3x1BNBpCKFYoS7Ob5YA==",
"requires": { "requires": {
"axios": "^1.6.1", "axios": "^1.6.1",
"axios-cache-interceptor": "^0.10.3", "axios-cache-interceptor": "^0.10.3",
@ -11297,6 +11356,7 @@
"http-cookie-agent": "^6.0.8", "http-cookie-agent": "^6.0.8",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"node-gzip": "^1.1.2", "node-gzip": "^1.1.2",
"socks-proxy-agent": "^8.0.5",
"tough-cookie": "^5.0.0", "tough-cookie": "^5.0.0",
"winston": "^3.3.3", "winston": "^3.3.3",
"xml-js": "^1.6.11" "xml-js": "^1.6.11"
@ -12006,6 +12066,22 @@
} }
} }
}, },
"ip-address": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
"requires": {
"jsbn": "1.1.0",
"sprintf-js": "^1.1.3"
},
"dependencies": {
"sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
}
}
},
"is-arrayish": { "is-arrayish": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@ -12650,6 +12726,11 @@
"esprima": "^4.0.0" "esprima": "^4.0.0"
} }
}, },
"jsbn": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
},
"jsesc": { "jsesc": {
"version": "2.5.2", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@ -13776,6 +13857,30 @@
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
}, },
"smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
},
"socks": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
"integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
"requires": {
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
}
},
"socks-proxy-agent": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
"integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
"requires": {
"agent-base": "^7.1.2",
"debug": "^4.3.4",
"socks": "^2.8.3"
}
},
"source-map": { "source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",

View file

@ -40,8 +40,8 @@
"@alex_neo/jest-expect-message": "^1.0.5", "@alex_neo/jest-expect-message": "^1.0.5",
"@eslint/eslintrc": "^3.2.0", "@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.17.0", "@eslint/js": "^9.17.0",
"@freearhey/core": "^0.5.0", "@freearhey/core": "^0.5.1",
"@ntlab/sfetch": "^1.0.0", "@ntlab/sfetch": "^1.2.0",
"@octokit/core": "^6.1.3", "@octokit/core": "^6.1.3",
"@octokit/plugin-paginate-rest": "^11.3.6", "@octokit/plugin-paginate-rest": "^11.3.6",
"@octokit/plugin-rest-endpoint-methods": "^13.2.6", "@octokit/plugin-rest-endpoint-methods": "^13.2.6",
@ -67,7 +67,7 @@
"csv-parser": "^3.0.0", "csv-parser": "^3.0.0",
"cwait": "^1.1.2", "cwait": "^1.1.2",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"epg-grabber": "^0.37.4", "epg-grabber": "^0.38.0",
"epg-parser": "^0.3.1", "epg-parser": "^0.3.1",
"eslint": "^9.17.0", "eslint": "^9.17.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
@ -98,6 +98,7 @@
"serve": "^14.2.4", "serve": "^14.2.4",
"signale": "^1.4.0", "signale": "^1.4.0",
"skip-postinstall": "^1.0.0", "skip-postinstall": "^1.0.0",
"socks-proxy-agent": "^8.0.5",
"srcset": "^4.0.0", "srcset": "^4.0.0",
"table2array": "^0.0.2", "table2array": "^0.0.2",
"tabletojson": "^2.0.7", "tabletojson": "^2.0.7",

View file

@ -26,7 +26,7 @@ async function main() {
const logger = new Logger() const logger = new Logger()
const file = new File(options.config) const file = new File(options.config)
const dir = file.dirname() const dir = file.dirname()
const config = (await import(pathToFileURL(options.config))).default const config = (await import(pathToFileURL(options.config).toString())).default
const outputFilepath = options.output || `${dir}/${config.site}.channels.xml` const outputFilepath = options.output || `${dir}/${config.site}.channels.xml`
let channels = new Collection() let channels = new Collection()

View file

@ -16,6 +16,7 @@ program
.option('-l, --lang <code>', 'Filter channels by language (ISO 639-2 code)') .option('-l, --lang <code>', 'Filter channels by language (ISO 639-2 code)')
.option('-t, --timeout <milliseconds>', 'Override the default timeout for each request') .option('-t, --timeout <milliseconds>', 'Override the default timeout for each request')
.option('-d, --delay <milliseconds>', 'Override the default delay between request') .option('-d, --delay <milliseconds>', 'Override the default delay between request')
.option('-x, --proxy <url>', 'Use the specified proxy')
.option( .option(
'--days <days>', '--days <days>',
'Override the number of days for which the program will be loaded (defaults to the value from the site config)', 'Override the number of days for which the program will be loaded (defaults to the value from the site config)',
@ -42,6 +43,7 @@ export type GrabOptions = {
lang?: string lang?: string
days?: number days?: number
cron?: string cron?: string
proxy?: string
} }
const options: GrabOptions = program.opts() const options: GrabOptions = program.opts()

View file

@ -40,19 +40,20 @@ async function main() {
const data = new Collection() const data = new Collection()
sites.forEach((site: Site) => { sites.forEach((site: Site) => {
data.add([ data.add([
`<a href="sites/${site.domain}">${site.domain}</a>`, { value: `<a href="sites/${site.domain}">${site.domain}</a>` },
`${site.totalChannels} / ${site.markedChannels}`, { value: site.totalChannels, align: 'right' },
site.getStatus().emoji, { value: site.markedChannels, align: 'right' },
site.getIssues().all().join(', ') { value: site.getStatus().emoji, align: 'center' },
{ value: site.getIssues().all().join(', ') }
]) ])
}) })
logger.info('updating sites.md...') logger.info('updating sites.md...')
const table = new HTMLTable(data.all(), [ const table = new HTMLTable(data.all(), [
{ name: 'Site' }, { name: 'Site', align: 'left' },
{ name: 'Channels *', align: 'center' }, { name: 'Channels<br>(total / with xmltv-id)', colspan: 2, align: 'left' },
{ name: 'Status' }, { name: 'Status', align: 'left' },
{ name: 'Notes' } { name: 'Notes', align: 'left' }
]) ])
const rootStorage = new Storage(ROOT_DIR) const rootStorage = new Storage(ROOT_DIR)
const sitesTemplate = await new Storage().load('scripts/templates/_sites.md') const sitesTemplate = await new Storage().load('scripts/templates/_sites.md')

View file

@ -7,7 +7,7 @@ export class ConfigLoader {
const fileUrl = pathToFileURL(filepath).toString() const fileUrl = pathToFileURL(filepath).toString()
const config = (await import(fileUrl)).default const config = (await import(fileUrl)).default
const defaultConfig = { const defaultConfig = {
days: 2, days: 1,
delay: 0, delay: 0,
output: 'guide.xml', output: 'guide.xml',
request: { request: {

View file

@ -1,8 +1,9 @@
import { EPGGrabber, GrabCallbackData, EPGGrabberMock, SiteConfig, Channel } from 'epg-grabber' import { EPGGrabber, GrabCallbackData, EPGGrabberMock, SiteConfig, Channel } from 'epg-grabber'
import { Logger, Collection } from '@freearhey/core' import { Logger, Collection } from '@freearhey/core'
import { Queue } from './' import { Queue, ProxyParser } from './'
import { GrabOptions } from '../commands/epg/grab' import { GrabOptions } from '../commands/epg/grab'
import { TaskQueue, PromisyClass } from 'cwait' import { TaskQueue, PromisyClass } from 'cwait'
import { SocksProxyAgent } from 'socks-proxy-agent'
type GrabberProps = { type GrabberProps = {
logger: Logger logger: Logger
@ -14,6 +15,7 @@ export class Grabber {
logger: Logger logger: Logger
queue: Queue queue: Queue
options: GrabOptions options: GrabOptions
grabber: EPGGrabber | EPGGrabberMock
constructor({ logger, queue, options }: GrabberProps) { constructor({ logger, queue, options }: GrabberProps) {
this.logger = logger this.logger = logger
@ -23,6 +25,7 @@ export class Grabber {
} }
async grab(): Promise<{ channels: Collection; programs: Collection }> { async grab(): Promise<{ channels: Collection; programs: Collection }> {
const proxyParser = new ProxyParser()
const taskQueue = new TaskQueue(Promise as PromisyClass, this.options.maxConnections) const taskQueue = new TaskQueue(Promise as PromisyClass, this.options.maxConnections)
const total = this.queue.size() const total = this.queue.size()
@ -49,6 +52,24 @@ export class Grabber {
config.delay = delay config.delay = delay
} }
if (this.options.proxy !== undefined) {
const proxy = proxyParser.parse(this.options.proxy)
if (
proxy.protocol &&
['socks', 'socks5', 'socks5h', 'socks4', 'socks4a'].includes(String(proxy.protocol))
) {
const socksProxyAgent = new SocksProxyAgent(this.options.proxy)
config.request = {
...config.request,
...{ httpAgent: socksProxyAgent, httpsAgent: socksProxyAgent }
}
} else {
config.request = { ...config.request, ...{ proxy } }
}
}
const _programs = await this.grabber.grab( const _programs = await this.grabber.grab(
channel, channel,
date, date,

View file

@ -2,9 +2,15 @@ type Column = {
name: string name: string
nowrap?: boolean nowrap?: boolean
align?: string align?: string
colspan?: number
} }
type DataItem = string[] type DataItem = {
value: string
nowrap?: boolean
align?: string
colspan?: number
}[]
export class HTMLTable { export class HTMLTable {
data: DataItem[] data: DataItem[]
@ -20,20 +26,23 @@ export class HTMLTable {
output += ' <thead>\r\n <tr>' output += ' <thead>\r\n <tr>'
for (const column of this.columns) { for (const column of this.columns) {
output += `<th align="left">${column.name}</th>` const nowrap = column.nowrap ? ' nowrap' : ''
const align = column.align ? ` align="${column.align}"` : ''
const colspan = column.colspan ? ` colspan="${column.colspan}"` : ''
output += `<th${align}${nowrap}${colspan}>${column.name}</th>`
} }
output += '</tr>\r\n </thead>\r\n' output += '</tr>\r\n </thead>\r\n'
output += ' <tbody>\r\n' output += ' <tbody>\r\n'
for (const item of this.data) { for (const row of this.data) {
output += ' <tr>' output += ' <tr>'
let i = 0 for (const item of row) {
for (const prop in item) { const nowrap = item.nowrap ? ' nowrap' : ''
const column = this.columns[i] const align = item.align ? ` align="${item.align}"` : ''
const nowrap = column.nowrap ? ' nowrap' : '' const colspan = item.colspan ? ` colspan="${item.colspan}"` : ''
const align = column.align ? ` align="${column.align}"` : ''
output += `<td${align}${nowrap}>${item[prop]}</td>` output += `<td${align}${nowrap}${colspan}>${item.value}</td>`
i++
} }
output += '</tr>\r\n' output += '</tr>\r\n'
} }

View file

@ -13,3 +13,4 @@ export * from './queueCreator'
export * from './issueLoader' export * from './issueLoader'
export * from './issueParser' export * from './issueParser'
export * from './htmlTable' export * from './htmlTable'
export * from './proxyParser'

View file

@ -0,0 +1,27 @@
import { URL } from 'node:url'
type ProxyParserResult = {
protocol: string | null
auth: {
username: string | null
password: string | null
}
host: string
port: number | null
}
export class ProxyParser {
parse(_url: string): ProxyParserResult {
const parsed = new URL(_url)
return {
protocol: parsed.protocol.replace(':', '') || null,
auth: {
username: parsed.username || null,
password: parsed.password || null
},
host: parsed.hostname,
port: parsed.port ? parseInt(parsed.port) : null
}
}
}

View file

@ -1,5 +1,3 @@
# Sites # Sites
\* Total number of channels / with a valid `xmltv-id`
_TABLE_ _TABLE_

View file

@ -6,7 +6,7 @@ dayjs.extend(customParseFormat)
dayjs.extend(utc) dayjs.extend(utc)
const date = dayjs.utc('2025-01-12', 'YYYY-MM-DD').startOf('d') const date = dayjs.utc('2025-01-12', 'YYYY-MM-DD').startOf('d')
const channel = { site_id: 'bbc1', xmltv_id: 'BBCOne.uk' } const channel = { site_id: 'bbc1' }
it('can generate valid url', () => { it('can generate valid url', () => {
expect(url({ channel, date })).toBe('https://example.com/api/bbc1/2025-01-12') expect(url({ channel, date })).toBe('https://example.com/api/bbc1/2025-01-12')
@ -32,11 +32,7 @@ it('can parse response', () => {
}) })
it('can handle empty guide', () => { it('can handle empty guide', () => {
const result = parser({ const results = parser({ content: '' })
date,
channel,
content: ''
})
expect(result).toMatchObject([]) expect(results).toMatchObject([])
}) })

View file

@ -1,14 +1,12 @@
# Sites # Sites
\* Total number of channels / with a valid `xmltv-id`
<table> <table>
<thead> <thead>
<tr><th align="left">Site</th><th align="left">Channels *</th><th align="left">Status</th><th align="left">Notes</th></tr> <tr><th align="left">Site</th><th align="left" colspan="2">Channels<br>(total / with xmltv-id)</th><th align="left">Status</th><th align="left">Notes</th></tr>
</thead> </thead>
<tbody> <tbody>
<tr><td><a href="sites/iltalehti.fi">iltalehti.fi</a></td><td align="center">142 / 44</td><td>🟡</td><td>https://github.com/iptv-org/epg/issues/2396</td></tr> <tr><td><a href="sites/iltalehti.fi">iltalehti.fi</a></td><td align="right">142</td><td align="right">44</td><td align="center">🟡</td><td>https://github.com/iptv-org/epg/issues/2396</td></tr>
<tr><td><a href="sites/indihometv.com">indihometv.com</a></td><td align="center">130 / 124</td><td>🟢</td><td></td></tr> <tr><td><a href="sites/indihometv.com">indihometv.com</a></td><td align="right">130</td><td align="right">124</td><td align="center">🟢</td><td></td></tr>
<tr><td><a href="sites/kan.org.il">kan.org.il</a></td><td align="center">6 / 6</td><td>🔴</td><td>https://github.com/iptv-org/epg/issues/2273</td></tr> <tr><td><a href="sites/kan.org.il">kan.org.il</a></td><td align="right">6</td><td align="right">6</td><td align="center">🔴</td><td>https://github.com/iptv-org/epg/issues/2273</td></tr>
</tbody> </tbody>
</table> </table>

View file

@ -9,9 +9,6 @@
<programme start="20221019044000 +0000" stop="20221019071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme> <programme start="20221019044000 +0000" stop="20221019071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="en">Program1 (example.com)</title></programme> <programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="en">Program1 (example.com)</title></programme>
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example.com)</title></programme> <programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example.com)</title></programme>
<programme start="20221020044000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
<programme start="20221019043000 +0000" stop="20221019071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme> <programme start="20221019043000 +0000" stop="20221019071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme>
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme>
<programme start="20221019043000 +0000" stop="20221019071000 +0000" channel="Channel4.us"><title lang="en">Program1 (example2.com)</title></programme> <programme start="20221019043000 +0000" stop="20221019071000 +0000" channel="Channel4.us"><title lang="en">Program1 (example2.com)</title></programme>
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel4.us"><title lang="en">Program1 (example2.com)</title></programme>
</tv> </tv>

View file

@ -9,9 +9,6 @@
<programme start="20221019044000 +0000" stop="20221019071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme> <programme start="20221019044000 +0000" stop="20221019071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="en">Program1 (example.com)</title></programme> <programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="en">Program1 (example.com)</title></programme>
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example.com)</title></programme> <programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example.com)</title></programme>
<programme start="20221020044000 +0000" stop="20221020071000 +0000" channel="Channel1.us"><title lang="fr">Programme1 (example2.com)</title></programme>
<programme start="20221019043000 +0000" stop="20221019071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme> <programme start="20221019043000 +0000" stop="20221019071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme>
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel3.us"><title lang="en">Program1 (example2.com)</title></programme>
<programme start="20221019043000 +0000" stop="20221019071000 +0000" channel="Channel4.us"><title lang="en">Program1 (example2.com)</title></programme> <programme start="20221019043000 +0000" stop="20221019071000 +0000" channel="Channel4.us"><title lang="en">Program1 (example2.com)</title></programme>
<programme start="20221020043000 +0000" stop="20221020071000 +0000" channel="Channel4.us"><title lang="en">Program1 (example2.com)</title></programme>
</tv> </tv>

Binary file not shown.

View file

@ -6,7 +6,7 @@ dayjs.extend(customParseFormat)
dayjs.extend(utc) dayjs.extend(utc)
const date = dayjs.utc('2025-01-12', 'YYYY-MM-DD').startOf('d') const date = dayjs.utc('2025-01-12', 'YYYY-MM-DD').startOf('d')
const channel = { site_id: 'bbc1', xmltv_id: 'BBCOne.uk' } const channel = { site_id: 'bbc1' }
it('can generate valid url', () => { it('can generate valid url', () => {
expect(url({ channel, date })).toBe('https://example.com/api/bbc1/2025-01-12') expect(url({ channel, date })).toBe('https://example.com/api/bbc1/2025-01-12')
@ -32,11 +32,7 @@ it('can parse response', () => {
}) })
it('can handle empty guide', () => { it('can handle empty guide', () => {
const result = parser({ const results = parser({ content: '' })
date,
channel,
content: ''
})
expect(result).toMatchObject([]) expect(results).toMatchObject([])
}) })

View file

@ -97,6 +97,30 @@ describe('epg:grab', () => {
expect(stdout).toContain('ERR: Connection timeout') expect(stdout).toContain('ERR: Connection timeout')
}) })
it('can grab epg via https proxy', () => {
const cmd = `${ENV_VAR} npm run grab --- --site=example.com --proxy=https://bob:123456@proxy.com:1234 --output="${path.resolve(
'tests/__data__/output/guide.xml'
)}"`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
expect(content('tests/__data__/output/guide.xml')).toEqual(
content('tests/__data__/expected/guide2.xml')
)
})
it('can grab epg via socks5 proxy', () => {
const cmd = `${ENV_VAR} npm run grab --- --site=example.com --proxy=socks5://bob:123456@proxy.com:1234 --output="${path.resolve(
'tests/__data__/output/guide.xml'
)}"`
const stdout = execSync(cmd, { encoding: 'utf8' })
if (process.env.DEBUG === 'true') console.log(cmd, stdout)
expect(content('tests/__data__/output/guide.xml')).toEqual(
content('tests/__data__/expected/guide2.xml')
)
})
}) })
function content(filepath: string) { function content(filepath: string) {

View file

@ -396,10 +396,10 @@
dependencies: dependencies:
levn "^0.4.1" levn "^0.4.1"
"@freearhey/core@^0.5.0": "@freearhey/core@^0.5.1":
version "0.5.0" version "0.5.1"
resolved "https://registry.npmjs.org/@freearhey/core/-/core-0.5.0.tgz" resolved "https://registry.npmjs.org/@freearhey/core/-/core-0.5.1.tgz"
integrity sha512-FcA5Pv9RvFvLYAwNmD/2vlSR49Rx+kihJ+xbIUgIACHY6lBUptfbNznm00DQoUyWRJG/cfT3dkYCwIxSUsdP+w== integrity sha512-UDKIOyrtcUXaiAeIvjNFTI6DlempiOQaRB83CqHNF1VPRHNBiNhGhERWyInHE2cjLp/cc0CA/IykOYS39kBK7Q==
dependencies: dependencies:
"@types/fs-extra" "^11.0.2" "@types/fs-extra" "^11.0.2"
"@types/lodash" "^4.14.198" "@types/lodash" "^4.14.198"
@ -741,10 +741,10 @@
"@nodelib/fs.scandir" "2.1.5" "@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0" fastq "^1.6.0"
"@ntlab/sfetch@^1.0.0": "@ntlab/sfetch@^1.2.0":
version "1.0.0" version "1.2.0"
resolved "https://registry.npmjs.org/@ntlab/sfetch/-/sfetch-1.0.0.tgz" resolved "https://registry.npmjs.org/@ntlab/sfetch/-/sfetch-1.2.0.tgz"
integrity sha512-AWrC43z1TncvB7S7dl9Wn8xZpCqdKFBfXqaN3BXPfJeS3gxV9Fm86eAsW95YdXTOgPWbCC/GAgVuXi6Aot6DkQ== integrity sha512-9SE4NnqWo8l6mG0rnAkgng6ozSamIpF3EC+GOTQGGa6eAC0tNJvzrylMz6YRjjEGH6mOfn7ZBAuKj5WIZUul6A==
dependencies: dependencies:
axios "^1.7.9" axios "^1.7.9"
@ -1271,7 +1271,7 @@ acorn-walk@^8.1.1:
resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz" resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz"
integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
agent-base@^7.1.3: agent-base@^7.1.2, agent-base@^7.1.3:
version "7.1.3" version "7.1.3"
resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz" resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz"
integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==
@ -2158,10 +2158,10 @@ entities@^4.2.0, entities@^4.3.0, entities@^4.4.0:
resolved "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz" resolved "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz"
integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
epg-grabber@^0.37.4: epg-grabber@^0.38.0:
version "0.37.4" version "0.38.0"
resolved "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.37.4.tgz" resolved "https://registry.npmjs.org/epg-grabber/-/epg-grabber-0.38.0.tgz"
integrity sha512-PS104bH9tHRa9kivSwx47AKMkfHwKy51XQTx+GO6sIXvIp2Z4LBpwMEXGcfPoAsdIGxgs2Wrl0dZ/QGL+7x6YQ== integrity sha512-jbwTgi6G7e+zrb2oNC0C7mcQYoRkFnvhXCurexeICaEy4avRB6WS5rD/yfqYoiqaXOM3x1BNBpCKFYoS7Ob5YA==
dependencies: dependencies:
axios "^1.6.1" axios "^1.6.1"
axios-cache-interceptor "^0.10.3" axios-cache-interceptor "^0.10.3"
@ -2176,6 +2176,7 @@ epg-grabber@^0.37.4:
http-cookie-agent "^6.0.8" http-cookie-agent "^6.0.8"
lodash "^4.17.21" lodash "^4.17.21"
node-gzip "^1.1.2" node-gzip "^1.1.2"
socks-proxy-agent "^8.0.5"
tough-cookie "^5.0.0" tough-cookie "^5.0.0"
winston "^3.3.3" winston "^3.3.3"
xml-js "^1.6.11" xml-js "^1.6.11"
@ -2835,6 +2836,14 @@ inquirer@^8.2.6:
through "^2.3.6" through "^2.3.6"
wrap-ansi "^6.0.1" wrap-ansi "^6.0.1"
ip-address@^9.0.5:
version "9.0.5"
resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz"
integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==
dependencies:
jsbn "1.1.0"
sprintf-js "^1.1.3"
is-arrayish@^0.2.1: is-arrayish@^0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
@ -3373,6 +3382,11 @@ js-yaml@^4.1.0:
dependencies: dependencies:
argparse "^2.0.1" argparse "^2.0.1"
jsbn@1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz"
integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
jsesc@^2.5.1: jsesc@^2.5.1:
version "2.5.2" version "2.5.2"
resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"
@ -4393,6 +4407,28 @@ slash@^3.0.0:
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
smart-buffer@^4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
socks-proxy-agent@^8.0.5:
version "8.0.5"
resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz"
integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==
dependencies:
agent-base "^7.1.2"
debug "^4.3.4"
socks "^2.8.3"
socks@^2.8.3:
version "2.8.3"
resolved "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz"
integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==
dependencies:
ip-address "^9.0.5"
smart-buffer "^4.2.0"
source-map-support@0.5.13: source-map-support@0.5.13:
version "0.5.13" version "0.5.13"
resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz"
@ -4406,6 +4442,11 @@ source-map@^0.6.0, source-map@^0.6.1:
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
sprintf-js@^1.1.3:
version "1.1.3"
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz"
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
sprintf-js@~1.0.2: sprintf-js@~1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"