mirror of
https://github.com/TheBinaryNinja/tvapp2.git
synced 2026-06-05 02:05:42 -04:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
998d706bf7
|
|||
|
f4a394bd3b
|
|||
|
898bbe4827
|
|||
|
66b69d5629
|
|||
|
818729d6ed
|
|||
|
33a2a90eb1
|
|||
|
2ff6c193c9
|
37
.github/workflows/release.yml
vendored
37
.github/workflows/release.yml
vendored
@@ -355,13 +355,28 @@ jobs:
|
||||
if: ${{ startsWith( inputs.PRERELEASE, false ) }}
|
||||
run: |
|
||||
filename_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip"
|
||||
sha256="$(shasum --algorithm 256 ${filename_zip} | awk '{ print $1 }')"
|
||||
shasum --algorithm 256 ${filename_zip} > SHA256SUMS.txt
|
||||
|
||||
# import gpg key (base64)
|
||||
echo '${{ secrets.ADMINSERV_GPG_KEY_B64 }}' | base64 -d | gpg --import
|
||||
|
||||
# get sha1 and sha256 for .zip and .gz files
|
||||
find . -maxdepth 1 \( -name '*.zip' -o -name '*.gz' \) -printf '%P\n' | xargs -r sha1sum | gpg --digest-algo 256 --clearsign > sha1sum.txt.asc
|
||||
find . -maxdepth 1 \( -name '*.zip' -o -name '*.gz' \) -printf '%P\n' | xargs -r sha256sum | gpg --digest-algo sha256 --clearsign > sha256sum.txt.asc
|
||||
|
||||
# get sha1sum; assign to variable
|
||||
sha1sum="$(shasum --algorithm 1 ${filename_zip} | awk '{ print $1 }')"
|
||||
echo "SHA1SUM=${sha1sum}" >> $GITHUB_ENV
|
||||
|
||||
# get sha256sum; assign to variable
|
||||
sha256sum="$(shasum --algorithm 256 ${filename_zip} | awk '{ print $1 }')"
|
||||
echo "SHA256SUM=${sha256sum}" >> $GITHUB_ENV
|
||||
|
||||
# no longer needed, replaced by find . command
|
||||
# shasum --algorithm 256 ${filename_zip} > SHA256SUMS.txt
|
||||
echo "FILE_ZIP=${filename_zip}" >> $GITHUB_ENV
|
||||
echo "SHA256SUM=${sha256}" >> $GITHUB_ENV
|
||||
|
||||
filename_compose_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-docker-compose.zip"
|
||||
sha256_compose="$(shasum --algorithm 256 ${filename_compose_zip} | awk '{ print $1 }')"
|
||||
sha256sum_compose="$(shasum --algorithm 256 ${filename_compose_zip} | awk '{ print $1 }')"
|
||||
echo "FILE_COMPOSE_ZIP=${filename_compose_zip}" >> $GITHUB_ENV
|
||||
|
||||
# #
|
||||
@@ -372,8 +387,12 @@ jobs:
|
||||
id: task_release_checksum_rc_set
|
||||
if: ${{ startsWith( inputs.PRERELEASE, true ) }}
|
||||
run: |
|
||||
# get filename
|
||||
filename_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip"
|
||||
# get sha256 checksum
|
||||
sha256="$(shasum --algorithm 256 ${filename_zip} | awk '{ print $1 }')"
|
||||
|
||||
# write sha256sum to file
|
||||
shasum --algorithm 256 ${filename_zip} > SHA256SUMS.txt
|
||||
echo "FILE_ZIP=${filename_zip}" >> $GITHUB_ENV
|
||||
echo "SHA256SUM=${sha256}" >> $GITHUB_ENV
|
||||
@@ -412,7 +431,7 @@ jobs:
|
||||
if: ${{ startsWith( inputs.PRERELEASE, false ) }}
|
||||
run: |
|
||||
echo Zipping STABLE Package .zip ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
|
||||
zip -jr ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip SHA256SUMS.txt
|
||||
zip -jr ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip sha1sum.txt.asc sha256sum.txt.asc
|
||||
ls
|
||||
|
||||
# #
|
||||
@@ -424,7 +443,7 @@ jobs:
|
||||
if: ${{ startsWith( inputs.PRERELEASE, true ) }}
|
||||
run: |
|
||||
echo Zipping PRE-RELEASE Package .zip ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip
|
||||
zip -jr ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip SHA256SUMS.txt
|
||||
zip -jr ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip sha1sum.txt.asc sha256sum.txt.asc
|
||||
ls
|
||||
|
||||
# #
|
||||
@@ -578,7 +597,8 @@ jobs:
|
||||
files: |
|
||||
${{ env.PROJECT_NAME }}-v${{ env.PACKAGE_VERSION }}-docker-compose.zip
|
||||
${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
|
||||
SHA256SUMS.txt
|
||||
sha1sum.txt.asc
|
||||
sha256sum.txt.asc
|
||||
prerelease: false
|
||||
body: |
|
||||
${{ steps.task_release_changelog_categorized.outputs.changelog }}
|
||||
@@ -611,7 +631,8 @@ jobs:
|
||||
files: |
|
||||
${{ env.PROJECT_NAME }}-v${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}-docker-compose.zip
|
||||
${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip
|
||||
SHA256SUMS.txt
|
||||
sha1sum.txt.asc
|
||||
sha256sum.txt.asc
|
||||
prerelease: false
|
||||
body: |
|
||||
> [!WARNING]
|
||||
|
||||
@@ -103,6 +103,7 @@ ENV FILE_M3U="playlist.m3u8"
|
||||
ENV FILE_EPG="xmltv.xml"
|
||||
ENV FILE_TAR="xmltv.xml.gz"
|
||||
ENV HEALTH_TIMER=600000
|
||||
ENV TASK_CRON_SYNC="0 0 */3 * *"
|
||||
ENV LOG_LEVEL=4
|
||||
ENV TZ="Etc/UTC"
|
||||
|
||||
|
||||
@@ -168,6 +168,8 @@ For the [environment variables](#environment-variables), you may specify these i
|
||||
| `FILE_EPG` | `xmltv.xml` | Filename for XML guide data file |
|
||||
| `FILE_GZP` | `xmltv.xml.gz` | Filename for XML compressed as gzip .gz |
|
||||
| `STREAM_QUALITY` | `hd` | Stream quality<br />Can be either `hd` or `sd` |
|
||||
| `TASK_CRON_SYNC` | `0 0 */3 * *` | Defines how often to refresh the M3U and XML IPTV data |
|
||||
| `HEALTH_TIMER` | `600000` | How often (in milliseconds) to run a health check |
|
||||
| `DIR_BUILD` | `/usr/src/app` | Path inside container where TVApp2 will be built. <br /><br /> <sup>⚠️ This should not be used unless you know what you're doing</sup> |
|
||||
| `DIR_RUN` | `/usr/bin/app` | Path inside container where TVApp2 will be placed after it is built <br /><br /> <sup>⚠️ This should not be used unless you know what you're doing</sup> |
|
||||
| `LOG_LEVEL` | `4` | Level of logging to display in console<br/>`7` Trace <sup><sub>& below</sub></sup><br />`6` Verbose <sup><sub>& below</sub></sup><br />`5` Debug <sup><sub>& below</sub></sup><br />`4` Info <sup><sub>& below</sub></sup><br />`3` Notice <sup><sub>& below</sub></sup><br />`2` Warn <sup><sub>& below</sub></sup><br />`1` Error <sup><sub>only</sub></sup> |
|
||||
@@ -1219,6 +1221,8 @@ This docker container contains the following env variables:
|
||||
| `FILE_EPG` | `xmltv.xml` | Filename for XML guide data file |
|
||||
| `FILE_GZP` | `xmltv.xml.gz` | Filename for XML compressed as gzip .gz |
|
||||
| `STREAM_QUALITY` | `hd` | Stream quality<br />Can be either `hd` or `sd` |
|
||||
| `TASK_CRON_SYNC` | `0 0 */3 * *` | Defines how often to refresh the M3U and XML IPTV data |
|
||||
| `HEALTH_TIMER` | `600000` | How often (in milliseconds) to run a health check |
|
||||
| `DIR_BUILD` | `/usr/src/app` | Path inside container where TVApp2 will be built. <br /><br /> <sup>⚠️ This should not be used unless you know what you're doing</sup> |
|
||||
| `DIR_RUN` | `/usr/bin/app` | Path inside container where TVApp2 will be placed after it is built <br /><br /> <sup>⚠️ This should not be used unless you know what you're doing</sup> |
|
||||
| `LOG_LEVEL` | `4` | Level of logging to display in console<br/>`7` Trace <sup><sub>& below</sub></sup><br />`6` Verbose <sup><sub>& below</sub></sup><br />`5` Debug <sup><sub>& below</sub></sup><br />`4` Info <sup><sub>& below</sub></sup><br />`3` Notice <sup><sub>& below</sub></sup><br />`2` Warn <sup><sub>& below</sub></sup><br />`1` Error <sup><sub>only</sub></sup> |
|
||||
|
||||
@@ -12,6 +12,8 @@ import zlib from 'zlib';
|
||||
import chalk from 'chalk';
|
||||
import ejs from 'ejs';
|
||||
import moment from 'moment';
|
||||
import cron, { schedule } from 'node-cron';
|
||||
import * as crons from 'cron';
|
||||
|
||||
/*
|
||||
Old CJS variables converted to ESM
|
||||
@@ -80,7 +82,8 @@ const envWebFolder = process.env.WEB_FOLDER || 'www';
|
||||
const envWebEncoding = process.env.WEB_ENCODING || 'deflate, br';
|
||||
const envProxyHeader = process.env.WEB_PROXY_HEADER || 'x-forwarded-for';
|
||||
const envHealthTimer = process.env.HEALTH_TIMER || 600000;
|
||||
const LOG_LEVEL = process.env.LOG_LEVEL || 10;
|
||||
const envTaskCronSync = process.env.TASK_CRON_SYNC || '0 0 */3 * *';
|
||||
const LOG_LEVEL = process.env.LOG_LEVEL || 4;
|
||||
|
||||
/*
|
||||
Define > Externals
|
||||
@@ -1762,6 +1765,25 @@ async function initialize()
|
||||
const start = performance.now();
|
||||
try
|
||||
{
|
||||
const validation = crons.validateCronExpression( envTaskCronSync );
|
||||
if ( !validation.valid )
|
||||
{
|
||||
Log.error( `core`, chalk.yellow( `[schedule]` ), chalk.white( `❌` ),
|
||||
chalk.redBright( `<msg>` ), chalk.gray( `Specified cron schedule is not valid` ),
|
||||
chalk.redBright( `<schedule>` ), chalk.whiteBright.bgBlack( ` ${ envTaskCronSync } ` ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
const cronNextRunDt = new Date( crons.sendAt( envTaskCronSync ) );
|
||||
const cronNextRun = moment( cronNextRunDt ).format( 'MM-DD-YYYY h:mm A' );
|
||||
|
||||
Log.info( `core`, chalk.yellow( `[schedule]` ), chalk.white( `ℹ️` ),
|
||||
chalk.blueBright( `<msg>` ), chalk.gray( `TVApp2 will refresh channel and guide data at` ),
|
||||
chalk.blueBright( `<schedule>` ), chalk.whiteBright.gray( ` ${ envTaskCronSync } ` ),
|
||||
chalk.blueBright( `<nextrun>` ), chalk.whiteBright.gray( ` ${ cronNextRun } ` ),
|
||||
chalk.blueBright( `<nextrunIso>` ), chalk.whiteBright.gray( ` ${ cronNextRunDt } ` ) );
|
||||
}
|
||||
|
||||
Log.info( `core`, chalk.yellow( `[initiate]` ), chalk.white( `ℹ️` ),
|
||||
chalk.blueBright( `<msg>` ), chalk.gray( `Starting TVApp2 container. Assigning bound IP to host network adapter` ),
|
||||
chalk.blueBright( `<hostIp>` ), chalk.gray( `${ envWebIP }` ),
|
||||
@@ -2305,3 +2327,43 @@ const server = http.createServer( ( request, response ) =>
|
||||
});
|
||||
})();
|
||||
|
||||
/*
|
||||
Crons > Next Sync
|
||||
*/
|
||||
|
||||
cron.schedule( envTaskCronSync, async() =>
|
||||
{
|
||||
Log.ok( `task`, chalk.yellow( `[resync]` ), chalk.white( `✅` ),
|
||||
chalk.blueBright( `<msg>` ), chalk.gray( `Ran cron / task to re-sync IPTV data` ),
|
||||
chalk.blueBright( `<schedule>` ), chalk.whiteBright.bgBlack( ` ${ envTaskCronSync } ` ) );
|
||||
|
||||
await initialize();
|
||||
});
|
||||
|
||||
/*
|
||||
Crons > Announce Next Sync
|
||||
should show every 30 minutes
|
||||
*/
|
||||
|
||||
cron.schedule( '*/30 * * * *', async() =>
|
||||
{
|
||||
const validation = crons.validateCronExpression( envTaskCronSync );
|
||||
if ( !validation.valid )
|
||||
{
|
||||
Log.error( `core`, chalk.yellow( `[schedule]` ), chalk.white( `❌` ),
|
||||
chalk.redBright( `<msg>` ), chalk.gray( `Specified cron schedule is not valid. Re-write the cron so that it is properly formatted` ),
|
||||
chalk.redBright( `<env>` ), chalk.gray( `TASK_CRON_SYNC` ),
|
||||
chalk.redBright( `<schedule>` ), chalk.whiteBright.bgBlack( ` ${ envTaskCronSync } ` ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
const cronNextRunDt = new Date( crons.sendAt( envTaskCronSync ) );
|
||||
const cronNextRun = moment( cronNextRunDt ).format( 'MM-DD-YYYY h:mm A' );
|
||||
|
||||
Log.info( `core`, chalk.yellow( `[schedule]` ), chalk.white( `ℹ️` ),
|
||||
chalk.blueBright( `<msg>` ), chalk.gray( `Next IPTV data refresh at` ),
|
||||
chalk.blueBright( `<schedule>` ), chalk.whiteBright.gray( ` ${ envTaskCronSync } ` ),
|
||||
chalk.blueBright( `<nextrun>` ), chalk.whiteBright.gray( ` ${ cronNextRun } ` ),
|
||||
chalk.blueBright( `<nextrunIso>` ), chalk.whiteBright.gray( ` ${ cronNextRunDt } ` ) );
|
||||
}
|
||||
});
|
||||
|
||||
51
tvapp2/package-lock.json
generated
51
tvapp2/package-lock.json
generated
@@ -1,20 +1,22 @@
|
||||
{
|
||||
"name": "tvapp2",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "tvapp2",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^5.3.0",
|
||||
"cron": "^4.3.0",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "5.1.0",
|
||||
"moment": "2.30.1",
|
||||
"node-cron": "^4.0.3",
|
||||
"playwright": "^1.52.0",
|
||||
"user-agents": "^1.1.529"
|
||||
"user-agents": "^1.1.537"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@stylistic/eslint-plugin-js": "^4.2.0",
|
||||
@@ -297,6 +299,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz",
|
||||
"integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
|
||||
@@ -842,6 +850,19 @@
|
||||
"node": ">=6.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cron": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cron/-/cron-4.3.0.tgz",
|
||||
"integrity": "sha512-ciiYNLfSlF9MrDqnbMdRWFiA6oizSF7kA1osPP9lRzNu0Uu+AWog1UKy7SkckiDY2irrNjeO6qLyKnXC8oxmrw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/luxon": "~3.6.0",
|
||||
"luxon": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -2929,6 +2950,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz",
|
||||
"integrity": "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -3050,6 +3080,15 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cron": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.0.3.tgz",
|
||||
"integrity": "sha512-YPEUlbYGgpfN44OtCm4KkK4TXjeIB4arERbDWP7kJgM+QHFK9AdM6/3bp4M3oB1QBrL5INyTRLAPei87j49foA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
@@ -4326,9 +4365,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/user-agents": {
|
||||
"version": "1.1.529",
|
||||
"resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.1.529.tgz",
|
||||
"integrity": "sha512-8/ha9jnpBjUhC7+kpdAimo+mQVUMFhTJEkGVRSUsxK6YWuVZ6il+6ErVMjWpfX7q1Ft0m/4+XpPJhGuqZesFTQ==",
|
||||
"version": "1.1.537",
|
||||
"resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.1.537.tgz",
|
||||
"integrity": "sha512-D3t8f1G3Kd3Ak0t9Md9oNsK59Ms1hs9FhdwkMafkaNpwpMcq/FHuHHT/ky64Dy8aKJkMFcEBeVN0zQmtoTKCKg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"lodash.clonedeep": "^4.5.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tvapp2",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"description": "This package allows you to generate M3U playlists and EPG guides from various online IPTV services.",
|
||||
"author": "BinaryNinja",
|
||||
"license": "MIT",
|
||||
@@ -72,8 +72,10 @@
|
||||
"iptv"
|
||||
],
|
||||
"dependencies": {
|
||||
"cron": "^4.3.0",
|
||||
"node-cron": "^4.0.3",
|
||||
"playwright": "^1.52.0",
|
||||
"user-agents": "^1.1.529",
|
||||
"user-agents": "^1.1.537",
|
||||
"chalk": "^5.3.0",
|
||||
"ejs": "^3.1.10",
|
||||
"moment": "2.30.1",
|
||||
|
||||
Reference in New Issue
Block a user