Compare commits

...

16 Commits
1.5.2 ... 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
9 changed files with 691 additions and 226 deletions

View File

@@ -74,6 +74,21 @@ on:
default: '1.0.0'
type: string
# #
# Registry Name
#
# options:
# - github
# - dockerhub
# - gitea
# #
IMAGE_REGISTRY:
description: '📘 Registry Name'
required: true
default: 'dockerhub'
type: string
# #
# Dockerhub Author
#
@@ -100,6 +115,18 @@ on:
default: 'thebinaryninja'
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
# false workflow will behave normally, and push any changes detected to the files
@@ -137,8 +164,10 @@ on:
env:
IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }}
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_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_2: BinaryServ
@@ -280,7 +309,7 @@ jobs:
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_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z
echo "GITHUB_SHA1=`git rev-parse HEAD`" >> ${GITHUB_ENV}
echo "GITHUB_SHA1=$(git rev-parse HEAD)" >> $GITHUB_ENV # 012cd0cc44c576c4a57b8a18d86793f244d1080a
# #
# Release Dockerhub Install Dependencies
@@ -413,6 +442,7 @@ jobs:
flavor: |
latest=false
labels: |
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
@@ -420,11 +450,13 @@ jobs:
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=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-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${GITHUB_SHA1}
annotations: |
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.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
@@ -432,10 +464,11 @@ jobs:
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=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-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${GITHUB_SHA1}
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# #
# Release Dockerhub Build and Push Amd64
@@ -446,21 +479,41 @@ jobs:
uses: docker/build-push-action@v6
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with:
allow: |
network.host
network: host
context: .
file: Dockerfile
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_dh_meta.outputs.labels }}
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
provenance: false
sbom: false
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
build-args: |-
ARCH=amd64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }}
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
@@ -499,21 +552,41 @@ jobs:
uses: docker/build-push-action@v6
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with:
allow: |
network.host
network: host
context: .
file: Dockerfile
platforms: linux/arm64
push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_dh_meta.outputs.labels }}
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
provenance: false
sbom: false
tags: |
${{ steps.task_release_dh_meta.outputs.tags }}
build-args: |-
ARCH=arm64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }}
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

View File

@@ -74,6 +74,21 @@ on:
default: '1.0.0'
type: string
# #
# Registry Name
#
# options:
# - github
# - dockerhub
# - gitea
# #
IMAGE_REGISTRY:
description: '📘 Registry Name'
required: true
default: 'gitea'
type: string
# #
# Gitea Author
#
@@ -111,6 +126,18 @@ on:
default: 'git.binaryninja.net'
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
# false workflow will behave normally, and push any changes detected to the files
@@ -148,9 +175,11 @@ on:
env:
IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }}
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_USERNAME: ${{ github.event.inputs.IMAGE_GITEA_USERNAME || 'BinaryNinja' }}
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_2: BinaryServ
@@ -292,7 +321,7 @@ jobs:
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_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z
echo "GITHUB_SHA1=`git rev-parse HEAD`" >> ${GITHUB_ENV}
echo "GITHUB_SHA1=$(git rev-parse HEAD)" >> $GITHUB_ENV # 012cd0cc44c576c4a57b8a18d86793f244d1080a
# #
# Release Gitea Install Dependencies
@@ -429,6 +458,7 @@ jobs:
flavor: |
latest=false
labels: |
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
@@ -436,11 +466,13 @@ jobs:
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=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-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${GITHUB_SHA1}
annotations: |
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.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
@@ -448,10 +480,11 @@ jobs:
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=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-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${GITHUB_SHA1}
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# #
# Release Gitea Meta arm64
@@ -481,6 +514,7 @@ jobs:
flavor: |
latest=false
labels: |
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
@@ -488,11 +522,13 @@ jobs:
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=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-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${GITHUB_SHA1}
annotations: |
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.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
@@ -500,10 +536,11 @@ jobs:
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=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-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${GITHUB_SHA1}
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# #
# Release Gitea Meta Release
@@ -545,6 +582,7 @@ jobs:
flavor: |
latest=false
labels: |
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
@@ -552,9 +590,13 @@ jobs:
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=gitea
org.opencontainers.image.registry=${{ env.IMAGE_REGISTRY }}
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.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
@@ -562,8 +604,11 @@ jobs:
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=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-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
@@ -574,21 +619,41 @@ jobs:
uses: docker/build-push-action@v6
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with:
allow: |
network.host
network: host
context: .
file: Dockerfile
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_gi_meta_amd64.outputs.labels }}
tags: |
${{ steps.task_release_gi_meta_amd64.outputs.tags }}
provenance: false
sbom: false
tags: |
${{ steps.task_release_gi_meta_amd64.outputs.tags }}
build-args: |-
ARCH=amd64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }}
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
@@ -627,21 +692,41 @@ jobs:
uses: docker/build-push-action@v6
if: ( github.event_name == 'workflow_dispatch' && inputs.DRY_RUN == false ) || ( github.event_name == 'push' )
with:
allow: |
network.host
network: host
context: .
file: Dockerfile
platforms: linux/arm64
push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.task_release_gi_meta_arm64.outputs.labels }}
tags: |
${{ steps.task_release_gi_meta_arm64.outputs.tags }}
provenance: false
sbom: false
tags: |
${{ steps.task_release_gi_meta_arm64.outputs.tags }}
build-args: |-
ARCH=arm64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }}
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

View File

@@ -74,6 +74,21 @@ on:
default: '1.0.0'
type: string
# #
# Registry Name
#
# options:
# - github
# - dockerhub
# - gitea
# #
IMAGE_REGISTRY:
description: '📘 Registry Name'
required: true
default: 'github'
type: string
# #
# Image Author
#
@@ -99,6 +114,18 @@ on:
default: 'TheBinaryNinja'
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
# false workflow will behave normally, and push any changes detected to the files
@@ -136,8 +163,10 @@ on:
env:
IMAGE_NAME: ${{ github.event.inputs.IMAGE_NAME || 'tvapp2' }}
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_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_2: BinaryServ
@@ -277,7 +306,7 @@ jobs:
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_TS=$(date -u +'%FT%T.%3NZ')" >> $GITHUB_ENV # 2025-02-25T12:50:11.569Z
echo "GITHUB_SHA1=`git rev-parse HEAD`" >> ${GITHUB_ENV}
echo "GITHUB_SHA1=$(git rev-parse HEAD)" >> $GITHUB_ENV # 012cd0cc44c576c4a57b8a18d86793f244d1080a
# #
# Release Github Install Dependencies
@@ -411,6 +440,7 @@ jobs:
flavor: |
latest=false
labels: |
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
@@ -418,11 +448,13 @@ jobs:
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=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-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${GITHUB_SHA1}
annotations: |
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.version=${{ env.IMAGE_VERSION }}
org.opencontainers.image.licenses=MIT
@@ -430,10 +462,11 @@ jobs:
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=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-alpine=${{ env.IMAGE_ALPINE_VERSION }}
org.tvapp2.image.build-release="${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}"
org.tvapp2.image.build-sha1=${GITHUB_SHA1}
org.tvapp2.image.build-sha1=${{ env.GITHUB_SHA1 }}
# #
# Release Github Build and Push Amd64
@@ -452,18 +485,33 @@ jobs:
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
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
sbom: false
tags: |
${{ steps.task_release_gh_meta.outputs.tags }}
build-args: |-
ARCH=amd64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }}
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
@@ -510,18 +558,33 @@ jobs:
platforms: linux/arm64
push: ${{ github.event_name != 'pull_request' }}
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
sbom: false
tags: |
${{ steps.task_release_gh_meta.outputs.tags }}
build-args: |-
ARCH=arm64
RELEASE=${{ inputs.DEV_RELEASE == true && 'development' || 'stable' }}
VERSION=${{ env.IMAGE_VERSION }}
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

View File

@@ -429,6 +429,9 @@ jobs:
sha256sum_compose="$(shasum --algorithm 256 ${filename_compose_zip} | awk '{ print $1 }')"
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
# #
@@ -461,6 +464,9 @@ jobs:
sha256_compose="$(shasum --algorithm 256 ${filename_compose_zip} | awk '{ print $1 }')"
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
# #
@@ -668,7 +674,7 @@ jobs:
if: |
startsWith( inputs.RC_RELEASE, false ) ||
startsWith( env.RC_RELEASE, false )
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v2.2.2
env:
CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
@@ -685,6 +691,8 @@ jobs:
${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}.zip
sha1sum.txt.asc
sha256sum.txt.asc
sha256sum.sig
sha1sum.sig
prerelease: false
body: |
${{ steps.task_release_changelog_categorized.outputs.changelog }}
@@ -704,7 +712,7 @@ jobs:
if: |
startsWith( inputs.RC_RELEASE, true ) ||
startsWith( env.RC_RELEASE, true )
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v2.2.2
env:
CHANGELOG_CATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
CHANGELOG_UNCATEGORIZED: ${{ steps.task_release_changelog_categorized.outputs.changelog }}
@@ -721,6 +729,8 @@ jobs:
${{ env.PROJECT_NAME }}-${{ env.PACKAGE_VERSION }}-rc.${{ inputs.RC_VERSION }}.zip
sha1sum.txt.asc
sha256sum.txt.asc
sha256sum.sig
sha1sum.sig
prerelease: false
body: |
> [!WARNING]

View File

@@ -58,6 +58,7 @@ ARG BUILDDATE
ARG VERSION
ARG RELEASE
ARG GIT_SHA1=0000000000000000000000000000000000000000
ARG REGISTRY=local
# #
# Set Labels
@@ -74,16 +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.url="https://github.com/thebinaryninja/tvapp2/pkgs/container/tvapp2"
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.registry="local"
LABEL org.opencontainers.image.release="${RELEASE}"
LABEL org.opencontainers.image.registry="${REGISTRY:-local}"
LABEL org.opencontainers.image.release="${RELEASE:-stable}"
LABEL org.tvapp2.image.maintainers="Aetherinox, iFlip721, Optx"
LABEL org.tvapp2.image.build-version="Version:- ${VERSION} Date:- ${BUILDDATE}"
LABEL org.tvapp2.image.build-version-alpine="${ALPINE_VERSION}"
LABEL org.tvapp2.image.build-architecture="${ARCH}"
LABEL org.tvapp2.image.build-release="${RELEASE}"
LABEL org.tvapp2.image.build-sha1="${GIT_SHA1}"
LABEL org.tvapp2.image.build-version="Version:- ${VERSION} Date:- ${BUILDDATE:-3.21}"
LABEL org.tvapp2.image.build-version-alpine="${ALPINE_VERSION:-3.21}"
LABEL org.tvapp2.image.build-architecture="${ARCH:-amd64}"
LABEL org.tvapp2.image.build-release="${RELEASE:-stable}"
LABEL org.tvapp2.image.build-sha1="${GIT_SHA1:-0000000000000000000000000000000000000000}"
# #
# Set Env Var
@@ -91,7 +92,7 @@ LABEL org.tvapp2.image.build-sha1="${GIT_SHA1}"
ENV NODE_VERSION=22.8.0
ENV YARN_VERSION=1.22.22
ENV RELEASE="${RELEASE}"
ENV RELEASE="${RELEASE:-stable}"
ENV DIR_BUILD=/usr/src/app
ENV DIR_RUN=/usr/bin/app
ENV URL_REPO="https://git.binaryninja.net/binaryninja/"

View File

@@ -12,8 +12,12 @@ import zlib from 'zlib';
import chalk from 'chalk';
import ejs from 'ejs';
import moment from 'moment';
import * as child from 'child_process';
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 * as child from 'child_process';
import * as crons from 'cron';
/*
@@ -33,7 +37,6 @@ const __dirname = path.dirname( __filename ); // get name of directory
/*
const gitHash = child.execSync( 'git rev-parse HEAD' ).toString().trim();
*/
const gitHash = `f6484e00dea57891cdeb3123aca124ca7388b22b`;
/*
chalk.level
@@ -51,6 +54,13 @@ const gitHash = `f6484e00dea57891cdeb3123aca124ca7388b22b`;
chalk.level = 3;
/*
*/
TimeAgo.addDefaultLocale( en );
const timeAgo = new TimeAgo( );
/*
Define > General
@@ -88,7 +98,9 @@ const envWebEncoding = process.env.WEB_ENCODING || 'deflate, br';
const envProxyHeader = process.env.WEB_PROXY_HEADER || 'x-forwarded-for';
const envHealthTimer = process.env.HEALTH_TIMER || 600000;
const envTaskCronSync = process.env.TASK_CRON_SYNC || '0 0 */3 * *';
const envGitSHA1 = process.env.GIT_SHA1 || '0000000000000000000000000000000000000000';
const LOG_LEVEL = process.env.LOG_LEVEL || 4;
let TIME_STARTUP = 0;
/*
Define > Externals
@@ -179,45 +191,45 @@ class Log
static verbose( ...msg )
{
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 )
{
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 )
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 )
{
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 )
{
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 )
{
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 )
{
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 )
{
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( ' ' ) ) );
}
}
@@ -231,7 +243,6 @@ if ( process.pkg )
chalk.blueBright( `<msg>` ), chalk.gray( `Starting server utilizing process.execPath` ) );
const basePath = path.dirname( process.execPath );
FILE_URL = path.join( basePath, envWebFolder, `${ envFileURL }` );
FILE_M3U = path.join( basePath, envWebFolder, `${ envFileM3U }` );
FILE_XML = path.join( basePath, envWebFolder, `${ envFileXML }` );
@@ -249,6 +260,64 @@ else
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
@@ -266,43 +335,6 @@ const clientIp = ( req ) =>
req.socket?.remoteAddress ) ||
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
@@ -318,17 +350,17 @@ async function serviceCheck( service, uri )
try
{
const response = await fetch( uri );
const resp = await fetch( uri );
/* 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;
}
/* 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 )
{
@@ -343,17 +375,17 @@ async function serviceCheck( service, uri )
try
{
const response = await fetch( uriRetry );
const resp = await fetch( uriRetry );
/* 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;
}
/* 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 )
{
@@ -373,17 +405,17 @@ async function serviceCheck( service, uri )
try
{
const response = await fetch( uriRetry );
const resp = await fetch( uriRetry );
/* 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;
}
/* 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 )
{
@@ -394,14 +426,6 @@ async function serviceCheck( service, uri )
}
}
/*
Semaphore > Initialize
@arg int threads_max
*/
const semaphore = new Semaphore( 5 );
/*
Func > Download File
@@ -715,7 +739,7 @@ async function fetchRemote( url, req )
{
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<url>` ), chalk.gray( `${ url }` ) );
@@ -728,7 +752,7 @@ async function fetchRemote( url, req )
}
}, ( 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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<code>` ), chalk.gray( `${ resp.statusCode }` ),
@@ -736,7 +760,7 @@ async function fetchRemote( url, req )
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<code>` ), chalk.gray( `${ resp.statusCode }` ),
@@ -759,7 +783,7 @@ async function fetchRemote( url, req )
{
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ),
@@ -770,7 +794,7 @@ async function fetchRemote( url, req )
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ),
@@ -786,7 +810,7 @@ async function fetchRemote( url, req )
{
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ),
@@ -797,7 +821,7 @@ async function fetchRemote( url, req )
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ),
@@ -813,7 +837,7 @@ async function fetchRemote( url, req )
{
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ),
@@ -824,7 +848,7 @@ async function fetchRemote( url, req )
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ),
@@ -836,7 +860,7 @@ async function fetchRemote( url, req )
}
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( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<encoding>` ), chalk.gray( `${ encoding }` ),
@@ -875,6 +899,8 @@ async function serveKey( req, res )
method: req.method || 'GET',
code: 400,
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()
};
@@ -930,6 +956,8 @@ async function serveKey( req, res )
method: req.method || 'GET',
code: 500,
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()
};
@@ -1227,6 +1255,8 @@ async function serveM3UPlaylist( req, res )
method: req.method || 'GET',
code: 404,
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()
};
@@ -1317,6 +1347,8 @@ async function serveM3UPlaylist( req, res )
method: req.method || 'GET',
code: 500,
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()
};
@@ -1375,6 +1407,8 @@ async function serveM3UPlaylist( req, res )
method: req.method || 'GET',
code: 500,
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()
};
@@ -1424,6 +1458,8 @@ async function serveHealthCheck( req, res )
method: req.method || 'GET',
code: 200,
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()
};
@@ -1431,12 +1467,16 @@ async function serveHealthCheck( req, res )
'Content-Type': 'application/json'
});
const paramQuery = new URL( req.url, `http://${ req.headers.host }` ).searchParams.get( 'query' );
if ( paramQuery !== 'query' )
{
Log.ok( `/api`, chalk.yellow( `[health]` ), chalk.white( `` ),
chalk.greenBright( `<msg>` ), chalk.gray( `Response` ),
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 ) );
return;
@@ -1457,6 +1497,8 @@ async function serveHealthCheck( req, res )
method: req.method || 'GET',
code: 503,
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()
};
@@ -1587,6 +1629,8 @@ async function serveM3U( res, req )
method: req.method || 'GET',
code: 500,
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()
};
@@ -1652,6 +1696,8 @@ async function serveXML( res, req )
method: req.method || 'GET',
code: 500,
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()
};
@@ -1717,6 +1763,8 @@ async function serveGZP( res, req )
method: req.method || 'GET',
code: 500,
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()
};
@@ -1904,9 +1952,10 @@ async function initialize()
FILE_GZP_MODIFIED = getFileModified( FILE_GZP );
const end = performance.now();
TIME_STARTUP = `${ end - start }`;
Log.info( `core`, chalk.yellow( `[initiate]` ), chalk.white( `` ),
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( `<gateway>` ), chalk.gray( `${ envIpGateway }` ),
chalk.blueBright( `<port>` ), chalk.gray( `${ envWebPort }` ) );
@@ -1940,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
@@ -1951,8 +2000,8 @@ const server = http.createServer( ( request, response ) =>
/www/css/tvapp2.min.css
*/
const method = request.method || 'GET';
let reqUrl = request.url;
const method = req.method || 'GET';
let reqUrl = req.url;
if ( reqUrl === '/' )
reqUrl = 'index.html';
@@ -1974,8 +2023,8 @@ const server = http.createServer( ( request, response ) =>
Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Request started` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ),
chalk.blueBright( `<request.url>` ), chalk.gray( `${ request.url }` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<request.url>` ), chalk.gray( `${ req.url }` ),
chalk.blueBright( `<reqUrl>` ), chalk.gray( `${ reqUrl }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
@@ -1997,31 +2046,33 @@ const server = http.createServer( ( request, response ) =>
@todo integrate real api system after express replaces node http
*/
const apiKey = new URL( request.url, `http://${ request.headers.host }` ).searchParams.get( 'key' );
const referer = request.headers.referer || null;
const apiKey = new URL( req.url, `http://${ req.headers.host }` ).searchParams.get( 'key' );
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 =
{
ip: envIpContainer, gateway: envIpGateway, client: clientIp( request ),
message: `must specify api key: http://${ request.headers.host }/api/restart?key=XXXXXXXX`,
status: `unauthorized`, ref: request.url, method: method || 'GET', code: 401,
uptime: Math.round( process.uptime() ), timestamp: Date.now()
ip: envIpContainer, gateway: envIpGateway, client: clientIp( req ),
message: `must specify api key: http://${ req.headers.host }/api/restart?key=XXXXXXXX`,
status: `unauthorized`, ref: req.url, method: method || 'GET', code: 401,
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'
});
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( `<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( `<method>` ), chalk.gray( `${ method }` ) );
response.end( JSON.stringify( statusCheck ) );
resp.end( JSON.stringify( statusCheck ) );
return;
}
@@ -2034,24 +2085,26 @@ const server = http.createServer( ( request, response ) =>
{
const statusCheck =
{
ip: envIpContainer, gateway: envIpGateway, client: clientIp( request ),
message: `incorrect api key specified: http://${ request.headers.host }/api/restart?key=XXXXXXXX`,
status: `unauthorized`, ref: request.url, method: method || 'GET', code: 401,
uptime: Math.round( process.uptime() ), timestamp: Date.now()
ip: envIpContainer, gateway: envIpGateway, client: clientIp( req ),
message: `incorrect api key specified: http://${ req.headers.host }/api/restart?key=XXXXXXXX`,
status: `unauthorized`, ref: req.url, method: method || 'GET', code: 401,
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'
});
Log.error( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.redBright( `<msg>` ), chalk.gray( `Unauthorized (401): incorrect api key specified` ),
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( `<method>` ), chalk.gray( `${ method }` ) );
response.end( JSON.stringify( statusCheck ) );
resp.end( JSON.stringify( statusCheck ) );
return;
}
@@ -2061,28 +2114,30 @@ const server = http.createServer( ( request, response ) =>
{
ip: envIpContainer,
gateway: envIpGateway,
client: clientIp( request ),
client: clientIp( req ),
message: 'Restart command received',
status: 'ok',
ref: request.url,
ref: req.url,
method: method || 'GET',
code: 200,
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()
};
response.writeHead( statusCheck.code, {
resp.writeHead( statusCheck.code, {
'Content-Type': 'application/json'
});
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access restart api` ),
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( `<method>` ), chalk.gray( `${ method }` ) );
response.end( JSON.stringify( statusCheck ) );
resp.end( JSON.stringify( statusCheck ) );
return;
}
@@ -2091,11 +2146,11 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access 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( `<method>` ), chalk.gray( `${ method }` ) );
await serveM3U( response, request );
await serveM3U( resp, req );
return;
}
@@ -2104,11 +2159,11 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access 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( `<method>` ), chalk.gray( `${ method }` ) );
await serveM3UPlaylist( request, response );
await serveM3UPlaylist( req, resp );
return;
}
@@ -2117,11 +2172,11 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access 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( `<method>` ), chalk.gray( `${ method }` ) );
await serveKey( request, response );
await serveKey( req, resp );
return;
}
@@ -2130,11 +2185,11 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access 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( `<method>` ), chalk.gray( `${ method }` ) );
await serveXML( response, request );
await serveXML( resp, req );
return;
}
@@ -2143,24 +2198,29 @@ const server = http.createServer( ( request, response ) =>
Log.info( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.blueBright( `<msg>` ), chalk.gray( `Requesting to access epg gzip (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( `<method>` ), chalk.gray( `${ method }` ) );
await serveGZP( response, request );
await serveGZP( resp, req );
return;
}
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' );
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( request ) }` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
}
await serveHealthCheck( request, response );
await serveHealthCheck( req, resp );
return;
}
@@ -2170,7 +2230,7 @@ const server = http.createServer( ( request, response ) =>
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( `<client>` ), chalk.gray( `${ clientIp( request ) }` ),
chalk.blueBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
chalk.blueBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
@@ -2200,15 +2260,18 @@ const server = http.createServer( ( request, response ) =>
appUrlGithub: repository.url.substr( 0, repository.url.lastIndexOf( '.' ) ),
appUrlDiscord: discord.url,
appUrlDocs: docs.url,
appGitHashShort: gitHash.substring( 0, 9 ),
appGitHashLong: gitHash
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 ) =>
{
if ( !err )
{
Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ),
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( `<method>` ), chalk.gray( `${ method }` ) );
@@ -2244,21 +2307,33 @@ const server = http.createServer( ( request, response ) =>
if ( fileMime !== 'text/html' )
data = fs.readFileSync( `./${ envWebFolder }/${ loadFile }` );
response.setHeader( 'Content-type', fileMime );
response.end( data );
resp.setHeader( 'Content-type', fileMime );
resp.end( data );
if ( fileMime === 'text/html' || fileMime === 'application/xml' || fileMime === 'application/json' )
{
Log.ok( `http`, chalk.yellow( `[requests]` ), chalk.white( `` ),
chalk.greenBright( `<msg>` ), chalk.gray( `Request to load file` ),
chalk.greenBright( `<client>` ), chalk.gray( `${ clientIp( request ) }` ),
chalk.greenBright( `<client>` ), chalk.gray( `${ clientIp( req ) }` ),
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
{
Log.debug( `http`, chalk.yellow( `[requests]` ), chalk.white( `⚙️` ),
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( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.blueBright( `<method>` ), chalk.gray( `${ method }` ) );
@@ -2273,35 +2348,36 @@ const server = http.createServer( ( request, response ) =>
{
ip: envIpContainer,
gateway: envIpGateway,
client: clientIp( request ),
client: clientIp( req ),
message: 'Page not found',
status: 'healthy',
ref: request.url,
ref: req.url,
method: method || 'GET',
code: 404,
uptime: Math.round( process.uptime() ),
uptimeHuman: timeAgo.format( Date.now() - process.uptime() * 1000, 'twitter' ),
timestamp: Date.now()
};
response.writeHead( statusCheck.code, {
resp.writeHead( statusCheck.code, {
'Content-Type': 'application/json'
});
Log.error( `http`, chalk.redBright( `[requests]` ), chalk.white( `` ),
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( `<error>` ), chalk.gray( `${ err }` ),
chalk.redBright( `<file>` ), chalk.gray( `${ loadFile }` ),
chalk.redBright( `<method>` ), chalk.gray( `${ method }` ) );
response.end( JSON.stringify( statusCheck ) );
resp.end( JSON.stringify( statusCheck ) );
}
});
};
handleRequest().catch( ( err ) =>
{
response.writeHead( 500, {
resp.writeHead( 500, {
'Content-Type': 'text/plain'
});
@@ -2310,7 +2386,7 @@ const server = http.createServer( ( request, response ) =>
chalk.redBright( `<code>` ), chalk.gray( `500` ),
chalk.redBright( `<error>` ), chalk.gray( `${ err }` ) );
response.end( 'Internal Server Error' );
resp.end( 'Internal Server Error' );
});
});

122
tvapp2/package-lock.json generated
View File

@@ -13,7 +13,9 @@
"cron": "^4.3.1",
"ejs": "^3.1.10",
"express": "5.1.0",
"javascript-time-ago": "2.5.11",
"moment": "2.30.1",
"nconf": "1.0.0-beta.2",
"node-cron": "^4.1.0",
"playwright": "^1.52.0",
"user-agents": "^1.1.557"
@@ -448,7 +450,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -1088,7 +1089,6 @@
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT"
},
"node_modules/encodeurl": {
@@ -1274,6 +1274,15 @@
"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": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -2022,7 +2031,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
@@ -2320,6 +2328,15 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"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": {
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
@@ -2551,7 +2568,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -2818,6 +2834,15 @@
"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": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@@ -3076,6 +3101,86 @@
"dev": true,
"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": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
@@ -3589,11 +3694,16 @@
"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": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -4005,7 +4115,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
@@ -4079,7 +4188,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"

View File

@@ -1,6 +1,6 @@
{
"name": "tvapp2",
"version": "1.5.2",
"version": "1.5.3",
"description": "This package allows you to generate M3U playlists and EPG guides from various online IPTV services.",
"author": "BinaryNinja",
"license": "MIT",
@@ -79,7 +79,9 @@
"chalk": "^5.4.1",
"ejs": "^3.1.10",
"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": {
"@aetherinox/noxenv": "^1.1.1",

View File

@@ -21,7 +21,7 @@
<a target="_blank" data-bs-toggle="tooltip" title="View Github Repository" class="header-name" href="<%= appUrlGithub %>">TVApp2 for Docker</a>
</div>
<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 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 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>
@@ -125,7 +125,7 @@
<div class="container">
<div class="col text-center text-muted text-small text-nowrap">
<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>
@@ -299,6 +299,7 @@
let timerDelayMS = 10000;
let timerStartMS = Date.now(); // returns milliseconds
const timerHealthRun = '<%= healthTimer %>'; // time in milliseconds until health check ran AFTER initial run
const timerUptime = 1000;
/*
Action > Healthcheck
@@ -317,7 +318,7 @@
url: 'api/health',
type: 'GET',
data: {
internal: 1
query: 'healthcheck'
},
beforeSend: function( data )
{
@@ -362,6 +363,54 @@
}).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
*/
@@ -373,7 +422,7 @@
url: 'api/restart',
type: 'GET',
data: {
internal: 1
query: 'sync'
},
beforeSend: function( data )
{
@@ -458,11 +507,8 @@
jQuery(function($)
{
$(document.body).tooltip({ selector: "[title]" });
$('#action-health')
.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 tooltip = bootstrap.Tooltip.getInstance('#action-health') // Returns a Bootstrap tooltip instance
tooltip.setContent({ '.tooltip-inner': `Health check in ${ timeLeft }` })
});
const Heart = document.getElementsByClassName('fa-heart');
@@ -495,6 +541,7 @@
*/
setTimeout( function() { runHealthCheck(); }, timerDelayMS );
setTimeout( function() { runUptime(); }, 1000 );
/*
Action > Tooltip Resync Timers