Compare commits

..

40 Commits
1.5.1 ... 1.5.3

Author SHA1 Message Date
9eaa896b2d ci: revert action script softprops/action-gh-release from v2.3.0 to v2.2.2
Latest version 2.3.0 contains bugs; see https://github.com/softprops/action-gh-release/issues/627
2025-06-10 09:17:20 -07:00
ed7abff25a ci: add .sig generation to release workflow 2025-06-10 09:14:47 -07:00
4a8f35c0eb refactor(lint): There must be a space after this paren @stylistic/js/space-in-parens 2025-06-10 09:06:10 -07:00
1debab8452 refactor: add uptimeLong to api 2025-06-10 08:49:49 -07:00
53cfd4789e fix: health timer resetting due to incompatible code 2025-06-10 08:28:32 -07:00
d9a89e143a feat: add uptime, startup time logic 2025-06-10 08:12:31 -07:00
55e998bb46 feat: add uptime, startup time in footer 2025-06-10 07:58:11 -07:00
bd40d20911 build: bump version 1.5.3 2025-06-10 07:55:14 -07:00
efc5dac8f4 build(deps): add package nconf
package nconf will be utilized to store HDHomeRun config settings
2025-06-02 03:41:06 -07:00
c33a35003b ci: update docker annotations to add chomp 2025-06-01 16:56:44 -07:00
a10c1bcff9 ci: add org.opencontainers.image.description 2025-06-01 16:41:53 -07:00
2025e04b61 ci: update env var IMAGE_ALPINE_VERSION 2025-06-01 16:38:33 -07:00
77e2b5e7d6 ci: add network settings, add annotations 2025-06-01 16:31:59 -07:00
9b2b7682e3 ci: update build scripts, add default ARG values 2025-06-01 15:37:14 -07:00
433abb0fec feat: refresh health timer automatically during hover 2025-06-01 14:12:49 -07:00
012cd0cc44 feat: add git hash to footer 2025-06-01 12:38:10 -07:00
f56f934514 build: update tvapp2 sub package 2025-06-01 11:51:06 -07:00
c9aaad376b build(deps): bump user-agents from 1.1.556 to 1.1.557 2025-06-01 11:28:57 -07:00
3ebd2478fe build(s6-overlay): add new build structure 2025-06-01 11:22:52 -07:00
b3fbaa1d97 build(run): update logic for root tvapp2 script 2025-06-01 11:21:01 -07:00
94da974373 fix(build): add compatibility for detecting commands for older operating systems 2025-06-01 11:09:23 -07:00
fd76d3ce59 ci: reintegrate root run tvapp2 script 2025-06-01 10:55:17 -07:00
7c5420d279 build( re-integrate root plugins file 2025-06-01 10:48:17 -07:00
c2ab89457b build: update packages 2025-06-01 10:16:20 -07:00
8f87fae452 feat: add git hash to webui footer 2025-06-01 10:07:07 -07:00
d5c9c3550a feat: web ui now opens links in new window 2025-06-01 10:06:48 -07:00
b654cc3469 feat: add git hash reporting 2025-06-01 10:04:51 -07:00
fdb99d57d6 feat: show tvapp2 version as console message 2025-06-01 10:04:36 -07:00
e3e611d47b feat: add tracking for daddylive 2025-06-01 10:04:08 -07:00
b8ef37188c feat: try http first for MoveOnJoy 2025-06-01 10:03:42 -07:00
f8d68789fc feat: add child_process support 2025-06-01 10:03:06 -07:00
e0c9df41d7 fix: change fl2.moveonjoy to fl6.moveonjoy 2025-06-01 09:51:42 -07:00
1363ed4f8a build: update dockerfile to add GIT_SHA1 2025-06-01 09:47:36 -07:00
3e914b7a99 docs(readme): update 2025-06-01 09:46:31 -07:00
d690256369 ci: update workflows 2025-06-01 09:44:36 -07:00
18c37feed8 feat: container startup message now shows public and docker ip assignment 2025-05-13 20:04:11 -07:00
d21a8721cf ci: update release workflow, remove v from docker-compose file 2025-05-13 01:59:31 -07:00
d0192d9a72 ci: update release workflow 2025-05-13 01:28:15 -07:00
684963bc2b ci: update hash digest algorithm 2025-05-13 01:17:01 -07:00
220b995f28 ci: update release workflow 2025-05-13 01:15:13 -07:00
23 changed files with 1854 additions and 714 deletions

View File

@@ -14,6 +14,9 @@ body:
4. Before creating this bug report, ensure you updated your applications to the latest versions. 4. Before creating this bug report, ensure you updated your applications to the latest versions.
Check your configurations to ensure there are no typos or errors. Check your configurations to ensure there are no typos or errors.
Docker users should attempt to re-pull the TVApp2 image to ensure caching is not the cause of an issue. Docker users should attempt to re-pull the TVApp2 image to ensure caching is not the cause of an issue.
5. To get detailed logs of the issue, set the environment variable:
`LOG_LEVEL=5`
Restart the docker container and you should get more detailed logs.
<br /> <br />
@@ -126,9 +129,9 @@ body:
- type: textarea - type: textarea
id: docker-compose id: docker-compose
attributes: attributes:
label: docker-compose.yml label: docker-compose.yml / Run command
description: | description: |
Copy / paste your `docker-compose.yml` file here Copy / paste your `docker-compose.yml` file or run command here
- type: textarea - type: textarea
id: logs id: logs
@@ -137,6 +140,7 @@ body:
description: | description: |
Paste your docker logs here. Paste your docker logs here.
You can get your docker logs by opening terminal and running `docker logs tvapp2` You can get your docker logs by opening terminal and running `docker logs tvapp2`
To get detailed logs, set the environment variable `LOG_LEVEL=5` and restart the container.
- type: textarea - type: textarea
id: screenshots id: screenshots

View File

@@ -74,6 +74,21 @@ on:
default: '1.0.0' default: '1.0.0'
type: string type: string
# #
# Registry Name
#
# options:
# - github
# - dockerhub
# - gitea
# #
IMAGE_REGISTRY:
description: '📘 Registry Name'
required: true
default: 'dockerhub'
type: string
# # # #
# Dockerhub Author # Dockerhub Author
# #
@@ -100,6 +115,18 @@ on:
default: 'thebinaryninja' default: 'thebinaryninja'
type: string type: string
# #
# Alpine Version
#
# specifies the alpine base docker image version
# #
IMAGE_ALPINE_VERSION:
description: '📀 Alpine Version'
required: true
default: '3.21'
type: string
# # # #
# true no changes to the repo will be made # true no changes to the repo will be made
# false workflow will behave normally, and push any changes detected to the files # false workflow will behave normally, and push any changes detected to the files
@@ -137,8 +164,10 @@ on:
env: env:
IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }} IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }}
IMAGE_VERSION: ${{ github.event.inputs.IMAGE_VERSION || '1.0.0' }} IMAGE_VERSION: ${{ github.event.inputs.IMAGE_VERSION || '1.0.0' }}
IMAGE_REGISTRY: ${{ github.event.inputs.IMAGE_VERSION || 'dockerhub' }}
IMAGE_DOCKERHUB_AUTHOR: ${{ github.event.inputs.IMAGE_DOCKERHUB_AUTHOR || 'thebinaryninja' }} IMAGE_DOCKERHUB_AUTHOR: ${{ github.event.inputs.IMAGE_DOCKERHUB_AUTHOR || 'thebinaryninja' }}
IMAGE_DOCKERHUB_USERNAME: ${{ github.event.inputs.IMAGE_DOCKERHUB_USERNAME || 'thebinaryninja' }} IMAGE_DOCKERHUB_USERNAME: ${{ github.event.inputs.IMAGE_DOCKERHUB_USERNAME || 'thebinaryninja' }}
IMAGE_ALPINE_VERSION: ${{ github.event.inputs.IMAGE_ALPINE_VERSION || '3.21' }}
BOT_NAME_1: EuropaServ BOT_NAME_1: EuropaServ
BOT_NAME_2: BinaryServ BOT_NAME_2: BinaryServ
@@ -280,6 +309,7 @@ jobs:
echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV # 02-25-2025 12:49 echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV # 02-25-2025 12:49
echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV # 20250225 echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV # 20250225
echo "NOW_DOCKER_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z echo "NOW_DOCKER_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z
echo "GITHUB_SHA1=$(git rev-parse HEAD)" >> $GITHUB_ENV # 012cd0cc44c576c4a57b8a18d86793f244d1080a
# # # #
# Release Dockerhub Install Dependencies # Release Dockerhub Install Dependencies
@@ -412,6 +442,7 @@ jobs:
flavor: | flavor: |
latest=false latest=false
labels: | labels: |
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -419,9 +450,13 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=dockerhub org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
annotations: | org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -429,8 +464,11 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=dockerhub org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Dockerhub Build and Push Amd64 # Release Dockerhub Build and Push Amd64
@@ -441,20 +479,41 @@ jobs:
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' ) if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with: with:
allow: |
network.host
network: host
context: . context: .
file: Dockerfile file: Dockerfile
platforms: linux/amd64 platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_dh_meta.outputs.labels }} labels: ${{ steps.task_release_dh_meta.outputs.labels }}
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
provenance: false provenance: false
sbom: false sbom: false
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
build-args: |- build-args: |-
ARCH=amd64 ARCH=amd64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }} RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }} VERSION=${{ env.IMAGE_VERSION }}
BUILDDATE=${{ env.NOW_DOCKER_LABEL }} BUILDDATE=${{ env.NOW_DOCKER_LABEL }}
GIT_SHA1=${{ env.GITHUB_SHA1 }}
ALPINE_VERSION=${{ env.IMAGE_ALPINE_VERSION }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
org.opencontainers.image.architecture=amd64
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-architecture=amd64
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Dockerhub Export Digest Amd64 # Release Dockerhub Export Digest Amd64
@@ -493,20 +552,41 @@ jobs:
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' ) if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with: with:
allow: |
network.host
network: host
context: . context: .
file: Dockerfile file: Dockerfile
platforms: linux/arm64 platforms: linux/arm64
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_dh_meta.outputs.labels }} labels: ${{ steps.task_release_dh_meta.outputs.labels }}
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
provenance: false provenance: false
sbom: false sbom: false
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
build-args: |- build-args: |-
ARCH=arm64 ARCH=arm64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }} RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }} VERSION=${{ env.IMAGE_VERSION }}
BUILDDATE=${{ env.NOW_DOCKER_LABEL }} BUILDDATE=${{ env.NOW_DOCKER_LABEL }}
GIT_SHA1=${{ env.GITHUB_SHA1 }}
ALPINE_VERSION=${{ env.IMAGE_ALPINE_VERSION }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
org.opencontainers.image.architecture=arm64
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-architecture=arm64
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Dockerhub Export Digest Arm64 # Release Dockerhub Export Digest Arm64
@@ -536,22 +616,6 @@ jobs:
if-no-files-found: error if-no-files-found: error
retention-days: 10 retention-days: 10
# #
# Release Dockerhub Push Manifest
# #
- name: '📦 Push Manifest'
id: task_release_dh_manifest
uses: int128/docker-manifest-create-action@v2
with:
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
sources: |
${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}@${{ steps.task_release_dh_push_amd64.outputs.digest }}
${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}@${{ steps.task_release_dh_push_arm64.outputs.digest }}
index-annotations: |
${{ steps.task_release_dh_meta.outputs.labels }}
# # # #
# Release Dockerhub Checkpoint Amd64 # Release Dockerhub Checkpoint Amd64
# # # #
@@ -560,23 +624,24 @@ jobs:
id: task_release_dh_checkpoint id: task_release_dh_checkpoint
run: | run: |
echo "" echo ""
echo "[ GITHUB ] ---------------------------------------------------------------------------------------------" echo "---- [ GITHUB ] ----------------------------------------------------------------------------------------"
echo "github.actor.............................. ${{ github.actor }}" echo "github.actor.............................. ${{ github.actor }}"
echo "github.ref ............................... ${{ github.ref }}" echo "github.ref ............................... ${{ github.ref }}"
echo "github.ref_name .......................... ${{ github.ref_name }}" echo "github.ref_name .......................... ${{ github.ref_name }}"
echo "github.event_name ........................ ${{ github.event_name }}" echo "github.event_name ........................ ${{ github.event_name }}"
echo "github.repository_owner .................. ${{ github.repository_owner }}" echo "github.repository_owner .................. ${{ github.repository_owner }}"
echo "github.repository ........................ ${{ github.repository }}" echo "github.repository ........................ ${{ github.repository }}"
echo "" echo "github.sha ............................... ${{ github.sha }}"
echo "[ INPUTS ] ---------------------------------------------------------------------------------------------" echo -e ""
echo "---- [ INPUTS ] ----------------------------------------------------------------------------------------"
echo "inputs.IMAGE_NAME ........................ ${{ inputs.IMAGE_NAME }}" echo "inputs.IMAGE_NAME ........................ ${{ inputs.IMAGE_NAME }}"
echo "inputs.IMAGE_VERSION ..................... ${{ inputs.IMAGE_VERSION }}" echo "inputs.IMAGE_VERSION ..................... ${{ inputs.IMAGE_VERSION }}"
echo "inputs.IMAGE_DOCKERHUB_AUTHOR ............ ${{ inputs.IMAGE_DOCKERHUB_AUTHOR }}" echo "inputs.IMAGE_DOCKERHUB_AUTHOR ............ ${{ inputs.IMAGE_DOCKERHUB_AUTHOR }}"
echo "inputs.IMAGE_DOCKERHUB_USERNAME .......... ${{ inputs.IMAGE_DOCKERHUB_USERNAME }}" echo "inputs.IMAGE_DOCKERHUB_USERNAME .......... ${{ inputs.IMAGE_DOCKERHUB_USERNAME }}"
echo "inputs.DEV_RELEASE ....................... ${{ inputs.DEV_RELEASE }}" echo "inputs.DEV_RELEASE ....................... ${{ inputs.DEV_RELEASE }}"
echo "inputs.DRY_RUN ........................... ${{ inputs.DRY_RUN }}" echo "inputs.DRY_RUN ........................... ${{ inputs.DRY_RUN }}"
echo "" echo -e ""
echo "[ ENV ] ------------------------------------------------------------------------------------------------" echo "---- [ ENV ] -------------------------------------------------------------------------------------------"
echo "env.IMAGE_NAME ........................... ${{ env.IMAGE_NAME }}" echo "env.IMAGE_NAME ........................... ${{ env.IMAGE_NAME }}"
echo "env.IMAGE_VERSION ........................ ${{ env.IMAGE_VERSION }}" echo "env.IMAGE_VERSION ........................ ${{ env.IMAGE_VERSION }}"
echo "env.IMAGE_VERSION_1DIGIT ................. ${{ env.IMAGE_VERSION_1DIGIT }}" echo "env.IMAGE_VERSION_1DIGIT ................. ${{ env.IMAGE_VERSION_1DIGIT }}"
@@ -591,22 +656,39 @@ jobs:
echo "env.REGISTRY_REPO_ORG_AUTHOR_LC .......... ${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}" echo "env.REGISTRY_REPO_ORG_AUTHOR_LC .......... ${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}"
echo "env.REGISTRY_REPO_AUTHOR_LC .............. ${{ env.REGISTRY_REPO_AUTHOR_LC }}" echo "env.REGISTRY_REPO_AUTHOR_LC .............. ${{ env.REGISTRY_REPO_AUTHOR_LC }}"
echo "env.DOCKER_SHA ........................... ${{ env.DOCKER_SHA }}" echo "env.DOCKER_SHA ........................... ${{ env.DOCKER_SHA }}"
echo "" echo "env.GITHUB_SHA1 .......................... ${{ env.GITHUB_SHA1 }}"
echo "[ DOCKER IMAGES ] --------------------------------------------------------------------------------------" echo -e ""
echo "---- [ DOCKER IMAGES ] ---------------------------------------------------------------------------------"
echo "registry ................................. Dockerhub" echo "registry ................................. Dockerhub"
echo "tags ..................................... ${{ steps.task_release_dh_meta.outputs.tags }}" echo "tags ..................................... ${{ steps.task_release_dh_meta.outputs.tags }}"
echo "labels ................................... ${{ steps.task_release_dh_meta.outputs.labels }}" echo "labels ................................... ${{ steps.task_release_dh_meta.outputs.labels }}"
echo "digest ................................... ${{ steps.task_release_dh_push_amd64.outputs.digest }}" echo "digest ................................... ${{ steps.task_release_dh_push_amd64.outputs.digest }}"
echo "" echo -e ""
echo "(release) tags ........................... ${{ steps.task_release_dh_meta.outputs.tags }}" echo "(release) tags ........................... ${{ steps.task_release_dh_meta.outputs.tags }}"
echo "(release) labels ......................... ${{ steps.task_release_dh_meta.outputs.labels }}" echo "(release) labels ......................... ${{ steps.task_release_dh_meta.outputs.labels }}"
echo "" echo -e ""
echo "[ DOCKER DIGESTS ] -------------------------------------------------------------------------------------" echo "---- [ DOCKER DIGESTS ] --------------------------------------------------------------------------------"
echo "docker image id (amd64) .................. ${{ steps.task_release_dh_push_amd64.outputs.imageid }}" echo "docker image id (amd64) .................. ${{ steps.task_release_dh_push_amd64.outputs.imageid }}"
echo "docker digest (amd64) .................... ${{ steps.task_release_dh_push_amd64.outputs.digest }}" echo "docker digest (amd64) .................... ${{ steps.task_release_dh_push_amd64.outputs.digest }}"
echo "docker image id (arm64) .................. ${{ steps.task_release_dh_push_arm64.outputs.imageid }}" echo "docker image id (arm64) .................. ${{ steps.task_release_dh_push_arm64.outputs.imageid }}"
echo "docker digest (arm64) .................... ${{ steps.task_release_dh_push_arm64.outputs.digest }}" echo "docker digest (arm64) .................... ${{ steps.task_release_dh_push_arm64.outputs.digest }}"
# #
# Release Dockerhub Push Manifest
# #
- name: '📦 Push Manifest'
id: task_release_dh_manifest
uses: int128/docker-manifest-create-action@v2
with:
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
sources: |
${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}@${{ steps.task_release_dh_push_amd64.outputs.digest }}
${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}@${{ steps.task_release_dh_push_arm64.outputs.digest }}
index-annotations: |
${{ steps.task_release_dh_meta.outputs.labels }}
# # # #
# Release Dockerhub Get Weekly Commits # Release Dockerhub Get Weekly Commits
# # # #

View File

@@ -74,6 +74,21 @@ on:
default: '1.0.0' default: '1.0.0'
type: string type: string
# #
# Registry Name
#
# options:
# - github
# - dockerhub
# - gitea
# #
IMAGE_REGISTRY:
description: '📘 Registry Name'
required: true
default: 'gitea'
type: string
# # # #
# Gitea Author # Gitea Author
# #
@@ -106,10 +121,22 @@ on:
# # # #
IMAGE_GITEA_WEBSITE: IMAGE_GITEA_WEBSITE:
description: '🌎 Gitea Website' description: '🌎 Gitea Website'
required: true required: true
default: 'git.binaryninja.net' default: 'git.binaryninja.net'
type: string type: string
# #
# Alpine Version
#
# specifies the alpine base docker image version
# #
IMAGE_ALPINE_VERSION:
description: '📀 Alpine Version'
required: true
default: '3.21'
type: string
# # # #
# true no changes to the repo will be made # true no changes to the repo will be made
@@ -148,9 +175,11 @@ on:
env: env:
IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }} IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }}
IMAGE_VERSION: ${{ github.event.inputs.IMAGE_VERSION || '1.0.0' }} IMAGE_VERSION: ${{ github.event.inputs.IMAGE_VERSION || '1.0.0' }}
IMAGE_REGISTRY: ${{ github.event.inputs.IMAGE_VERSION || 'gitea' }}
IMAGE_GITEA_AUTHOR: ${{ github.event.inputs.IMAGE_GITEA_AUTHOR || 'BinaryNinja' }} IMAGE_GITEA_AUTHOR: ${{ github.event.inputs.IMAGE_GITEA_AUTHOR || 'BinaryNinja' }}
IMAGE_GITEA_USERNAME: ${{ github.event.inputs.IMAGE_GITEA_USERNAME || 'BinaryNinja' }} IMAGE_GITEA_USERNAME: ${{ github.event.inputs.IMAGE_GITEA_USERNAME || 'BinaryNinja' }}
IMAGE_GITEA_WEBSITE: ${{ github.event.inputs.IMAGE_GITEA_WEBSITE || 'git.binaryninja.net' }} IMAGE_GITEA_WEBSITE: ${{ github.event.inputs.IMAGE_GITEA_WEBSITE || 'git.binaryninja.net' }}
IMAGE_ALPINE_VERSION: ${{ github.event.inputs.IMAGE_ALPINE_VERSION || '3.21' }}
BOT_NAME_1: EuropaServ BOT_NAME_1: EuropaServ
BOT_NAME_2: BinaryServ BOT_NAME_2: BinaryServ
@@ -292,6 +321,7 @@ jobs:
echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV # 02-25-2025 12:49 echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV # 02-25-2025 12:49
echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV # 20250225 echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV # 20250225
echo "NOW_DOCKER_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z echo "NOW_DOCKER_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z
echo "GITHUB_SHA1=$(git rev-parse HEAD)" >> $GITHUB_ENV # 012cd0cc44c576c4a57b8a18d86793f244d1080a
# # # #
# Release Gitea Install Dependencies # Release Gitea Install Dependencies
@@ -428,6 +458,7 @@ jobs:
flavor: | flavor: |
latest=false latest=false
labels: | labels: |
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -435,9 +466,13 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=gitea org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
annotations: | org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -445,8 +480,11 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=gitea org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Gitea Meta arm64 # Release Gitea Meta arm64
@@ -476,6 +514,7 @@ jobs:
flavor: | flavor: |
latest=false latest=false
labels: | labels: |
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -483,9 +522,13 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=gitea org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
annotations: | org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -493,8 +536,11 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=gitea org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Gitea Meta Release # Release Gitea Meta Release
@@ -536,6 +582,7 @@ jobs:
flavor: | flavor: |
latest=false latest=false
labels: | labels: |
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -543,9 +590,13 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=gitea org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
annotations: | org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -553,8 +604,11 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=gitea org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Gitea Build and Push Amd64 # Release Gitea Build and Push Amd64
@@ -565,20 +619,41 @@ jobs:
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' ) if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with: with:
allow: |
network.host
network: host
context: . context: .
file: Dockerfile file: Dockerfile
platforms: linux/amd64 platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_gi_meta_amd64.outputs.labels }} labels: ${{ steps.task_release_gi_meta_amd64.outputs.labels }}
tags: |
${{ steps.task_release_gi_meta_amd64.outputs.tags }}
provenance: false provenance: false
sbom: false sbom: false
tags: |
${{ steps.task_release_gi_meta_amd64.outputs.tags }}
build-args: |- build-args: |-
ARCH=amd64 ARCH=amd64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }} RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }} VERSION=${{ env.IMAGE_VERSION }}
BUILDDATE=${{ env.NOW_DOCKER_LABEL }} BUILDDATE=${{ env.NOW_DOCKER_LABEL }}
GIT_SHA1=${{ env.GITHUB_SHA1 }}
ALPINE_VERSION=${{ env.IMAGE_ALPINE_VERSION }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
org.opencontainers.image.architecture=amd64
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-architecture=amd64
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Gitea Export Digest Amd64 # Release Gitea Export Digest Amd64
@@ -617,20 +692,41 @@ jobs:
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' ) if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with: with:
allow: |
network.host
network: host
context: . context: .
file: Dockerfile file: Dockerfile
platforms: linux/arm64 platforms: linux/arm64
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_gi_meta_arm64.outputs.labels }} labels: ${{ steps.task_release_gi_meta_arm64.outputs.labels }}
tags: |
${{ steps.task_release_gi_meta_arm64.outputs.tags }}
provenance: false provenance: false
sbom: false sbom: false
tags: |
${{ steps.task_release_gi_meta_arm64.outputs.tags }}
build-args: |- build-args: |-
ARCH=arm64 ARCH=arm64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }} RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }} VERSION=${{ env.IMAGE_VERSION }}
BUILDDATE=${{ env.NOW_DOCKER_LABEL }} BUILDDATE=${{ env.NOW_DOCKER_LABEL }}
GIT_SHA1=${{ env.GITHUB_SHA1 }}
ALPINE_VERSION=${{ env.IMAGE_ALPINE_VERSION }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
org.opencontainers.image.architecture=arm64
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-architecture=arm64
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Gitea Export Digest Arm64 # Release Gitea Export Digest Arm64
@@ -660,22 +756,6 @@ jobs:
if-no-files-found: error if-no-files-found: error
retention-days: 10 retention-days: 10
# #
# Release Gitea Push Manifest
# #
- name: '📦 Push Manifest'
id: task_release_gi_manifest
uses: int128/docker-manifest-create-action@v2
with:
tags: |
${{ steps.task_release_gi_meta_release.outputs.tags }}
sources: |
${{ env.IMAGE_GITEA_WEBSITE }}/${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}@${{ steps.task_release_gi_push_amd64.outputs.digest }}
${{ env.IMAGE_GITEA_WEBSITE }}/${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}@${{ steps.task_release_gi_push_arm64.outputs.digest }}
index-annotations: |
${{ steps.task_release_gi_meta_release.outputs.labels }}
# # # #
# Release Gitea Checkpoint # Release Gitea Checkpoint
# # # #
@@ -684,15 +764,16 @@ jobs:
id: task_release_gi_checkpoint id: task_release_gi_checkpoint
run: | run: |
echo "" echo ""
echo "[ GITHUB ] ---------------------------------------------------------------------------------------------" echo "---- [ GITHUB ] ----------------------------------------------------------------------------------------"
echo "github.actor.............................. ${{ github.actor }}" echo "github.actor.............................. ${{ github.actor }}"
echo "github.ref ............................... ${{ github.ref }}" echo "github.ref ............................... ${{ github.ref }}"
echo "github.ref_name .......................... ${{ github.ref_name }}" echo "github.ref_name .......................... ${{ github.ref_name }}"
echo "github.event_name ........................ ${{ github.event_name }}" echo "github.event_name ........................ ${{ github.event_name }}"
echo "github.repository_owner .................. ${{ github.repository_owner }}" echo "github.repository_owner .................. ${{ github.repository_owner }}"
echo "github.repository ........................ ${{ github.repository }}" echo "github.repository ........................ ${{ github.repository }}"
echo "" echo "github.sha ............................... ${{ github.sha }}"
echo "[ INPUTS ] ---------------------------------------------------------------------------------------------" echo -e ""
echo "---- [ INPUTS ] ----------------------------------------------------------------------------------------"
echo "inputs.IMAGE_NAME ........................ ${{ inputs.IMAGE_NAME }}" echo "inputs.IMAGE_NAME ........................ ${{ inputs.IMAGE_NAME }}"
echo "inputs.IMAGE_VERSION ..................... ${{ inputs.IMAGE_VERSION }}" echo "inputs.IMAGE_VERSION ..................... ${{ inputs.IMAGE_VERSION }}"
echo "inputs.IMAGE_GITEA_USERNAME .............. ${{ inputs.IMAGE_GITEA_AUTHOR }}" echo "inputs.IMAGE_GITEA_USERNAME .............. ${{ inputs.IMAGE_GITEA_AUTHOR }}"
@@ -700,8 +781,8 @@ jobs:
echo "inputs.IMAGE_GITEA_WEBSITE ............... ${{ inputs.IMAGE_GITEA_WEBSITE }}" echo "inputs.IMAGE_GITEA_WEBSITE ............... ${{ inputs.IMAGE_GITEA_WEBSITE }}"
echo "inputs.DEV_RELEASE ....................... ${{ inputs.DEV_RELEASE }}" echo "inputs.DEV_RELEASE ....................... ${{ inputs.DEV_RELEASE }}"
echo "inputs.DRY_RUN ........................... ${{ inputs.DRY_RUN }}" echo "inputs.DRY_RUN ........................... ${{ inputs.DRY_RUN }}"
echo "" echo -e ""
echo "[ ENV ] ------------------------------------------------------------------------------------------------" echo "---- [ ENV ] -------------------------------------------------------------------------------------------"
echo "env.IMAGE_NAME ........................... ${{ env.IMAGE_NAME }}" echo "env.IMAGE_NAME ........................... ${{ env.IMAGE_NAME }}"
echo "env.IMAGE_VERSION ........................ ${{ env.IMAGE_VERSION }}" echo "env.IMAGE_VERSION ........................ ${{ env.IMAGE_VERSION }}"
echo "env.IMAGE_VERSION_1DIGIT ................. ${{ env.IMAGE_VERSION_1DIGIT }}" echo "env.IMAGE_VERSION_1DIGIT ................. ${{ env.IMAGE_VERSION_1DIGIT }}"
@@ -717,8 +798,9 @@ jobs:
echo "env.REGISTRY_REPO_ORG_AUTHOR_LC .......... ${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}" echo "env.REGISTRY_REPO_ORG_AUTHOR_LC .......... ${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}"
echo "env.REGISTRY_REPO_AUTHOR_LC .............. ${{ env.REGISTRY_REPO_AUTHOR_LC }}" echo "env.REGISTRY_REPO_AUTHOR_LC .............. ${{ env.REGISTRY_REPO_AUTHOR_LC }}"
echo "env.DOCKER_SHA ........................... ${{ env.DOCKER_SHA }}" echo "env.DOCKER_SHA ........................... ${{ env.DOCKER_SHA }}"
echo "" echo "env.GITHUB_SHA1 .......................... ${{ env.GITHUB_SHA1 }}"
echo "[ DOCKER IMAGES ] --------------------------------------------------------------------------------------" echo -e ""
echo "---- [ DOCKER IMAGES ] ---------------------------------------------------------------------------------"
echo "registry ................................. Gitea" echo "registry ................................. Gitea"
echo "(amd64) tags ............................. ${{ steps.task_release_gi_meta_amd64.outputs.tags }}" echo "(amd64) tags ............................. ${{ steps.task_release_gi_meta_amd64.outputs.tags }}"
echo "(amd64) labels ........................... ${{ steps.task_release_gi_meta_amd64.outputs.labels }}" echo "(amd64) labels ........................... ${{ steps.task_release_gi_meta_amd64.outputs.labels }}"
@@ -730,13 +812,29 @@ jobs:
echo "" echo ""
echo "(release) tags ........................... ${{ steps.task_release_gi_meta_release.outputs.tags }}" echo "(release) tags ........................... ${{ steps.task_release_gi_meta_release.outputs.tags }}"
echo "(release) labels ......................... ${{ steps.task_release_gi_meta_release.outputs.labels }}" echo "(release) labels ......................... ${{ steps.task_release_gi_meta_release.outputs.labels }}"
echo "" echo -e ""
echo "[ DOCKER DIGESTS ] -------------------------------------------------------------------------------------" echo "---- [ DOCKER DIGESTS ] --------------------------------------------------------------------------------"
echo "docker image id (amd64) .................. ${{ steps.task_release_gi_push_amd64.outputs.imageid }}" echo "docker image id (amd64) .................. ${{ steps.task_release_gi_push_amd64.outputs.imageid }}"
echo "docker digest (amd64) .................... ${{ steps.task_release_gi_push_amd64.outputs.digest }}" echo "docker digest (amd64) .................... ${{ steps.task_release_gi_push_amd64.outputs.digest }}"
echo "docker image id (arm64) .................. ${{ steps.task_release_gi_push_arm64.outputs.imageid }}" echo "docker image id (arm64) .................. ${{ steps.task_release_gi_push_arm64.outputs.imageid }}"
echo "docker digest (arm64) .................... ${{ steps.task_release_gi_push_arm64.outputs.digest }}" echo "docker digest (arm64) .................... ${{ steps.task_release_gi_push_arm64.outputs.digest }}"
# #
# Release Gitea Push Manifest
# #
- name: '📦 Push Manifest'
id: task_release_gi_manifest
uses: int128/docker-manifest-create-action@v2
with:
tags: |
${{ steps.task_release_gi_meta_release.outputs.tags }}
sources: |
${{ env.IMAGE_GITEA_WEBSITE }}/${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}@${{ steps.task_release_gi_push_amd64.outputs.digest }}
${{ env.IMAGE_GITEA_WEBSITE }}/${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}@${{ steps.task_release_gi_push_arm64.outputs.digest }}
index-annotations: |
${{ steps.task_release_gi_meta_release.outputs.labels }}
# # # #
# Release Gitea Get Weekly Commits # Release Gitea Get Weekly Commits
# # # #

View File

@@ -74,6 +74,21 @@ on:
default: '1.0.0' default: '1.0.0'
type: string type: string
# #
# Registry Name
#
# options:
# - github
# - dockerhub
# - gitea
# #
IMAGE_REGISTRY:
description: '📘 Registry Name'
required: true
default: 'github'
type: string
# # # #
# Image Author # Image Author
# #
@@ -99,6 +114,18 @@ on:
default: 'TheBinaryNinja' default: 'TheBinaryNinja'
type: string type: string
# #
# Alpine Version
#
# specifies the alpine base docker image version
# #
IMAGE_ALPINE_VERSION:
description: '📀 Alpine Version'
required: true
default: '3.21'
type: string
# # # #
# true no changes to the repo will be made # true no changes to the repo will be made
# false workflow will behave normally, and push any changes detected to the files # false workflow will behave normally, and push any changes detected to the files
@@ -136,8 +163,10 @@ on:
env: env:
IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }} IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }}
IMAGE_VERSION: ${{ github.event.inputs.IMAGE_VERSION || '1.0.0' }} IMAGE_VERSION: ${{ github.event.inputs.IMAGE_VERSION || '1.0.0' }}
IMAGE_REGISTRY: ${{ github.event.inputs.IMAGE_VERSION || 'github' }}
IMAGE_GHCR_AUTHOR: ${{ github.event.inputs.IMAGE_GHCR_AUTHOR || 'BinaryNinja' }} IMAGE_GHCR_AUTHOR: ${{ github.event.inputs.IMAGE_GHCR_AUTHOR || 'BinaryNinja' }}
IMAGE_GHCR_USERNAME: ${{ github.event.inputs.IMAGE_GHCR_USERNAME || 'BinaryNinja' }} IMAGE_GHCR_USERNAME: ${{ github.event.inputs.IMAGE_GHCR_USERNAME || 'BinaryNinja' }}
IMAGE_ALPINE_VERSION: ${{ github.event.inputs.IMAGE_ALPINE_VERSION || '3.21' }}
BOT_NAME_1: EuropaServ BOT_NAME_1: EuropaServ
BOT_NAME_2: BinaryServ BOT_NAME_2: BinaryServ
@@ -277,6 +306,7 @@ jobs:
echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV # 02-25-2025 12:49 echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV # 02-25-2025 12:49
echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV # 20250225 echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV # 20250225
echo "NOW_DOCKER_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z echo "NOW_DOCKER_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z
echo "GITHUB_SHA1=$(git rev-parse HEAD)" >> $GITHUB_ENV # 012cd0cc44c576c4a57b8a18d86793f244d1080a
# # # #
# Release Github Install Dependencies # Release Github Install Dependencies
@@ -410,6 +440,7 @@ jobs:
flavor: | flavor: |
latest=false latest=false
labels: | labels: |
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -417,9 +448,13 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=github org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
annotations: | org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }} org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }} org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT org.opencontainers.image.licenses=MIT
@@ -427,8 +462,11 @@ jobs:
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }} org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }} org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=github org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}" org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Github Build and Push Amd64 # Release Github Build and Push Amd64
@@ -440,24 +478,40 @@ jobs:
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' ) if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with: with:
allow: | allow: |
network.host network.host
network: host network: host
context: . context: .
file: Dockerfile file: Dockerfile
platforms: linux/amd64 platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_gh_meta.outputs.labels }} labels: ${{ steps.task_release_gh_meta.outputs.labels }}
tags: |
${{ steps.task_release_gh_meta.outputs.tags }}
annotations: |
${{ steps.task_release_gh_meta.outputs.annotations }}
provenance: false provenance: false
sbom: false sbom: false
tags: |
${{ steps.task_release_gh_meta.outputs.tags }}
build-args: |- build-args: |-
ARCH=amd64 ARCH=amd64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }} RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }} VERSION=${{ env.IMAGE_VERSION }}
BUILDDATE=${{ env.NOW_DOCKER_LABEL }} BUILDDATE=${{ env.NOW_DOCKER_LABEL }}
GIT_SHA1=${{ env.GITHUB_SHA1 }}
ALPINE_VERSION=${{ env.IMAGE_ALPINE_VERSION }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
org.opencontainers.image.architecture=amd64
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-architecture=amd64
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Github Export Digest Amd64 # Release Github Export Digest Amd64
@@ -497,24 +551,40 @@ jobs:
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' ) if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with: with:
allow: | allow: |
network.host network.host
network: host network: host
context: . context: .
file: Dockerfile file: Dockerfile
platforms: linux/arm64 platforms: linux/arm64
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_gh_meta.outputs.labels }} labels: ${{ steps.task_release_gh_meta.outputs.labels }}
tags: |
${{ steps.task_release_gh_meta.outputs.tags }}
annotations: |
${{ steps.task_release_gh_meta.outputs.annotations }}
provenance: false provenance: false
sbom: false sbom: false
tags: |
${{ steps.task_release_gh_meta.outputs.tags }}
build-args: |- build-args: |-
ARCH=arm64 ARCH=arm64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }} RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }} VERSION=${{ env.IMAGE_VERSION }}
BUILDDATE=${{ env.NOW_DOCKER_LABEL }} BUILDDATE=${{ env.NOW_DOCKER_LABEL }}
GIT_SHA1=${{ env.GITHUB_SHA1 }}
ALPINE_VERSION=${{ env.IMAGE_ALPINE_VERSION }}
annotations: |-
org.opencontainers.image.description=TVApp2
org.opencontainers.image.created=${{ env.NOW_DOCKER_TS }}
org.opencontainers.image.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
org.opencontainers.image.architecture=arm64
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.vendor=${{ env.REGISTRY_REPO_AUTHOR_LC }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
org.opencontainers.image.development=${{ inputs.DEV_RELEASE == true && 'true' || 'false' }}
org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
org.tvapp2.image.build-version="Version:- ${{ env.IMAGE_VERSION }} Date:- ${{ env.NOW_DOCKER_LABEL }}"
org.tvapp2.image.build-version-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-architecture=arm64
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# # # #
# Release Github Export Digest Arm64 # Release Github Export Digest Arm64
@@ -544,6 +614,63 @@ jobs:
if-no-files-found: error if-no-files-found: error
retention-days: 10 retention-days: 10
# #
# Release Github Checkpoint
# #
- name: '⚠️ Checkpoint'
id: task_release_gh_checkpoint
run: |
echo ""
echo "---- [ GITHUB ] ----------------------------------------------------------------------------------------"
echo "github.actor.............................. ${{ github.actor }}"
echo "github.ref ............................... ${{ github.ref }}"
echo "github.ref_name .......................... ${{ github.ref_name }}"
echo "github.event_name ........................ ${{ github.event_name }}"
echo "github.repository_owner .................. ${{ github.repository_owner }}"
echo "github.repository ........................ ${{ github.repository }}"
echo "github.sha ............................... ${{ github.sha }}"
echo -e ""
echo "---- [ INPUTS ] ----------------------------------------------------------------------------------------"
echo "inputs.IMAGE_NAME ........................ ${{ inputs.IMAGE_NAME }}"
echo "inputs.IMAGE_VERSION ..................... ${{ inputs.IMAGE_VERSION }}"
echo "inputs.IMAGE_GHCR_AUTHOR ................. ${{ inputs.IMAGE_GHCR_AUTHOR }}"
echo "inputs.IMAGE_GHCR_USERNAME ............... ${{ inputs.IMAGE_GHCR_USERNAME }}"
echo "inputs.DEV_RELEASE ....................... ${{ inputs.DEV_RELEASE }}"
echo "inputs.DRY_RUN ........................... ${{ inputs.DRY_RUN }}"
echo -e ""
echo "---- [ ENV ] -------------------------------------------------------------------------------------------"
echo "env.IMAGE_NAME ........................... ${{ env.IMAGE_NAME }}"
echo "env.IMAGE_VERSION ........................ ${{ env.IMAGE_VERSION }}"
echo "env.IMAGE_VERSION_1DIGIT ................. ${{ env.IMAGE_VERSION_1DIGIT }}"
echo "env.IMAGE_VERSION_2DIGIT ................. ${{ env.IMAGE_VERSION_2DIGIT }}"
echo "env.IMAGE_GHCR_AUTHOR .................... ${{ env.IMAGE_GHCR_AUTHOR }}"
echo "env.IMAGE_GHCR_USERNAME .................. ${{ env.IMAGE_GHCR_USERNAME }}"
echo "env.NOW .................................. ${{ env.NOW }}"
echo "env.NOW_SHORT ............................ ${{ env.NOW_SHORT }}"
echo "env.NOW_LONG ............................. ${{ env.NOW_LONG }}"
echo "env.NOW_DOCKER_LABEL ..................... ${{ env.NOW_DOCKER_LABEL }}"
echo "env.NOW_DOCKER_TS ........................ ${{ env.NOW_DOCKER_TS }}"
echo "env.REGISTRY_REPO_ORG_AUTHOR_LC .......... ${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}"
echo "env.REGISTRY_REPO_AUTHOR_LC .............. ${{ env.REGISTRY_REPO_AUTHOR_LC }}"
echo "env.DOCKER_SHA ........................... ${{ env.DOCKER_SHA }}"
echo "env.GITHUB_SHA1 .......................... ${{ env.GITHUB_SHA1 }}"
echo -e ""
echo "---- [ DOCKER IMAGES ] ---------------------------------------------------------------------------------"
echo "registry ................................. Github GHCR"
echo "tags ..................................... ${{ steps.task_release_gh_meta.outputs.tags }}"
echo "labels ................................... ${{ steps.task_release_gh_meta.outputs.labels }}"
echo "digest ................................... ${{ steps.task_release_gh_push_amd64.outputs.digest }}"
echo -e ""
echo "(release) tags ........................... ${{ steps.task_release_gh_meta.outputs.tags }}"
echo "(release) labels ......................... ${{ steps.task_release_gh_meta.outputs.labels }}"
echo -e ""
echo "---- [ DOCKER DIGESTS ] --------------------------------------------------------------------------------"
echo "docker image id (amd64) .................. ${{ steps.task_release_gh_push_amd64.outputs.imageid }}"
echo "docker digest (amd64) .................... ${{ steps.task_release_gh_push_amd64.outputs.digest }}"
echo "docker image id (arm64) .................. ${{ steps.task_release_gh_push_arm64.outputs.imageid }}"
echo "docker digest (arm64) .................... ${{ steps.task_release_gh_push_arm64.outputs.digest }}"
# # # #
# Release Github Push Manifest # Release Github Push Manifest
# # # #
@@ -561,62 +688,6 @@ jobs:
index-annotations: | index-annotations: |
${{ steps.task_release_gh_meta.outputs.labels }} ${{ steps.task_release_gh_meta.outputs.labels }}
# #
# Release Github Checkpoint
# #
- name: '⚠️ Checkpoint'
id: task_release_gh_checkpoint
run: |
echo ""
echo "[ GITHUB ] ---------------------------------------------------------------------------------------------"
echo "github.actor.............................. ${{ github.actor }}"
echo "github.ref ............................... ${{ github.ref }}"
echo "github.ref_name .......................... ${{ github.ref_name }}"
echo "github.event_name ........................ ${{ github.event_name }}"
echo "github.repository_owner .................. ${{ github.repository_owner }}"
echo "github.repository ........................ ${{ github.repository }}"
echo ""
echo "[ INPUTS ] ---------------------------------------------------------------------------------------------"
echo "inputs.IMAGE_NAME ........................ ${{ inputs.IMAGE_NAME }}"
echo "inputs.IMAGE_VERSION ..................... ${{ inputs.IMAGE_VERSION }}"
echo "inputs.IMAGE_GHCR_AUTHOR ................. ${{ inputs.IMAGE_GHCR_AUTHOR }}"
echo "inputs.IMAGE_GHCR_USERNAME ............... ${{ inputs.IMAGE_GHCR_USERNAME }}"
echo "inputs.DEV_RELEASE ....................... ${{ inputs.DEV_RELEASE }}"
echo "inputs.DRY_RUN ........................... ${{ inputs.DRY_RUN }}"
echo ""
echo "[ ENV ] ------------------------------------------------------------------------------------------------"
echo "env.IMAGE_NAME ........................... ${{ env.IMAGE_NAME }}"
echo "env.IMAGE_VERSION ........................ ${{ env.IMAGE_VERSION }}"
echo "env.IMAGE_VERSION_1DIGIT ................. ${{ env.IMAGE_VERSION_1DIGIT }}"
echo "env.IMAGE_VERSION_2DIGIT ................. ${{ env.IMAGE_VERSION_2DIGIT }}"
echo "env.IMAGE_GHCR_AUTHOR .................... ${{ env.IMAGE_GHCR_AUTHOR }}"
echo "env.IMAGE_GHCR_USERNAME .................. ${{ env.IMAGE_GHCR_USERNAME }}"
echo "env.NOW .................................. ${{ env.NOW }}"
echo "env.NOW_SHORT ............................ ${{ env.NOW_SHORT }}"
echo "env.NOW_LONG ............................. ${{ env.NOW_LONG }}"
echo "env.NOW_DOCKER_LABEL ..................... ${{ env.NOW_DOCKER_LABEL }}"
echo "env.NOW_DOCKER_TS ........................ ${{ env.NOW_DOCKER_TS }}"
echo "env.DOCKER_IMAGE ......................... ${{ env.DOCKER_IMAGE }}"
echo "env.REGISTRY_REPO_ORG_AUTHOR_LC .......... ${{ env.REGISTRY_REPO_ORG_AUTHOR_LC }}"
echo "env.REGISTRY_REPO_AUTHOR_LC .............. ${{ env.REGISTRY_REPO_AUTHOR_LC }}"
echo "env.DOCKER_SHA ........................... ${{ env.DOCKER_SHA }}"
echo ""
echo "[ DOCKER IMAGES ] --------------------------------------------------------------------------------------"
echo "registry ................................. Github GHCR"
echo "tags ..................................... ${{ steps.task_release_gh_meta.outputs.tags }}"
echo "labels ................................... ${{ steps.task_release_gh_meta.outputs.labels }}"
echo "digest ................................... ${{ steps.task_release_gh_push_amd64.outputs.digest }}"
echo ""
echo "(release) tags ........................... ${{ steps.task_release_gh_meta.outputs.tags }}"
echo "(release) labels ......................... ${{ steps.task_release_gh_meta.outputs.labels }}"
echo ""
echo "[ DOCKER DIGESTS ] -------------------------------------------------------------------------------------"
echo "docker image id (amd64) .................. ${{ steps.task_release_gh_push_amd64.outputs.imageid }}"
echo "docker digest (amd64) .................... ${{ steps.task_release_gh_push_amd64.outputs.digest }}"
echo "docker image id (arm64) .................. ${{ steps.task_release_gh_push_arm64.outputs.imageid }}"
echo "docker digest (arm64) .................... ${{ steps.task_release_gh_push_arm64.outputs.digest }}"
# # # #
# Release Github Get Weekly Commits # Release Github Get Weekly Commits
# # # #

View File

@@ -77,23 +77,23 @@ on:
type: boolean type: boolean
# # # #
# ENABLE: released version will be marked as pre-release # true released version will be marked as a development build and will have the v1.x.x-development tag instead of -latest
# DISABLE: release version will be marked as stable / normal release # false release version will be marked with -latest docker tag
# # # #
PRERELEASE: RC_RELEASE:
description: '🧪 Build RC (Pre-release)' description: '🧪 Build RC (Pre-release)'
required: true required: true
default: false default: false
type: boolean type: boolean
# # # #
# Release Candidate version number # only needed if env variable `RC_ONLY` = true
# this will be added to the end of your released app in the releases page. # sets the version number for the release candidate
# e.g: tvapp2-v1.0.0-rc.1 # e.g: noxenv-v1.0.0-rc.1
# # # #
VERSION_RC: RC_VERSION:
description: '🧪 RC (Pre-release) Ver (tvapp2-rc.v1)' description: '🧪 RC (Pre-release) Ver (tvapp2-rc.v1)'
required: false required: false
type: string type: string
@@ -105,15 +105,17 @@ on:
env: env:
PROJECT_NAME: ${{ github.event.inputs.PROJECT_NAME || 'tvapp2' }} PROJECT_NAME: ${{ github.event.inputs.PROJECT_NAME || 'tvapp2' }}
CHANGELOG_MODE_COMMIT: true CHANGELOG_MODE_COMMIT: ${{ github.event.inputs.CHANGELOG_MODE_COMMIT || true }}
SHOW_UNCATEGORIZED: false SHOW_UNCATEGORIZED: ${{ github.event.inputs.SHOW_UNCATEGORIZED || false }}
PRERELEASE: false RC_RELEASE: ${{ github.event.inputs.RC_RELEASE || false }}
VERSION_RC: '1' RC_VERSION: ${{ github.event.inputs.RC_VERSION || '1' }}
ASSIGN_USER: Aetherinox ASSIGN_USER: Aetherinox
BOT_NAME_1: EuropaServ BOT_NAME_1: EuropaServ
BOT_NAME_2: BinaryServ BOT_NAME_2: BinaryServ
BOT_NAME_DEPENDABOT: dependabot[bot] BOT_NAME_DEPENDABOT: dependabot[bot]
BOT_NAME_RENOVATE: renovate[bot] BOT_NAME_RENOVATE: renovate[bot]
GPG_KEY_BASE64: ${{ secrets.ADMINSERV_GPG_KEY_B64 }}
GPG_KEY_PASSPHRASE: ${{ secrets.ADMINSERV_GPG_PASSPHRASE }}
# # # #
# Jobs # Jobs
@@ -207,6 +209,20 @@ jobs:
packages: write packages: write
steps: steps:
# #
# Release Set Env Variables
# #
- name: >-
🕛 Get Timestamp
id: task_release_label_set_timestamp
run: |
echo "YEAR=$(date +'%Y')" >> $GITHUB_ENV
echo "NOW=$(date +'%m-%d-%Y %H:%M:%S')" >> $GITHUB_ENV
echo "NOW_SHORT=$(date +'%m-%d-%Y')" >> $GITHUB_ENV
echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV
echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV
# # # #
# Release Checkout # Release Checkout
# # # #
@@ -218,17 +234,22 @@ jobs:
fetch-depth: 0 fetch-depth: 0
# # # #
# Release Set Env Variables # Release Start
# # # #
- name: >- - name: >-
🕛 Get Timestamp ✅ Start
id: task_release_label_set_timestamp id: task_release_start
run: | run: |
echo "NOW=$(date +'%m-%d-%Y %H:%M:%S')" >> $GITHUB_ENV echo "―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――"
echo "NOW_SHORT=$(date +'%m-%d-%Y')" >> $GITHUB_ENV echo " Starting Documentation Build script"
echo "NOW_LONG=$(date +'%m-%d-%Y %H:%M')" >> $GITHUB_ENV echo " Runner .............. ${{ runner.name }}"
echo "NOW_DOCKER_LABEL=$(date +'%Y%m%d')" >> $GITHUB_ENV echo " Workflow ............ ${{ github.workflow }} (#${{ github.workflow_ref }})"
echo " Run Number .......... #${{ github.run_number }}"
echo " Run ID .............. https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
echo " Triggered By ........ ${{ github.actor }}"
echo " Time ................ ${{ env.NOW_LONG }}"
echo "―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――"
# # # #
# Release Print Version Debug # Release Print Version Debug
@@ -288,15 +309,17 @@ jobs:
# Release Build Stable # Release Build Stable
# # # #
- name: '🔨 Build Stable ( ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip )' - name: '🔨 Build Stable ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip'
id: task_release_build_st id: task_release_build_st
if: ${{ startsWith( inputs.PRERELEASE, false ) }} if: |
startsWith( inputs.RC_RELEASE, false ) ||
startsWith( env.RC_RELEASE, false )
run: | run: |
echo Building STABLE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip echo Building STABLE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip Dockerfile Dockerfile.aarch64 docker-compose.yml docker-entrypoint.sh root/ tvapp2/package.json README.md LICENSE zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip Dockerfile Dockerfile.aarch64 docker-compose.yml docker-entrypoint.sh root/ tvapp2/package.json README.md LICENSE
echo Building STABLE Package ${{ env.PROJECT_NAME }}-v${{ env.PACKAGE_VERSION }}-docker-compose.zip echo Building STABLE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-docker-compose.zip
zip -r ${{ env.PROJECT_NAME }}-v${{ env.PACKAGE_VERSION }}-docker-compose.zip docker-compose.yml README.md LICENSE zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-docker-compose.zip docker-compose.yml README.md LICENSE
env: env:
NODE_AUTH_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }} NODE_AUTH_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }}
@@ -304,15 +327,17 @@ jobs:
# Release Build Release Candidate # Release Build Release Candidate
# # # #
- name: '🔨 Build RC ( ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip )' - name: '🔨 Build Release Candidate ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip'
id: task_release_build_rc id: task_release_build_rc
if: ${{ startsWith( inputs.PRERELEASE, true ) }} if: |
startsWith( inputs.RC_RELEASE, true ) ||
startsWith( env.RC_RELEASE, true )
run: | run: |
echo Building PRE-RELEASE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip echo Building PRE-RELEASE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip
zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip Dockerfile Dockerfile.aarch64 docker-compose.yml docker-entrypoint.sh root/ tvapp2/package.json README.md LICENSE zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip Dockerfile Dockerfile.aarch64 docker-compose.yml docker-entrypoint.sh root/ tvapp2/package.json README.md LICENSE
echo Building PRE-RELEASE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}-docker-compose.zip echo Building PRE-RELEASE Package ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}-docker-compose.zip
zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}-docker-compose.zip docker-compose.yml README.md LICENSE zip -r ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}-docker-compose.zip docker-compose.yml README.md LICENSE
env: env:
NODE_AUTH_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }} NODE_AUTH_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }}
@@ -346,21 +371,46 @@ jobs:
echo "Tag already present: ${{ env.TAG_EXISTS }}" echo "Tag already present: ${{ env.TAG_EXISTS }}"
echo "Tag already present: ${{ steps.task_release_tag_create.outputs.tag_exists }}" echo "Tag already present: ${{ steps.task_release_tag_create.outputs.tag_exists }}"
# #
# Release GPG Import Key (No Passphrase)
#
# requires your GPG private key, converted to base64 binary .gpg (not armored .asc)
# #
- name: '🪪 GPG Import Signing Key W/o Passphrase'
id: task_release_gpg_import_nopass
if: env.GPG_KEY_BASE64 != '' && env.GPG_KEY_PASSPHRASE == ''
run: |
echo $GPG_KEY_BASE64 | base64 -di | gpg --import
# #
# Release GPG Import Key (With Passphrase)
#
# requires your GPG private key, converted to base64 binary .gpg (not armored .asc)
# #
- name: '🪪 GPG Import Signing Key w/ Passphrase'
id: task_release_gpg_import_withpass
if: env.GPG_KEY_BASE64 != '' && env.GPG_KEY_PASSPHRASE != ''
run: |
echo "$GPG_KEY_BASE64" | base64 -di > /tmp/signing-key.gpg
echo "$GPG_KEY_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --import /tmp/signing-key.gpg
(echo "$GPG_KEY_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1)
# # # #
# Release Checksum Stable # Release Checksum Stable
# # # #
- name: '🆔 Checksum Stable' - name: '🆔 Checksum Stable'
id: task_release_checksum_st_set id: task_release_checksum_st_set
if: ${{ startsWith( inputs.PRERELEASE, false ) }} if: |
startsWith( inputs.RC_RELEASE, false ) ||
startsWith( env.RC_RELEASE, false )
run: | run: |
filename_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip" filename_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip"
# import gpg key (base64)
echo '${{ secrets.ADMINSERV_GPG_KEY_B64 }}' | base64 -d | gpg --import
# get sha1 and sha256 for .zip and .gz files # 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 sha1sum | gpg --digest-algo sha256 --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 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 # get sha1sum; assign to variable
@@ -379,28 +429,44 @@ jobs:
sha256sum_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 echo "FILE_COMPOSE_ZIP=${filename_compose_zip}" >> $GITHUB_ENV
gpg --batch --yes --quiet --armor --detach-sig --sign --output sha256sum.sig sha256sum.txt.asc
gpg --batch --yes --quiet --armor --detach-sig --sign --output sha1sum.sig sha1sum.txt.asc
# # # #
# Release Checksum Release Candidate # Release Checksum Release Candidate
# # # #
- name: '🆔 Checksum RC' - name: '🆔 Checksum Release Candidate'
id: task_release_checksum_rc_set id: task_release_checksum_rc_set
if: ${{ startsWith( inputs.PRERELEASE, true ) }} if: |
startsWith( inputs.RC_RELEASE, true ) ||
startsWith( env.RC_RELEASE, true )
run: | run: |
# get filename filename_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip"
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 # get sha1 and sha256 for .zip and .gz files
shasum --algorithm 256 ${filename_zip} > SHA256SUMS.txt find . -maxdepth 1 \( -name '*.zip' -o -name '*.gz' \) -printf '%P\n' | xargs -r sha1sum | gpg --digest-algo sha256 --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 "FILE_ZIP=${filename_zip}" >> $GITHUB_ENV
echo "SHA256SUM=${sha256}" >> $GITHUB_ENV
filename_compose_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}-docker-compose.zip" filename_compose_zip="${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}-docker-compose.zip"
sha256_compose="$(shasum --algorithm 256 ${filename_compose_zip} | awk '{ print $1 }')" sha256_compose="$(shasum --algorithm 256 ${filename_compose_zip} | awk '{ print $1 }')"
echo "FILE_COMPOSE_ZIP=${filename_compose_zip}" >> $GITHUB_ENV echo "FILE_COMPOSE_ZIP=${filename_compose_zip}" >> $GITHUB_ENV
gpg --batch --yes --quiet --armor --detach-sig --sign --output sha256sum.sig sha256sum.txt.asc
gpg --batch --yes --quiet --armor --detach-sig --sign --output sha1sum.sig sha1sum.txt.asc
# # # #
# Release Checksum Print # Release Checksum Print
# # # #
@@ -423,31 +489,13 @@ jobs:
avatarSize: 42 avatarSize: 42
# # # #
# Release Checksum Add (Stable) # Release Changelog Generate Tags
# # #
# generates a changelog from the github api. requires a PREVIOUS_TAG in order to figure
- name: '📦 Zip Add Checksum Stable' # out the changes made between the two versions.
id: task_release_zip_st #
if: ${{ startsWith( inputs.PRERELEASE, false ) }} # outputs:
run: | # ${{ steps.changelog.outputs.changelog }}
echo Zipping STABLE Package .zip ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
zip -jr ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip sha1sum.txt.asc sha256sum.txt.asc
ls
# #
# Release Checksum Add (Release Candidate)
# #
- name: '📦 Zip Add Checksum RC'
id: task_release_zip_rc
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 sha1sum.txt.asc sha256sum.txt.asc
ls
# #
# Release Generate Tags
# # # #
- name: '📝 Changelog Pre Setup (Categorized Commits)' - name: '📝 Changelog Pre Setup (Categorized Commits)'
@@ -562,14 +610,56 @@ jobs:
echo "$CHANGELOG_UNCATEGORIZED" echo "$CHANGELOG_UNCATEGORIZED"
# # # #
# Release List Tree # Release Verbose List Tree
# # # #
- name: '⚙️ Debug Tree Listing' - name: '⚙️ Verbose Tree Listing'
id: task_release_debug_tree id: task_release_verbose_tree
run: | run: |
tree tree
# #
# Release Verbose Changelog Print Categorized
# #
- name: '⚙️ Verbose Changelog Categorized'
id: task_release_changelog_verbose_categorized
if: |
startsWith( inputs.SHOW_UNCATEGORIZED, false ) ||
startsWith( env.SHOW_UNCATEGORIZED, false )
env:
CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
run: |
echo
echo "---- CHANGELOG [ Categorized ] -----------------------------------------------"
echo
echo "$CHANGELOG_CATEGORIZED"
echo
echo "---- CHANGELOG ---------------------------------------------------------------"
echo
# #
# Release Verbose Changelog Print Uncategorized
# #
- name: '⚙️ Verbose Changelog Uncategorized'
id: task_release_changelog_verbose_uncategorized
if: |
startsWith( inputs.SHOW_UNCATEGORIZED, true ) ||
startsWith( env.SHOW_UNCATEGORIZED, true )
env:
CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
run: |
echo
echo "---- CHANGELOG [ Uncategorized ] ---------------------------------------------"
echo
echo "$CHANGELOG_UNCATEGORIZED"
echo
echo "---- CHANGELOG ---------------------------------------------------------------"
echo
# # # #
# Release Post Release (Stable) # Release Post Release (Stable)
# #
@@ -582,10 +672,12 @@ jobs:
- name: '🏳️ Post Stable' - name: '🏳️ Post Stable'
id: task_release_bundle_st id: task_release_bundle_st
if: | if: |
startsWith( inputs.PRERELEASE, false ) || startsWith( inputs.RC_RELEASE, false ) ||
startsWith( env.PRERELEASE, false ) startsWith( env.RC_RELEASE, false )
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2.2.2
env: env:
CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
GITHUB_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }} GITHUB_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }}
with: with:
token: ${{ secrets.ADMINSERV_TOKEN_CL }} token: ${{ secrets.ADMINSERV_TOKEN_CL }}
@@ -595,10 +687,12 @@ jobs:
draft: false draft: false
generate_release_notes: false generate_release_notes: false
files: | files: |
${{ env.PROJECT_NAME }}-v${{ env.PACKAGE_VERSION }}-docker-compose.zip ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-docker-compose.zip
${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
sha1sum.txt.asc sha1sum.txt.asc
sha256sum.txt.asc sha256sum.txt.asc
sha256sum.sig
sha1sum.sig
prerelease: false prerelease: false
body: | body: |
${{ steps.task_release_changelog_categorized.outputs.changelog }} ${{ steps.task_release_changelog_categorized.outputs.changelog }}
@@ -613,14 +707,16 @@ jobs:
# ${{ steps.task_release_bundle_st.outputs.id # ${{ steps.task_release_bundle_st.outputs.id
# # # #
- name: "🏳️ Post Release Candidate" - name: '🏳️ Post Release Candidate'
id: task_release_bundle_rc id: task_release_bundle_rc
if: | if: |
startsWith( inputs.PRERELEASE, true ) || startsWith( inputs.RC_RELEASE, true ) ||
startsWith( env.PRERELEASE, true ) startsWith( env.RC_RELEASE, true )
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2.2.2
env: env:
GITHUB_TOKEN: ${{ secrets.ADMINSERV_TOKEN }} CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
GITHUB_TOKEN: ${{ secrets.ADMINSERV_TOKEN_CL }}
with: with:
token: ${{ secrets.ADMINSERV_TOKEN }} token: ${{ secrets.ADMINSERV_TOKEN }}
name: v${{ env.PACKAGE_VERSION }} name: v${{ env.PACKAGE_VERSION }}
@@ -629,10 +725,12 @@ jobs:
draft: false draft: false
generate_release_notes: false generate_release_notes: false
files: | files: |
${{ env.PROJECT_NAME }}-v${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}-docker-compose.zip ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}-docker-compose.zip
${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.VERSION_RC }}.zip ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip
sha1sum.txt.asc sha1sum.txt.asc
sha256sum.txt.asc sha256sum.txt.asc
sha256sum.sig
sha1sum.sig
prerelease: false prerelease: false
body: | body: |
> [!WARNING] > [!WARNING]
@@ -676,19 +774,37 @@ jobs:
echo "---- CHANGELOG ---------------------------------------------------------------" echo "---- CHANGELOG ---------------------------------------------------------------"
# # # #
# Release Upload Artifacts Release Files # Release Upload Artifacts Release Files Stable
# # # #
- name: >- - name: >-
📋 Upload Artifacts ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip 📋 Upload Artifacts Stable ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
id: task_release_artifact id: task_release_artifact_stable
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
if: always() if: |
startsWith( inputs.RC_RELEASE, false ) ||
startsWith( env.RC_RELEASE, false )
with: with:
name: "${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}" name: "${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}"
path: ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip path: ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
retention-days: 30 retention-days: 30
# #
# Release Upload Artifacts Release Files Release Candidate
# #
- name: >-
📋 Upload Artifacts RC ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
id: task_release_artifact_rc
uses: actions/upload-artifact@v4
if: |
startsWith( inputs.RC_RELEASE, true ) ||
startsWith( env.RC_RELEASE, true )
with:
name: "${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}"
path: ${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip
retention-days: 30
# # # #
# Job Complete # Job Complete
# # # #

View File

@@ -57,6 +57,8 @@ ARG ALPINE_VERSION=3.21
ARG BUILDDATE ARG BUILDDATE
ARG VERSION ARG VERSION
ARG RELEASE ARG RELEASE
ARG GIT_SHA1=0000000000000000000000000000000000000000
ARG REGISTRY=local
# # # #
# Set Labels # Set Labels
@@ -73,15 +75,16 @@ LABEL org.opencontainers.image.repo.3="https://github.com/aetherinox/docker-base
LABEL org.opencontainers.image.documentation="https://thebinaryninja.github.io/tvapp2" LABEL org.opencontainers.image.documentation="https://thebinaryninja.github.io/tvapp2"
LABEL org.opencontainers.image.url="https://github.com/thebinaryninja/tvapp2/pkgs/container/tvapp2" LABEL org.opencontainers.image.url="https://github.com/thebinaryninja/tvapp2/pkgs/container/tvapp2"
LABEL org.opencontainers.image.licenses="MIT" LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.architecture="${ARCH}" LABEL org.opencontainers.image.architecture="${ARCH:-amd64}"
LABEL org.opencontainers.image.ref.name="main" LABEL org.opencontainers.image.ref.name="main"
LABEL org.opencontainers.image.registry="local" LABEL org.opencontainers.image.registry="${REGISTRY:-local}"
LABEL org.opencontainers.image.release="${RELEASE}" LABEL org.opencontainers.image.release="${RELEASE:-stable}"
LABEL org.tvapp2.image.maintainers="Aetherinox, iFlip721, Optx" LABEL org.tvapp2.image.maintainers="Aetherinox, iFlip721, Optx"
LABEL org.tvapp2.image.build-version="Version:- ${VERSION} Date:- ${BUILDDATE}" LABEL org.tvapp2.image.build-version="Version:- ${VERSION} Date:- ${BUILDDATE:-3.21}"
LABEL org.tvapp2.image.build-version-alpine="${ALPINE_VERSION}" LABEL org.tvapp2.image.build-version-alpine="${ALPINE_VERSION:-3.21}"
LABEL org.tvapp2.image.build-architecture="${ARCH}" LABEL org.tvapp2.image.build-architecture="${ARCH:-amd64}"
LABEL org.tvapp2.image.build-release="${RELEASE}" LABEL org.tvapp2.image.build-release="${RELEASE:-stable}"
LABEL org.tvapp2.image.build-sha1="${GIT_SHA1:-0000000000000000000000000000000000000000}"
# # # #
# Set Env Var # Set Env Var
@@ -89,7 +92,7 @@ LABEL org.tvapp2.image.build-release="${RELEASE}"
ENV NODE_VERSION=22.8.0 ENV NODE_VERSION=22.8.0
ENV YARN_VERSION=1.22.22 ENV YARN_VERSION=1.22.22
ENV RELEASE="${RELEASE}" ENV RELEASE="${RELEASE:-stable}"
ENV DIR_BUILD=/usr/src/app ENV DIR_BUILD=/usr/src/app
ENV DIR_RUN=/usr/bin/app ENV DIR_RUN=/usr/bin/app
ENV URL_REPO="https://git.binaryninja.net/binaryninja/" ENV URL_REPO="https://git.binaryninja.net/binaryninja/"
@@ -106,6 +109,7 @@ ENV HEALTH_TIMER=600000
ENV TASK_CRON_SYNC="0 0 */3 * *" ENV TASK_CRON_SYNC="0 0 */3 * *"
ENV LOG_LEVEL=4 ENV LOG_LEVEL=4
ENV TZ="Etc/UTC" ENV TZ="Etc/UTC"
ENV GIT_SHA1=${GIT_SHA1:-0000000000000000000000000000000000000000}
# # # #
# Install # Install
@@ -117,6 +121,7 @@ RUN \
curl \ curl \
bash \ bash \
nano \ nano \
git \
npm \ npm \
openssl openssl

111
README.md
View File

@@ -7,7 +7,7 @@
<div align="center"> <div align="center">
<img src="docs/img/screenshots/01.png" height="320"> <img src="docs/img/screenshots/01.gif" height="450">
<br /> <br />
<br /> <br />
@@ -154,13 +154,34 @@ For the [environment variables](#environment-variables), you may specify these i
#### Environment Variables #### Environment Variables
The following is a list of environment variables you can declare within your `docker-compose.yml` or docker run command:
<br />
> [!CAUTION]
> Do **not** add `"` quotation marks to environment variables.
>
> ✔️ Correct
> ```yml
> environment:
> - TASK_CRON_SYNC=*/60 * * * *
> ```
>
> ❌ Incorrect
> ```yml
> environment:
> - TASK_CRON_SYNC="*/60 * * * *"
> ```
<br />
| Env Var | Default | Description | | Env Var | Default | Description |
| --- | --- | --- | | --- | --- | --- |
| `TZ` | `Etc/UTC` | Timezone for error / log reporting | | `TZ` | `Etc/UTC` | Timezone for error / log reporting |
| `WEB_IP` | `0.0.0.0` | IP to use for webserver | | `WEB_IP` | `0.0.0.0` | IP to use for webserver |
| `WEB_PORT` | `4124` | Port to use for webserver | | `WEB_PORT` | `4124` | Port to use for webserver |
| `WEB_FOLDER` | `www` | Internal container folder to keep TVApp2 web files in. <br /><br /> <sup>⚠️ This should not be used unless you know what you're doing</sup> | | `WEB_FOLDER` | `www` | Internal container folder to keep TVApp2 web files in. <br /><br /> <sup>⚠️ This should not be used unless you know what you're doing</sup> |
| `WEB_ENCODING` | `deflate, br` | Defines the HTTP `Accept-Encoding` request and response header. This value specifies what content encoding the sender can understand<br /><br />Gzip compression can be enabled by specifying `'gzip, deflate, br'` | | `WEB_ENCODING` | `deflate, br` | Defines the HTTP `Accept-Encoding` request and response header. This value specifies what content encoding the sender can understand<br /><br />Gzip compression can be enabled by specifying `'gzip, deflate, br'`, however, [it may break Jellyfin users](#build-error-err-27-jellyfinlivetvguideguidemanager-error-getting-programs-for-channel-xxxxxxxxxxxxxxx-source-2-systemxmlxmlexception--hexadecimal-value-0x1f-is-an-invalid-character-line-1-position-1). |
| `WEB_PROXY_HEADER` | `x-forwarded-for` | Defines the header to look for when finding a client's IP address. Used to get a client's IP when behind a reverse proxy or Cloudflare | | `WEB_PROXY_HEADER` | `x-forwarded-for` | Defines the header to look for when finding a client's IP address. Used to get a client's IP when behind a reverse proxy or Cloudflare |
| `URL_REPO` | `https://git.binaryninja.net/BinaryNinja/` | Determines where the data files will be downloaded from. Do not change this or you will be unable to get M3U and EPG data. | | `URL_REPO` | `https://git.binaryninja.net/BinaryNinja/` | Determines where the data files will be downloaded from. Do not change this or you will be unable to get M3U and EPG data. |
| `FILE_URL` | `urls.txt` | Filename for `urls.txt` cache file | | `FILE_URL` | `urls.txt` | Filename for `urls.txt` cache file |
@@ -368,7 +389,7 @@ This repository offers two types of docker image; `stable` and `development`. Yo
| Build | Tags | | Build | Tags |
| ------------------------- | ----------------------------------------------------------------------------- | | ------------------------- | ----------------------------------------------------------------------------- |
| `Stable` | `🔖 tvapp2:latest` <br /> `🔖 tvapp2:1.5.0` <br /> `🔖 tvapp2:1.5` <br /> `🔖 tvapp2:1` | | `Stable` | `🔖 tvapp2:latest` <br /> `🔖 tvapp2:1.5.2` <br /> `🔖 tvapp2:1.5` <br /> `🔖 tvapp2:1` |
| `Development` | `🔖 tvapp2:development` | | `Development` | `🔖 tvapp2:development` |
<br /> <br />
@@ -580,18 +601,19 @@ Creates the TVApp2 `amd64` docker image:
# Build tvapp2 amd64 # Build tvapp2 amd64
docker buildx build \ docker buildx build \
--build-arg ARCH=amd64 \ --build-arg ARCH=amd64 \
--build-arg VERSION=1.5.0 \ --build-arg VERSION=1.5.2 \
--build-arg BUILDDATE=20260812 \ --build-arg BUILDDATE=20260812 \
--build-arg RELEASE=stable \ --build-arg RELEASE=stable \
--tag ghcr.io/thebinaryninja/tvapp2:1.5.0 \ --tag ghcr.io/thebinaryninja/tvapp2:1.5.2 \
--tag ghcr.io/thebinaryninja/tvapp2:1.5 \ --tag ghcr.io/thebinaryninja/tvapp2:1.5 \
--tag ghcr.io/thebinaryninja/tvapp2:1 \ --tag ghcr.io/thebinaryninja/tvapp2:1 \
--tag ghcr.io/thebinaryninja/tvapp2:latest \ --tag ghcr.io/thebinaryninja/tvapp2:latest \
--attest type=provenance,disabled=true \ --attest type=provenance,disabled=true \
--attest type=sbom,disabled=true \ --attest type=sbom,disabled=true \
--output type=docker \
--builder default \
--file Dockerfile \ --file Dockerfile \
--platform linux/amd64 \ --platform linux/amd64 \
--output type=docker \
--allow network.host \ --allow network.host \
--network host \ --network host \
--no-cache \ --no-cache \
@@ -609,18 +631,19 @@ Creates the TVApp2 `arm64` docker image:
# Build tvapp2 arm64 # Build tvapp2 arm64
docker buildx build \ docker buildx build \
--build-arg ARCH=arm64 \ --build-arg ARCH=arm64 \
--build-arg VERSION=1.5.0 \ --build-arg VERSION=1.5.2 \
--build-arg BUILDDATE=20260812 \ --build-arg BUILDDATE=20260812 \
--build-arg RELEASE=stable \ --build-arg RELEASE=stable \
--tag ghcr.io/thebinaryninja/tvapp2:1.5.0 \ --tag ghcr.io/thebinaryninja/tvapp2:1.5.2 \
--tag ghcr.io/thebinaryninja/tvapp2:1.5 \ --tag ghcr.io/thebinaryninja/tvapp2:1.5 \
--tag ghcr.io/thebinaryninja/tvapp2:1 \ --tag ghcr.io/thebinaryninja/tvapp2:1 \
--tag ghcr.io/thebinaryninja/tvapp2:latest \ --tag ghcr.io/thebinaryninja/tvapp2:latest \
--attest type=provenance,disabled=true \ --attest type=provenance,disabled=true \
--attest type=sbom,disabled=true \ --attest type=sbom,disabled=true \
--output type=docker \
--builder default \
--file Dockerfile \ --file Dockerfile \
--platform linux/arm64 \ --platform linux/arm64 \
--output type=docker \
--allow network.host \ --allow network.host \
--network host \ --network host \
--no-cache \ --no-cache \
@@ -742,8 +765,8 @@ docker run --privileged --rm tonistiigi/binfmt --install all
Once the emulator is installed; we will now build two images. When building these two images; we will ensure the `--tag` value is different for each one, by adding the architecture to the end. This ensures we don't overwrite one image with the newer one. We need to have two seperate docker images with two different tags. Once the emulator is installed; we will now build two images. When building these two images; we will ensure the `--tag` value is different for each one, by adding the architecture to the end. This ensures we don't overwrite one image with the newer one. We need to have two seperate docker images with two different tags.
- `--tag ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64` - `--tag ghcr.io/thebinaryninja/tvapp2:1.5.2-amd64`
- `--tag ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64` - `--tag ghcr.io/thebinaryninja/tvapp2:1.5.2-arm64`
<br /> <br />
@@ -754,10 +777,10 @@ Once the emulator is installed; we will now build two images. When building thes
> >
> | Registry | Tag | > | Registry | Tag |
> | --- | --- | > | --- | --- |
> | Dockerhub | `--tag thebinaryninja/tvapp2:1.5.0-amd64`<br>`--tag thebinaryninja/tvapp2:1.5.0-arm64` | > | Dockerhub | `--tag thebinaryninja/tvapp2:1.5.2-amd64`<br>`--tag thebinaryninja/tvapp2:1.5.2-arm64` |
> | Github (GHCR) | `--tag ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64`<br>`--tag ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64` | > | Github (GHCR) | `--tag ghcr.io/thebinaryninja/tvapp2:1.5.2-amd64`<br>`--tag ghcr.io/thebinaryninja/tvapp2:1.5.2-arm64` |
> | Registry v2 | `--tag registry.domain.lan/thebinaryninja/tvapp2:1.5.0-amd64`<br>`--tag registry.domain.lan/thebinaryninja/tvapp2:1.5.0-arm64` | > | Registry v2 | `--tag registry.domain.lan/thebinaryninja/tvapp2:1.5.2-amd64`<br>`--tag registry.domain.lan/thebinaryninja/tvapp2:1.5.2-arm64` |
> | Gitea | `--tag git.binaryninja.net/binaryninja/tvapp2:1.5.0-amd64`<br>`--tag git.binaryninja.net/binaryninja/tvapp2:1.5.0-arm64` | > | Gitea | `--tag git.binaryninja.net/binaryninja/tvapp2:1.5.2-amd64`<br>`--tag git.binaryninja.net/binaryninja/tvapp2:1.5.2-arm64` |
<br /> <br />
@@ -778,15 +801,16 @@ Creates the TVApp2 **Stable** release `amd64` docker image:
# Build Tvapp2 amd64 - (stable release) # Build Tvapp2 amd64 - (stable release)
docker buildx build \ docker buildx build \
--build-arg ARCH=amd64 \ --build-arg ARCH=amd64 \
--build-arg VERSION=1.5.0 \ --build-arg VERSION=1.5.2 \
--build-arg BUILDDATE=20260812 \ --build-arg BUILDDATE=20260812 \
--build-arg RELEASE=stable \ --build-arg RELEASE=stable \
--tag ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64 \ --tag ghcr.io/thebinaryninja/tvapp2:1.5.2-amd64 \
--attest type=provenance,disabled=true \ --attest type=provenance,disabled=true \
--attest type=sbom,disabled=true \ --attest type=sbom,disabled=true \
--output type=docker \
--builder default \
--file Dockerfile \ --file Dockerfile \
--platform linux/amd64 \ --platform linux/amd64 \
--output type=docker \
--allow network.host \ --allow network.host \
--network host \ --network host \
--no-cache \ --no-cache \
@@ -805,15 +829,16 @@ Creates the TVApp2 **Stable** release `arm64` docker image:
# Build Tvapp2 arm64 - (stable release) # Build Tvapp2 arm64 - (stable release)
docker buildx build \ docker buildx build \
--build-arg ARCH=arm64 \ --build-arg ARCH=arm64 \
--build-arg VERSION=1.5.0 \ --build-arg VERSION=1.5.2 \
--build-arg BUILDDATE=20260812 \ --build-arg BUILDDATE=20260812 \
--build-arg RELEASE=stable \ --build-arg RELEASE=stable \
--tag ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64 \ --tag ghcr.io/thebinaryninja/tvapp2:1.5.2-arm64 \
--attest type=provenance,disabled=true \ --attest type=provenance,disabled=true \
--attest type=sbom,disabled=true \ --attest type=sbom,disabled=true \
--output type=docker \
--builder default \
--file Dockerfile \ --file Dockerfile \
--platform linux/arm64 \ --platform linux/arm64 \
--output type=docker \
--allow network.host \ --allow network.host \
--network host \ --network host \
--no-cache \ --no-cache \
@@ -832,15 +857,16 @@ Creates the TVApp2 **Development** release `amd64` docker image:
# Build Tvapp2 amd64 - (development release) # Build Tvapp2 amd64 - (development release)
docker buildx build \ docker buildx build \
--build-arg ARCH=amd64 \ --build-arg ARCH=amd64 \
--build-arg VERSION=1.5.0 \ --build-arg VERSION=1.5.2 \
--build-arg BUILDDATE=20260812 \ --build-arg BUILDDATE=20260812 \
--build-arg RELEASE=development \ --build-arg RELEASE=development \
--tag ghcr.io/thebinaryninja/tvapp2:development-amd64 \ --tag ghcr.io/thebinaryninja/tvapp2:development-amd64 \
--attest type=provenance,disabled=true \ --attest type=provenance,disabled=true \
--attest type=sbom,disabled=true \ --attest type=sbom,disabled=true \
--output type=docker \
--builder default \
--file Dockerfile \ --file Dockerfile \
--platform linux/amd64 \ --platform linux/amd64 \
--output type=docker \
--allow network.host \ --allow network.host \
--network host \ --network host \
--no-cache \ --no-cache \
@@ -859,15 +885,16 @@ Creates the TVApp2 **Development** release `arm64` docker image:
# Build Tvapp2 arm64 - (development release) # Build Tvapp2 arm64 - (development release)
docker buildx build \ docker buildx build \
--build-arg ARCH=arm64 \ --build-arg ARCH=arm64 \
--build-arg VERSION=1.5.0 \ --build-arg VERSION=1.5.2 \
--build-arg BUILDDATE=20260812 \ --build-arg BUILDDATE=20260812 \
--build-arg RELEASE=development \ --build-arg RELEASE=development \
--tag ghcr.io/thebinaryninja/tvapp2:development-arm64 \ --tag ghcr.io/thebinaryninja/tvapp2:development-arm64 \
--attest type=provenance,disabled=true \ --attest type=provenance,disabled=true \
--attest type=sbom,disabled=true \ --attest type=sbom,disabled=true \
--output type=docker \
--builder default \
--file Dockerfile \ --file Dockerfile \
--platform linux/arm64 \ --platform linux/arm64 \
--output type=docker \
--allow network.host \ --allow network.host \
--network host \ --network host \
--no-cache \ --no-cache \
@@ -880,8 +907,8 @@ docker buildx build \
After completing the `docker buildx` commands above; you should now have a few new images. Each image should have its own separate docker tags which do not conflict. If you decided to not build the **development** releases below; that is fine. After completing the `docker buildx` commands above; you should now have a few new images. Each image should have its own separate docker tags which do not conflict. If you decided to not build the **development** releases below; that is fine.
- `--tag ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64` - `--tag ghcr.io/thebinaryninja/tvapp2:1.5.2-amd64`
- `--tag ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64` - `--tag ghcr.io/thebinaryninja/tvapp2:1.5.2-arm64`
- `--tag ghcr.io/thebinaryninja/tvapp2:development-amd64` - `--tag ghcr.io/thebinaryninja/tvapp2:development-amd64`
- `--tag ghcr.io/thebinaryninja/tvapp2:development-arm64` - `--tag ghcr.io/thebinaryninja/tvapp2:development-arm64`
@@ -907,15 +934,15 @@ You can also get the hash digests by running the commands:
<br /> <br />
```shell ```shell
$ docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64 $ docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.2-amd64
Name: ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64 Name: ghcr.io/thebinaryninja/tvapp2:1.5.2-amd64
MediaType: application/vnd.docker.distribution.manifest.v2+json MediaType: application/vnd.docker.distribution.manifest.v2+json
Digest: sha256:0abe1b1c119959b3b1ccc23c56a7ee2c4c908c6aaef290d4ab2993859d807a3b Digest: sha256:0abe1b1c119959b3b1ccc23c56a7ee2c4c908c6aaef290d4ab2993859d807a3b
$ docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64 $ docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.2-arm64
Name: ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64 Name: ghcr.io/thebinaryninja/tvapp2:1.5.2-arm64
MediaType: application/vnd.docker.distribution.manifest.v2+json MediaType: application/vnd.docker.distribution.manifest.v2+json
Digest: sha256:e68b9de8669eac64d4e4d2a8343c56705e05e9a907cf0b542343f9b536d9c473 Digest: sha256:e68b9de8669eac64d4e4d2a8343c56705e05e9a907cf0b542343f9b536d9c473
``` ```
@@ -962,14 +989,14 @@ Digest: sha256:c719ccb034946e3f0625003f25026d001768794e38a1ba8aafc9146291d548
> ```shell > ```shell
> $ docker images --all --no-trunc | grep thebinaryninja > $ docker images --all --no-trunc | grep thebinaryninja
> >
> ghcr.io/thebinaryninja/tvapp2 1.5.0-arm64 sha256:48520ca15fed6483d2d5b79993126c311f833002345b0e12b8eceb5bf9def966 42 minutes ago 46MB > ghcr.io/thebinaryninja/tvapp2 1.5.2-arm64 sha256:48520ca15fed6483d2d5b79993126c311f833002345b0e12b8eceb5bf9def966 42 minutes ago 46MB
> >
> ghcr.io/thebinaryninja/tvapp2 1.5.0-amd64 sha256:54a9b7d390199532d5667fae67120d77e2f459bd6108b27ce94e0cfec8f3c41f 43 minutes ago 45MB > ghcr.io/thebinaryninja/tvapp2 1.5.2-amd64 sha256:54a9b7d390199532d5667fae67120d77e2f459bd6108b27ce94e0cfec8f3c41f 43 minutes ago 45MB
> ``` > ```
> >
> To get the correct sha256 digest, use: > To get the correct sha256 digest, use:
> - `docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64` > - `docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.2-amd64`
> - `docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64` > - `docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.2-arm64`
> - `docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:development-amd64` > - `docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:development-amd64`
> - `docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:development-arm64` > - `docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:development-arm64`
> >
@@ -989,7 +1016,7 @@ For the **stable** releases, use:
# # # #
docker buildx imagetools create \ docker buildx imagetools create \
--tag ghcr.io/thebinaryninja/tvapp2:1.5.0 \ --tag ghcr.io/thebinaryninja/tvapp2:1.5.2 \
--tag ghcr.io/thebinaryninja/tvapp2:1.5 \ --tag ghcr.io/thebinaryninja/tvapp2:1.5 \
--tag ghcr.io/thebinaryninja/tvapp2:1 \ --tag ghcr.io/thebinaryninja/tvapp2:1 \
--tag ghcr.io/thebinaryninja/tvapp2:latest \ --tag ghcr.io/thebinaryninja/tvapp2:latest \
@@ -998,9 +1025,9 @@ docker buildx imagetools create \
[+] Building 0.2s (4/4) FINISHED [+] Building 0.2s (4/4) FINISHED
=> [internal] pushing ghcr.io/thebinaryninja/tvapp2:latest 0.2s => [internal] pushing ghcr.io/thebinaryninja/tvapp2:latest 0.2s
=> [internal] pushing ghcr.io/thebinaryninja/tvapp2:1.5 0.2s
=> [internal] pushing ghcr.io/thebinaryninja/tvapp2:1 0.2s => [internal] pushing ghcr.io/thebinaryninja/tvapp2:1 0.2s
=> [internal] pushing ghcr.io/thebinaryninja/tvapp2:1.5.0 0.2s => [internal] pushing ghcr.io/thebinaryninja/tvapp2:1.5 0.2s
=> [internal] pushing ghcr.io/thebinaryninja/tvapp2:1.5.2 0.2s
``` ```
<br /> <br />
@@ -1046,8 +1073,8 @@ In this example, we take the existing two files we created earlier, and merge th
```shell ```shell
# Example 1 (using tag) # Example 1 (using tag)
docker manifest create ghcr.io/thebinaryninja/tvapp2:latest \ docker manifest create ghcr.io/thebinaryninja/tvapp2:latest \
--amend ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64 \ --amend ghcr.io/thebinaryninja/tvapp2:1.5.2-amd64 \
--amend ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64 --amend ghcr.io/thebinaryninja/tvapp2:1.5.2-arm64
# Example 2 (using sha256 hash) # Example 2 (using sha256 hash)
docker manifest create ghcr.io/thebinaryninja/tvapp2:latest \ docker manifest create ghcr.io/thebinaryninja/tvapp2:latest \
@@ -1088,7 +1115,7 @@ To build the project, `🗔 cd` into the project folder and run the build comman
```shell ```shell
cd /home/docker/tvapp2/ cd /home/docker/tvapp2/
npm run docker:build:amd64 --VERSION=1.5.0 --BUILDDATE=20260812 npm run docker:build:amd64 --VERSION=1.5.2 --BUILDDATE=20260812
``` ```
<br /> <br />
@@ -1213,7 +1240,7 @@ This docker container contains the following env variables:
| `WEB_IP` | `0.0.0.0` | IP to use for webserver | | `WEB_IP` | `0.0.0.0` | IP to use for webserver |
| `WEB_PORT` | `4124` | Port to use for webserver | | `WEB_PORT` | `4124` | Port to use for webserver |
| `WEB_FOLDER` | `www` | Internal container folder to keep TVApp2 web files in. <br /><br /> <sup>⚠️ This should not be used unless you know what you're doing</sup> | | `WEB_FOLDER` | `www` | Internal container folder to keep TVApp2 web files in. <br /><br /> <sup>⚠️ This should not be used unless you know what you're doing</sup> |
| `WEB_ENCODING` | `deflate, br` | Defines the HTTP `Accept-Encoding` request and response header. This value specifies what content encoding the sender can understand<br /><br />Gzip compression can be enabled by specifying `'gzip, deflate, br'` | | `WEB_ENCODING` | `deflate, br` | Defines the HTTP `Accept-Encoding` request and response header. This value specifies what content encoding the sender can understand<br /><br />Gzip compression can be enabled by specifying `'gzip, deflate, br'`, however, [it may break Jellyfin users](#build-error-err-27-jellyfinlivetvguideguidemanager-error-getting-programs-for-channel-xxxxxxxxxxxxxxx-source-2-systemxmlxmlexception--hexadecimal-value-0x1f-is-an-invalid-character-line-1-position-1). |
| `WEB_PROXY_HEADER` | `x-forwarded-for` | Defines the header to look for when finding a client's IP address. Used to get a client's IP when behind a reverse proxy or Cloudflare | | `WEB_PROXY_HEADER` | `x-forwarded-for` | Defines the header to look for when finding a client's IP address. Used to get a client's IP when behind a reverse proxy or Cloudflare |
| `URL_REPO` | `https://git.binaryninja.net/BinaryNinja/` | Determines where the data files will be downloaded from. Do not change this or you will be unable to get M3U and EPG data. | | `URL_REPO` | `https://git.binaryninja.net/BinaryNinja/` | Determines where the data files will be downloaded from. Do not change this or you will be unable to get M3U and EPG data. |
| `FILE_URL` | `urls.txt` | Filename for `urls.txt` cache file | | `FILE_URL` | `urls.txt` | Filename for `urls.txt` cache file |

BIN
docs/img/screenshots/01.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -9,10 +9,80 @@
# @repo.3 https://github.com/aetherinox/docker-base-alpine # @repo.3 https://github.com/aetherinox/docker-base-alpine
# # # #
# #
# define > colors
#
# Use the color table at:
# - https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
# #
declare -A c=(
[end]=$'\e[0m'
[white]=$'\e[97m'
[bold]=$'\e[1m'
[dim]=$'\e[2m'
[underline]=$'\e[4m'
[strike]=$'\e[9m'
[blink]=$'\e[5m'
[inverted]=$'\e[7m'
[hidden]=$'\e[8m'
[black]=$'\e[0;30m'
[redl]=$'\e[0;91m'
[redd]=$'\e[0;31m'
[magental]=$'\e[0;95m'
[magentad]=$'\e[0;35mm'
[bluel]=$'\e[0;94m'
[blued]=$'\e[0;34m'
[cyanl]=$'\e[0;96m'
[cyand]=$'\e[0;36m'
[greenl]=$'\e[0;92m'
[greend]=$'\e[0;32m'
[yellowl]=$'\e[0;93m'
[yellowd]=$'\e[0;33m'
[greyl]=$'\e[0;37m'
[greyd]=$'\e[0;90m'
[navy]=$'\e[38;5;62m'
[olive]=$'\e[38;5;144m'
[peach]=$'\e[38;5;210m'
)
# #
# unicode for emojis
# https://apps.timwhitlock.info/emoji/tables/unicode
# #
declare -A icon=(
["symbolic link"]=$'\xF0\x9F\x94\x97' # 🔗
["regular file"]=$'\xF0\x9F\x93\x84' # 📄
["directory"]=$'\xF0\x9F\x93\x81' # 📁
["regular empty file"]=$'\xe2\xad\x95' # ⭕
["log"]=$'\xF0\x9F\x93\x9C' # 📜
["1"]=$'\xF0\x9F\x93\x9C' # 📜
["2"]=$'\xF0\x9F\x93\x9C' # 📜
["3"]=$'\xF0\x9F\x93\x9C' # 📜
["4"]=$'\xF0\x9F\x93\x9C' # 📜
["5"]=$'\xF0\x9F\x93\x9C' # 📜
["pem"]=$'\xF0\x9F\x94\x92' # 🔑
["pub"]=$'\xF0\x9F\x94\x91' # 🔒
["pfx"]=$'\xF0\x9F\x94\x92' # 🔑
["p12"]=$'\xF0\x9F\x94\x92' # 🔑
["key"]=$'\xF0\x9F\x94\x91' # 🔒
["crt"]=$'\xF0\x9F\xAA\xAA ' # 🪪
["gz"]=$'\xF0\x9F\x93\xA6' # 📦
["zip"]=$'\xF0\x9F\x93\xA6' # 📦
["gzip"]=$'\xF0\x9F\x93\xA6' # 📦
["deb"]=$'\xF0\x9F\x93\xA6' # 📦
["sh"]=$'\xF0\x9F\x97\x94' # 🗔
)
# #
# define > general
# #
PLUGINS_PATH="/config/www/plugins" PLUGINS_PATH="/config/www/plugins"
# # # #
# Plugins > Start # Plugins > Start
# # # #
echo -e " Loader : Checking tvapp2-plugins" printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}Checking tvapp2-plugins${c[end]}"

View File

@@ -1 +1 @@
echo -e " Core : Completed loading container" echo -e " Completed loading container"

View File

@@ -1,35 +1,160 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
# #
# defaults
# #
PUID=${PUID:-911} PUID=${PUID:-911}
PGID=${PGID:-911} PGID=${PGID:-911}
DIR_BUILD=${DIR_BUILD:-/usr/src/app}
DIR_RUN=${DIR_RUN:-/usr/bin/app}
bHasError=false
# #
# define > colors
#
# Use the color table at:
# - https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
# #
declare -A c=(
[end]=$'\e[0m'
[white]=$'\e[97m'
[bold]=$'\e[1m'
[dim]=$'\e[2m'
[underline]=$'\e[4m'
[strike]=$'\e[9m'
[blink]=$'\e[5m'
[inverted]=$'\e[7m'
[hidden]=$'\e[8m'
[black]=$'\e[0;30m'
[redl]=$'\e[0;91m'
[redd]=$'\e[0;31m'
[magental]=$'\e[0;95m'
[magentad]=$'\e[0;35mm'
[bluel]=$'\e[0;94m'
[blued]=$'\e[0;34m'
[cyanl]=$'\e[0;96m'
[cyand]=$'\e[0;36m'
[greenl]=$'\e[0;92m'
[greend]=$'\e[0;32m'
[yellowl]=$'\e[0;93m'
[yellowd]=$'\e[0;33m'
[greyl]=$'\e[0;37m'
[greyd]=$'\e[0;90m'
[navy]=$'\e[38;5;62m'
[olive]=$'\e[38;5;144m'
[peach]=$'\e[38;5;210m'
)
# #
# unicode for emojis
# https://apps.timwhitlock.info/emoji/tables/unicode
# #
declare -A icon=(
["symbolic link"]=$'\xF0\x9F\x94\x97' # 🔗
["regular file"]=$'\xF0\x9F\x93\x84' # 📄
["directory"]=$'\xF0\x9F\x93\x81' # 📁
["regular empty file"]=$'\xe2\xad\x95' # ⭕
["log"]=$'\xF0\x9F\x93\x9C' # 📜
["1"]=$'\xF0\x9F\x93\x9C' # 📜
["2"]=$'\xF0\x9F\x93\x9C' # 📜
["3"]=$'\xF0\x9F\x93\x9C' # 📜
["4"]=$'\xF0\x9F\x93\x9C' # 📜
["5"]=$'\xF0\x9F\x93\x9C' # 📜
["pem"]=$'\xF0\x9F\x94\x92' # 🔑
["pub"]=$'\xF0\x9F\x94\x91' # 🔒
["pfx"]=$'\xF0\x9F\x94\x92' # 🔑
["p12"]=$'\xF0\x9F\x94\x92' # 🔑
["key"]=$'\xF0\x9F\x94\x91' # 🔒
["crt"]=$'\xF0\x9F\xAA\xAA ' # 🪪
["gz"]=$'\xF0\x9F\x93\xA6' # 📦
["zip"]=$'\xF0\x9F\x93\xA6' # 📦
["gzip"]=$'\xF0\x9F\x93\xA6' # 📦
["deb"]=$'\xF0\x9F\x93\xA6' # 📦
["sh"]=$'\xF0\x9F\x97\x94' # 🗔
)
# #
# get container ips
# #
IP_GATEWAY=$(/sbin/ip route|awk '/default/ { print $3 }') IP_GATEWAY=$(/sbin/ip route|awk '/default/ { print $3 }')
IP_CONTAINER=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1') IP_CONTAINER=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1')
# #
# usermod
# -o, --non-unique allow using duplicate (non-unique) UID
# -g, --gid GROUP force use GROUP as new primary group
# -G, --groups GROUPS new list of supplementary GROUPS
# -u, --uid UID new UID for the user account
# -U, --unlock unlock the user account
#
# groupmod
# -g, --gid GID change the group ID to GID
# -o, --non-unique allow to use a duplicate (non-unique) GID
# #
if [[ -z ${TVAPP_READ_ONLY_FS} ]] && [[ -z ${TVAPP_NON_ROOT_USER} ]]; then if [[ -z ${TVAPP_READ_ONLY_FS} ]] && [[ -z ${TVAPP_NON_ROOT_USER} ]]; then
groupmod -o -g "$PGID" dockerx groupmod -o -g "$PGID" dockerx
usermod -o -u "$PUID" dockerx usermod -o -u "$PUID" dockerx
fi fi
if { [[ -z ${TVAPP_READ_ONLY_FS} ]] && [[ -z ${TVAPP_NON_ROOT_USER} ]]; } || [[ ! ${TVAPP_FIRST_PARTY} = "true" ]]; then # #
cat /etc/s6-overlay/s6-rc.d/init-adduser/branding # s6 > branding
else # #
cat /run/branding
fi printf '%-1s\n' " ${c[greyd]}──────────────────────────────────────────────────────────────────────────────────────────${c[end]}"
printf '%-1s\n' " ${c[greyd]} TVApp2 Docker Image${c[end]}"
printf '%-1s\n' " ${c[greyd]}──────────────────────────────────────────────────────────────────────────────────────────${c[end]}"
printf '%-2s\n' " ${c[greyd]}The TvApp2 image allows you to fetch M3U playlist and EPG data for numerous IPTV ${c[end]}"
printf '%-2s\n' " ${c[greyd]}services online. ${c[end]}"
echo -e
printf '%-2s\n' " ${c[greyd]}Once the files are fetched by the image, you can visit the self-hosted webpage, copy ${c[end]}"
printf '%-2s\n' " ${c[greyd]}the links to the M3U and EPG files; and add them to your favorite IPTV app such as ${c[end]}"
printf '%-2s\n' " ${c[greyd]}Jellyfin, Plex, or Emby. ${c[end]}"
echo -e
printf '%-2s\n' " ${c[greyd]}For more information about this project; visit the links below. This app is served on ${c[end]}"
printf '%-2s\n' " ${c[greyd]}multiple repositories as backup. Use any of the repo links below: ${c[end]}"
echo -e
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}TVApp2 Repo 1${c[end]}" "${c[end]}https://github.com/TheBinaryNinja/tvapp2 ${c[end]}"
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}TVApp2 Repo 2${c[end]}" "${c[end]}https://git.binaryninja.net/BinaryNinja/tvapp2 ${c[end]}"
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}Base Alpine Image${c[end]}" "${c[end]}https://github.com/Aetherinox/docker-base-alpine ${c[end]}"
echo -e
printf '%-2s\n' " ${c[greyd]}If you are making this container available on a public-facing domain, please consider ${c[end]}"
printf '%-2s\n' " ${c[greyd]}using Traefik and Authentik to protect this container from outside access. Your M3U ${c[end]}"
printf '%-2s\n' " ${c[greyd]}and EPG files will be available for the public to download and use. ${c[end]}"
# if { [[ -z ${TVAPP_READ_ONLY_FS} ]] && [[ -z ${TVAPP_NON_ROOT_USER} ]]; } || [[ ! ${TVAPP_FIRST_PARTY} = "true" ]]; then
# cat /etc/s6-overlay/s6-rc.d/init-adduser/branding
# else
# cat /run/branding
# fi
# #
# branding > non-root user
# #
if [[ -z ${TVAPP_NON_ROOT_USER} ]]; then if [[ -z ${TVAPP_NON_ROOT_USER} ]]; then
echo "" echo -e
echo " User:Group $(id -u dockerx):$(id -g dockerx)" printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}User:Group${c[end]}" "${c[end]}$(id -u dockerx):$(id -g dockerx)${c[end]}"
else else
echo " User:Group $(stat /run -c %u):$(stat /run -c %g)" printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}User:Group${c[end]}" "${c[end]}$(stat /run -c %u):$(stat /run -c %g)${c[end]}"
fi fi
echo " Port(s) $(echo $WEB_PORT)" printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}Port(s)${c[end]}" "${c[end]}$(echo $WEB_PORT)${c[end]}"
echo " Gateway $(echo $IP_GATEWAY)" printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}Gateway${c[end]}" "${c[end]}$(echo $IP_GATEWAY)${c[end]}"
echo " Web Server $(echo $IP_CONTAINER:$WEB_PORT)" printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}Web Server${c[end]}" "${c[end]}$(echo $IP_CONTAINER:$WEB_PORT)${c[end]}"
echo " App Folder $(echo $DIR_RUN)" printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}App Folder${c[end]}" "${c[end]}$(echo $DIR_RUN)${c[end]}"
echo "" echo -e
echo '──────────────────────────────────────────────────────────────────────────────────────────' printf '%-1s\n' " ${c[greyd]}──────────────────────────────────────────────────────────────────────────────────────────${c[end]}"
# #
# set permissions
# #
if [[ -z ${TVAPP_READ_ONLY_FS} ]] && [[ -z ${TVAPP_NON_ROOT_USER} ]]; then if [[ -z ${TVAPP_READ_ONLY_FS} ]] && [[ -z ${TVAPP_NON_ROOT_USER} ]]; then
aetherxown dockerx:dockerx /app aetherxown dockerx:dockerx /app

View File

@@ -1,22 +1,88 @@
#!/usr/bin/with-contenv bash #!/usr/bin/with-contenv bash
# shellcheck shell=bash # shellcheck shell=bash
# #
# define > colors
#
# Use the color table at:
# - https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
# #
declare -A c=(
[end]=$'\e[0m'
[white]=$'\e[97m'
[bold]=$'\e[1m'
[dim]=$'\e[2m'
[underline]=$'\e[4m'
[strike]=$'\e[9m'
[blink]=$'\e[5m'
[inverted]=$'\e[7m'
[hidden]=$'\e[8m'
[black]=$'\e[0;30m'
[redl]=$'\e[0;91m'
[redd]=$'\e[0;31m'
[magental]=$'\e[0;95m'
[magentad]=$'\e[0;35mm'
[bluel]=$'\e[0;94m'
[blued]=$'\e[0;34m'
[cyanl]=$'\e[0;96m'
[cyand]=$'\e[0;36m'
[greenl]=$'\e[0;92m'
[greend]=$'\e[0;32m'
[yellowl]=$'\e[0;93m'
[yellowd]=$'\e[0;33m'
[greyl]=$'\e[0;37m'
[greyd]=$'\e[0;90m'
[navy]=$'\e[38;5;62m'
[olive]=$'\e[38;5;144m'
[peach]=$'\e[38;5;210m'
)
# #
# unicode for emojis
# https://apps.timwhitlock.info/emoji/tables/unicode
# #
declare -A icon=(
["symbolic link"]=$'\xF0\x9F\x94\x97' # 🔗
["regular file"]=$'\xF0\x9F\x93\x84' # 📄
["directory"]=$'\xF0\x9F\x93\x81' # 📁
["regular empty file"]=$'\xe2\xad\x95' # ⭕
["log"]=$'\xF0\x9F\x93\x9C' # 📜
["1"]=$'\xF0\x9F\x93\x9C' # 📜
["2"]=$'\xF0\x9F\x93\x9C' # 📜
["3"]=$'\xF0\x9F\x93\x9C' # 📜
["4"]=$'\xF0\x9F\x93\x9C' # 📜
["5"]=$'\xF0\x9F\x93\x9C' # 📜
["pem"]=$'\xF0\x9F\x94\x92' # 🔑
["pub"]=$'\xF0\x9F\x94\x91' # 🔒
["pfx"]=$'\xF0\x9F\x94\x92' # 🔑
["p12"]=$'\xF0\x9F\x94\x92' # 🔑
["key"]=$'\xF0\x9F\x94\x91' # 🔒
["crt"]=$'\xF0\x9F\xAA\xAA ' # 🪪
["gz"]=$'\xF0\x9F\x93\xA6' # 📦
["zip"]=$'\xF0\x9F\x93\xA6' # 📦
["gzip"]=$'\xF0\x9F\x93\xA6' # 📦
["deb"]=$'\xF0\x9F\x93\xA6' # 📦
["sh"]=$'\xF0\x9F\x97\x94' # 🗔
)
# Directories # Directories
SCRIPTS_DIR="/custom-cont-init.d" SCRIPTS_DIR="/custom-cont-init.d"
# Make sure custom init directory exists and has files in it # Make sure custom init directory exists and has files in it
if [[ -e "${SCRIPTS_DIR}" ]] && [[ -n "$(/bin/ls -A ${SCRIPTS_DIR} 2>/dev/null)" ]]; then if [[ -e "${SCRIPTS_DIR}" ]] && [[ -n "$(/bin/ls -A ${SCRIPTS_DIR} 2>/dev/null)" ]]; then
echo -e " Loader : Plugins found, loading them ..." printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}Loading any found plugins${c[end]}"
for SCRIPT in "${SCRIPTS_DIR}"/*; do for SCRIPT in "${SCRIPTS_DIR}"/*; do
NAME="$(basename "${SCRIPT}")" NAME="$(basename "${SCRIPT}")"
if [[ -f "${SCRIPT}" ]]; then if [[ -f "${SCRIPT}" ]]; then
echo -e " Loader : Executing ..." printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}Executing${c[end]}"
/bin/bash "${SCRIPT}" /bin/bash "${SCRIPT}"
echo -e " Loader : ${NAME}: Ran Successfully with code [$?]" printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}Successfully ran with code ${c[bluel]}[$?]${c[end]}"
elif [[ ! -f "${SCRIPT}" ]]; then elif [[ ! -f "${SCRIPT}" ]]; then
echo -e " Loader : ${NAME}: Not a valid file" printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}${c[bluel]}${NAME}${c[end]} is not a valid file${c[end]}"
fi fi
done done
else else
echo -e " Loader : No Plugins found, skipping..." printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}No plugins found; skipping${c[end]}"
fi fi

View File

@@ -1,14 +1,113 @@
#!/usr/bin/with-contenv sh #!/usr/bin/with-contenv bash
# shellcheck shell=bash
# # # #
# Store env variables in s6 # defaults
# #
PUID=${PUID:-911}
PGID=${PGID:-911}
DIR_BUILD=${DIR_BUILD:-/usr/src/app}
DIR_RUN=${DIR_RUN:-/usr/bin/app}
bHasError=false
# #
# define > colors
#
# Use the color table at:
# - https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
# #
declare -A c=(
[end]=$'\e[0m'
[white]=$'\e[97m'
[bold]=$'\e[1m'
[dim]=$'\e[2m'
[underline]=$'\e[4m'
[strike]=$'\e[9m'
[blink]=$'\e[5m'
[inverted]=$'\e[7m'
[hidden]=$'\e[8m'
[black]=$'\e[0;30m'
[redl]=$'\e[0;91m'
[redd]=$'\e[0;31m'
[magental]=$'\e[0;95m'
[magentad]=$'\e[0;35mm'
[bluel]=$'\e[0;94m'
[blued]=$'\e[0;34m'
[cyanl]=$'\e[0;96m'
[cyand]=$'\e[0;36m'
[greenl]=$'\e[0;92m'
[greend]=$'\e[0;32m'
[yellowl]=$'\e[0;93m'
[yellowd]=$'\e[0;33m'
[greyl]=$'\e[0;37m'
[greyd]=$'\e[0;90m'
[navy]=$'\e[38;5;62m'
[olive]=$'\e[38;5;144m'
[peach]=$'\e[38;5;210m'
)
# #
# unicode for emojis
# https://apps.timwhitlock.info/emoji/tables/unicode
# #
declare -A icon=(
["symbolic link"]=$'\xF0\x9F\x94\x97' # 🔗
["regular file"]=$'\xF0\x9F\x93\x84' # 📄
["directory"]=$'\xF0\x9F\x93\x81' # 📁
["regular empty file"]=$'\xe2\xad\x95' # ⭕
["log"]=$'\xF0\x9F\x93\x9C' # 📜
["1"]=$'\xF0\x9F\x93\x9C' # 📜
["2"]=$'\xF0\x9F\x93\x9C' # 📜
["3"]=$'\xF0\x9F\x93\x9C' # 📜
["4"]=$'\xF0\x9F\x93\x9C' # 📜
["5"]=$'\xF0\x9F\x93\x9C' # 📜
["pem"]=$'\xF0\x9F\x94\x92' # 🔑
["pub"]=$'\xF0\x9F\x94\x91' # 🔒
["pfx"]=$'\xF0\x9F\x94\x92' # 🔑
["p12"]=$'\xF0\x9F\x94\x92' # 🔑
["key"]=$'\xF0\x9F\x94\x91' # 🔒
["crt"]=$'\xF0\x9F\xAA\xAA ' # 🪪
["gz"]=$'\xF0\x9F\x93\xA6' # 📦
["zip"]=$'\xF0\x9F\x93\xA6' # 📦
["gzip"]=$'\xF0\x9F\x93\xA6' # 📦
["deb"]=$'\xF0\x9F\x93\xA6' # 📦
["sh"]=$'\xF0\x9F\x97\x94' # 🗔
)
# #
# define > system
# #
sys_os_ver="1.0.0"
sys_os_name="Unknown"
# #
# s6 > store env variables
# #
printf '%-29s %-65s\n' " ${c[bluel]}STATUS${c[end]}" "${c[end]}Fetching docker container and gateway addresses${c[end]}"
# #
# get container ips
# # # #
ip_gateway=$(/sbin/ip route|awk '/default/ { print $3 }') ip_gateway=$(/sbin/ip route|awk '/default/ { print $3 }')
ip_container=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1') ip_container=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1')
printf "$ip_gateway" > /var/run/s6/container_environment/IP_GATEWAY if [ -d "/var/run/s6/container_environment/" ]; then
printf "$ip_container" > /var/run/s6/container_environment/IP_CONTAINER printf "$ip_gateway" > /var/run/s6/container_environment/IP_GATEWAY
printf "$ip_container" > /var/run/s6/container_environment/IP_CONTAINER
else
printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Cannot generate s6-overlay env files; folder ${c[redl]}/var/run/s6/container_environment/${c[end]} does not exist${c[end]}"
bHasError=true
fi
# #
# s6 > export env vars
# #
export IP_GATEWAY=$ip_gateway export IP_GATEWAY=$ip_gateway
export IP_GATEWAY=$ip_container export IP_GATEWAY=$ip_container
@@ -17,8 +116,75 @@ export IP_GATEWAY=$ip_container
# install and startup for tvapp2 # install and startup for tvapp2
# # # #
cp -r ${DIR_BUILD}/* ${DIR_RUN} printf '%-29s %-65s\n' " ${c[bluel]}STATUS${c[end]}" "${c[end]}Copying ${c[bluel]}${DIR_BUILD}${c[end]} to ${c[bluel]}${DIR_RUN}${c[end]}"
rm -rf ${DIR_BUILD}/* if [ -z "${DIR_BUILD}" ]; then
cd ${DIR_RUN} printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Cannot copy; env var ${c[redl]}\${DIR_BUILD}${c[end]} missing${c[end]}"
npm install --omit=dev bHasError=true
npm start else
if [ -d "${DIR_BUILD}/" ]; then
cp -r ${DIR_BUILD}/* ${DIR_RUN}
else
printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Cannot copy folder ${c[redl]}${DIR_BUILD}${c[end]} to ${c[redl]}${DIR_RUN}${c[end]}; build folder ${c[redl]}${DIR_BUILD}${c[end]} does not exist${c[end]}"
bHasError=true
fi
fi
# #
# remove build directory
# #
printf '%-29s %-65s\n' " ${c[bluel]}STATUS${c[end]}" "${c[end]}Remove ${c[bluel]}${DIR_BUILD}/${c[end]}"
if [ -z "${DIR_BUILD}" ]; then
printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Cannot remove; env var ${c[redl]}\${DIR_BUILD}${c[end]} missing${c[end]}"
else
if [ -d "${DIR_BUILD}" ]; then
rm -rf "${DIR_BUILD}/"
else
printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Cannot remove; build folder ${c[redl]}${DIR_BUILD}${c[end]} does not exist. Restart the container to re-initialize build folder.${c[end]}"
fi
fi
# #
# cd to BUILD_RUN directory
# #
printf '%-29s %-65s\n' " ${c[bluel]}STATUS${c[end]}" "${c[end]}Changing to run directory ${c[bluel]}${DIR_RUN}/${c[end]}"
if [ -z "${DIR_RUN}" ]; then
printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Cannot cd; env var ${c[redl]}\${DIR_RUN}${c[end]} missing${c[end]}"
bHasError=true
else
if [ -d "${DIR_RUN}" ]; then
cd ${DIR_RUN}
else
printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Cannot cd; run folder ${c[redl]}${DIR_RUN}${c[end]} does not exist${c[end]}"
bHasError=true
fi
fi
# #
# install tvapp2 via npm
# #
printf '%-29s %-65s\n' " ${c[bluel]}STATUS${c[end]}" "${c[end]}Running command ${c[bluel]}npm install --omit=dev${c[end]}"
if ! command -v npm; then
printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Cannot install TVApp2 with npm because package ${c[redl]}npm${c[end]} not installed${c[end]}"
bHasError=true
else
npm install --omit=dev
printf '%-29s %-65s\n' " ${c[bluel]}STATUS${c[end]}" "${c[end]}Running command ${c[bluel]}npm start${c[end]}"
npm start
fi
# #
# finished run script
# #
printf '%-29s %-65s\n' " ${c[greenl]}OK${c[end]}" "${c[end]}Finished initializing script${c[end]}"
if [ "$bHasError" = true ] ; then
printf '%-29s %-65s\n' "" ""
printf '%-29s %-65s\n' " ${c[redl]}ERROR${c[end]}" "${c[end]}Fatal errors were detected${c[end]}"
printf '%-29s %-65s\n' " ${c[redl]}${c[end]}" "${c[end]}The run script detected that certain steps failed. This app may not${c[end]}"
printf '%-29s %-65s\n' " ${c[redl]}${c[end]}" "${c[end]}work properly. Try restarting the container.${c[end]}"
printf '%-29s %-65s\n' "" ""
fi

View File

@@ -12,7 +12,12 @@ import zlib from 'zlib';
import chalk from 'chalk'; import chalk from 'chalk';
import ejs from 'ejs'; import ejs from 'ejs';
import moment from 'moment'; import moment from 'moment';
import TimeAgo from 'javascript-time-ago';
import en from 'javascript-time-ago/locale/en';
import nconf from 'nconf';
import crypto from 'node:crypto';
import cron, { schedule } from 'node-cron'; import cron, { schedule } from 'node-cron';
import * as child from 'child_process';
import * as crons from 'cron'; import * as crons from 'cron';
/* /*
@@ -29,6 +34,9 @@ const cache = new Map();
const { name, author, version, repository, discord, docs } = JSON.parse( fs.readFileSync( './package.json' ) ); const { name, author, version, repository, discord, docs } = JSON.parse( fs.readFileSync( './package.json' ) );
const __filename = fileURLToPath( import.meta.url ); // get resolved path to file const __filename = fileURLToPath( import.meta.url ); // get resolved path to file
const __dirname = path.dirname( __filename ); // get name of directory const __dirname = path.dirname( __filename ); // get name of directory
/*
const gitHash = child.execSync( 'git rev-parse HEAD' ).toString().trim();
*/
/* /*
chalk.level chalk.level
@@ -46,6 +54,13 @@ const __dirname = path.dirname( __filename ); // get name of directory
chalk.level = 3; chalk.level = 3;
/*
*/
TimeAgo.addDefaultLocale( en );
const timeAgo = new TimeAgo( );
/* /*
Define > General Define > General
@@ -83,7 +98,9 @@ const envWebEncoding = process.env.WEB_ENCODING || 'deflate, br';
const envProxyHeader = process.env.WEB_PROXY_HEADER || 'x-forwarded-for'; const envProxyHeader = process.env.WEB_PROXY_HEADER || 'x-forwarded-for';
const envHealthTimer = process.env.HEALTH_TIMER || 600000; const envHealthTimer = process.env.HEALTH_TIMER || 600000;
const envTaskCronSync = process.env.TASK_CRON_SYNC || '0 0 */3 * *'; const envTaskCronSync = process.env.TASK_CRON_SYNC || '0 0 */3 * *';
const envGitSHA1 = process.env.GIT_SHA1 || '0000000000000000000000000000000000000000';
const LOG_LEVEL = process.env.LOG_LEVEL || 4; const LOG_LEVEL = process.env.LOG_LEVEL || 4;
let TIME_STARTUP = 0;
/* /*
Define > Externals Define > Externals
@@ -110,8 +127,8 @@ const USERAGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:138.0) Gecko/201
http://127.0.0.1:4124/gz http://127.0.0.1:4124/gz
http://127.0.0.1:4124/playlist http://127.0.0.1:4124/playlist
http://127.0.0.1:4124/key http://127.0.0.1:4124/key
http://127.0.0.1:4124/channel http://127.0.0.1:4124/channel?url=https://thetvapp.to/tv/bbc-america-live-stream/
http://127.0.0.1:4124/health http://127.0.0.1:4124/api/health
*/ */
const subdomainGZP = [ 'gzip', 'gz' ]; const subdomainGZP = [ 'gzip', 'gz' ];
@@ -174,45 +191,45 @@ class Log
static verbose( ...msg ) static verbose( ...msg )
{ {
if ( LOG_LEVEL >= 6 ) if ( LOG_LEVEL >= 6 )
console.debug( chalk.white.bgBlack.blackBright.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.gray( msg.join( ' ' ) ) ); console.debug( chalk.white.bgBlack.blackBright.bold( ` ${ name } ` ), chalk.white( `⚙️` ), this.now(), chalk.gray( msg.join( ' ' ) ) );
} }
static debug( ...msg ) static debug( ...msg )
{ {
if ( LOG_LEVEL >= 7 ) if ( LOG_LEVEL >= 7 )
console.trace( chalk.white.bgMagenta.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.magentaBright( msg.join( ' ' ) ) ); console.trace( chalk.white.bgMagenta.bold( ` ${ name } ` ), chalk.white( `⚙️` ), this.now(), chalk.magentaBright( msg.join( ' ' ) ) );
else if ( LOG_LEVEL >= 5 ) else if ( LOG_LEVEL >= 5 )
console.debug( chalk.white.bgGray.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.gray( msg.join( ' ' ) ) ); console.debug( chalk.white.bgGray.bold( ` ${ name } ` ), chalk.white( `⚙️` ), this.now(), chalk.gray( msg.join( ' ' ) ) );
} }
static info( ...msg ) static info( ...msg )
{ {
if ( LOG_LEVEL >= 4 ) if ( LOG_LEVEL >= 4 )
console.info( chalk.white.bgBlueBright.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.blueBright( msg.join( ' ' ) ) ); console.info( chalk.white.bgBlueBright.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.blueBright( msg.join( ' ' ) ) );
} }
static ok( ...msg ) static ok( ...msg )
{ {
if ( LOG_LEVEL >= 4 ) if ( LOG_LEVEL >= 4 )
console.log( chalk.white.bgGreen.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.greenBright( msg.join( ' ' ) ) ); console.log( chalk.white.bgGreen.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.greenBright( msg.join( ' ' ) ) );
} }
static notice( ...msg ) static notice( ...msg )
{ {
if ( LOG_LEVEL >= 3 ) if ( LOG_LEVEL >= 3 )
console.log( chalk.white.bgYellow.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.yellowBright( msg.join( ' ' ) ) ); console.log( chalk.white.bgYellow.bold( ` ${ name } ` ), chalk.white( `📌` ), this.now(), chalk.yellowBright( msg.join( ' ' ) ) );
} }
static warn( ...msg ) static warn( ...msg )
{ {
if ( LOG_LEVEL >= 2 ) if ( LOG_LEVEL >= 2 )
console.warn( chalk.white.bgYellow.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.yellowBright( msg.join( ' ' ) ) ); console.warn( chalk.white.bgYellow.bold( ` ${ name } ` ), chalk.white( `⚠️` ), this.now(), chalk.yellowBright( msg.join( ' ' ) ) );
} }
static error( ...msg ) static error( ...msg )
{ {
if ( LOG_LEVEL >= 1 ) if ( LOG_LEVEL >= 1 )
console.error( chalk.white.bgRedBright.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.redBright( msg.join( ' ' ) ) ); console.error( chalk.white.bgRedBright.bold( ` ${ name } ` ), chalk.white( `` ), this.now(), chalk.redBright( msg.join( ' ' ) ) );
} }
} }
@@ -226,7 +243,6 @@ if ( process.pkg )
chalk.blueBright( `<msg>` ), chalk.gray( `Starting server utilizing process.execPath` ) ); chalk.blueBright( `<msg>` ), chalk.gray( `Starting server utilizing process.execPath` ) );
const basePath = path.dirname( process.execPath ); const basePath = path.dirname( process.execPath );
FILE_URL = path.join( basePath, envWebFolder, `${ envFileURL }` ); FILE_URL = path.join( basePath, envWebFolder, `${ envFileURL }` );
FILE_M3U = path.join( basePath, envWebFolder, `${ envFileM3U }` ); FILE_M3U = path.join( basePath, envWebFolder, `${ envFileM3U }` );
FILE_XML = path.join( basePath, envWebFolder, `${ envFileXML }` ); FILE_XML = path.join( basePath, envWebFolder, `${ envFileXML }` );
@@ -244,6 +260,64 @@ else
FILE_GZP = path.resolve( __dirname, envWebFolder, `${ envFileGZP }` ); FILE_GZP = path.resolve( __dirname, envWebFolder, `${ envFileGZP }` );
} }
/*
helper > sleep
*/
function sleep( ms )
{
return new Promise( ( resolve ) =>
{
setTimeout( resolve, ms );
});
}
/*
Semaphore > Declare
allows multiple threads to work with the same shared resources
*/
class Semaphore
{
constructor( max )
{
this.max = max;
this.queue = [];
this.active = 0;
}
async acquire()
{
if ( this.active < this.max )
{
this.active++;
return;
}
return new Promise( ( resolve ) => this.queue.push( resolve ) );
}
release()
{
this.active--;
if ( this.queue.length > 0 )
{
const resolve = this.queue.shift();
this.active++;
resolve();
}
}
}
/*
Semaphore > Initialize
@arg int threads_max
*/
const semaphore = new Semaphore( 5 );
/* /*
Get Client IP Get Client IP
@@ -261,43 +335,6 @@ const clientIp = ( req ) =>
req.socket?.remoteAddress ) || req.socket?.remoteAddress ) ||
envIpContainer ); envIpContainer );
/*
/*
Semaphore > Declare
allows multiple threads to work with the same shared resources
*/
class Semaphore
{
constructor( max )
{
this.max = max;
this.queue = [];
this.active = 0;
}
async acquire()
{
if ( this.active < this.max )
{
this.active++;
return;
}
return new Promise( ( resolve ) => this.queue.push( resolve ) );
}
release()
{
this.active--;
if ( this.queue.length > 0 )
{
const resolve = this.queue.shift();
this.active++;
resolve();
}
}
}
/* /*
Check Service Status Check Service Status
@@ -313,17 +350,17 @@ async function serviceCheck( service, uri )
try try
{ {
const response = await fetch( uri ); const resp = await fetch( uri );
/* try 1 > domain down */ /* try 1 > domain down */
if ( response.status !== 200 ) if ( resp.status !== 200 )
{ {
Log.error( `ping`, chalk.redBright( `[response]` ), chalk.white( `` ), chalk.redBright( `<msg>` ), chalk.gray( `Service Offline; failed to communicate with service, possibly down` ), chalk.redBright( `<code>` ), chalk.gray( `${ response.status }` ), chalk.redBright( `<service>` ), chalk.gray( `${ service }` ), chalk.redBright( `<address>` ), chalk.gray( `${ uri }` ) ); Log.error( `ping`, chalk.redBright( `[response]` ), chalk.white( `` ), chalk.redBright( `<msg>` ), chalk.gray( `Service Offline; failed to communicate with service, possibly down` ), chalk.redBright( `<code>` ), chalk.gray( `${ resp.status }` ), chalk.redBright( `<service>` ), chalk.gray( `${ service }` ), chalk.redBright( `<address>` ), chalk.gray( `${ uri }` ) );
return; return;
} }
/* try 1 > domain up */ /* try 1 > domain up */
Log.ok( `ping`, chalk.yellow( `[response]` ), chalk.white( `` ), chalk.greenBright( `<msg>` ), chalk.gray( `Service Online` ), chalk.greenBright( `<code>` ), chalk.gray( `${ response.status }` ), chalk.greenBright( `<service>` ), chalk.gray( `${ service }` ), chalk.greenBright( `<address>` ), chalk.gray( `${ uri }` ) ); Log.ok( `ping`, chalk.yellow( `[response]` ), chalk.white( `` ), chalk.greenBright( `<msg>` ), chalk.gray( `Service Online` ), chalk.greenBright( `<code>` ), chalk.gray( `${ resp.status }` ), chalk.greenBright( `<service>` ), chalk.gray( `${ service }` ), chalk.greenBright( `<address>` ), chalk.gray( `${ uri }` ) );
} }
catch ( err ) catch ( err )
{ {
@@ -338,17 +375,17 @@ async function serviceCheck( service, uri )
try try
{ {
const response = await fetch( uriRetry ); const resp = await fetch( uriRetry );
/* try 2 > http > domain down */ /* try 2 > http > domain down */
if ( response.status !== 200 ) if ( resp.status !== 200 )
{ {
Log.error( `ping`, chalk.redBright( `[response]` ), chalk.white( `` ), chalk.redBright( `<msg>` ), chalk.gray( `Service Offline; failed to communicate with service, possibly down` ), chalk.redBright( `<code>` ), chalk.gray( `${ response.status }` ), chalk.redBright( `<service>` ), chalk.gray( `${ service }` ), chalk.redBright( `<address>` ), chalk.gray( `${ uriRetry }` ) ); Log.error( `ping`, chalk.redBright( `[response]` ), chalk.white( `` ), chalk.redBright( `<msg>` ), chalk.gray( `Service Offline; failed to communicate with service, possibly down` ), chalk.redBright( `<code>` ), chalk.gray( `${ resp.status }` ), chalk.redBright( `<service>` ), chalk.gray( `${ service }` ), chalk.redBright( `<address>` ), chalk.gray( `${ uriRetry }` ) );
return; return;
} }
/* try 2 > http > domain up */ /* try 2 > http > domain up */
Log.ok( `ping`, chalk.yellow( `[response]` ), chalk.white( `` ), chalk.greenBright( `<msg>` ), chalk.gray( `Service Online` ), chalk.greenBright( `<code>` ), chalk.gray( `${ response.status }` ), chalk.greenBright( `<service>` ), chalk.gray( `${ service }` ), chalk.greenBright( `<address>` ), chalk.gray( `${ uriRetry }` ) ); Log.ok( `ping`, chalk.yellow( `[response]` ), chalk.white( `` ), chalk.greenBright( `<msg>` ), chalk.gray( `Service Online` ), chalk.greenBright( `<code>` ), chalk.gray( `${ resp.status }` ), chalk.greenBright( `<service>` ), chalk.gray( `${ service }` ), chalk.greenBright( `<address>` ), chalk.gray( `${ uriRetry }` ) );
} }
catch ( err ) catch ( err )
{ {
@@ -368,17 +405,17 @@ async function serviceCheck( service, uri )
try try
{ {
const response = await fetch( uriRetry ); const resp = await fetch( uriRetry );
/* try 2 > https > domain down */ /* try 2 > https > domain down */
if ( response.status !== 200 ) if ( resp.status !== 200 )
{ {
Log.error( `ping`, chalk.redBright( `[response]` ), chalk.white( `` ), chalk.redBright( `<msg>` ), chalk.gray( `Service Offline; failed to communicate with service, possibly down` ), chalk.redBright( `<code>` ), chalk.gray( `${ response.status }` ), chalk.redBright( `<service>` ), chalk.gray( `${ service }` ), chalk.redBright( `<address>` ), chalk.gray( `${ uriRetry }` ) ); Log.error( `ping`, chalk.redBright( `[response]` ), chalk.white( `` ), chalk.redBright( `<msg>` ), chalk.gray( `Service Offline; failed to communicate with service, possibly down` ), chalk.redBright( `<code>` ), chalk.gray( `${ resp.status }` ), chalk.redBright( `<service>` ), chalk.gray( `${ service }` ), chalk.redBright( `<address>` ), chalk.gray( `${ uriRetry }` ) );
return; return;
} }
/* try 2 > https > domain up */ /* try 2 > https > domain up */
Log.ok( `ping`, chalk.yellow( `[response]` ), chalk.white( `` ), chalk.greenBright( `<msg>` ), chalk.gray( `Service Online` ), chalk.greenBright( `<code>` ), chalk.gray( `${ response.status }` ), chalk.greenBright( `<service>` ), chalk.gray( `${ service }` ), chalk.greenBright( `<address>` ), chalk.gray( `${ uriRetry }` ) ); Log.ok( `ping`, chalk.yellow( `[response]` ), chalk.white( `` ), chalk.greenBright( `<msg>` ), chalk.gray( `Service Online` ), chalk.greenBright( `<code>` ), chalk.gray( `${ resp.status }` ), chalk.greenBright( `<service>` ), chalk.gray( `${ service }` ), chalk.greenBright( `<address>` ), chalk.gray( `${ uriRetry }` ) );
} }
catch ( err ) catch ( err )
{ {
@@ -389,14 +426,6 @@ async function serviceCheck( service, uri )
} }
} }
/*
Semaphore > Initialize
@arg int threads_max
*/
const semaphore = new Semaphore( 5 );
/* /*
Func > Download File Func > Download File
@@ -710,7 +739,7 @@ async function fetchRemote( url, req )
{ {
return new Promise( ( resolve, reject ) => return new Promise( ( resolve, reject ) =>
{ {
Log.info( `remo`, chalk.yellow( `[generate]` ), chalk.white( `` ), Log.info( `live`, chalk.yellow( `[generate]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Preparing to fetch remote request` ), chalk.blueBright( `<msg>` ), chalk.gray( `Preparing to fetch remote request` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<url>` ), chalk.gray( `${ url }` ) ); chalk.blueBright( `<url>` ), chalk.gray( `${ url }` ) );
@@ -723,7 +752,7 @@ async function fetchRemote( url, req )
} }
}, ( resp ) => }, ( resp ) =>
{ {
Log.info( `remo`, chalk.yellow( `[retrieve]` ), chalk.white( `` ), Log.info( `live`, chalk.yellow( `[retrieve]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Getting response from remote fetch request` ), chalk.blueBright( `<msg>` ), chalk.gray( `Getting response from remote fetch request` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<code>` ), chalk.gray( `${ resp.statusCode }` ), chalk.blueBright( `<code>` ), chalk.gray( `${ resp.statusCode }` ),
@@ -731,7 +760,7 @@ async function fetchRemote( url, req )
if ( resp.statusCode !== 200 ) if ( resp.statusCode !== 200 )
{ {
Log.error( `remo`, chalk.redBright( `[retrieve]` ), chalk.white( `` ), Log.error( `live`, chalk.redBright( `[retrieve]` ), chalk.white( `` ),
chalk.redBright( `<msg>` ), chalk.gray( `Remote fetch returned status code other than 200` ), chalk.redBright( `<msg>` ), chalk.gray( `Remote fetch returned status code other than 200` ),
chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<code>` ), chalk.gray( `${ resp.statusCode }` ), chalk.redBright( `<code>` ), chalk.gray( `${ resp.statusCode }` ),
@@ -754,7 +783,7 @@ async function fetchRemote( url, req )
{ {
if ( err ) if ( err )
{ {
Log.error( `remo`, chalk.redBright( `[retrieve]` ), chalk.white( `` ), Log.error( `live`, chalk.redBright( `[retrieve]` ), chalk.white( `` ),
chalk.redBright( `<msg>` ), chalk.gray( `Remote fetch could not complete encoding type ${ encoding }` ), chalk.redBright( `<msg>` ), chalk.gray( `Remote fetch could not complete encoding type ${ encoding }` ),
chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ), chalk.redBright( `<error>` ), chalk.gray( `${ err }` ),
@@ -765,7 +794,7 @@ async function fetchRemote( url, req )
return reject( err ); return reject( err );
} }
Log.debug( `remo`, chalk.yellow( `[retrieve]` ), chalk.white( `⚙️` ), Log.debug( `live`, chalk.yellow( `[retrieve]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Remote fetch detected encoding type ${ encoding }; decoding` ), chalk.blueBright( `<msg>` ), chalk.gray( `Remote fetch detected encoding type ${ encoding }; decoding` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ), chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ),
@@ -781,7 +810,7 @@ async function fetchRemote( url, req )
{ {
if ( err ) if ( err )
{ {
Log.error( `remo`, chalk.redBright( `[retrieve]` ), chalk.white( `` ), Log.error( `live`, chalk.redBright( `[retrieve]` ), chalk.white( `` ),
chalk.redBright( `<msg>` ), chalk.gray( `Remote fetch could not complete encoding type ${ encoding }` ), chalk.redBright( `<msg>` ), chalk.gray( `Remote fetch could not complete encoding type ${ encoding }` ),
chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ), chalk.redBright( `<error>` ), chalk.gray( `${ err }` ),
@@ -792,7 +821,7 @@ async function fetchRemote( url, req )
return reject( err ); return reject( err );
} }
Log.debug( `remo`, chalk.yellow( `[retrieve]` ), chalk.white( `⚙️` ), Log.debug( `live`, chalk.yellow( `[retrieve]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Remote fetch detected encoding type ${ encoding }; decoding` ), chalk.blueBright( `<msg>` ), chalk.gray( `Remote fetch detected encoding type ${ encoding }; decoding` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ), chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ),
@@ -808,7 +837,7 @@ async function fetchRemote( url, req )
{ {
if ( err ) if ( err )
{ {
Log.error( `remo`, chalk.redBright( `[retrieve]` ), chalk.white( `` ), Log.error( `live`, chalk.redBright( `[retrieve]` ), chalk.white( `` ),
chalk.redBright( `<msg>` ), chalk.gray( `Remote fetch could not complete encoding type ${ encoding } (brotli decompress)` ), chalk.redBright( `<msg>` ), chalk.gray( `Remote fetch could not complete encoding type ${ encoding } (brotli decompress)` ),
chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ), chalk.redBright( `<error>` ), chalk.gray( `${ err }` ),
@@ -819,7 +848,7 @@ async function fetchRemote( url, req )
return reject( err ); return reject( err );
} }
Log.debug( `remo`, chalk.yellow( `[retrieve]` ), chalk.white( `⚙️` ), Log.debug( `live`, chalk.yellow( `[retrieve]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Remote fetch detected encoding type ${ encoding } (brotli decompress); decoding` ), chalk.blueBright( `<msg>` ), chalk.gray( `Remote fetch detected encoding type ${ encoding } (brotli decompress); decoding` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ), chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ),
@@ -831,7 +860,7 @@ async function fetchRemote( url, req )
} }
else else
{ {
Log.debug( `remo`, chalk.yellow( `[retrieve]` ), chalk.white( `⚙️` ), Log.debug( `live`, chalk.yellow( `[retrieve]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Remote fetch contains no headers to decode; resolving buffer` ), chalk.blueBright( `<msg>` ), chalk.gray( `Remote fetch contains no headers to decode; resolving buffer` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ), chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ),
@@ -870,6 +899,8 @@ async function serveKey( req, res )
method: req.method || 'GET', method: req.method || 'GET',
code: 400, code: 400,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -925,6 +956,8 @@ async function serveKey( req, res )
method: req.method || 'GET', method: req.method || 'GET',
code: 500, code: 500,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1222,6 +1255,8 @@ async function serveM3UPlaylist( req, res )
method: req.method || 'GET', method: req.method || 'GET',
code: 404, code: 404,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1312,6 +1347,8 @@ async function serveM3UPlaylist( req, res )
method: req.method || 'GET', method: req.method || 'GET',
code: 500, code: 500,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1370,6 +1407,8 @@ async function serveM3UPlaylist( req, res )
method: req.method || 'GET', method: req.method || 'GET',
code: 500, code: 500,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1419,6 +1458,8 @@ async function serveHealthCheck( req, res )
method: req.method || 'GET', method: req.method || 'GET',
code: 200, code: 200,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1426,12 +1467,16 @@ async function serveHealthCheck( req, res )
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}); });
Log.ok( `/api`, chalk.yellow( `[health]` ), chalk.white( `` ), const paramQuery = new URL( req.url, `http://${ req.headers.host }` ).searchParams.get( 'query' );
chalk.greenBright( `<msg>` ), chalk.gray( `Response` ), if ( paramQuery !== 'query' )
chalk.greenBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ), {
chalk.greenBright( `<code>` ), chalk.gray( `${ statusCheck.code }` ), Log.ok( `/api`, chalk.yellow( `[health]` ), chalk.white( `` ),
chalk.greenBright( `<status>` ), chalk.gray( `${ statusCheck.status }` ), chalk.greenBright( `<msg>` ), chalk.gray( `Response` ),
chalk.greenBright( `<uptime>` ), chalk.gray( `${ process.uptime() }` ) ); chalk.greenBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.greenBright( `<code>` ), chalk.gray( `${ statusCheck.code }` ),
chalk.greenBright( `<status>` ), chalk.gray( `${ statusCheck.status }` ),
chalk.greenBright( `<uptime>` ), chalk.gray( `${ process.uptime() }` ) );
}
res.end( JSON.stringify( statusCheck ) ); res.end( JSON.stringify( statusCheck ) );
return; return;
@@ -1452,6 +1497,8 @@ async function serveHealthCheck( req, res )
method: req.method || 'GET', method: req.method || 'GET',
code: 503, code: 503,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1522,11 +1569,34 @@ async function serveM3U( res, req )
const updatedContent = formattedContent const updatedContent = formattedContent
.replace( /(https?:\/\/[^\s]*thetvapp[^\s]*)/g, ( fullUrl ) => .replace( /(https?:\/\/[^\s]*thetvapp[^\s]*)/g, ( fullUrl ) =>
{ {
Log.debug( `.m3u`, chalk.yellow( `[rewriter]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Rewriting url for keyword` ),
chalk.blueBright( `<keyword>` ), chalk.gray( `*thetvapp` ),
chalk.blueBright( `<from>` ), chalk.gray( `${ fullUrl }` ),
chalk.blueBright( `<to>` ), chalk.gray( `${ baseUrl }/channel?url=${ encodeURIComponent( fullUrl ) }` ) );
return `${ baseUrl }/channel?url=${ encodeURIComponent( fullUrl ) }`; return `${ baseUrl }/channel?url=${ encodeURIComponent( fullUrl ) }`;
}) })
.replace( /(https?:\/\/[^\s]*tvpass[^\s]*)/g, ( fullUrl ) => .replace( /(https?:\/\/[^\s]*tvpass[^\s]*)/g, ( fullUrl ) =>
{ {
Log.debug( `.m3u`, chalk.yellow( `[rewriter]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Rewriting url for keyword` ),
chalk.blueBright( `<keyword>` ), chalk.gray( `*tvpass` ),
chalk.blueBright( `<from>` ), chalk.gray( `${ fullUrl }` ),
chalk.blueBright( `<to>` ), chalk.gray( `${ baseUrl }/channel?url=${ encodeURIComponent( fullUrl ) }` ) );
return `${ baseUrl }/channel?url=${ encodeURIComponent( fullUrl ) }`; return `${ baseUrl }/channel?url=${ encodeURIComponent( fullUrl ) }`;
})
.replace( /(https?:\/\/[^\s]*fl2.moveonjoy[^\s]*)/g, ( fullUrl ) =>
{
const urlRewrite = fullUrl.replace( 'fl2.moveonjoy', 'fl6.moveonjoy' );
Log.debug( `.m3u`, chalk.yellow( `[rewriter]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Rewriting url for keyword` ),
chalk.blueBright( `<keyword>` ), chalk.gray( `*fl2.moveonjoy` ),
chalk.blueBright( `<from>` ), chalk.gray( `${ fullUrl }` ),
chalk.blueBright( `<to>` ), chalk.gray( `${ urlRewrite }` ) );
return `${ urlRewrite }`;
}); });
res.writeHead( 200, { res.writeHead( 200, {
@@ -1559,6 +1629,8 @@ async function serveM3U( res, req )
method: req.method || 'GET', method: req.method || 'GET',
code: 500, code: 500,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1624,6 +1696,8 @@ async function serveXML( res, req )
method: req.method || 'GET', method: req.method || 'GET',
code: 500, code: 500,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1689,6 +1763,8 @@ async function serveGZP( res, req )
method: req.method || 'GET', method: req.method || 'GET',
code: 500, code: 500,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
@@ -1876,9 +1952,10 @@ async function initialize()
FILE_GZP_MODIFIED = getFileModified( FILE_GZP ); FILE_GZP_MODIFIED = getFileModified( FILE_GZP );
const end = performance.now(); const end = performance.now();
TIME_STARTUP = `${ end - start }`;
Log.info( `core`, chalk.yellow( `[initiate]` ), chalk.white( `` ), Log.info( `core`, chalk.yellow( `[initiate]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `TVApp2 container is ready` ), chalk.blueBright( `<msg>` ), chalk.gray( `TVApp2 container is ready` ),
chalk.blueBright( `<time>` ), chalk.gray( `took ${ end - start }ms` ), chalk.blueBright( `<time>` ), chalk.gray( `took ${ TIME_STARTUP }ms` ),
chalk.blueBright( `<ip>` ), chalk.gray( `${ envIpContainer }` ), chalk.blueBright( `<ip>` ), chalk.gray( `${ envIpContainer }` ),
chalk.blueBright( `<gateway>` ), chalk.gray( `${ envIpGateway }` ), chalk.blueBright( `<gateway>` ), chalk.gray( `${ envIpGateway }` ),
chalk.blueBright( `<port>` ), chalk.gray( `${ envWebPort }` ) ); chalk.blueBright( `<port>` ), chalk.gray( `${ envWebPort }` ) );
@@ -1912,7 +1989,7 @@ async function initialize()
}) })
*/ */
const server = http.createServer( ( request, response ) => const server = http.createServer( ( req, resp ) =>
{ {
/* /*
If request.url === '/'; load index.html as default page If request.url === '/'; load index.html as default page
@@ -1923,8 +2000,8 @@ const server = http.createServer( ( request, response ) =>
/www/css/tvapp2.min.css /www/css/tvapp2.min.css
*/ */
const method = request.method || 'GET'; const method = req.method || 'GET';
let reqUrl = request.url; let reqUrl = req.url;
if ( reqUrl === '/' ) if ( reqUrl === '/' )
reqUrl = 'index.html'; reqUrl = 'index.html';
@@ -1946,8 +2023,8 @@ const server = http.createServer( ( request, response ) =>
Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ), Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Request started` ), chalk.blueBright( `<msg>` ), chalk.gray( `Request started` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<request.url>` ), chalk.gray( `${ request.url }` ), chalk.blueBright( `<request.url>` ), chalk.gray( `${ req.url }` ),
chalk.blueBright( `<reqUrl>` ), chalk.gray( `${ reqUrl }` ), chalk.blueBright( `<reqUrl>` ), chalk.gray( `${ reqUrl }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
@@ -1969,31 +2046,33 @@ const server = http.createServer( ( request, response ) =>
@todo integrate real api system after express replaces node http @todo integrate real api system after express replaces node http
*/ */
const apiKey = new URL( request.url, `http://${ request.headers.host }` ).searchParams.get( 'key' ); const apiKey = new URL( req.url, `http://${ req.headers.host }` ).searchParams.get( 'key' );
const referer = request.headers.referer || null; const referer = req.headers.referer || null;
if ( ( !referer && envApiKey && !apiKey ) || ( referer && !referer.includes( request.headers.host ) ) ) if ( ( !referer && envApiKey && !apiKey ) || ( referer && !referer.includes( req.headers.host ) ) )
{ {
const statusCheck = const statusCheck =
{ {
ip: envIpContainer, gateway: envIpGateway, client: clientIp( request ), ip: envIpContainer, gateway: envIpGateway, client: clientIp( req ),
message: `must specify api key: http://${ request.headers.host }/api/restart?key=XXXXXXXX`, message: `must specify api key: http://${ req.headers.host }/api/restart?key=XXXXXXXX`,
status: `unauthorized`, ref: request.url, method: method || 'GET', code: 401, status: `unauthorized`, ref: req.url, method: method || 'GET', code: 401,
uptime: Math.round( process.uptime() ), timestamp: Date.now() uptime: Math.round( process.uptime() ), timestamp: Date.now(),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' )
}; };
response.writeHead( statusCheck.code, { resp.writeHead( statusCheck.code, {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}); });
Log.error( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), Log.error( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.redBright( `<msg>` ), chalk.gray( `Unauthorized (401): restart attempt did not specify api key using ?key=XXX parameter` ), chalk.redBright( `<msg>` ), chalk.gray( `Unauthorized (401): restart attempt did not specify api key using ?key=XXX parameter` ),
chalk.redBright( `<type>` ), chalk.gray( `api/restart` ), chalk.redBright( `<type>` ), chalk.gray( `api/restart` ),
chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.redBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.redBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.redBright( `<method>` ), chalk.gray( `${ method }` ) );
response.end( JSON.stringify( statusCheck ) ); resp.end( JSON.stringify( statusCheck ) );
return; return;
} }
@@ -2006,24 +2085,26 @@ const server = http.createServer( ( request, response ) =>
{ {
const statusCheck = const statusCheck =
{ {
ip: envIpContainer, gateway: envIpGateway, client: clientIp( request ), ip: envIpContainer, gateway: envIpGateway, client: clientIp( req ),
message: `incorrect api key specified: http://${ request.headers.host }/api/restart?key=XXXXXXXX`, message: `incorrect api key specified: http://${ req.headers.host }/api/restart?key=XXXXXXXX`,
status: `unauthorized`, ref: request.url, method: method || 'GET', code: 401, status: `unauthorized`, ref: req.url, method: method || 'GET', code: 401,
uptime: Math.round( process.uptime() ), timestamp: Date.now() uptime: Math.round( process.uptime() ), timestamp: Date.now(),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' )
}; };
response.writeHead( statusCheck.code, { resp.writeHead( statusCheck.code, {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}); });
Log.error( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), Log.error( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.redBright( `<msg>` ), chalk.gray( `Unauthorized (401): incorrect api key specified` ), chalk.redBright( `<msg>` ), chalk.gray( `Unauthorized (401): incorrect api key specified` ),
chalk.redBright( `<type>` ), chalk.gray( `api/restart` ), chalk.redBright( `<type>` ), chalk.gray( `api/restart` ),
chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.redBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.redBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.redBright( `<method>` ), chalk.gray( `${ method }` ) );
response.end( JSON.stringify( statusCheck ) ); resp.end( JSON.stringify( statusCheck ) );
return; return;
} }
@@ -2033,28 +2114,30 @@ const server = http.createServer( ( request, response ) =>
{ {
ip: envIpContainer, ip: envIpContainer,
gateway: envIpGateway, gateway: envIpGateway,
client: clientIp( request ), client: clientIp( req ),
message: 'Restart command received', message: 'Restart command received',
status: 'ok', status: 'ok',
ref: request.url, ref: req.url,
method: method || 'GET', method: method || 'GET',
code: 200, code: 200,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeShort: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
uptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'round' ),
timestamp: Date.now() timestamp: Date.now()
}; };
response.writeHead( statusCheck.code, { resp.writeHead( statusCheck.code, {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}); });
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access restart api` ), chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access restart api` ),
chalk.blueBright( `<type>` ), chalk.gray( `api/restart` ), chalk.blueBright( `<type>` ), chalk.gray( `api/restart` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
response.end( JSON.stringify( statusCheck ) ); resp.end( JSON.stringify( statusCheck ) );
return; return;
} }
@@ -2063,11 +2146,11 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access m3u playlist` ), chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access m3u playlist` ),
chalk.blueBright( `<type>` ), chalk.gray( `m3u playlist` ), chalk.blueBright( `<type>` ), chalk.gray( `m3u playlist` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
await serveM3U( response, request ); await serveM3U( resp, req );
return; return;
} }
@@ -2076,11 +2159,11 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access channel` ), chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access channel` ),
chalk.blueBright( `<type>` ), chalk.gray( `channel` ), chalk.blueBright( `<type>` ), chalk.gray( `channel` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
await serveM3UPlaylist( request, response ); await serveM3UPlaylist( req, resp );
return; return;
} }
@@ -2089,11 +2172,11 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access key` ), chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access key` ),
chalk.blueBright( `<type>` ), chalk.gray( `key` ), chalk.blueBright( `<type>` ), chalk.gray( `key` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
await serveKey( request, response ); await serveKey( req, resp );
return; return;
} }
@@ -2102,11 +2185,11 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access epg (uncompressed)` ), chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access epg (uncompressed)` ),
chalk.blueBright( `<type>` ), chalk.gray( `epg (uncompressed)` ), chalk.blueBright( `<type>` ), chalk.gray( `epg (uncompressed)` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
await serveXML( response, request ); await serveXML( resp, req );
return; return;
} }
@@ -2115,24 +2198,29 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access epg gzip (compressed)` ), chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access epg gzip (compressed)` ),
chalk.blueBright( `<type>` ), chalk.gray( `epg (compressed)` ), chalk.blueBright( `<type>` ), chalk.gray( `epg (compressed)` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
await serveGZP( response, request ); await serveGZP( resp, req );
return; return;
} }
if ( subdomainHealth.some( ( urlKeyword ) => loadFile.startsWith( urlKeyword ) ) && method === 'GET' ) if ( subdomainHealth.some( ( urlKeyword ) => loadFile.startsWith( urlKeyword ) ) && method === 'GET' )
{ {
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), const paramQuery = new URL( req.url, `http://${ req.headers.host }` ).searchParams.get( 'query' );
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access health api` ),
chalk.blueBright( `<type>` ), chalk.gray( `api/health` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
await serveHealthCheck( request, response ); if ( paramQuery !== 'uptime' )
{
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access health api` ),
chalk.blueBright( `<type>` ), chalk.gray( `api/health` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
}
await serveHealthCheck( req, resp );
return; return;
} }
@@ -2142,7 +2230,7 @@ const server = http.createServer( ( request, response ) =>
Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ), Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Request not captured by subdomain keyword checks; sending request to ejs` ), chalk.blueBright( `<msg>` ), chalk.gray( `Request not captured by subdomain keyword checks; sending request to ejs` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
@@ -2169,16 +2257,21 @@ const server = http.createServer( ( request, response ) =>
appRelease: envAppRelease, appRelease: envAppRelease,
appName: name, appName: name,
appVersion: version, appVersion: version,
appUrlGithub: repository.url, appUrlGithub: repository.url.substr( 0, repository.url.lastIndexOf( '.' ) ),
appUrlDiscord: discord.url, appUrlDiscord: discord.url,
appUrlDocs: docs.url appUrlDocs: docs.url,
appGitHashShort: envGitSHA1.substring( 0, 9 ),
appGitHashLong: envGitSHA1,
appUptimeShort: timeAgo.format( Date.now() - Math.round( process.uptime() ) * 1000, 'twitter' ),
appUptimeLong: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
appStartup: Math.round( TIME_STARTUP ) / 1000
}, ( err, data ) => }, ( err, data ) =>
{ {
if ( !err ) if ( !err )
{ {
Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ), Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Request accepted by ejs` ), chalk.blueBright( `<msg>` ), chalk.gray( `Request accepted by ejs` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
@@ -2214,21 +2307,33 @@ const server = http.createServer( ( request, response ) =>
if ( fileMime !== 'text/html' ) if ( fileMime !== 'text/html' )
data = fs.readFileSync( `./${ envWebFolder }/${ loadFile }` ); data = fs.readFileSync( `./${ envWebFolder }/${ loadFile }` );
response.setHeader( 'Content-type', fileMime ); resp.setHeader( 'Content-type', fileMime );
response.end( data ); resp.end( data );
Log.ok( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ), if ( fileMime === 'text/html' || fileMime === 'application/xml' || fileMime === 'application/json' )
chalk.greenBright( `<msg>` ), chalk.gray( `Request to load file` ), {
chalk.greenBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), Log.ok( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.greenBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.greenBright( `<msg>` ), chalk.gray( `Request to load file` ),
chalk.greenBright( `<mime>` ), chalk.gray( `${ fileMime }` ), chalk.greenBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.greenBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.greenBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.greenBright( `<mime>` ), chalk.gray( `${ fileMime }` ),
chalk.greenBright( `<method>` ), chalk.gray( `${ method }` ) );
}
else
{
Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Request to load file` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<mime>` ), chalk.gray( `${ fileMime }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
}
} }
else else
{ {
Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ), Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Request rejected by ejs` ), chalk.blueBright( `<msg>` ), chalk.gray( `Request rejected by ejs` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<error>` ), chalk.gray( `${ err }` ), chalk.blueBright( `<error>` ), chalk.gray( `${ err }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
@@ -2243,35 +2348,36 @@ const server = http.createServer( ( request, response ) =>
{ {
ip: envIpContainer, ip: envIpContainer,
gateway: envIpGateway, gateway: envIpGateway,
client: clientIp( request ), client: clientIp( req ),
message: 'Page not found', message: 'Page not found',
status: 'healthy', status: 'healthy',
ref: request.url, ref: req.url,
method: method || 'GET', method: method || 'GET',
code: 404, code: 404,
uptime: Math.round( process.uptime() ), uptime: Math.round( process.uptime() ),
uptimeHuman: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
timestamp: Date.now() timestamp: Date.now()
}; };
response.writeHead( statusCheck.code, { resp.writeHead( statusCheck.code, {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}); });
Log.error( `http`, chalk.redBright( `[requests]` ), chalk.white( `` ), Log.error( `http`, chalk.redBright( `[requests]` ), chalk.white( `` ),
chalk.redBright( `<msg>` ), chalk.gray( `${ statusCheck.message }` ), chalk.redBright( `<msg>` ), chalk.gray( `${ statusCheck.message }` ),
chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ), chalk.redBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<code>` ), chalk.gray( `${ statusCheck.code }` ), chalk.redBright( `<code>` ), chalk.gray( `${ statusCheck.code }` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ), chalk.redBright( `<error>` ), chalk.gray( `${ err }` ),
chalk.redBright( `<file>` ), chalk.gray( `${ loadFile }` ), chalk.redBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.redBright( `<method>` ), chalk.gray( `${ method }` ) ); chalk.redBright( `<method>` ), chalk.gray( `${ method }` ) );
response.end( JSON.stringify( statusCheck ) ); resp.end( JSON.stringify( statusCheck ) );
} }
}); });
}; };
handleRequest().catch( ( err ) => handleRequest().catch( ( err ) =>
{ {
response.writeHead( 500, { resp.writeHead( 500, {
'Content-Type': 'text/plain' 'Content-Type': 'text/plain'
}); });
@@ -2280,7 +2386,7 @@ const server = http.createServer( ( request, response ) =>
chalk.redBright( `<code>` ), chalk.gray( `500` ), chalk.redBright( `<code>` ), chalk.gray( `500` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ) ); chalk.redBright( `<error>` ), chalk.gray( `${ err }` ) );
response.end( 'Internal Server Error' ); resp.end( 'Internal Server Error' );
}); });
}); });
@@ -2313,7 +2419,9 @@ const server = http.createServer( ( request, response ) =>
serviceCheck( 'TVPass.org', 'https://tvpass.org' ); serviceCheck( 'TVPass.org', 'https://tvpass.org' );
serviceCheck( 'TheTVApp.to', 'https://thetvapp.to' ); serviceCheck( 'TheTVApp.to', 'https://thetvapp.to' );
serviceCheck( 'MoveOnJoy.com', 'https://moveonjoy.com' ); serviceCheck( 'MoveOnJoy.com', 'http://moveonjoy.com' );
serviceCheck( 'Daddylive.dad', 'https://daddylive.dad' );
serviceCheck( 'Newkso.ru', 'https://zekonew.newkso.ru/zeko' );
/* /*
start web server start web server
@@ -2323,7 +2431,13 @@ const server = http.createServer( ( request, response ) =>
{ {
Log.ok( `core`, chalk.yellow( `[initiate]` ), chalk.white( `` ), Log.ok( `core`, chalk.yellow( `[initiate]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Server is now running on` ), chalk.blueBright( `<msg>` ), chalk.gray( `Server is now running on` ),
chalk.blueBright( `<address>` ), chalk.whiteBright.bgBlack( ` ${ envWebIP }:${ envWebPort } ` ) ); chalk.blueBright( `<ipPublic>` ), chalk.whiteBright.bgBlack( ` ${ envWebIP }:${ envWebPort } ` ),
chalk.blueBright( `<ipDocker>` ), chalk.whiteBright.bgBlack( ` ${ envIpContainer }:${ envWebPort } ` ) );
Log.info( `core`, chalk.yellow( `[initiate]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Running TVApp2 version` ),
chalk.blueBright( `<version>` ), chalk.gray( ` ${ version } ` ),
chalk.blueBright( `<release>` ), chalk.gray( ` ${ envAppRelease } ` ) );
}); });
})(); })();

View File

@@ -1,26 +1,43 @@
{ {
"name": "tvapp2", "name": "tvapp2",
"version": "1.5.0", "version": "1.5.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"node_modules/@babel/runtime": { "node_modules/@aetherinox/noxenv": {
"version": "7.27.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", "resolved": "https://registry.npmjs.org/@aetherinox/noxenv/-/noxenv-1.1.1.tgz",
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", "integrity": "sha512-oSk7rEI4xzC4R1IykulJf+H2hZ6/OQIqX2ZA60IIU3yy91l5UgjkeHIDQguIdC2zVfjPeW5JqI14NMZyH4WMfw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "cross-spawn": "^7.0.6",
"uuid": "^11.1.0"
}, },
"bin": {
"noxenv": "src/bin/noxenv.js",
"noxenv-shell": "src/bin/noxenv-shell.js"
},
"engines": {
"node": ">=20.9.0",
"npm": ">=10",
"yarn": ">=1"
}
},
"node_modules/@babel/runtime": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz",
"integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==",
"dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@eslint-community/eslint-utils": { "node_modules/@eslint-community/eslint-utils": {
"version": "4.6.1", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
"integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==", "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -60,9 +77,9 @@
} }
}, },
"node_modules/@eslint/config-array": { "node_modules/@eslint/config-array": {
"version": "0.19.2", "version": "0.20.0",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
"integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@@ -74,10 +91,20 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@eslint/config-helpers": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz",
"integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/core": { "node_modules/@eslint/core": {
"version": "0.9.1", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
"integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@@ -112,13 +139,16 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.17.0", "version": "9.28.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
"integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://eslint.org/donate"
} }
}, },
"node_modules/@eslint/object-schema": { "node_modules/@eslint/object-schema": {
@@ -132,32 +162,19 @@
} }
}, },
"node_modules/@eslint/plugin-kit": { "node_modules/@eslint/plugin-kit": {
"version": "0.2.8", "version": "0.3.1",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz",
"integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@eslint/core": "^0.13.0", "@eslint/core": "^0.14.0",
"levn": "^0.4.1" "levn": "^0.4.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
"integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@humanfs/core": { "node_modules/@humanfs/core": {
"version": "0.19.1", "version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -211,9 +228,9 @@
} }
}, },
"node_modules/@humanwhocodes/retry": { "node_modules/@humanwhocodes/retry": {
"version": "0.4.2", "version": "0.4.3",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
"integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
@@ -232,9 +249,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@stylistic/eslint-plugin-js": { "node_modules/@stylistic/eslint-plugin-js": {
"version": "4.2.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.2.0.tgz", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.4.0.tgz",
"integrity": "sha512-MiJr6wvyzMYl/wElmj8Jns8zH7Q1w8XoVtm+WM6yDaTrfxryMyb8n0CMxt82fo42RoLIfxAEtM6tmQVxqhk0/A==", "integrity": "sha512-UeeQNRF73zJXnNGGbvwgUgzS+vzVGQoRuQKR6RhQCRHQmaBaVHxDDQVmN9RPLCnRxVjO/v8cqq/yMDqC7DikSQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -269,6 +286,12 @@
"dev": true, "dev": true,
"license": "MIT" "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": { "node_modules/@types/uuid": {
"version": "10.0.0", "version": "10.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
@@ -814,6 +837,19 @@
"node": ">=6.6.0" "node": ">=6.6.0"
} }
}, },
"node_modules/cron": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/cron/-/cron-4.3.1.tgz",
"integrity": "sha512-7x7DoEOxV11t3OPWWMjj1xrL1PGkTV5RV+/54IJTZD7gStiaMploY43EkeBSkDZTLRbUwk+OISbQ0TR133oXyA==",
"license": "MIT",
"dependencies": {
"@types/luxon": "~3.6.0",
"luxon": "~3.6.0"
},
"engines": {
"node": ">=18.x"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -884,9 +920,9 @@
} }
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.0", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
@@ -1065,9 +1101,9 @@
} }
}, },
"node_modules/es-abstract": { "node_modules/es-abstract": {
"version": "1.23.9", "version": "1.23.10",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz",
"integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "integrity": "sha512-MtUbM072wlJNyeYAe0mhzrD+M6DIJa96CZAOBBrhDbgKnB4MApIKefcyAB1eOdYn8cUNZgvwBvEzdoAYsxgEIw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1075,18 +1111,18 @@
"arraybuffer.prototype.slice": "^1.0.4", "arraybuffer.prototype.slice": "^1.0.4",
"available-typed-arrays": "^1.0.7", "available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8", "call-bind": "^1.0.8",
"call-bound": "^1.0.3", "call-bound": "^1.0.4",
"data-view-buffer": "^1.0.2", "data-view-buffer": "^1.0.2",
"data-view-byte-length": "^1.0.2", "data-view-byte-length": "^1.0.2",
"data-view-byte-offset": "^1.0.1", "data-view-byte-offset": "^1.0.1",
"es-define-property": "^1.0.1", "es-define-property": "^1.0.1",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0", "es-object-atoms": "^1.1.1",
"es-set-tostringtag": "^2.1.0", "es-set-tostringtag": "^2.1.0",
"es-to-primitive": "^1.3.0", "es-to-primitive": "^1.3.0",
"function.prototype.name": "^1.1.8", "function.prototype.name": "^1.1.8",
"get-intrinsic": "^1.2.7", "get-intrinsic": "^1.3.0",
"get-proto": "^1.0.0", "get-proto": "^1.0.1",
"get-symbol-description": "^1.1.0", "get-symbol-description": "^1.1.0",
"globalthis": "^1.0.4", "globalthis": "^1.0.4",
"gopd": "^1.2.0", "gopd": "^1.2.0",
@@ -1102,13 +1138,13 @@
"is-shared-array-buffer": "^1.0.4", "is-shared-array-buffer": "^1.0.4",
"is-string": "^1.1.1", "is-string": "^1.1.1",
"is-typed-array": "^1.1.15", "is-typed-array": "^1.1.15",
"is-weakref": "^1.1.0", "is-weakref": "^1.1.1",
"math-intrinsics": "^1.1.0", "math-intrinsics": "^1.1.0",
"object-inspect": "^1.13.3", "object-inspect": "^1.13.4",
"object-keys": "^1.1.1", "object-keys": "^1.1.1",
"object.assign": "^4.1.7", "object.assign": "^4.1.7",
"own-keys": "^1.0.1", "own-keys": "^1.0.1",
"regexp.prototype.flags": "^1.5.3", "regexp.prototype.flags": "^1.5.4",
"safe-array-concat": "^1.1.3", "safe-array-concat": "^1.1.3",
"safe-push-apply": "^1.0.0", "safe-push-apply": "^1.0.0",
"safe-regex-test": "^1.1.0", "safe-regex-test": "^1.1.0",
@@ -1121,7 +1157,7 @@
"typed-array-byte-offset": "^1.0.4", "typed-array-byte-offset": "^1.0.4",
"typed-array-length": "^1.0.7", "typed-array-length": "^1.0.7",
"unbox-primitive": "^1.1.0", "unbox-primitive": "^1.1.0",
"which-typed-array": "^1.1.18" "which-typed-array": "^1.1.19"
}, },
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -1227,22 +1263,23 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.17.0", "version": "9.28.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
"integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.0", "@eslint/config-array": "^0.20.0",
"@eslint/core": "^0.9.0", "@eslint/config-helpers": "^0.2.1",
"@eslint/eslintrc": "^3.2.0", "@eslint/core": "^0.14.0",
"@eslint/js": "9.17.0", "@eslint/eslintrc": "^3.3.1",
"@eslint/plugin-kit": "^0.2.3", "@eslint/js": "9.28.0",
"@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.1", "@humanwhocodes/retry": "^0.4.2",
"@types/estree": "^1.0.6", "@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15", "@types/json-schema": "^7.0.15",
"ajv": "^6.12.4", "ajv": "^6.12.4",
@@ -1250,7 +1287,7 @@
"cross-spawn": "^7.0.6", "cross-spawn": "^7.0.6",
"debug": "^4.3.2", "debug": "^4.3.2",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.2.0", "eslint-scope": "^8.3.0",
"eslint-visitor-keys": "^4.2.0", "eslint-visitor-keys": "^4.2.0",
"espree": "^10.3.0", "espree": "^10.3.0",
"esquery": "^1.5.0", "esquery": "^1.5.0",
@@ -1303,9 +1340,9 @@
} }
}, },
"node_modules/eslint-compat-utils/node_modules/semver": { "node_modules/eslint-compat-utils/node_modules/semver": {
"version": "7.7.1", "version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
@@ -1445,13 +1482,13 @@
} }
}, },
"node_modules/eslint-plugin-n": { "node_modules/eslint-plugin-n": {
"version": "17.15.0", "version": "17.18.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.15.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.18.0.tgz",
"integrity": "sha512-xF3zJkOfLlFOm5TvmqmsnA9/fO+/z2pYs0dkuKXKN/ymS6UB1yEcaoIkqxLKQ9Dw/WmLX/Tdh6/5ZS5azVixFQ==", "integrity": "sha512-hvZ/HusueqTJ7VDLoCpjN0hx4N4+jHIWTXD4TMLHy9F23XkDagR9v+xQWRWR57yY55GPF8NnD4ox9iGTxirY8A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.1", "@eslint-community/eslint-utils": "^4.5.0",
"enhanced-resolve": "^5.17.1", "enhanced-resolve": "^5.17.1",
"eslint-plugin-es-x": "^7.8.0", "eslint-plugin-es-x": "^7.8.0",
"get-tsconfig": "^4.8.1", "get-tsconfig": "^4.8.1",
@@ -1510,9 +1547,9 @@
} }
}, },
"node_modules/eslint-plugin-n/node_modules/semver": { "node_modules/eslint-plugin-n/node_modules/semver": {
"version": "7.7.1", "version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
@@ -2016,9 +2053,9 @@
} }
}, },
"node_modules/get-tsconfig": { "node_modules/get-tsconfig": {
"version": "4.10.0", "version": "4.10.1",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
"integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2887,6 +2924,15 @@
"dev": true, "dev": true,
"license": "MIT" "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": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -3008,6 +3054,15 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/node-cron": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.1.0.tgz",
"integrity": "sha512-OS+3ORu+h03/haS6Di8Qr7CrVs4YaKZZOynZwQpyPZDnR3tqRbwJmuP2gVR16JfhLgyNlloAV1VTrrWlRogCFA==",
"license": "ISC",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/node-fetch": { "node_modules/node-fetch": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
@@ -3336,8 +3391,6 @@
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz",
"integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.52.0" "playwright-core": "1.52.0"
@@ -3354,8 +3407,6 @@
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz",
"integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"
@@ -3486,13 +3537,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true,
"license": "MIT"
},
"node_modules/regexp.prototype.flags": { "node_modules/regexp.prototype.flags": {
"version": "1.5.4", "version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
@@ -4062,9 +4106,9 @@
} }
}, },
"node_modules/tapable": { "node_modules/tapable": {
"version": "2.2.1", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -4284,9 +4328,9 @@
} }
}, },
"node_modules/user-agents": { "node_modules/user-agents": {
"version": "1.1.529", "version": "1.1.557",
"resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.1.529.tgz", "resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.1.557.tgz",
"integrity": "sha512-8/ha9jnpBjUhC7+kpdAimo+mQVUMFhTJEkGVRSUsxK6YWuVZ6il+6ErVMjWpfX7q1Ft0m/4+XpPJhGuqZesFTQ==", "integrity": "sha512-7WD00n8KYmGlQEVgV4qRvH7NkcRt9KgEd7Sc95nRPcHCK8iOa5Ke85psgQKI6R+iWmBuuQKNKl2e46m6EvUTfA==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"lodash.clonedeep": "^4.5.0" "lodash.clonedeep": "^4.5.0"

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,6 +1,6 @@
{ {
"name": "user-agents", "name": "user-agents",
"version": "1.1.529", "version": "1.1.557",
"description": "A JavaScript library for generating random user agents. ", "description": "A JavaScript library for generating random user agents. ",
"main": "dist/index.js", "main": "dist/index.js",
"repository": "git@github.com:intoli/user-agents.git", "repository": "git@github.com:intoli/user-agents.git",

Binary file not shown.

362
tvapp2/package-lock.json generated
View File

@@ -1,32 +1,35 @@
{ {
"name": "tvapp2", "name": "tvapp2",
"version": "1.5.1", "version": "1.5.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "tvapp2", "name": "tvapp2",
"version": "1.5.1", "version": "1.5.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chalk": "^5.3.0", "chalk": "^5.4.1",
"cron": "^4.3.0", "cron": "^4.3.1",
"ejs": "^3.1.10", "ejs": "^3.1.10",
"express": "5.1.0", "express": "5.1.0",
"javascript-time-ago": "2.5.11",
"moment": "2.30.1", "moment": "2.30.1",
"node-cron": "^4.0.3", "nconf": "1.0.0-beta.2",
"node-cron": "^4.1.0",
"playwright": "^1.52.0", "playwright": "^1.52.0",
"user-agents": "^1.1.537" "user-agents": "^1.1.557"
}, },
"devDependencies": { "devDependencies": {
"@stylistic/eslint-plugin-js": "^4.2.0", "@aetherinox/noxenv": "^1.1.1",
"@stylistic/eslint-plugin-js": "^4.4.0",
"@types/uuid": "^10.0.0", "@types/uuid": "^10.0.0",
"all-contributors-cli": "^6.26.1", "all-contributors-cli": "^6.26.1",
"env-cmd": "^10.1.0", "env-cmd": "^10.1.0",
"eslint": "9.17.0", "eslint": "9.28.0",
"eslint-plugin-chai-friendly": "^1.0.1", "eslint-plugin-chai-friendly": "^1.0.1",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-n": "17.15.0", "eslint-plugin-n": "17.18.0",
"eslint-plugin-promise": "7.2.1", "eslint-plugin-promise": "7.2.1",
"uuid": "^11.1.0" "uuid": "^11.1.0"
}, },
@@ -34,23 +37,40 @@
"node": ">=20" "node": ">=20"
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@aetherinox/noxenv": {
"version": "7.27.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", "resolved": "https://registry.npmjs.org/@aetherinox/noxenv/-/noxenv-1.1.1.tgz",
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", "integrity": "sha512-oSk7rEI4xzC4R1IykulJf+H2hZ6/OQIqX2ZA60IIU3yy91l5UgjkeHIDQguIdC2zVfjPeW5JqI14NMZyH4WMfw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "cross-spawn": "^7.0.6",
"uuid": "^11.1.0"
}, },
"bin": {
"noxenv": "src/bin/noxenv.js",
"noxenv-shell": "src/bin/noxenv-shell.js"
},
"engines": {
"node": ">=20.9.0",
"npm": ">=10",
"yarn": ">=1"
}
},
"node_modules/@babel/runtime": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz",
"integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==",
"dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@eslint-community/eslint-utils": { "node_modules/@eslint-community/eslint-utils": {
"version": "4.6.1", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
"integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==", "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -90,9 +110,9 @@
} }
}, },
"node_modules/@eslint/config-array": { "node_modules/@eslint/config-array": {
"version": "0.19.2", "version": "0.20.0",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
"integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@@ -104,10 +124,20 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@eslint/config-helpers": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz",
"integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/core": { "node_modules/@eslint/core": {
"version": "0.9.1", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
"integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@@ -142,13 +172,16 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.17.0", "version": "9.28.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
"integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://eslint.org/donate"
} }
}, },
"node_modules/@eslint/object-schema": { "node_modules/@eslint/object-schema": {
@@ -162,32 +195,19 @@
} }
}, },
"node_modules/@eslint/plugin-kit": { "node_modules/@eslint/plugin-kit": {
"version": "0.2.8", "version": "0.3.1",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz",
"integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@eslint/core": "^0.13.0", "@eslint/core": "^0.14.0",
"levn": "^0.4.1" "levn": "^0.4.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
"integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@humanfs/core": { "node_modules/@humanfs/core": {
"version": "0.19.1", "version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -241,9 +261,9 @@
} }
}, },
"node_modules/@humanwhocodes/retry": { "node_modules/@humanwhocodes/retry": {
"version": "0.4.2", "version": "0.4.3",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
"integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
@@ -262,9 +282,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@stylistic/eslint-plugin-js": { "node_modules/@stylistic/eslint-plugin-js": {
"version": "4.2.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.2.0.tgz", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.4.0.tgz",
"integrity": "sha512-MiJr6wvyzMYl/wElmj8Jns8zH7Q1w8XoVtm+WM6yDaTrfxryMyb8n0CMxt82fo42RoLIfxAEtM6tmQVxqhk0/A==", "integrity": "sha512-UeeQNRF73zJXnNGGbvwgUgzS+vzVGQoRuQKR6RhQCRHQmaBaVHxDDQVmN9RPLCnRxVjO/v8cqq/yMDqC7DikSQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -430,7 +450,6 @@
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@@ -851,9 +870,9 @@
} }
}, },
"node_modules/cron": { "node_modules/cron": {
"version": "4.3.0", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/cron/-/cron-4.3.0.tgz", "resolved": "https://registry.npmjs.org/cron/-/cron-4.3.1.tgz",
"integrity": "sha512-ciiYNLfSlF9MrDqnbMdRWFiA6oizSF7kA1osPP9lRzNu0Uu+AWog1UKy7SkckiDY2irrNjeO6qLyKnXC8oxmrw==", "integrity": "sha512-7x7DoEOxV11t3OPWWMjj1xrL1PGkTV5RV+/54IJTZD7gStiaMploY43EkeBSkDZTLRbUwk+OISbQ0TR133oXyA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/luxon": "~3.6.0", "@types/luxon": "~3.6.0",
@@ -933,9 +952,9 @@
} }
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.0", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
@@ -1070,7 +1089,6 @@
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/encodeurl": { "node_modules/encodeurl": {
@@ -1114,9 +1132,9 @@
} }
}, },
"node_modules/es-abstract": { "node_modules/es-abstract": {
"version": "1.23.9", "version": "1.23.10",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.10.tgz",
"integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "integrity": "sha512-MtUbM072wlJNyeYAe0mhzrD+M6DIJa96CZAOBBrhDbgKnB4MApIKefcyAB1eOdYn8cUNZgvwBvEzdoAYsxgEIw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1124,18 +1142,18 @@
"arraybuffer.prototype.slice": "^1.0.4", "arraybuffer.prototype.slice": "^1.0.4",
"available-typed-arrays": "^1.0.7", "available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8", "call-bind": "^1.0.8",
"call-bound": "^1.0.3", "call-bound": "^1.0.4",
"data-view-buffer": "^1.0.2", "data-view-buffer": "^1.0.2",
"data-view-byte-length": "^1.0.2", "data-view-byte-length": "^1.0.2",
"data-view-byte-offset": "^1.0.1", "data-view-byte-offset": "^1.0.1",
"es-define-property": "^1.0.1", "es-define-property": "^1.0.1",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0", "es-object-atoms": "^1.1.1",
"es-set-tostringtag": "^2.1.0", "es-set-tostringtag": "^2.1.0",
"es-to-primitive": "^1.3.0", "es-to-primitive": "^1.3.0",
"function.prototype.name": "^1.1.8", "function.prototype.name": "^1.1.8",
"get-intrinsic": "^1.2.7", "get-intrinsic": "^1.3.0",
"get-proto": "^1.0.0", "get-proto": "^1.0.1",
"get-symbol-description": "^1.1.0", "get-symbol-description": "^1.1.0",
"globalthis": "^1.0.4", "globalthis": "^1.0.4",
"gopd": "^1.2.0", "gopd": "^1.2.0",
@@ -1151,13 +1169,13 @@
"is-shared-array-buffer": "^1.0.4", "is-shared-array-buffer": "^1.0.4",
"is-string": "^1.1.1", "is-string": "^1.1.1",
"is-typed-array": "^1.1.15", "is-typed-array": "^1.1.15",
"is-weakref": "^1.1.0", "is-weakref": "^1.1.1",
"math-intrinsics": "^1.1.0", "math-intrinsics": "^1.1.0",
"object-inspect": "^1.13.3", "object-inspect": "^1.13.4",
"object-keys": "^1.1.1", "object-keys": "^1.1.1",
"object.assign": "^4.1.7", "object.assign": "^4.1.7",
"own-keys": "^1.0.1", "own-keys": "^1.0.1",
"regexp.prototype.flags": "^1.5.3", "regexp.prototype.flags": "^1.5.4",
"safe-array-concat": "^1.1.3", "safe-array-concat": "^1.1.3",
"safe-push-apply": "^1.0.0", "safe-push-apply": "^1.0.0",
"safe-regex-test": "^1.1.0", "safe-regex-test": "^1.1.0",
@@ -1170,7 +1188,7 @@
"typed-array-byte-offset": "^1.0.4", "typed-array-byte-offset": "^1.0.4",
"typed-array-length": "^1.0.7", "typed-array-length": "^1.0.7",
"unbox-primitive": "^1.1.0", "unbox-primitive": "^1.1.0",
"which-typed-array": "^1.1.18" "which-typed-array": "^1.1.19"
}, },
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -1256,6 +1274,15 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/escape-html": { "node_modules/escape-html": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -1276,22 +1303,23 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.17.0", "version": "9.28.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
"integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.0", "@eslint/config-array": "^0.20.0",
"@eslint/core": "^0.9.0", "@eslint/config-helpers": "^0.2.1",
"@eslint/eslintrc": "^3.2.0", "@eslint/core": "^0.14.0",
"@eslint/js": "9.17.0", "@eslint/eslintrc": "^3.3.1",
"@eslint/plugin-kit": "^0.2.3", "@eslint/js": "9.28.0",
"@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.1", "@humanwhocodes/retry": "^0.4.2",
"@types/estree": "^1.0.6", "@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15", "@types/json-schema": "^7.0.15",
"ajv": "^6.12.4", "ajv": "^6.12.4",
@@ -1299,7 +1327,7 @@
"cross-spawn": "^7.0.6", "cross-spawn": "^7.0.6",
"debug": "^4.3.2", "debug": "^4.3.2",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.2.0", "eslint-scope": "^8.3.0",
"eslint-visitor-keys": "^4.2.0", "eslint-visitor-keys": "^4.2.0",
"espree": "^10.3.0", "espree": "^10.3.0",
"esquery": "^1.5.0", "esquery": "^1.5.0",
@@ -1352,9 +1380,9 @@
} }
}, },
"node_modules/eslint-compat-utils/node_modules/semver": { "node_modules/eslint-compat-utils/node_modules/semver": {
"version": "7.7.1", "version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
@@ -1494,13 +1522,13 @@
} }
}, },
"node_modules/eslint-plugin-n": { "node_modules/eslint-plugin-n": {
"version": "17.15.0", "version": "17.18.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.15.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.18.0.tgz",
"integrity": "sha512-xF3zJkOfLlFOm5TvmqmsnA9/fO+/z2pYs0dkuKXKN/ymS6UB1yEcaoIkqxLKQ9Dw/WmLX/Tdh6/5ZS5azVixFQ==", "integrity": "sha512-hvZ/HusueqTJ7VDLoCpjN0hx4N4+jHIWTXD4TMLHy9F23XkDagR9v+xQWRWR57yY55GPF8NnD4ox9iGTxirY8A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.1", "@eslint-community/eslint-utils": "^4.5.0",
"enhanced-resolve": "^5.17.1", "enhanced-resolve": "^5.17.1",
"eslint-plugin-es-x": "^7.8.0", "eslint-plugin-es-x": "^7.8.0",
"get-tsconfig": "^4.8.1", "get-tsconfig": "^4.8.1",
@@ -1559,9 +1587,9 @@
} }
}, },
"node_modules/eslint-plugin-n/node_modules/semver": { "node_modules/eslint-plugin-n/node_modules/semver": {
"version": "7.7.1", "version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
@@ -1959,20 +1987,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -2017,7 +2031,6 @@
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"license": "ISC", "license": "ISC",
"engines": { "engines": {
"node": "6.* || 8.* || >= 10.*" "node": "6.* || 8.* || >= 10.*"
@@ -2079,9 +2092,9 @@
} }
}, },
"node_modules/get-tsconfig": { "node_modules/get-tsconfig": {
"version": "4.10.0", "version": "4.10.1",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
"integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2315,6 +2328,15 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/ini": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
"integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
"license": "ISC",
"engines": {
"node": ">=10"
}
},
"node_modules/inquirer": { "node_modules/inquirer": {
"version": "7.3.3", "version": "7.3.3",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
@@ -2546,7 +2568,6 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@@ -2813,6 +2834,15 @@
"url": "https://github.com/chalk/chalk?sponsor=1" "url": "https://github.com/chalk/chalk?sponsor=1"
} }
}, },
"node_modules/javascript-time-ago": {
"version": "2.5.11",
"resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.5.11.tgz",
"integrity": "sha512-Zeyf5R7oM1fSMW9zsU3YgAYwE0bimEeF54Udn2ixGd8PUwu+z1Yc5t4Y8YScJDMHD6uCx6giLt3VJR5K4CMwbg==",
"license": "MIT",
"dependencies": {
"relative-time-format": "^1.1.6"
}
},
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@@ -3071,6 +3101,86 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/nconf": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/nconf/-/nconf-1.0.0-beta.2.tgz",
"integrity": "sha512-1AsulxjcXgTHRZ1ZCKj4AzdPJI1MlbFkdrd9Pzd3s+K9XiDZfJRO0351dIGuT3wcaSTRd5s3sPoFHR6Kk9W6lA==",
"license": "MIT",
"dependencies": {
"ini": "^2.0.0",
"yargs": "^17.0.0"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/nconf/node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/nconf/node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/nconf/node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"license": "ISC",
"engines": {
"node": ">=10"
}
},
"node_modules/nconf/node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"license": "MIT",
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/nconf/node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
@@ -3081,9 +3191,9 @@
} }
}, },
"node_modules/node-cron": { "node_modules/node-cron": {
"version": "4.0.3", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.0.3.tgz", "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.1.0.tgz",
"integrity": "sha512-YPEUlbYGgpfN44OtCm4KkK4TXjeIB4arERbDWP7kJgM+QHFK9AdM6/3bp4M3oB1QBrL5INyTRLAPei87j49foA==", "integrity": "sha512-OS+3ORu+h03/haS6Di8Qr7CrVs4YaKZZOynZwQpyPZDnR3tqRbwJmuP2gVR16JfhLgyNlloAV1VTrrWlRogCFA==",
"license": "ISC", "license": "ISC",
"engines": { "engines": {
"node": ">=6.0.0" "node": ">=6.0.0"
@@ -3417,8 +3527,6 @@
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz",
"integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.52.0" "playwright-core": "1.52.0"
@@ -3435,8 +3543,6 @@
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz",
"integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"
@@ -3567,13 +3673,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"dev": true,
"license": "MIT"
},
"node_modules/regexp.prototype.flags": { "node_modules/regexp.prototype.flags": {
"version": "1.5.4", "version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
@@ -3595,11 +3694,16 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/relative-time-format": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/relative-time-format/-/relative-time-format-1.1.6.tgz",
"integrity": "sha512-aCv3juQw4hT1/P/OrVltKWLlp15eW1GRcwP1XdxHrPdZE9MtgqFpegjnTjLhi2m2WI9MT/hQQtE+tjEWG1hgkQ==",
"license": "MIT"
},
"node_modules/require-directory": { "node_modules/require-directory": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@@ -4011,7 +4115,6 @@
"version": "4.2.3", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"emoji-regex": "^8.0.0", "emoji-regex": "^8.0.0",
@@ -4085,7 +4188,6 @@
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ansi-regex": "^5.0.1" "ansi-regex": "^5.0.1"
@@ -4143,9 +4245,9 @@
} }
}, },
"node_modules/tapable": { "node_modules/tapable": {
"version": "2.2.1", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -4365,9 +4467,9 @@
} }
}, },
"node_modules/user-agents": { "node_modules/user-agents": {
"version": "1.1.537", "version": "1.1.557",
"resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.1.537.tgz", "resolved": "https://registry.npmjs.org/user-agents/-/user-agents-1.1.557.tgz",
"integrity": "sha512-D3t8f1G3Kd3Ak0t9Md9oNsK59Ms1hs9FhdwkMafkaNpwpMcq/FHuHHT/ky64Dy8aKJkMFcEBeVN0zQmtoTKCKg==", "integrity": "sha512-7WD00n8KYmGlQEVgV4qRvH7NkcRt9KgEd7Sc95nRPcHCK8iOa5Ke85psgQKI6R+iWmBuuQKNKl2e46m6EvUTfA==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"lodash.clonedeep": "^4.5.0" "lodash.clonedeep": "^4.5.0"

View File

@@ -1,6 +1,6 @@
{ {
"name": "tvapp2", "name": "tvapp2",
"version": "1.5.1", "version": "1.5.3",
"description": "This package allows you to generate M3U playlists and EPG guides from various online IPTV services.", "description": "This package allows you to generate M3U playlists and EPG guides from various online IPTV services.",
"author": "BinaryNinja", "author": "BinaryNinja",
"license": "MIT", "license": "MIT",
@@ -72,26 +72,29 @@
"iptv" "iptv"
], ],
"dependencies": { "dependencies": {
"cron": "^4.3.0", "cron": "^4.3.1",
"node-cron": "^4.0.3", "node-cron": "^4.1.0",
"playwright": "^1.52.0", "playwright": "^1.52.0",
"user-agents": "^1.1.537", "user-agents": "^1.1.557",
"chalk": "^5.3.0", "chalk": "^5.4.1",
"ejs": "^3.1.10", "ejs": "^3.1.10",
"moment": "2.30.1", "moment": "2.30.1",
"express": "5.1.0" "express": "5.1.0",
"nconf": "1.0.0-beta.2",
"javascript-time-ago": "2.5.11"
}, },
"devDependencies": { "devDependencies": {
"@aetherinox/noxenv": "^1.1.1",
"@types/uuid": "^10.0.0", "@types/uuid": "^10.0.0",
"all-contributors-cli": "^6.26.1", "all-contributors-cli": "^6.26.1",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"env-cmd": "^10.1.0", "env-cmd": "^10.1.0",
"eslint": "9.17.0", "eslint": "9.28.0",
"eslint-plugin-chai-friendly": "^1.0.1", "eslint-plugin-chai-friendly": "^1.0.1",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-n": "17.15.0", "eslint-plugin-n": "17.18.0",
"eslint-plugin-promise": "7.2.1", "eslint-plugin-promise": "7.2.1",
"@stylistic/eslint-plugin-js": "^4.2.0" "@stylistic/eslint-plugin-js": "^4.4.0"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=20"

View File

@@ -18,14 +18,14 @@
<nav class="navbar sticky-top container"> <nav class="navbar sticky-top container">
<div class="navbar-brand"> <div class="navbar-brand">
<i data-bs-toggle="tooltip" title="v<%= appVersion %>" class="logo fa-sharp-duotone fa-regular fa-tv" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i> <i data-bs-toggle="tooltip" title="v<%= appVersion %>" class="logo fa-sharp-duotone fa-regular fa-tv" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i>
<a class="header-name" href="<%= appUrlGithub %>">TVApp2 for Docker</a> <a target="_blank" data-bs-toggle="tooltip" title="View Github Repository" class="header-name" href="<%= appUrlGithub %>">TVApp2 for Docker</a>
</div> </div>
<div class="navbar-social"> <div class="navbar-social">
<a href=""><i id="action-health" data-bs-toggle="tooltip" title="Health" class="heart logo health fa-duotone fa-solid fa-heart" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a> <i id="action-health" data-bs-toggle="tooltip" title="Health" class="heart logo health fa-duotone fa-solid fa-heart" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i>
<a href="javascript:runResync();"><i id="action-resync" data-bs-toggle="tooltip" title="Resync" class="restart fa-solid fa-rotate" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a> <a href="javascript:runResync();"><i id="action-resync" data-bs-toggle="tooltip" title="Resync" class="restart fa-solid fa-rotate" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
<a href="<%= appUrlDocs %>"><i data-bs-toggle="tooltip" title="Documentation" class="logo fa-duotone fa-solid fa-book-open-cover" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a> <a target="_blank" href="<%= appUrlDocs %>"><i data-bs-toggle="tooltip" title="Documentation" class="logo fa-duotone fa-solid fa-book-open-cover" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
<a href="<%= appUrlGithub %>"><i data-bs-toggle="tooltip" title="Github" class="logo fa-logos fa-github" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a> <a target="_blank" href="<%= appUrlGithub %>"><i data-bs-toggle="tooltip" title="Github" class="logo fa-logos fa-github" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
<a href="<%= appUrlDiscord %>"><i data-bs-toggle="tooltip" title="Discord" class="logo fa-logos fa-discord" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a> <a target="_blank" href="<%= appUrlDiscord %>"><i data-bs-toggle="tooltip" title="Discord" class="logo fa-logos fa-discord" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);" aria-hidden="true"></i></a>
</div> </div>
</nav> </nav>
</div> </div>
@@ -124,8 +124,8 @@
<div class="footer-inner"> <div class="footer-inner">
<div class="container"> <div class="container">
<div class="col text-center text-muted text-small text-nowrap"> <div class="col text-center text-muted text-small text-nowrap">
<small>Developed by BinaryNinja - <a data-bs-toggle="tooltip" title="<%= appRelease %> build" href="<%= appUrlGithub %>"><%= appName %> (<%= appRelease %>)</a> - v<%= appVersion %></small><br /> <small>Developed by BinaryNinja - <a data-bs-toggle="tooltip" title="v<%= appVersion %> <%= appRelease %> (<%= appGitHashShort %>)" href="<%= appUrlGithub %>"><%= appName %> (<%= appRelease %>)</a> v<%= appVersion %> <a target="_blank" data-bs-toggle="tooltip" title="View Github commit" href="<%= appUrlGithub %>/commit/<%= appGitHashLong %>"><%= appGitHashShort %></a></small><br />
<small>This utility is for educational purposes only</small> <small>Uptime <a id="uptime" href="" data-bs-toggle="tooltip" title="<%= appUptimeLong %>"> <%= appUptimeShort %> </a> | Startup <a id="startup" href=""><%= appStartup %>s</a></small>
</div> </div>
</div> </div>
</div> </div>
@@ -299,6 +299,7 @@
let timerDelayMS = 10000; let timerDelayMS = 10000;
let timerStartMS = Date.now(); // returns milliseconds let timerStartMS = Date.now(); // returns milliseconds
const timerHealthRun = '<%= healthTimer %>'; // time in milliseconds until health check ran AFTER initial run const timerHealthRun = '<%= healthTimer %>'; // time in milliseconds until health check ran AFTER initial run
const timerUptime = 1000;
/* /*
Action > Healthcheck Action > Healthcheck
@@ -317,7 +318,7 @@
url: 'api/health', url: 'api/health',
type: 'GET', type: 'GET',
data: { data: {
internal: 1 query: 'healthcheck'
}, },
beforeSend: function( data ) beforeSend: function( data )
{ {
@@ -362,6 +363,54 @@
}).responseText; }).responseText;
} }
function runUptime()
{
const toastTypeClass = [];
toastTypeClass[ 'DEFAULT' ] = 'text-bg-primary';
toastTypeClass[ 'UNHEALTHY' ] = 'text-bg-warning';
toastTypeClass[ 'HEALTHY' ] = 'text-bg-success';
toastTypeClass[ 'ERROR' ] = 'text-bg-danger';
$.ajax(
{
url: 'api/health',
type: 'GET',
data: {
query: 'uptime'
},
success: function( data )
{
const status = data.message;
const code = data.code;
const uptimeShort = data.uptimeShort;
const uptimeLong = data.uptimeLong;
if ( status )
{
$('a#uptime').text(`${ uptimeShort }`);
const tooltip = bootstrap.Tooltip.getInstance('#uptime') // Returns a Bootstrap tooltip instance
tooltip.setContent( { '.tooltip-inner': `App started ${ uptimeLong }` } )
}
},
error: function( data )
{
const toastClass = toastTypeClass['ERROR'];
const toastElm = document.getElementById('tvapp2Toast');
toastElm.classList.add(toastClass);
$('.toast #toast-title').html(`Could not get uptime from api`);
$('.toast #toast-message').html(`Failed to communicate with the api. Try restarting the docker container to restore connection.`);
$('#tvapp2Toast').toast('show');
}
}).always(function()
{
setTimeout(function()
{
runUptime();
}, parseInt(timerUptime));
}).responseText;
}
/* /*
Action > Do Resync Action > Do Resync
*/ */
@@ -373,7 +422,7 @@
url: 'api/restart', url: 'api/restart',
type: 'GET', type: 'GET',
data: { data: {
internal: 1 query: 'sync'
}, },
beforeSend: function( data ) beforeSend: function( data )
{ {
@@ -458,11 +507,8 @@
jQuery(function($) jQuery(function($)
{ {
$(document.body).tooltip({ selector: "[title]" }); const tooltip = bootstrap.Tooltip.getInstance('#action-health') // Returns a Bootstrap tooltip instance
$('#action-health') tooltip.setContent({ '.tooltip-inner': `Health check in ${ timeLeft }` })
.attr('data-original-title', `Health check in ${ timeLeft }`)
.attr('aria-label', `Health check in ${ timeLeft }`)
.attr('data-bs-original-title', `Health check in ${ timeLeft }`)
}); });
const Heart = document.getElementsByClassName('fa-heart'); const Heart = document.getElementsByClassName('fa-heart');
@@ -495,6 +541,7 @@
*/ */
setTimeout( function() { runHealthCheck(); }, timerDelayMS ); setTimeout( function() { runHealthCheck(); }, timerDelayMS );
setTimeout( function() { runUptime(); }, 1000 );
/* /*
Action > Tooltip Resync Timers Action > Tooltip Resync Timers