mirror of
https://github.com/TheBinaryNinja/tvapp2.git
synced 2026-06-11 19:05:41 -04:00
Compare commits
83 Commits
1.5.5
...
2x-feature
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82fb6c3bcd | ||
|
|
a697acc0f3 | ||
| 7046428246 | |||
|
|
245034a43a | ||
|
|
986e83632b | ||
|
|
30aa901b4d | ||
|
|
321a0e8540 | ||
|
|
cb8f769e34 | ||
|
|
38ff77a04e | ||
|
|
292cd8dd94 | ||
|
|
3878059314 | ||
|
|
7a7e50c7ba | ||
|
|
564dd536fc | ||
|
|
0e29805351 | ||
| dc76267da3 | |||
| 147b11b22d | |||
|
|
b992e4ff01 | ||
|
|
b46a922464 | ||
| d4abc705a0 | |||
| 454d13c608 | |||
|
|
6086dbbad2 | ||
|
|
b9607dddce | ||
|
|
1a7aeb4450 | ||
|
|
d973af6a8d | ||
|
2dae279f93
|
|||
|
09d17717ab
|
|||
|
bf4454f635
|
|||
|
9e531d823f
|
|||
| d17aa23e98 | |||
| 63f7c1d665 | |||
|
c5c2f741f0
|
|||
|
ec24c51eea
|
|||
|
fa2c4073e3
|
|||
|
255d093269
|
|||
|
73a264b1c2
|
|||
|
|
c112230e05 | ||
|
|
02dd911e93 | ||
|
9c3ee3d146
|
|||
|
4c8d5d03d9
|
|||
|
c729594864
|
|||
|
713626810b
|
|||
|
6e5c261065
|
|||
|
2f1027e068
|
|||
|
739f547731
|
|||
|
3f7ecdb84e
|
|||
|
e037764c3f
|
|||
|
c8aa866dfd
|
|||
|
84b1199878
|
|||
|
04150d5320
|
|||
|
11ccf2909f
|
|||
|
631942ca75
|
|||
|
4ee603d7a2
|
|||
|
7cfe22b72e
|
|||
|
e6701cda95
|
|||
|
865a2fd645
|
|||
|
05f362153f
|
|||
|
997eb72378
|
|||
|
69805151c8
|
|||
|
47ec5267ec
|
|||
|
3a87b51f41
|
|||
|
ffc8cfe68e
|
|||
|
7f5fffa5e6
|
|||
|
b16f4a9fb3
|
|||
|
ebf0b84a05
|
|||
|
b724930c6a
|
|||
|
603e444d35
|
|||
|
f274b807f2
|
|||
|
d0c8920b98
|
|||
|
4c0d49508f
|
|||
|
2a09bc1ea3
|
|||
|
259d27a2ce
|
|||
|
|
8aefbb39e0 | ||
|
|
e417b9f5d8 | ||
|
|
9458587d59 | ||
|
|
468c8c10fc | ||
|
|
6d90a88b60 | ||
|
|
7231199f9e | ||
|
|
41c0c9f685 | ||
|
|
79c5c648c9 | ||
|
|
0ba2e23171 | ||
|
|
b0f3869621 | ||
|
|
b709d53e40 | ||
|
|
b198168d75 |
4
.github/workflows/deploy-clean.yml
vendored
4
.github/workflows/deploy-clean.yml
vendored
@@ -152,8 +152,8 @@ jobs:
|
||||
cleanup:
|
||||
name: >-
|
||||
🧹 Deployments › Clean
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
permissions: write-all
|
||||
|
||||
|
||||
@@ -182,8 +182,8 @@ jobs:
|
||||
job-docker-release-tags-create:
|
||||
name: >-
|
||||
📦 Release › Create Tag
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 4
|
||||
outputs:
|
||||
package_version: ${{ steps.task_initialize_package_getversion.outputs.PACKAGE_VERSION }}
|
||||
@@ -374,8 +374,8 @@ jobs:
|
||||
job-docker-release-dockerhub:
|
||||
name: >-
|
||||
📦 Release › Dockerhub
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 10
|
||||
needs: [ job-docker-release-tags-create ]
|
||||
permissions:
|
||||
|
||||
38
.github/workflows/deploy-docker-gitea.yml
vendored
38
.github/workflows/deploy-docker-gitea.yml
vendored
@@ -194,8 +194,8 @@ jobs:
|
||||
job-docker-release-tags-create:
|
||||
name: >-
|
||||
📦 Release › Create Tag
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 4
|
||||
outputs:
|
||||
package_version: ${{ steps.task_initialize_package_getversion.outputs.PACKAGE_VERSION }}
|
||||
@@ -386,8 +386,8 @@ jobs:
|
||||
job-docker-release-gitea:
|
||||
name: >-
|
||||
📦 Release › Gitea
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 10
|
||||
needs: [ job-docker-release-tags-create ]
|
||||
permissions:
|
||||
@@ -571,6 +571,32 @@ jobs:
|
||||
id: task_release_gi_qemu
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
# #
|
||||
# Required to fix insecure SSL error with docker buildx
|
||||
# #
|
||||
|
||||
- name: '⚙️ Configure Docker daemon to allow insecure registry'
|
||||
run: |
|
||||
echo "Configuring daemon to treat ${REGISTRY_HOST} as insecure"
|
||||
sudo mkdir -p /etc/docker
|
||||
sudo tee /etc/docker/daemon.json > /dev/null <<'JSON'
|
||||
{
|
||||
"insecure-registries": ["git.binaryninja.net:443"]
|
||||
}
|
||||
JSON
|
||||
|
||||
# Restart Docker
|
||||
sudo service docker restart
|
||||
env:
|
||||
REGISTRY_HOST: git.binaryninja.net
|
||||
|
||||
# #
|
||||
# Make sure change in docker daemon config successful
|
||||
# #
|
||||
|
||||
- name: '⚙️ Check Docker Daemon Configuration'
|
||||
run: cat /etc/docker/daemon.json
|
||||
|
||||
# #
|
||||
# Release › Gitea › Setup BuildX › Amd64
|
||||
# #
|
||||
@@ -581,6 +607,10 @@ jobs:
|
||||
with:
|
||||
version: latest
|
||||
driver-opts: 'image=moby/buildkit:latest'
|
||||
driver: docker
|
||||
buildkitd-flags: --allow-insecure-entitlement
|
||||
install: true
|
||||
use: true
|
||||
|
||||
# #
|
||||
# Release › Gitea › Registry Login › Amd64
|
||||
|
||||
12
.github/workflows/deploy-docker-github.yml
vendored
12
.github/workflows/deploy-docker-github.yml
vendored
@@ -181,8 +181,8 @@ jobs:
|
||||
job-docker-release-tags-create:
|
||||
name: >-
|
||||
📦 Release › Create Tag
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 4
|
||||
outputs:
|
||||
package_version: ${{ steps.task_initialize_package_getversion.outputs.PACKAGE_VERSION }}
|
||||
@@ -371,8 +371,8 @@ jobs:
|
||||
job-docker-release-github:
|
||||
name: >-
|
||||
📦 Release › Github
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 10
|
||||
needs: [ job-docker-release-tags-create ]
|
||||
permissions:
|
||||
@@ -954,8 +954,8 @@ jobs:
|
||||
job-docker-release-cleanup:
|
||||
name: >-
|
||||
🧹 Release › Cleanup
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
needs: [ job-docker-release-tags-create, job-docker-release-github ]
|
||||
permissions:
|
||||
|
||||
4
.github/workflows/documentation.yml
vendored
4
.github/workflows/documentation.yml
vendored
@@ -170,8 +170,8 @@ env:
|
||||
|
||||
jobs:
|
||||
build-docs:
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
16
.github/workflows/issues-new.yml
vendored
16
.github/workflows/issues-new.yml
vendored
@@ -165,8 +165,8 @@ jobs:
|
||||
job-labels-create:
|
||||
name: >-
|
||||
🎫 Labels › Verify Existing
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
|
||||
@@ -335,8 +335,8 @@ jobs:
|
||||
🏷️ Labels › Assign
|
||||
needs:
|
||||
- job-labels-create
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: 'read'
|
||||
@@ -1191,8 +1191,8 @@ jobs:
|
||||
🏷️ Labels › Phrase Search
|
||||
needs:
|
||||
- job-labels-create
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: 'read'
|
||||
@@ -1280,8 +1280,8 @@ jobs:
|
||||
job-assign-assignees:
|
||||
name: >-
|
||||
✍️ Issue › Assignees
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
needs: [ job-assign-labels ]
|
||||
# disable
|
||||
|
||||
4
.github/workflows/issues-scan.yml
vendored
4
.github/workflows/issues-scan.yml
vendored
@@ -160,8 +160,8 @@ jobs:
|
||||
job-pr-scan:
|
||||
name: >-
|
||||
🎫 Issues › Autoscan
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
16
.github/workflows/issues-stale.yml
vendored
16
.github/workflows/issues-stale.yml
vendored
@@ -181,8 +181,8 @@ jobs:
|
||||
job-labels-create:
|
||||
name: >-
|
||||
🎫 Labels › Verify Existing
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
|
||||
@@ -360,8 +360,8 @@ jobs:
|
||||
job-issues-nolabel:
|
||||
name: >-
|
||||
🎫 Labels › Assign Missing
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 4
|
||||
needs: job-labels-create
|
||||
steps:
|
||||
@@ -961,8 +961,8 @@ jobs:
|
||||
job-issues-stale:
|
||||
name: >-
|
||||
💤 Scan › Check Stale
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
needs:
|
||||
- job-labels-create
|
||||
@@ -1005,8 +1005,8 @@ jobs:
|
||||
job-issues-lock:
|
||||
name: >-
|
||||
🔒 Scan › Lock Inactive
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 5
|
||||
needs:
|
||||
- job-labels-create
|
||||
|
||||
4
.github/workflows/labels-clean.yml
vendored
4
.github/workflows/labels-clean.yml
vendored
@@ -146,8 +146,8 @@ jobs:
|
||||
issues-labels-clean:
|
||||
name: >-
|
||||
🧹 Labels › Clean
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 3
|
||||
permissions:
|
||||
contents: 'read'
|
||||
|
||||
4
.github/workflows/labels-create.yml
vendored
4
.github/workflows/labels-create.yml
vendored
@@ -193,8 +193,8 @@ jobs:
|
||||
issues-labels-create:
|
||||
name: >-
|
||||
🎫 Labels › Create
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: apollo-x64
|
||||
runs-on: ubuntu-latest
|
||||
# runs-on: apollo-x64
|
||||
timeout-minutes: 3
|
||||
permissions:
|
||||
contents: 'read'
|
||||
|
||||
335
.gitignore
vendored
335
.gitignore
vendored
@@ -1,323 +1,94 @@
|
||||
# #
|
||||
# Dependency directories
|
||||
# #
|
||||
|
||||
node_modules/
|
||||
tvapp2/node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# #
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
# #
|
||||
|
||||
web_modules/
|
||||
|
||||
# #
|
||||
# TypeScript cache
|
||||
# #
|
||||
|
||||
\*.tsbuildinfo
|
||||
|
||||
# #
|
||||
# Optional npm cache directory
|
||||
# #
|
||||
|
||||
.npm
|
||||
|
||||
# #
|
||||
# npm files
|
||||
# #
|
||||
|
||||
.npmrc
|
||||
|
||||
# #
|
||||
# Optional eslint cache
|
||||
# #
|
||||
|
||||
.eslintcache
|
||||
|
||||
# #
|
||||
# Optional stylelint cache
|
||||
# #
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# #
|
||||
# Microbundle cache
|
||||
# #
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# #
|
||||
# Optional REPL history
|
||||
# #
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# #
|
||||
# Output of 'npm pack'
|
||||
# #
|
||||
|
||||
\*.tgz
|
||||
|
||||
# #
|
||||
# Yarn Integrity file
|
||||
# #
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# #
|
||||
# Binaries
|
||||
# #
|
||||
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# #
|
||||
# TVApp2 Specific
|
||||
# #
|
||||
|
||||
*.dat
|
||||
*.xml
|
||||
*.txt
|
||||
|
||||
# #
|
||||
# Test binary
|
||||
# build with `go test -c`
|
||||
# #
|
||||
|
||||
*.test
|
||||
|
||||
# #
|
||||
# Coverage directory used by tools like istanbul
|
||||
# #
|
||||
|
||||
coverage
|
||||
\*.lcov
|
||||
*.out
|
||||
|
||||
# #
|
||||
# nyc test coverage
|
||||
# #
|
||||
|
||||
.nyc_output
|
||||
|
||||
# #
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
# #
|
||||
|
||||
.grunt
|
||||
|
||||
# #
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
# #
|
||||
|
||||
bower_components
|
||||
|
||||
# #
|
||||
# node-waf configuration
|
||||
# #
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# #
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
# #
|
||||
|
||||
build/Release
|
||||
|
||||
# #
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
# #
|
||||
|
||||
# #
|
||||
# Go workspace file
|
||||
# #
|
||||
|
||||
go.work
|
||||
|
||||
# #
|
||||
# Mac
|
||||
# #
|
||||
|
||||
.DS_STORE
|
||||
|
||||
# #
|
||||
# Visual Studio Code
|
||||
# #
|
||||
|
||||
.vscode/
|
||||
|
||||
# #
|
||||
# Temp folders
|
||||
# #
|
||||
|
||||
.temp/
|
||||
temp/
|
||||
work/
|
||||
|
||||
# #
|
||||
# Python Cache
|
||||
# #
|
||||
|
||||
__pycache__/
|
||||
|
||||
# #
|
||||
# Logs
|
||||
# #
|
||||
|
||||
logs
|
||||
_.log
|
||||
coverage
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
temp/
|
||||
work/
|
||||
logs
|
||||
keys
|
||||
tmp
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
pids
|
||||
lib-cov
|
||||
|
||||
|
||||
_.log
|
||||
_.pid
|
||||
_.seed
|
||||
__pycache__/
|
||||
|
||||
|
||||
\*.tsbuildinfo
|
||||
\*.tgz
|
||||
\*.lcov
|
||||
\*.pid.lock
|
||||
|
||||
|
||||
.npm
|
||||
.npmrc
|
||||
.eslintcache
|
||||
.stylelintcache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
.node_repl_history
|
||||
.yarn-integrity
|
||||
.DS_STORE
|
||||
|
||||
|
||||
.vscode/
|
||||
.temp/
|
||||
.nyc_output
|
||||
.grunt
|
||||
.lock-wscript
|
||||
.pnpm-debug.log*
|
||||
|
||||
# #
|
||||
# yarn v2
|
||||
# #
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.\*
|
||||
|
||||
# #
|
||||
# wrangler project
|
||||
# #
|
||||
|
||||
.dev.vars
|
||||
.wrangler/
|
||||
|
||||
# #
|
||||
# sources
|
||||
# #
|
||||
|
||||
.src
|
||||
|
||||
# #
|
||||
# dist
|
||||
# #
|
||||
|
||||
.dist
|
||||
|
||||
# #
|
||||
# Private Files
|
||||
# #
|
||||
|
||||
.dev
|
||||
keys
|
||||
|
||||
# #
|
||||
# dotenv environment variable files
|
||||
# #
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# #
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
# #
|
||||
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# #
|
||||
# Next.js build output
|
||||
# #
|
||||
|
||||
.next
|
||||
|
||||
# #
|
||||
# Nuxt.js build / generate output
|
||||
# #
|
||||
|
||||
.nuxt
|
||||
|
||||
# #
|
||||
# vuepress build output
|
||||
# #
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# #
|
||||
# Docusaurus cache and generated files
|
||||
# #
|
||||
|
||||
.docusaurus
|
||||
|
||||
# #
|
||||
# Serverless directories
|
||||
# #
|
||||
|
||||
.serverless/
|
||||
|
||||
# #
|
||||
# FuseBox cache
|
||||
# #
|
||||
|
||||
.fusebox/
|
||||
|
||||
# #
|
||||
# DynamoDB Local files
|
||||
# #
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# #
|
||||
# TernJS port file
|
||||
# #
|
||||
|
||||
.tern-port
|
||||
|
||||
# #
|
||||
# Gatsby files
|
||||
# #
|
||||
|
||||
.cache/
|
||||
|
||||
# #
|
||||
# Misc
|
||||
# #
|
||||
|
||||
tmp
|
||||
*.user
|
||||
|
||||
# #
|
||||
# Python files
|
||||
# #
|
||||
|
||||
.opt-*
|
||||
|
||||
# #
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
# #
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# #
|
||||
# Runtime data
|
||||
# #
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
\*.pid.lock
|
||||
|
||||
# #
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
# #
|
||||
|
||||
lib-cov
|
||||
*.user
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*c*de*
|
||||
*.dat
|
||||
*.xml
|
||||
*.txt
|
||||
*.test
|
||||
*.out
|
||||
|
||||
170
Dockerfile
170
Dockerfile
@@ -1,170 +0,0 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# #
|
||||
# @project TVApp2
|
||||
# @usage docker image which allows you to download a m3u playlist and EPG guide data from
|
||||
# multiple IPTV services.
|
||||
# @file Dockerfile
|
||||
# @repo https://github.com/TheBinaryNinja/tvapp2
|
||||
# https://git.binaryninja.net/BinaryNinja/tvapp2
|
||||
# https://github.com/aetherinox/docker-base-alpine
|
||||
#
|
||||
# build your own image by running
|
||||
# amd64 docker build --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 -t tvapp2:latest -t tvapp2:1.5.0 -t tvapp2:1.5.0-amd64 -f Dockerfile .
|
||||
# arm64 docker build --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 -t tvapp2:1.5.0-arm64 -f Dockerfile.aarch64 .
|
||||
#
|
||||
# OR; build using `docker buildx`
|
||||
# create docker buildx create --driver docker-container --name container --bootstrap --use
|
||||
# amd64 docker buildx build --build-arg ARCH=amd64 --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 --build-arg RELEASE=stable --tag ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64 --attest type=provenance,disabled=true --attest type=sbom,disabled=true --file Dockerfile --platform linux/amd64 --output type=docker --allow network.host --network host --no-cache --pull --push .
|
||||
# arm64 docker buildx build --build-arg ARCH=arm64 --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 --build-arg RELEASE=stable --tag ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64 --attest type=provenance,disabled=true --attest type=sbom,disabled=true --file Dockerfile --platform linux/arm64 --output type=docker --allow network.host --network host --no-cache --pull --push .
|
||||
#
|
||||
# OR; build single amd64 image
|
||||
# create docker buildx create --driver docker-container --name container --bootstrap --use
|
||||
# amd64 docker buildx build --build-arg ARCH=amd64 --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 --build-arg RELEASE=stable --tag ghcr.io/thebinaryninja/tvapp2:1.5.0 --tag ghcr.io/thebinaryninja/tvapp2:1.5 --tag ghcr.io/thebinaryninja/tvapp2:1 --tag ghcr.io/thebinaryninja/tvapp2:latest --attest type=provenance,disabled=true --attest type=sbom,disabled=true --file Dockerfile --platform linux/amd64 --output type=docker --allow network.host --network host --no-cache --push .
|
||||
#
|
||||
# OR; build official image (publish)
|
||||
# create docker buildx create --driver docker-container --name container --bootstrap --use
|
||||
# amd64-stable docker buildx build --build-arg ARCH=amd64 --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 --build-arg RELEASE=stable --tag ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64 --attest type=provenance,disabled=true --attest type=sbom,disabled=true --file Dockerfile --platform linux/amd64 --output type=docker --allow network.host --network host --no-cache --pull --push .
|
||||
# arm64-stable docker buildx build --build-arg ARCH=arm64 --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 --build-arg RELEASE=stable --tag ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64 --attest type=provenance,disabled=true --attest type=sbom,disabled=true --file Dockerfile --platform linux/arm64 --output type=docker --allow network.host --network host --no-cache --pull --push .
|
||||
# amd64-dev docker buildx build --build-arg ARCH=amd64 --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 --build-arg RELEASE=development --tag ghcr.io/thebinaryninja/tvapp2:development-amd64 --attest type=provenance,disabled=true --attest type=sbom,disabled=true --file Dockerfile --platform linux/amd64 --output type=docker --allow network.host --network host --no-cache --pull --push .
|
||||
# arm64-dev docker buildx build --build-arg ARCH=arm64 --build-arg VERSION=1.5.0 --build-arg BUILDDATE=20260812 --build-arg RELEASE=development --tag ghcr.io/thebinaryninja/tvapp2:development-arm64 --attest type=provenance,disabled=true --attest type=sbom,disabled=true --file Dockerfile --platform linux/arm64 --output type=docker --allow network.host --network host --no-cache --pull --push .
|
||||
# amd64-stable-hash docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.0-amd64
|
||||
# arm64-stable-hash docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:1.5.0-arm64
|
||||
# amd64-dev-hash docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:development-amd64
|
||||
# arm64-dev-hash docker buildx imagetools inspect ghcr.io/thebinaryninja/tvapp2:development-arm64
|
||||
# merge-stable docker buildx imagetools create --tag ghcr.io/thebinaryninja/tvapp2:1.5.0 --tag ghcr.io/thebinaryninja/tvapp2:1.5 --tag ghcr.io/thebinaryninja/tvapp2:1 --tag ghcr.io/thebinaryninja/tvapp2:latest sha256:0abe1b1c119959b3b1ccc23c56a7ee2c4c908c6aaef290d4ab2993859d807a3b sha256:e68b9de8669eac64d4e4d2a8343c56705e05e9a907cf0b542343f9b536d9c473
|
||||
# merge-dev docker buildx imagetools create --tag ghcr.io/thebinaryninja/tvapp2:development sha256:8f36385a28c8f6eb7394d903c9a7a2765b06f94266b32628389ee9e3e3d7e69d sha256:c719ccb034946e3f0625003f25026d001768794e38a1ba8aafc9146291d548c5
|
||||
# #
|
||||
|
||||
# #
|
||||
# FROM
|
||||
# any args defined before FROM cannot be called after FROM and the ARE is classified outside the build process.
|
||||
# You will have to re-define the arg after FROM to utilize it anywhere else in the build process.
|
||||
#
|
||||
# @ref https://docs.docker.com/reference/dockerfile/#understand-how-arg-and-from-interact
|
||||
# #
|
||||
|
||||
ARG ARCH=amd64
|
||||
ARG ALPINE_VERSION=3.22
|
||||
FROM --platform=linux/${ARCH} ghcr.io/aetherinox/alpine-base:${ALPINE_VERSION}
|
||||
|
||||
# #
|
||||
# Set Args
|
||||
# #
|
||||
|
||||
ARG ARCH=amd64
|
||||
ARG ALPINE_VERSION=3.22
|
||||
ARG BUILDDATE
|
||||
ARG VERSION
|
||||
ARG RELEASE
|
||||
ARG GIT_SHA1=0000000000000000000000000000000000000000
|
||||
ARG REGISTRY=local
|
||||
|
||||
# #
|
||||
# Set Labels
|
||||
# #
|
||||
|
||||
LABEL org.opencontainers.image.authors="Aetherinox, iFlip721, Optx"
|
||||
LABEL org.opencontainers.image.vendor="BinaryNinja"
|
||||
LABEL org.opencontainers.image.title="TVApp2"
|
||||
LABEL org.opencontainers.image.description="Automatic m3u and xml guide updater for TheTvApp, TVPass, and MoveOnJoy utilized within your IPTV client."
|
||||
LABEL org.opencontainers.image.source="https://github.com/thebinaryninja/tvapp2"
|
||||
LABEL org.opencontainers.image.repo.1="https://github.com/thebinaryninja/tvapp2"
|
||||
LABEL org.opencontainers.image.repo.2="https://git.binaryninja.net/binaryninja/tvapp2"
|
||||
LABEL org.opencontainers.image.repo.3="https://github.com/aetherinox/docker-base-alpine"
|
||||
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:-amd64}"
|
||||
LABEL org.opencontainers.image.ref.name="main"
|
||||
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:-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
|
||||
# #
|
||||
|
||||
ENV NODE_VERSION=22.16.0
|
||||
ENV YARN_VERSION=1.22.22
|
||||
ENV NPM_VERSION=10.9.2
|
||||
ENV RELEASE="${RELEASE:-stable}"
|
||||
ENV DIR_BUILD=/usr/src/app
|
||||
ENV DIR_RUN=/usr/bin/app
|
||||
ENV URL_REPO="https://git.binaryninja.net/binaryninja/"
|
||||
ENV WEB_IP="0.0.0.0"
|
||||
ENV WEB_PORT=4124
|
||||
ENV WEB_ENCODING="deflate, br"
|
||||
ENV WEB_PROXY_HEADER="x-forwarded-for"
|
||||
ENV STREAM_QUALITY="hd"
|
||||
ENV FILE_URL="urls.txt"
|
||||
ENV FILE_M3U="playlist.m3u8"
|
||||
ENV FILE_EPG="xmltv.xml"
|
||||
ENV FILE_TAR="xmltv.xml.gz"
|
||||
ENV HEALTH_TIMER=600000
|
||||
ENV TASK_CRON_SYNC="0 0 */3 * *"
|
||||
ENV LOG_LEVEL=4
|
||||
ENV TZ="Etc/UTC"
|
||||
ENV GIT_SHA1=${GIT_SHA1:-0000000000000000000000000000000000000000}
|
||||
|
||||
# #
|
||||
# Install
|
||||
# #
|
||||
|
||||
RUN \
|
||||
apk add --no-cache \
|
||||
wget \
|
||||
curl \
|
||||
bash \
|
||||
nano \
|
||||
git \
|
||||
npm \
|
||||
openssl
|
||||
|
||||
# #
|
||||
# Copy docker-entrypoint
|
||||
# #
|
||||
|
||||
COPY docker-entrypoint.sh /usr/local/bin/
|
||||
|
||||
# #
|
||||
# copy s6-overlays root to image root
|
||||
# #
|
||||
|
||||
COPY root/ /
|
||||
|
||||
# #
|
||||
# set work directory
|
||||
# #
|
||||
|
||||
WORKDIR ${DIR_BUILD}
|
||||
|
||||
# #
|
||||
# copy tvapp2 project to workdir
|
||||
# #
|
||||
|
||||
COPY tvapp2/ ./
|
||||
|
||||
# #
|
||||
# set work dir to built app
|
||||
# #
|
||||
|
||||
WORKDIR ${DIR_RUN}
|
||||
|
||||
# #
|
||||
# Ports and volumes
|
||||
# #
|
||||
|
||||
EXPOSE ${WEB_PORT}/tcp
|
||||
|
||||
# #
|
||||
# In case user sets up the cron for a longer duration, do a first run
|
||||
# and then keep the container running. Hacky, but whatever.
|
||||
# #
|
||||
|
||||
ENTRYPOINT ["/init"]
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 BinaryNinja
|
||||
Copyright (c) 2025-2026 BinaryNinja
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -184,6 +184,7 @@ The following is a list of environment variables you can declare within your `do
|
||||
| `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'`, 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 |
|
||||
| `HDHR_PORT` | `6077` | HDHomeRun server default listening port |
|
||||
| `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_M3U` | `playlist.m3u8` | Filename for M3U playlist file |
|
||||
@@ -1318,6 +1319,7 @@ This docker container contains the following env variables:
|
||||
| `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'`, 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 |
|
||||
| `HDHR_PORT` | `6077` | HDHomeRun server default listening port |
|
||||
| `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_M3U` | `playlist.m3u8` | Filename for M3U playlist file |
|
||||
|
||||
5
config/config.example.json
Normal file
5
config/config.example.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mongoUri": "mongodb://MONGO_ROOT_USER:MONGO_ROOT_PASS@mongo:27017/tvapp2?authSource=admin",
|
||||
"port": 3000,
|
||||
"logLevel": "info"
|
||||
}
|
||||
5
config/config.json
Normal file
5
config/config.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mongoUri": "mongodb://tvapp:tvapp@mongo:27017/tvapp2?authSource=admin",
|
||||
"port": 3000,
|
||||
"logLevel": "info"
|
||||
}
|
||||
1
dist/assets/ActiveStreamsScreen-Df8Wdk9n.js
vendored
Normal file
1
dist/assets/ActiveStreamsScreen-Df8Wdk9n.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/DashboardScreen-C8mAn1wl.js
vendored
Normal file
1
dist/assets/DashboardScreen-C8mAn1wl.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/EPGDetailScreen-CX4y1Ve9.js
vendored
Normal file
1
dist/assets/EPGDetailScreen-CX4y1Ve9.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/EPGSourcesScreen-Bh2qXoOm.js
vendored
Normal file
1
dist/assets/EPGSourcesScreen-Bh2qXoOm.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import{v as g,r,o as e,u as n,X as o,e as d,F as y,K as p,O as u,d as b,H as l,t as a,y as h,f as c,N as i,g as k,p as C,_ as m,q as S,Q as $,j as x}from"./index-CQPQcDLN.js";const E={class:"col"},z={class:"card flush"},N={class:"toolbar"},w=["onClick"],B={class:"src-name"},G={class:"src-url"},P={class:"stat-mini"},V={class:"stat-mini"},F={class:"stat-mini",style:{"min-width":"110px"}},L={style:{"font-size":"12px","font-weight":"500",color:"var(--text-1)"}},A=g({__name:"EPGSourcesScreen",emits:["add"],setup(O,{emit:_}){const v=_,f=$();return(R,s)=>(l(),r("div",E,[e("div",z,[e("div",N,[n(x,{value:"",onChange:()=>{},placeholder:"Search EPG sources"}),s[3]||(s[3]=e("span",{class:"spacer"},null,-1)),n(d,{variant:"ghost",icon:"refresh"},{default:o(()=>[...s[1]||(s[1]=[a("Sync all",-1)])]),_:1}),n(d,{variant:"primary",icon:"plus",onClick:s[0]||(s[0]=t=>v("add","epg"))},{default:o(()=>[...s[2]||(s[2]=[a("Add EPG source",-1)])]),_:1})]),(l(!0),r(y,null,p(u(b),t=>(l(),r("div",{key:t.id,class:"src-row",onClick:j=>u(f).push(`/epg-sources/${t.id}`)},[e("div",{class:h(["src-ico",{builtin:t.builtin,"epg-builtin":t.builtin}]),style:{color:"var(--good)"}},[n(c,{name:t.builtin?"tv":"epg",size:18},null,8,["name"])],2),e("div",null,[e("div",B,[a(i(t.name)+" ",1),n(k,{status:t.status,pulse:t.status==="good"},null,8,["status","pulse"]),t.builtin?(l(),C(m,{key:0,tone:"system"},{default:o(()=>[n(c,{name:"check",size:10}),s[4]||(s[4]=a("built-in",-1))]),_:1})):S("",!0),n(m,{tone:"cyan"},{default:o(()=>[a(i(t.interval),1)]),_:2},1024)]),e("div",G,i(t.url),1)]),e("div",P,[e("b",null,i(t.channels),1),s[5]||(s[5]=a("channels",-1))]),e("div",V,[e("b",null,i(t.programs.toLocaleString()),1),s[6]||(s[6]=a("programs",-1))]),e("div",F,[e("b",L,i(t.lastSync),1),s[7]||(s[7]=a(" last sync ",-1))]),n(d,{variant:"ghost",size:"sm",icon:"more"})],8,w))),128))])]))}});export{A as default};
|
||||
1
dist/assets/HistoryMetricsScreen-DAcDrLQC.js
vendored
Normal file
1
dist/assets/HistoryMetricsScreen-DAcDrLQC.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/ImportScreen-D7vLRk6-.js
vendored
Normal file
1
dist/assets/ImportScreen-D7vLRk6-.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/MappingScreen-BdiMBcth.js
vendored
Normal file
1
dist/assets/MappingScreen-BdiMBcth.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import{v as V,C as f,r,o as n,u as i,O as z,z as A,X as m,e as w,t as u,y as c,F as g,K as N,q as $,_ as k,I as D,J as B,n as E,H as l,N as p,p as y,f as v,i as G}from"./index-CQPQcDLN.js";import{_ as U}from"./Stat.vue_vue_type_script_setup_true_lang-BLQk8QX-.js";const K={class:"col"},T={class:"card",style:{display:"flex","align-items":"center",gap:"18px"}},j={style:{width:"180px",height:"6px",background:"var(--bg-2)","border-radius":"999px",overflow:"hidden"}},F={class:"map-grid"},O={class:"map-col"},P={class:"segmented",style:{padding:"2px"}},H={class:"map-list"},J=["onClick"],L={class:"nm"},q={class:"id"},X={key:0,class:"empty"},Q={class:"map-link",style:{"align-self":"center"}},R={class:"map-col"},W={class:"map-list"},Y=["onClick"],Z={class:"nm"},ee={class:"id"},ae=V({__name:"MappingScreen",setup(ne){const _=[{id:"bbc.one.uk",name:"BBC One"},{id:"bbc.two.uk",name:"BBC Two"},{id:"bbc.news.uk",name:"BBC News"},{id:"sky.sports.main.uk",name:"Sky Sports Main Event"},{id:"sky.sports.f1.uk",name:"Sky Sports F1"},{id:"itv1.uk",name:"ITV1"},{id:"channel4.uk",name:"Channel 4"},{id:"film4.uk",name:"Film4"},{id:"discovery.uk",name:"Discovery Channel UK"},{id:"natgeo.uk",name:"National Geographic UK"},{id:"cnn.int",name:"CNN International"},{id:"aljazeera.en",name:"Al Jazeera English"},{id:"hgtv.uk",name:"HGTV UK"},{id:"nickjr.uk",name:"Nick Jr UK"},{id:"tcm.uk",name:"TCM Movies"},{id:"eurosport1.uk",name:"Eurosport 1"}],a=D({});f.forEach(s=>{s.epg==="matched"&&s.tvg_id&&(a[s.id]=s.tvg_id)});const o=B(null),d=B("unmatched"),x=E(()=>f.filter(s=>d.value==="all"||(d.value==="unmatched"?!a[s.id]:!!a[s.id])));function S(s,e){a[s]=e}function I(s){delete a[s]}const C=E(()=>Object.keys(a).length),b=f.length;function h(s){return Object.entries(a).find(([,e])=>e===s)}return(s,e)=>(l(),r("div",K,[n("div",T,[i(v,{name:"map",size:20}),e[4]||(e[4]=n("div",{style:{flex:"1"}},[n("div",{style:{"font-weight":"600","font-size":"15px"}},"Channel ↔ EPG mapping"),n("div",{class:"muted",style:{"font-size":"var(--fs-xs)","margin-top":"2px"}}," Drag from left to right, or pick a channel and click the EPG ID. Auto-match runs nightly. ")],-1)),i(U,{label:"Matched",value:`${C.value} / ${z(b)}`},null,8,["value"]),n("div",j,[n("div",{style:A({width:C.value/z(b)*100+"%",height:"100%",background:"var(--accent)",boxShadow:"0 0 12px var(--accent)"})},null,4)]),i(w,{variant:"primary",icon:"refresh"},{default:m(()=>[...e[3]||(e[3]=[u("Auto-match",-1)])]),_:1})]),n("div",F,[n("div",O,[n("h3",null,[i(v,{name:"playlist",size:14}),e[5]||(e[5]=u(" M3U Channels ",-1)),e[6]||(e[6]=n("span",{class:"spacer"},null,-1)),n("div",P,[n("button",{class:c(d.value==="unmatched"?"active":""),onClick:e[0]||(e[0]=t=>d.value="unmatched"),style:{"font-size":"10.5px",padding:"3px 8px"}},"Unmatched",2),n("button",{class:c(d.value==="matched"?"active":""),onClick:e[1]||(e[1]=t=>d.value="matched"),style:{"font-size":"10.5px",padding:"3px 8px"}},"Matched",2),n("button",{class:c(d.value==="all"?"active":""),onClick:e[2]||(e[2]=t=>d.value="all"),style:{"font-size":"10.5px",padding:"3px 8px"}},"All",2)])]),n("div",H,[(l(!0),r(g,null,N(x.value,t=>(l(),r("div",{key:t.id,class:c(["map-item",{selected:o.value===t.id,matched:!!a[t.id]}]),onClick:M=>o.value=t.id},[i(G,{ch:t},null,8,["ch"]),n("div",L,p(t.tvg_name),1),a[t.id]?(l(),r(g,{key:0},[n("span",q,p(a[t.id]),1),i(w,{variant:"ghost",size:"sm",icon:"x",onClick:M=>I(t.id)},null,8,["onClick"])],64)):(l(),y(k,{key:1,tone:"warn"},{default:m(()=>[...e[7]||(e[7]=[u("unmatched",-1)])]),_:1}))],10,J))),128)),x.value.length===0?(l(),r("div",X,[...e[8]||(e[8]=[n("h3",null,"All matched 🎉",-1),n("p",null,"Every channel in this view has an EPG ID assigned.",-1)])])):$("",!0)])]),n("div",Q,[i(v,{name:"chevron-r",size:22})]),n("div",R,[n("h3",null,[i(v,{name:"epg",size:14}),e[9]||(e[9]=u(" EPG channel IDs ",-1)),e[10]||(e[10]=n("span",{class:"spacer"},null,-1)),i(k,null,{default:m(()=>[u(p(_.length),1)]),_:1})]),n("div",W,[(l(),r(g,null,N(_,t=>n("div",{key:t.id,class:c(["map-item",{selected:o.value&&!h(t.id),matched:!!h(t.id)}]),onClick:()=>{o.value&&!h(t.id)&&(S(o.value,t.id),o.value=null)}},[n("div",Z,p(t.name),1),n("span",ee,p(t.id),1),h(t.id)?(l(),y(k,{key:0,tone:"good"},{default:m(()=>[i(v,{name:"check",size:10}),e[11]||(e[11]=u("linked",-1))]),_:1})):o.value?(l(),y(k,{key:1,tone:"cyan"},{default:m(()=>[...e[12]||(e[12]=[u("click to link",-1)])]),_:1})):$("",!0)],10,Y)),64))])])])]))}});export{ae as default};
|
||||
1
dist/assets/PlaylistDetailScreen-F92VSAQ7.js
vendored
Normal file
1
dist/assets/PlaylistDetailScreen-F92VSAQ7.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/PlaylistsScreen-0ooKY6SX.js
vendored
Normal file
1
dist/assets/PlaylistsScreen-0ooKY6SX.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import{v as k,D as g,r as d,o as a,u as i,X as l,e as _,F as h,K as C,J as $,H as o,t as e,O as u,y as x,f as v,N as n,g as w,p as S,_ as c,q as N,Q as z,j as B}from"./index-CQPQcDLN.js";import{u as f}from"./useSettings-CPUgOpin.js";const V={class:"col"},j={class:"card flush"},A={class:"toolbar"},D=["onClick"],F={class:"src-name"},P={class:"src-url"},q={class:"stat-mini"},E={class:"stat-mini"},H={class:"stat-mini",style:{"min-width":"110px"}},I={style:{"font-size":"12px","font-weight":"500",color:"var(--text-1)"}},O=k({__name:"PlaylistsScreen",emits:["add"],setup(J,{emit:y}){const p=y,b=z(),m=$([]);return g(async()=>{const r=await fetch("/api/playlists");r.ok&&(m.value=await r.json())}),(r,s)=>(o(),d("div",V,[a("div",j,[a("div",A,[i(B,{value:"",onChange:()=>{},placeholder:"Search playlists"}),s[3]||(s[3]=a("span",{class:"spacer"},null,-1)),i(_,{variant:"ghost",icon:"refresh"},{default:l(()=>[...s[1]||(s[1]=[e("Sync all",-1)])]),_:1}),i(_,{variant:"primary",icon:"plus",onClick:s[0]||(s[0]=t=>p("add","playlist"))},{default:l(()=>[...s[2]||(s[2]=[e("Add playlist",-1)])]),_:1})]),(o(!0),d(h,null,C(m.value,t=>(o(),d("div",{key:t.id,class:"src-row",onClick:K=>u(b).push(`/playlists/${t.id}`)},[a("div",{class:x(["src-ico",{builtin:t.builtin}])},[i(v,{name:t.builtin?"tv":"playlist",size:18},null,8,["name"])],2),a("div",null,[a("div",F,[e(n(t.name)+" ",1),i(w,{status:t.status,pulse:t.status==="good"},null,8,["status","pulse"]),t.builtin?(o(),S(c,{key:0,tone:"system"},{default:l(()=>[i(v,{name:"check",size:10}),s[4]||(s[4]=e("built-in",-1))]),_:1})):N("",!0),i(c,{tone:"cyan"},{default:l(()=>[e(n(t.interval),1)]),_:2},1024)]),a("div",P,n(t.url),1)]),i(c,{tone:u(f)(t.id).active?"active":"disabled"},{default:l(()=>[e(n(u(f)(t.id).active?"Active":"Inactive"),1)]),_:2},1032,["tone"]),a("div",q,[a("b",null,n(t.channels),1),s[5]||(s[5]=e("channels",-1))]),a("div",E,[a("b",null,n(t.groups),1),s[6]||(s[6]=e("groups",-1))]),a("div",H,[a("b",I,n(t.lastSync),1),s[7]||(s[7]=e(" last sync ",-1))])],8,D))),128))])]))}});export{O as default};
|
||||
1
dist/assets/SettingsScreen-Daj_a2gr.js
vendored
Normal file
1
dist/assets/SettingsScreen-Daj_a2gr.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/Stat.vue_vue_type_script_setup_true_lang-BLQk8QX-.js
vendored
Normal file
1
dist/assets/Stat.vue_vue_type_script_setup_true_lang-BLQk8QX-.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import{v as l,r as o,o as t,N as a,z as n,L as r,H as i,t as m}from"./index-CQPQcDLN.js";const c={style:{"text-align":"right"}},d={class:"muted",style:{"font-size":"var(--fs-xs)","text-transform":"uppercase","letter-spacing":"0.06em"}},u=l({__name:"Stat",props:{label:{},value:{},small:{type:Boolean}},setup(e){return(s,f)=>(i(),o("div",c,[t("div",d,a(e.label),1),t("div",{style:n({fontWeight:600,fontSize:e.small?"var(--fs-sm)":"18px",fontVariantNumeric:"tabular-nums",marginTop:"2px"})},[r(s.$slots,"default",{},()=>[m(a(e.value),1)])],4)]))}});export{u as _};
|
||||
1
dist/assets/index-BzPI8e-F.css
vendored
Normal file
1
dist/assets/index-BzPI8e-F.css
vendored
Normal file
File diff suppressed because one or more lines are too long
26
dist/assets/index-CQPQcDLN.js
vendored
Normal file
26
dist/assets/index-CQPQcDLN.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/assets/useSettings-CPUgOpin.js
vendored
Normal file
1
dist/assets/useSettings-CPUgOpin.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import{n as c,J as s,I as l}from"./index-CQPQcDLN.js";const h=s("TVApp2 Workspace"),u=s("https://tvapp2.example.com"),o=s("/m3u/playlist.m3u8"),$=s("/epg/guide.xml.gz"),m=c(()=>`${u.value.replace(/\/$/,"")}${o.value.startsWith("/")?"":"/"}${o.value}`),e=l({});function i(t){return e[t]||(e[t]={active:!0,endpointMode:"global",customPath:`/playlists/${t}.m3u`}),e[t]}function d(t){const a=i(t),n=u.value.replace(/\/$/,"");if(a.endpointMode==="custom"){const p=a.customPath.startsWith("/")?a.customPath:`/${a.customPath}`;return`${n}${p}`}return m.value}export{u as a,o as b,h as d,$ as e,m,d as p,i as u};
|
||||
19
dist/index.html
vendored
Normal file
19
dist/index.html
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark" data-density="regular">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>TVApp2 — M3U & EPG Manager</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
||||
<style>
|
||||
@keyframes slidein { from { transform: translateX(20px); opacity: 0; } to { transform: none; opacity: 1; } }
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/index-CQPQcDLN.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BzPI8e-F.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
2
dist/types-node/vite.config.d.ts
vendored
Normal file
2
dist/types-node/vite.config.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
declare const _default: import("vite").UserConfig;
|
||||
export default _default;
|
||||
14
dist/types-node/vite.config.js
vendored
Normal file
14
dist/types-node/vite.config.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3000',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
126
docker-compose.yml
Executable file → Normal file
126
docker-compose.yml
Executable file → Normal file
@@ -1,50 +1,84 @@
|
||||
# #
|
||||
# TVApp2 Docker-compose.yml
|
||||
#
|
||||
# Automatic M3U playlist and XML guide updater for TheTvApp, TVPass, and MoveOnJoy utilized within your IPTV client.
|
||||
#
|
||||
# @url https://github.com/TheBinaryNinja/tvapp2
|
||||
# https://git.binaryninja.net/BinaryNinja/tvapp2
|
||||
#
|
||||
# @image:github ghcr.io/thebinaryninja/tvapp2:latest
|
||||
# ghcr.io/thebinaryninja/tvapp2:amd64
|
||||
# ghcr.io/thebinaryninja/tvapp2:arm64
|
||||
#
|
||||
# @image:dockerhub thebinaryninja/tvapp2:latest
|
||||
# thebinaryninja/tvapp2:1.0.0-amd64
|
||||
# thebinaryninja/tvapp2:1.0.0-arm64
|
||||
#
|
||||
# @image:gitea git.binaryninja.net/binaryninja/tvapp2:latest
|
||||
# git.binaryninja.net/binaryninja/tvapp2:1.0.0-amd64
|
||||
# git.binaryninja.net/binaryninja/tvapp2:1.0.0-arm64
|
||||
# #
|
||||
# Pinned image versions — bump in lockstep with docker/*.Dockerfile.
|
||||
# MONGO = 7.0.15
|
||||
# Requires Docker Engine >= 24.0 and Docker Compose >= 2.20 (Compose Spec).
|
||||
# The legacy top-level `version:` key is intentionally omitted (deprecated in Compose v2).
|
||||
|
||||
services:
|
||||
# One-shot init: writes ${TVAPP2_CONFIG_DIR}/config.json from the MONGO_ROOT_USER /
|
||||
# MONGO_ROOT_PASS values in .env. The JSON template is embedded below — NO host file is
|
||||
# bind-mounted — so a deployment host needs only this compose file + .env, nothing else to
|
||||
# ship. (Bind-mounting a host template is a footgun: if the file is missing Docker silently
|
||||
# creates it as an empty *directory*, and config.json ends up empty.) Left untouched if an
|
||||
# existing config.json already targets the compose "mongo" host; regenerated otherwise
|
||||
# (e.g. a stale @127.0.0.1: config left by an all-in-one run).
|
||||
config-init:
|
||||
image: alpine:3.20
|
||||
environment:
|
||||
MONGO_ROOT_USER: ${MONGO_ROOT_USER}
|
||||
MONGO_ROOT_PASS: ${MONGO_ROOT_PASS}
|
||||
volumes:
|
||||
- ${TVAPP2_CONFIG_DIR}:/out
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
if [ -s /out/config.json ] && grep -q '@mongo:' /out/config.json; then
|
||||
echo "[config-init] /out/config.json already targets @mongo: — leaving alone"
|
||||
exit 0
|
||||
fi
|
||||
if [ -s /out/config.json ]; then
|
||||
echo "[config-init] /out/config.json does not target @mongo: — regenerating"
|
||||
fi
|
||||
printf '{\n "mongoUri": "mongodb://%s:%s@mongo:27017/tvapp2?authSource=admin",\n "port": 3000,\n "logLevel": "info"\n}\n' \
|
||||
"$$MONGO_ROOT_USER" "$$MONGO_ROOT_PASS" > /out/config.json
|
||||
echo "[config-init] wrote /out/config.json"
|
||||
restart: "no"
|
||||
|
||||
# #
|
||||
# Service > TVApp2
|
||||
# #
|
||||
app:
|
||||
image: iflip721/tvapp2-app-stack:2.0.5-dev
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/app.Dockerfile
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
# config.json is generated by the config-init service from .env (embedded template).
|
||||
# Set TVAPP2_CONFIG_DIR in .env to the host directory that holds it.
|
||||
- ${TVAPP2_CONFIG_DIR}:/etc/tvapp2:rw
|
||||
depends_on:
|
||||
config-init:
|
||||
condition: service_completed_successfully
|
||||
mongo:
|
||||
condition: service_healthy
|
||||
networks: [tvnet]
|
||||
restart: unless-stopped
|
||||
|
||||
tvapp2:
|
||||
container_name: tvapp2
|
||||
image: ghcr.io/thebinaryninja/tvapp2:latest # Image: Github
|
||||
# image: thebinaryninja/tvapp2:latest # Image: Dockerhub
|
||||
# image: git.binaryninja.net/binaryninja/tvapp2:latest # Image: Gitea
|
||||
# image: tvapp2:latest # Image: Locally built
|
||||
hostname: tvapp2
|
||||
environment:
|
||||
TZ: "Etc/UTC"
|
||||
volumes:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./config:/config
|
||||
- ./app:/usr/bin/app
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "--fail", "http://127.0.0.1:4124/api/health?silent=true" ]
|
||||
interval: 30s
|
||||
retries: 5
|
||||
mongo:
|
||||
image: mongo:7.0.15
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER}
|
||||
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASS}
|
||||
ports:
|
||||
# Expose mongod on the host. Override the host-side port with
|
||||
# MONGO_HOST_PORT in .env (defaults to 27017).
|
||||
- "${MONGO_HOST_PORT:-27017}:27017"
|
||||
volumes:
|
||||
# Persistent MongoDB data. Set MONGO_DATA_PATH in .env to an absolute
|
||||
# host path (e.g. /srv/tvapp2/mongo) for a bind mount; leave unset to
|
||||
# use the named volume defined below.
|
||||
- ${MONGO_DATA_PATH:-mongo-data}:/data/db
|
||||
healthcheck:
|
||||
test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks: [tvnet]
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
# Fallback named volume — used only when MONGO_DATA_PATH is unset.
|
||||
mongo-data:
|
||||
|
||||
networks:
|
||||
tvnet:
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# #
|
||||
# @project TVApp2
|
||||
# @usage docker image which allows you to download a m3u playlist and EPG guide data from
|
||||
# multiple IPTV services.
|
||||
# @file docker-entrypoint.sh
|
||||
# @repo https://github.com/TheBinaryNinja/tvapp2
|
||||
# https://git.binaryninja.net/BinaryNinja/tvapp2
|
||||
# https://github.com/aetherinox/docker-base-alpine
|
||||
#
|
||||
# you can build your own image by running
|
||||
# amd64 docker build --build-arg VERSION=1.0.0 --build-arg BUILDDATE=20250218 -t tvapp2:latest -t tvapp2:1.0.0 -t tvapp2:1.0.0-amd64 -f Dockerfile .
|
||||
# arm64 docker build --build-arg VERSION=1.0.0 --build-arg BUILDDATE=20250218 -t tvapp2:1.0.0-arm64 -f Dockerfile.aarch64 .
|
||||
#
|
||||
# if you prefer to use `docker buildx`
|
||||
# create docker buildx create --driver docker-container --name container --bootstrap --use
|
||||
# amd64 docker buildx build --no-cache --pull --build-arg VERSION=1.0.0 --build-arg BUILDDATE=20250218 -t tvapp2:latest -t tvapp2:1.0.0 --platform=linux/amd64 --output type=docker --output type=docker .
|
||||
# arm64 docker buildx build --no-cache --pull --build-arg VERSION=1.0.0 --build-arg BUILDDATE=20250218 -t tvapp2:latest -t tvapp2:1.0.0 --platform=linux/arm64 --output type=docker --output type=docker .
|
||||
# #
|
||||
|
||||
set -e
|
||||
|
||||
# Run command with node if the first argument contains a "-" or is not a system command. The last
|
||||
# part inside the "{}" is a workaround for the following bug in ash/dash:
|
||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
|
||||
if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ] || { [ -f "${1}" ] && ! [ -x "${1}" ]; }; then
|
||||
set -- node "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
65
docker/app.Dockerfile
Normal file
65
docker/app.Dockerfile
Normal file
@@ -0,0 +1,65 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
# -----------------------------------------------------------------------------
|
||||
# docker/app.Dockerfile — TVApp2 "app stack" image (iflip721/tvapp2-app-stack)
|
||||
#
|
||||
# Three-stage build:
|
||||
# 1) spa-build — Vue 3 + Vite SPA → /spa/dist (root package.json)
|
||||
# 2) server-build — Express API (tsc) → /server/dist (server/package.json)
|
||||
# 3) runtime — prod-only Node; serves API + built SPA on :3000
|
||||
#
|
||||
# Runtime layout (must match server/src/index.ts publicDir and sources/paths.ts SEED_SOURCES_DIR):
|
||||
# /app/dist/ compiled server (dist/index.js, dist/sources/paths.js)
|
||||
# /app/public/ built SPA (resolve(<dist>,'..','public') => /app/public)
|
||||
# /app/seed-data/ source bundles (resolve(<dist>,'..','..','seed-data','sources'))
|
||||
# /app/package.json server pkg (type:module) + node_modules (express, mongoose only)
|
||||
#
|
||||
# Node pin: 22.11.0 LTS "Jod" on alpine 3.20 — keep in lockstep with CLAUDE.md.
|
||||
# -----------------------------------------------------------------------------
|
||||
ARG NODE_IMAGE=node:22.11.0-alpine3.20
|
||||
|
||||
# ---- Stage 1: build the SPA (root package) ----------------------------------
|
||||
FROM ${NODE_IMAGE} AS spa-build
|
||||
WORKDIR /spa
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY tsconfig.json tsconfig.node.json vite.config.ts index.html ./
|
||||
COPY public/ ./public/
|
||||
COPY src/ ./src/
|
||||
RUN npm run build # vue-tsc -b && vite build -> /spa/dist
|
||||
|
||||
# ---- Stage 2: build the server (server package) -----------------------------
|
||||
FROM ${NODE_IMAGE} AS server-build
|
||||
WORKDIR /server
|
||||
COPY server/package.json server/package-lock.json ./
|
||||
RUN npm ci # devDeps (typescript) needed to compile
|
||||
COPY server/tsconfig.json ./
|
||||
COPY server/src/ ./src/
|
||||
RUN npm run build # tsc -p . -> /server/dist
|
||||
|
||||
# ---- Stage 3: runtime -------------------------------------------------------
|
||||
FROM ${NODE_IMAGE} AS runtime
|
||||
ENV NODE_ENV=production \
|
||||
TVAPP2_CONFIG=/etc/tvapp2/config.json
|
||||
WORKDIR /app
|
||||
|
||||
# tini = correct PID 1 (forwards SIGTERM/SIGINT to the graceful-shutdown handler in index.ts).
|
||||
RUN apk add --no-cache tini
|
||||
|
||||
# Prod-only server deps (express, mongoose).
|
||||
COPY server/package.json server/package-lock.json ./
|
||||
RUN npm ci --omit=dev && npm cache clean --force
|
||||
|
||||
# Compiled server + built SPA + committed seed bundles.
|
||||
COPY --from=server-build /server/dist ./dist
|
||||
COPY --from=spa-build /spa/dist ./public
|
||||
COPY server/seed-data ./seed-data
|
||||
|
||||
USER node
|
||||
EXPOSE 3000
|
||||
|
||||
# Liveness: HTTP server up (body also reports mongo connected/disconnected).
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
||||
CMD wget -qO- http://127.0.0.1:3000/api/health || exit 1
|
||||
|
||||
ENTRYPOINT ["/sbin/tini", "--"]
|
||||
CMD ["node", "dist/index.js"]
|
||||
@@ -25,7 +25,7 @@
|
||||
services:
|
||||
|
||||
# #
|
||||
# Service › TVApp2 › Traefik Labels
|
||||
# Service › TVApp2
|
||||
# #
|
||||
|
||||
tvapp2:
|
||||
@@ -40,7 +40,6 @@ services:
|
||||
volumes:
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./config:/config
|
||||
- ./app:/usr/bin/app
|
||||
ulimits:
|
||||
@@ -56,7 +55,7 @@ services:
|
||||
- traefik.enable=true
|
||||
|
||||
# #
|
||||
# Scope > http
|
||||
# Routers › Web Interface › http
|
||||
# #
|
||||
|
||||
- traefik.http.routers.tvapp2-http.rule=Host(`tvapp2.localhost`) || Host(`tvapp2.domain.lan`) || Host(`www.tvapp2.domain.lan`) || Host(`${SERVICE_IP}`)
|
||||
@@ -66,7 +65,7 @@ services:
|
||||
- traefik.http.routers.tvapp2-http.middlewares=https-redirect@file
|
||||
|
||||
# #
|
||||
# Scope > https
|
||||
# Routers › Web Interface › https
|
||||
#
|
||||
# remove the authentik@file line if you do not wish to use Authentik or middleware
|
||||
# - traefik.http.routers.tvapp2-https.middlewares=authentik@file
|
||||
@@ -83,8 +82,26 @@ services:
|
||||
- traefik.http.routers.tvapp2-https.middlewares=authentik@file
|
||||
|
||||
# #
|
||||
# Load Balancer
|
||||
# Routers › HDHomeRun
|
||||
# #
|
||||
|
||||
- traefik.http.services.tvapp2.loadbalancer.server.port=http
|
||||
- traefik.http.services.tvapp2.loadbalancer.server.scheme=4124
|
||||
- traefik.http.routers.hdhr-https.rule=Host(`hdhr.domain.lan`)
|
||||
- traefik.http.routers.hdhr-https.service=hdhr
|
||||
- traefik.http.routers.hdhr-https.entrypoints=https
|
||||
- traefik.http.routers.hdhr-https.priority=1
|
||||
- traefik.http.routers.hdhr-https.tls=true
|
||||
- traefik.http.routers.hdhr-https.tls.certresolver=cloudflare
|
||||
|
||||
# #
|
||||
# Services › Main Web Interface
|
||||
# #
|
||||
|
||||
- traefik.http.services.tvapp2.loadbalancer.server.port=4124
|
||||
- traefik.http.services.tvapp2.loadbalancer.server.scheme=http
|
||||
|
||||
# #
|
||||
# Services › HDHomeRun Server (optional)
|
||||
# #
|
||||
|
||||
- traefik.http.services.hdhr.loadbalancer.server.port=6077
|
||||
- traefik.http.services.hdhr.loadbalancer.server.scheme=http
|
||||
|
||||
@@ -295,24 +295,24 @@ http:
|
||||
- "*.domain.lan"
|
||||
|
||||
# #
|
||||
# @container TVApp2
|
||||
# @desc utomatic M3U playlist and XML guide updater for TheTvApp, TVPass, and MoveOnJoy utilized within your IPTV client.
|
||||
# @container TVApp2 › Main
|
||||
# @desc automatic M3U playlist and XML guide updater for TheTvApp, TVPass, and MoveOnJoy utilized within your IPTV client.
|
||||
# @url https://github.com/TheBinaryNinja/tvapp2
|
||||
#
|
||||
# remove / comment out the authentik line if you do not plan to use authentik:
|
||||
# - authentik@file
|
||||
# remove / comment out the authentik line if you do not plan to use authentik:
|
||||
# - authentik@file
|
||||
# #
|
||||
|
||||
tvapp2-http:
|
||||
service: "tvapp2"
|
||||
tvapp2-server-http:
|
||||
service: "tvapp2-server"
|
||||
rule: "Host(`tvapp2.localhost`) || Host(`tvapp2.domain.lan`)"
|
||||
entryPoints:
|
||||
- http
|
||||
middlewares:
|
||||
- https-redirect@file
|
||||
|
||||
tvapp2-https:
|
||||
service: "tvapp2"
|
||||
tvapp2-server-https:
|
||||
service: "tvapp2-server"
|
||||
rule: "Host(`tvapp2.localhost`) || Host(`tvapp2.domain.lan`)"
|
||||
entryPoints:
|
||||
- https
|
||||
@@ -325,6 +325,37 @@ http:
|
||||
- main: "domain.lan"
|
||||
sans:
|
||||
- "*.domain.lan"
|
||||
# #
|
||||
# @container TVApp2 › HDHomeRun
|
||||
# @desc automatic M3U playlist and XML guide updater for TheTvApp, TVPass, and MoveOnJoy utilized within your IPTV client.
|
||||
# @url https://github.com/TheBinaryNinja/tvapp2
|
||||
#
|
||||
# remove / comment out the authentik line if you do not plan to use authentik:
|
||||
# - authentik@file
|
||||
# #
|
||||
|
||||
tvapp2-hdhr-http:
|
||||
service: "tvapp2-hdhr"
|
||||
rule: "Host(`hdhr.localhost`) || Host(`hdhr.domain.lan`)"
|
||||
entryPoints:
|
||||
- http
|
||||
middlewares:
|
||||
- https-redirect@file
|
||||
|
||||
tvapp2-hdhr-https:
|
||||
service: "tvapp2-hdhr"
|
||||
rule: "Host(`hdhr.localhost`) || Host(`hdhr.domain.lan`)"
|
||||
entryPoints:
|
||||
- https
|
||||
middlewares:
|
||||
- redirect-www@file
|
||||
- authentik@file
|
||||
tls:
|
||||
certResolver: cloudflare
|
||||
domains:
|
||||
- main: "domain.lan"
|
||||
sans:
|
||||
- "*.domain.lan"
|
||||
|
||||
# #
|
||||
# http › Services
|
||||
@@ -351,7 +382,12 @@ http:
|
||||
servers:
|
||||
- url: "http://plex:32400"
|
||||
|
||||
tvapp2:
|
||||
tvapp2-server:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://tvapp2:4124"
|
||||
|
||||
tvapp2-hdhr:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://tvapp2:4124"
|
||||
|
||||
18
index.html
Normal file
18
index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark" data-density="regular">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>TVApp2 — M3U & EPG Manager</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
||||
<style>
|
||||
@keyframes slidein { from { transform: translateX(20px); opacity: 0; } to { transform: none; opacity: 1; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
1575
package-lock.json
generated
Normal file
1575
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
package.json
Normal file
23
package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "tvapp2",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"hls.js": "^1.6.16",
|
||||
"mitt": "^3.0.1",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"typescript": "^5.7.2",
|
||||
"vite": "^6.0.5",
|
||||
"vue-tsc": "^2.2.0"
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# #
|
||||
# @project TVApp2
|
||||
# @usage Automatic m3u and xml guide updater for TheTvApp, TVPass, and MoveOnJoy utilized within your IPTV client.
|
||||
# @file plugins
|
||||
# @repo.1 https://github.com/TheBinaryNinja/tvapp2
|
||||
# @repo.2 https://git.binaryninja.net/BinaryNinja/tvapp2
|
||||
# @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 > Start
|
||||
# #
|
||||
|
||||
printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}Checking tvapp2-plugins${c[end]}"
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
echo -e " Completed loading container"
|
||||
@@ -1,21 +0,0 @@
|
||||
──────────────────────────────────────────────────────────────────────────────────────────
|
||||
TVApp2 Docker Image
|
||||
──────────────────────────────────────────────────────────────────────────────────────────
|
||||
The TvApp2 image allows you to fetch M3U playlist and EPG data for numerous
|
||||
IPTV services online.
|
||||
|
||||
Once the files are fetched by the image, you can visit the self-hosted webpage,
|
||||
copy the links to the M3U and EPG files; and add them to your favorite IPTV app
|
||||
such as Jellyfin, Plex, or Emby.
|
||||
|
||||
For more information about this project; visit the links below. This app is
|
||||
served on multiple repositories as backup. Use any of the repo links below:
|
||||
|
||||
TVApp2 Repo 1 https://github.com/TheBinaryNinja/tvapp2
|
||||
TVApp2 Repo 2 https://git.binaryninja.net/BinaryNinja/tvapp2
|
||||
Base Alpine Image https://github.com/Aetherinox/docker-base-alpine
|
||||
|
||||
If you are making this container available on a public-facing domain,
|
||||
please consider using Traefik and Authentik to protect this container from
|
||||
outside access. Your M3U and EPG files will be available for the public to
|
||||
download and use.
|
||||
@@ -1,176 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
# #
|
||||
# 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' # 🗔
|
||||
)
|
||||
|
||||
# #
|
||||
# distro info
|
||||
# #
|
||||
|
||||
sys_os_name="Unknown"
|
||||
sys_os_ver="1.0.0"
|
||||
|
||||
if [ -e /etc/alpine-release ]; then
|
||||
sys_os_name="Alpine"
|
||||
sys_os_ver="$(cat /etc/alpine-release)"
|
||||
fi
|
||||
|
||||
# #
|
||||
# get container ips
|
||||
# #
|
||||
|
||||
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')
|
||||
|
||||
# #
|
||||
# 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
|
||||
groupmod -o -g "$PGID" dockerx
|
||||
usermod -o -u "$PUID" dockerx
|
||||
fi
|
||||
|
||||
# #
|
||||
# s6 > branding
|
||||
# #
|
||||
|
||||
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
|
||||
echo -e
|
||||
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}Distro${c[end]}" "${c[end]}${sys_os_name} ${sys_os_ver}${c[end]}"
|
||||
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}User:Group${c[end]}" "${c[end]}$(id -u dockerx):$(id -g dockerx)${c[end]}"
|
||||
else
|
||||
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}User:Group${c[end]}" "${c[end]}$(stat /run -c %u):$(stat /run -c %g)${c[end]}"
|
||||
fi
|
||||
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}Port(s)${c[end]}" "${c[end]}$(echo $WEB_PORT)${c[end]}"
|
||||
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}Gateway${c[end]}" "${c[end]}$(echo $IP_GATEWAY)${c[end]}"
|
||||
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}Web Server${c[end]}" "${c[end]}$(echo $IP_CONTAINER:$WEB_PORT)${c[end]}"
|
||||
printf '%-6s %-35s %-65s\n' "" " ${c[greenl]}App Folder${c[end]}" "${c[end]}$(echo $DIR_RUN)${c[end]}"
|
||||
echo -e
|
||||
printf '%-1s\n' " ${c[greyd]}──────────────────────────────────────────────────────────────────────────────────────────${c[end]}"
|
||||
|
||||
# #
|
||||
# set permissions
|
||||
# #
|
||||
|
||||
if [[ -z ${TVAPP_READ_ONLY_FS} ]] && [[ -z ${TVAPP_NON_ROOT_USER} ]]; then
|
||||
aetherxown dockerx:dockerx /app
|
||||
aetherxown dockerx:dockerx /config
|
||||
aetherxown dockerx:dockerx $(echo $DIR_BUILD)
|
||||
fi
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-adduser/run
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
# This file doesn't do anything, it's just the end of the downstream image init process
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
for cron_user in dockerx root; do
|
||||
if [[ -z ${TVAPP_READ_ONLY_FS} ]] && [[ -z ${TVAPP_NON_ROOT_USER} ]]; then
|
||||
if [[ -f "/etc/crontabs/${cron_user}" ]]; then
|
||||
aetherxown "${cron_user}":"${cron_user}" "/etc/crontabs/${cron_user}"
|
||||
crontab -u "${cron_user}" "/etc/crontabs/${cron_user}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -f "/defaults/crontabs/${cron_user}" ]]; then
|
||||
mkdir -p /config/crontabs
|
||||
|
||||
# #
|
||||
# if crontabs do not exist in config
|
||||
# #
|
||||
|
||||
if [[ ! -f "/config/crontabs/${cron_user}" ]]; then
|
||||
|
||||
# #
|
||||
# copy crontab from system
|
||||
# #
|
||||
|
||||
if crontab -l -u "${cron_user}" >/dev/null 2>&1; then
|
||||
crontab -l -u "${cron_user}" >"/config/crontabs/${cron_user}"
|
||||
fi
|
||||
|
||||
# #
|
||||
# if crontabs still do not exist in config (were not copied from system)
|
||||
# copy crontab from image defaults (using -n, do not overwrite an existing file)
|
||||
# #
|
||||
|
||||
cp -n "/defaults/crontabs/${cron_user}" /config/crontabs/
|
||||
fi
|
||||
|
||||
# #
|
||||
# set perms and import user crontabs
|
||||
# #
|
||||
|
||||
aetherxown "${cron_user}":"${cron_user}" "/config/crontabs/${cron_user}"
|
||||
crontab -u "${cron_user}" "/config/crontabs/${cron_user}"
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-crontab-config/run
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/usr/bin/with-contenv 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
|
||||
SCRIPTS_DIR="/custom-cont-init.d"
|
||||
|
||||
# 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
|
||||
printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}Loading any found plugins${c[end]}"
|
||||
for SCRIPT in "${SCRIPTS_DIR}"/*; do
|
||||
NAME="$(basename "${SCRIPT}")"
|
||||
if [[ -f "${SCRIPT}" ]]; then
|
||||
printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}Executing${c[end]}"
|
||||
/bin/bash "${SCRIPT}"
|
||||
printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}Successfully ran with code ${c[bluel]}[$?]${c[end]}"
|
||||
elif [[ ! -f "${SCRIPT}" ]]; then
|
||||
printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}${c[bluel]}${NAME}${c[end]} is not a valid file${c[end]}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
printf '%-29s %-65s\n' " ${c[bluel]}Loader${c[end]}" "${c[end]}No plugins found; skipping${c[end]}"
|
||||
fi
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-custom-files/run
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
if find /run/s6/container_environment/FILE__* -maxdepth 1 > /dev/null 2>&1; then
|
||||
for FILENAME in /run/s6/container_environment/FILE__*; do
|
||||
SECRETFILE=$(cat "${FILENAME}")
|
||||
if [[ -f ${SECRETFILE} ]]; then
|
||||
FILESTRIP=${FILENAME//FILE__/}
|
||||
if [[ $(tail -n1 "${SECRETFILE}" | wc -l) != 0 ]]; then
|
||||
echo "[env-init] Your secret: ${FILENAME##*/}"
|
||||
echo " contains a trailing newline and may not work as expected"
|
||||
fi
|
||||
cat "${SECRETFILE}" >"${FILESTRIP}"
|
||||
echo "[env-init] ${FILESTRIP##*/} set from ${FILENAME##*/}"
|
||||
else
|
||||
echo "[env-init] cannot find secret in ${FILENAME##*/}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-envfile/run
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
# make folders
|
||||
mkdir -p \
|
||||
/config/keys \
|
||||
/run \
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-folders/run
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
# #
|
||||
# @project TVApp2
|
||||
# @usage Automatic m3u and xml guide updater for TheTvApp, TVPass, and MoveOnJoy utilized within your IPTV client.
|
||||
# @file run
|
||||
# @repo.1 https://github.com/TheBinaryNinja/tvapp2
|
||||
# @repo.2 https://git.binaryninja.net/BinaryNinja/tvapp2
|
||||
# @repo.3 https://github.com/aetherinox/docker-base-alpine
|
||||
# #
|
||||
|
||||
SUBJECT="/C=NA/ST=NA/L=NA/O=BinaryNinja/OU=TVApp2 Docker Image/CN=*"
|
||||
if [[ -f /config/keys/cert.key && -f /config/keys/cert.crt ]]; then
|
||||
echo -e " SSL : Using existing keys found in /config/keys"
|
||||
else
|
||||
echo -e " SSL : Generating self-signed keys in folder/config/keys. Replace if needed."
|
||||
rm -f \
|
||||
/config/keys/cert.key \
|
||||
/config/keys/cert.crt || true
|
||||
|
||||
mkdir -p /config/keys
|
||||
|
||||
OUT=$(openssl req -new -x509 -days 3650 -nodes -out /config/keys/cert.crt -keyout /config/keys/cert.key -subj "$SUBJECT" 2>/dev/null)
|
||||
fi
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-keygen/run
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
MIGRATIONS_DIR="/migrations"
|
||||
MIGRATIONS_HISTORY="/config/.migrations"
|
||||
|
||||
echo -e " Migrations : Started"
|
||||
|
||||
if [[ ! -d ${MIGRATIONS_DIR} ]]; then
|
||||
echo -e " Migrations : No migrations found"
|
||||
exit
|
||||
fi
|
||||
|
||||
for MIGRATION in $(find ${MIGRATIONS_DIR}/* | sort -n); do
|
||||
NAME="$(basename "${MIGRATION}")"
|
||||
if [[ -f ${MIGRATIONS_HISTORY} ]] && grep -Fxq "${NAME}" ${MIGRATIONS_HISTORY}; then
|
||||
echo -e " Migrations : ${NAME} › Skipped"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo -e " Migrations : ${NAME} › Executing"
|
||||
chmod +x "${MIGRATION}"
|
||||
|
||||
# #
|
||||
# Execute migration script in a subshell to prevent it from modifying the current environment
|
||||
# #
|
||||
|
||||
("${MIGRATION}")
|
||||
EXIT_CODE=$?
|
||||
if [[ ${EXIT_CODE} -ne 0 ]]; then
|
||||
echo -e " Migrations : ${NAME} › Failed with exit code ${EXIT_CODE}"
|
||||
exit "${EXIT_CODE}"
|
||||
fi
|
||||
|
||||
echo "${NAME}" >>${MIGRATIONS_HISTORY}
|
||||
echo -e " Migrations : ${NAME} › Success"
|
||||
done
|
||||
|
||||
echo -e " Migrations : Complete"
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-migrations/run
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
# Empty placeholder for end of mod init process
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-mods-package-install/run
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
# This file doesn't do anything, it's just the end of the mod init process
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
# permissions
|
||||
aetherxown -R dockerx:dockerx \
|
||||
/config/keys
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-permissions/run
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
# #
|
||||
# @project TVApp2
|
||||
# @usage Automatic m3u and xml guide updater for TheTvApp, TVPass, and MoveOnJoy utilized within your IPTV client.
|
||||
# @file run
|
||||
# @repo.1 https://github.com/TheBinaryNinja/tvapp2
|
||||
# @repo.2 https://git.binaryninja.net/BinaryNinja/tvapp2
|
||||
# @repo.3 https://github.com/aetherinox/docker-base-alpine
|
||||
# #
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
@@ -1 +0,0 @@
|
||||
/etc/s6-overlay/s6-rc.d/init-samples/run
|
||||
@@ -1 +0,0 @@
|
||||
oneshot
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user