mirror of
https://github.com/TheBinaryNinja/tvapp2.git
synced 2026-06-04 11:05:41 -04:00
1 line
67 KiB
JSON
1 line
67 KiB
JSON
{"config": {"lang": ["en"], "separator": "[\\s\\u200b\\-_,:!=\\[\\]()\"`/]+|\\.(?!\\d)|&[lg]t;|(?!\\b)(?=[A-Z][a-z])", "pipeline": ["stopWordFilter"]}, "docs": [{"location": "", "title": "TVApp2", "text": "<p>Welcome to the TVApp2 documentation</p>"}, {"location": "home/", "title": "Home", "text": "TVApp2 <p>This documentation is related to the github repository for TVApp2; a NodeJS powered application which allows you to fetch M3U playlists and EPG guide data from various popular online IPTV services such as TheTvApp, TVPass, and MoveOnJoy. These services provide high-quality and premium channels available as Live TV.</p> <p></p> <p>This documentation covers the following:</p> <ul> <li>How to install and configure TVApp2</li> <li>Managing your TVApp2 docker image</li> <li>Building your own docker image</li> <li>Traefik and Authentik Integration</li> </ul> <p></p> <p></p>", "tags": ["home"]}, {"location": "about/changelog/", "title": "Changelog", "text": "<p>This section outlines all releases of TVApp2, including the version of the release, and the changes made for that release.</p> <p></p> <p> </p> <p></p> <p></p>", "tags": ["changelog"]}, {"location": "about/changelog/#1.4.0", "title": "1.4.0 Apr 10, 2025", "text": "<ul> <li><code>feat</code>: add new environment variable <code>HEALTH_TIMER</code> (See feature below)</li> <li><code>feat</code>: new health check icon in top right; triggers every <code>10 minutes</code> and reports back to the web interface as a toast notification<ul> <li>health check shows timer until next health check is performed.</li> </ul> </li> <li><code>feat</code>: added bootstramp toast notifications and modals</li> <li><code>feat</code>: new modal dialog when when user triggers a re-sync of the m3u and epg data</li> <li><code>feat</code>: footer of web interface how discloses which build is being ran; <code>stable</code> or <code>development</code></li> <li><code>refactor</code>: console logging system overhauled with new syntax for how logs are displayed</li> <li><code>refactor</code>: additional logs added for <code>LOG_LEVEL=5</code> or higher</li> </ul>", "tags": ["changelog"]}, {"location": "about/changelog/#1.3.0", "title": "1.3.0 Apr 9, 2025", "text": "<ul> <li><code>feat</code>: new button to upper-right side of header which allows you to force re-sync your m3u and xml data.</li> <li><code>feat</code>: new api endpoint <code>/api/resync</code>; utilized to resync M3U and EPG data</li> <li><code>feat</code>: new api endpoint <code>/api/health</code>; utilized in your <code>docker-compose.yml</code> health check</li> <li><code>feat</code>: new env variable <code>WEB_ENCODING</code>; allows you to customize the HTTP <code>Accept-Encoding</code> request and response header</li> <li><code>feat</code>: new env variable <code>IP_GATEWAY</code>; stores assigned container gateway ip</li> <li><code>feat</code>: new env variable <code>IP_CONTAINER</code>; stores assigned container ip</li> <li><code>refactor</code>: env variables re-named<ul> <li><code>FILE_TAR</code> \u2192 <code>FILE_GZP</code></li> </ul> </li> <li><code>refactor</code>: errors and success messages now use api endpoint; lists timestamp, error code, etc.</li> <li><code>build</code>: bump bootstrap from <code>v4</code> to <code>v5</code></li> <li><code>fix</code>: bug in Jellyfin which caused EPG data syncing to error out for hosts which cannot support gzip compression<ul> <li>Error: [ERR] [27] Jellyfin.LiveTv.Guide.GuideManager: Error getting programs for channel XXXXXXXXXXXXXXX (Source 2) System.Xml.XmlException: '\u001f', hexadecimal value 0x1F, is an invalid character. Line 1, position 1.</li> </ul> </li> </ul>", "tags": ["changelog"]}, {"location": "about/changelog/#1.2.0", "title": "1.2.0 Apr 5, 2025", "text": "<ul> <li><code>feat</code>: add support for additional mime types and default file type</li> <li><code>style</code>: rename env variable <code>FILE_PLAYLIST</code> to <code>FILE_M3U</code></li> <li><code>build</code>: add new env vars to <code>Dockerfile</code><ul> <li><code>FILE_TAR</code></li> <li><code>FILE_URL</code></li> </ul> </li> <li><code>refactor</code>: m3u and epg files now stored in <code>www</code> folder</li> <li><code>fix</code>: html template links pointing to old repo</li> </ul>", "tags": ["changelog"]}, {"location": "about/changelog/#1.1.0", "title": "1.1.0 Mar 25, 2025", "text": "<ul> <li><code>feat</code>: new interface & theme for web ui<ul> <li>integrated bootstrap 4.x</li> <li>new dark theme</li> <li>all hosted files now display <code>date</code>, <code>download url</code>, <code>size</code>, and <code>description</code></li> <li>automatic viewport resizing depending on the device used</li> <li>new favicon</li> <li>localized css, js, and image support instead of relying on externally hosted resources</li> </ul> </li> <li><code>feat</code>: app now offers a compressed <code>gzip</code> for EPG guide data</li> <li><code>feat</code>: add multiple url paths to download each asset<ul> <li><code>/guide</code>, <code>/epg</code>, <code>xml</code></li> <li><code>/playlist</code>, <code>/m3u</code>, <code>/m3u8</code></li> <li><code>/gzip</code>, <code>/gz</code></li> </ul> </li> <li><code>feat</code>: add mew environment variables<ul> <li><code>LOG_LEVEL</code>: specifies what level of logs you will see in console</li> <li><code>STREAM_QUALITY</code>: specifies the quality of the stream; options: <code>hd</code> and <code>sd</code></li> <li><code>FILE_PLAYLIST</code>: filename that M3U playlist data will be stored to</li> <li><code>FILE_EPG</code>: filename that EPG / XML guide data will be stored to</li> <li><code>FILE_GZIP</code>: filename that compressed gzip guide data will be stored to</li> </ul> </li> <li><code>build</code>: app migrated from CommonJS to ES Modules</li> <li><code>build</code>: bump alpine base image from v3.20 to v3.21</li> <li><code>build</code>: migrated html template to independent file in <code>www</code> folder; utilizes <code>ejs</code> module</li> <li><code>build</code>: amd64 and arm64 docker images merged into one image with architecture support</li> <li><code>fix</code>: resolved bug where local server could not be started using nodejs; related to ip address variable</li> <li><code>build(deps)</code>: add package <code>ejs</code> 3.1.10</li> <li><code>build(deps)</code>: add package <code>chalk</code> 5.3.0</li> <li><code>build(deps)</code>: add package <code>moment</code> 2.30.1</li> <li><code>build(deps-dev)</code>: add package <code>eslint</code> 9.17.0</li> <li><code>build(deps-dev)</code>: add package <code>eslint-plugin-chai-friendly</code> 1.0.1</li> <li><code>build(deps-dev)</code>: add package <code>eslint-plugin-import</code> 2.31.0</li> <li><code>build(deps-dev)</code>: add package <code>eslint-plugin-n</code> 17.15.0</li> <li><code>build(deps-dev)</code>: add package <code>eslint-plugin-promise</code> 7.2.1</li> <li><code>build(deps-dev)</code>: add package <code>@stylistic/eslint-plugin-js</code> 3.1.0</li> <li><code>remove</code>: tvapp2.fonts.min.js</li> </ul>", "tags": ["changelog"]}, {"location": "about/changelog/#1.0.0", "title": "1.0.0 Feb 24, 2025", "text": "<ul> <li>Initial release</li> </ul>", "tags": ["changelog"]}, {"location": "about/contributing/", "title": "Contributing to TVApp2", "text": "", "tags": ["info"]}, {"location": "about/contributing/#contributing", "title": "\u267e\ufe0f Contributing \u267e\ufe0f", "text": "", "tags": ["info"]}, {"location": "about/contributing/#about", "title": "About", "text": "<p>Below are a list of ways that you can help contribute to this project, as well as policies and guides that explain how to get started.</p> <p>Please review everything on this page before you submit your contribution.</p> <p></p> <p></p> <ul> <li>About</li> <li>Issues, Bugs, Ideas</li> <li>Contributing</li> <li>Before Submitting Pull Requests</li> <li>Conventional Commit Specification<ul> <li>Types</li> <li>Example 1:</li> <li>Example 2:</li> </ul> </li> <li>Committing</li> <li>Languages<ul> <li>Python</li> <li>Indentation</li> <li>Line Length</li> <li>Blank Lines</li> <li>Imports</li> <li>Commenting</li> <li>Casing</li> <li>NodeJS</li> <li>Prettier</li> <li>ESLint<ul> <li>v9 \\& Newer (Config)</li> <li>v8 \\& Older (Config)</li> </ul> </li> <li>Packages</li> <li>Indentation</li> <li>Style</li> <li>Line Length</li> <li>Commenting</li> <li>Casing</li> </ul> </li> </ul> <p></p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#issues-bugs-ideas", "title": "Issues, Bugs, Ideas", "text": "<p>Stuff happens, and sometimes as best as we try, there may be issues within this project that we are unaware of. That is the great thing about open-source; anyone can use the program and contribute to making it better.</p> <p></p> <p>If you have found a bug, have an issue, or maybe even a cool idea; you can let us know by submitting it. However, before you submit your new issue, bug report, or feature request; head over to the Issues Section and ensure nobody else has already submitted it.</p> <p></p> <p>Once you are sure that your issue has not already being dealt with; you may submit a new issue at here. You'll be asked to specify exactly what your new submission targets, such as: - Bug report - Feature Suggestion</p> <p></p> <p>When writing a new submission; ensure you fill out any of the questions asked of you. If you do not provide enough information, we cannot help. Be as detailed as possible, and provide any logs or screenshots you may have to help us better understand what you mean. Failure to fill out the submission properly may result in it being closed without a response.</p> <p></p> <p>If you are submitting a bug report:</p> <ul> <li>Explain the issue</li> <li>Describe how you expect for a feature to work, and what you're seeing instead of what you expected.</li> <li>List possible options for a resolution or insight</li> <li>Provide screenshots, logs, or anything else that can visually help track down the issue.</li> </ul> <p></p> [![Submit Issue][btn-github-submit-img]][btn-github-submit-uri] <p></p> **[`^ back to top ^`](#about)** <p></p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#contributing_1", "title": "Contributing", "text": "<p>If you are looking to contribute to this project by actually submit your own code; please review this section completely. There is important information and policies provided below that you must follow for your pull request to get accepted.</p> <p>The source is here for everyone to collectively share and collaborate on. If you think you have a possible solution to a problem; don't be afraid to get your hands dirty.</p> <p>All contributions are made via pull requests. To create a pull request, you need a GitHub account. If you are unclear on this process, see GitHub's documentation on forking and pull requests. Pull requests should be targeted at the master branch.</p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#before-submitting-pull-requests", "title": "Before Submitting Pull Requests", "text": "<ul> <li>Follow the repository's code formatting conventions (see below);</li> <li>Include tests that prove that the change works as intended and does not add regressions;</li> <li>Document the changes in the code and/or the project's documentation;</li> <li>Your PR must pass the CI pipeline;</li> <li>When submitting your Pull Request, use one of the following branches:</li> <li>For bug fixes: <code>main</code> branch</li> <li>For features & functionality: <code>development</code> branch</li> <li>Include a proper git commit message following the Conventional Commit Specification.</li> </ul> <p>If you have completed the above tasks, the pull request is ready to be reviewed and your pull request's label will be changed to \"Ready for Review\". At this point, a human will need to step in and manually verify your submission.</p> <p>Reviewers will approve the pull request once they are satisfied with the patch it will be merged.</p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#conventional-commit-specification", "title": "Conventional Commit Specification", "text": "<p>When committing your changes, we require you to follow the Conventional Commit Specification. The Conventional Commits is a specification for the format and content of a commit message. The concept behind Conventional Commits is to provide a rich commit history that can be read and understood by both humans and automated tools. Conventional Commits have the following format:</p> <p></p> <pre><code><type>[(optional <scope>)]: <description>\n\n[optional <body>]\n\n[optional <footer(s)>]\n</code></pre> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#types", "title": "Types", "text": "<p>Our repositories make use of the following commit tags:</p> <p></p> Type Description <code>feat</code> <sup><sub>Introduce new feature</sub></sup> <code>fix</code> <sup><sub>Bug fix</sub></sup> <code>chore</code> <sup><sub>Includes technical or preventative maintenance task that is necessary for managing the app or repo, such as updating grunt tasks, but is not tied to any specific feature. Usually done for maintenance purposes.E.g: Edit .gitignore, .prettierrc, .prettierignore, .gitignore, eslint.config.js file</sub></sup> <code>revert</code> <sup><sub>Revert a previous commit</sub></sup> <code>style</code> <sup><sub>Update / reformat style of source code. Does not change the way app is implemented. Changes that do not affect the meaning of the codeE.g: white-space, formatting, missing semi-colons, change tabs to spaces, etc)</sub></sup> <code>docs</code> <sup><sub>Change website or markdown documents. Does not mean changes to the documentation generator script itself, only the documents created from the generator. E.g: documentation, readme.md or markdown <code>build</code> <sup><sub>Changes to the build / compilation / packaging process or auxiliary tools such as doc generationE.g: create new build tasks, update release script, etc.</sub></sup> <code>refactor</code> <sup><sub>Change to production code that leads to no behavior difference,E.g: split files, rename variables, rename package, improve code style, etc.</sub></sup> <code>test</code> <sup><sub>Add or refactor tests, no production code change. Changes the suite of automated tests for the app.</sub></sup> <code>ci</code> <sup><sub>Changes related to Continuous Integration (usually <code>yml</code> and other configuration files).</sub></sup> <code>perf</code> <sup><sub>Performance improvement of algorithms or execution time of the app. Does not change an existing feature.</sub></sup> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#example-1", "title": "Example 1:", "text": "<pre><code>feat(core): bug affecting menu [#22]\n^\u2500\u2500\u2500^\u2500\u2500\u2500\u2500^ ^\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500^ ^\u2500\u2500\u2500^\n| | | |\n| | | \u2514\u2500\u2500\u2500\u2af8 (ISSUE): Reference issue ID\n\u2502 \u2502 \u2502\n\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2af8 (DESC): Summary in present tense. Use lower case not title case!\n\u2502 \u2502\n\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2af8 (SCOPE): The package(s) that this change affects\n\u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2af8 (TYPE): See list above\n</code></pre>", "tags": ["info"]}, {"location": "about/contributing/#example-2", "title": "Example 2:", "text": "<pre><code><type>(<scope>): <short summary> [issue]\n | | | |\n | | | \u2514\u2500\u2af8 Reference issue id (optional)\n \u2502 \u2502 \u2502\n \u2502 \u2502 \u2514\u2500\u2af8 Summary in present tense. Not capitalized. No period at the end.\n \u2502 \u2502\n \u2502 \u2514\u2500\u2af8 Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|\n \u2502 elements|forms|http|language-service|localize|platform-browser|\n \u2502 platform-browser-dynamic|platform-server|router|service-worker|\n \u2502 upgrade|zone.js|packaging|changelog|docs-infra|migrations|ngcc|ve|\n \u2502 devtools....\n \u2502\n \u2514\u2500\u2af8 Commit Type: build|ci|doc|docs|feat|fix|perf|refactor|test\n website|chore|style|type|revert|deprecate\n</code></pre>", "tags": ["info"]}, {"location": "about/contributing/#committing", "title": "Committing", "text": "<p>If you are pushing a commit which addresses a submitted issue, reference your issue at the end of the commit message. You may also optionally add the major issue to the end of your commit body.</p> <p>References should be on their own line, following the word <code>Ref</code> or <code>Refs</code></p> <pre><code>Title: fix(core): fix error message displayed to users. [#22]\nDescription: The description of your commit\n\n Ref: #22, #34, #37\n</code></pre> <p> </p>", "tags": ["info"]}, {"location": "about/contributing/#languages", "title": "Languages", "text": "<p>The formatting of code greatly depends on the language being used for this repository. We provide various different languages below as this guide is utilized across multiple repositories.</p> <ul> <li>Python</li> <li>Javascript / Typescript / NodeJS</li> </ul> <p> </p>", "tags": ["info"]}, {"location": "about/contributing/#python", "title": "Python", "text": "<p>The following guidelines apply to any projects written with Python:</p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#indentation", "title": "Indentation", "text": "<p>Use <code>4 spaces</code> per indentation level.</p> <p></p> <p>[!TIP] \u2705 Correct <pre><code>def Encrypt( key : int, bytestr : bytes ):\n res = b''\n i_blk, left_bytes = divmod( len(bytestr), 3 )\n</code></pre></p> <p></p> <p>[!CAUTION] \u274c Wrong <pre><code>def encrypt( key : int, byteStr : bytes ):\n Res = b''\n iBlk, leftBytes = divmod( len(byteStr), 3 )\n</code></pre></p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#line-length", "title": "Line Length", "text": "<p>Keep the maximum character count to <code>100 characters per line</code>. If you are revising old code which doesn't follow this guideline; please rewrite it to conform.</p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#blank-lines", "title": "Blank Lines", "text": "<p>Surround top-level functions and class definitions with a blank in-between.</p> <p>Method definitions inside a class are surrounded by a single blank line.</p> <p>Extra blank lines may be used (sparingly) to separate groups of functions related to one another. Blank lines may be omitted between a bunch of related one-liners (e.g: set of dummy implementations).</p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#imports", "title": "Imports", "text": "<p>Imports should usually be on separate lines:</p> <p></p> <p>[!TIP] \u2705 Correct <pre><code>import os\nimport sys\n</code></pre></p> <p></p> <p>[!CAUTION] \u274c Wrong <pre><code>import sys, os\n</code></pre></p> <p></p> <p>The following is acceptable:</p> <p></p> <p>[!TIP] \u2705 Correct <pre><code>from mypkg import siblingA, siblingB, siblingC\n</code></pre></p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#commenting", "title": "Commenting", "text": "<p>Comment your code. It helps novice readers to better understand the process. It doesn't have to be painfully obvious explanations, but it helps to give an idea of what something does.</p> <p>Please append <code>#</code> to the beginning of each line.</p> <pre><code># #\n# byteString : b'1#Aetherx|232#1#233262#0#0#0#'\n# #\n\ndef Encrypt( key : int, byteString : bytes ):\n res = bytearray( )\n</code></pre> <p></p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#casing", "title": "Casing", "text": "<ul> <li>Stick to <code>camelCase</code>; unless:</li> <li>naming functions, capitalize the first letter</li> <li>Capitalize enums</li> <li>If you see code not conforming with this, please revise it in your pull request.</li> </ul> <p>[!TIP] \u2705 Correct <pre><code>def Encrypt( key : int, byteStr : bytes ):\n res = b''\n iBlock, leftBytes = divmod( len(byteStr), 3 )\n</code></pre></p> <p></p> <p>[!CAUTION] \u274c Wrong <pre><code>def encrypt( key : int, bytestr : bytes ):\n res = b''\n i_blk, left_bytes = divmod( len(bytestr), 3 )\n</code></pre></p> <p></p> <p></p> **[`^ back to top ^`](#about)** <p></p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#nodejs", "title": "NodeJS", "text": "<p>The following allows you to configure ESLint and Prettier.</p> <p> </p>", "tags": ["info"]}, {"location": "about/contributing/#prettier", "title": "Prettier", "text": "<p>We have opted to make use of ESLint over Prettier. We provide a detailed ESLint flag config file with very specific linting rules. Please review that section for more information.</p> <p> </p>", "tags": ["info"]}, {"location": "about/contributing/#eslint", "title": "ESLint", "text": "<p>Within the root folder of the repo, there are several configuration files which you should be using within the project. These files dictate how prettier and eslint will behave and what is acceptable / not acceptable.</p> <p></p> <p>Pick the config file below depending on which version of ESLint you are using. The v8 and older <code>.eslint</code> may not be there if we have migrated over to an Eslint v9 flat config file:</p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#v9-newer-config", "title": "v9 & Newer (Config)", "text": "<p>Our NodeJS applications require that you utilize ESLint v9 or newer which makes use of a flat config structure. You may find a copy of our flat config at the link below:</p> <ul> <li>\ud83d\udcc4 eslint.config.mjs</li> </ul> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#v8-older-config", "title": "v8 & Older (Config)", "text": "<ul> <li>We no longer utilize any version of ESLint older than version 9.</li> </ul> <p>[!NOTE] When submitting your pull request, these linting and style rules will be verified with all of your files. If you did not follow these rules; the linter tests on your pull request will fail; and you'll be expected to correct these issues before your submission will be transferred over for human review.</p> <p> </p>", "tags": ["info"]}, {"location": "about/contributing/#packages", "title": "Packages", "text": "<p>We use the following packages for linting and prettier.</p> <p></p> Package Repo File Description @stylistic/eslint-plugin-js package.json JavaScript stylistic rules for ESLint, migrated from eslint core. @stylistic/eslint-plugin-ts package.json TypeScript stylistic rules for ESLint, migrated from typescript-eslint. @stylistic/eslint-plugin-plus package.json Supplementary rules introduced by ESLint Stylistic. eslint-plugin-prettier package.json Runs Prettier as an ESLint rule and reports differences as individual ESLint issues. <p></p> <p>You can add the following to your <code>package.json</code> file:</p> <p>https://github.com/TheBinaryNinja/tvapp2/blob/1c75f11e9f0506ad3dd05133fdafc3aeb87686ca/tvapp2/package.json#L81-L92</p> <p> </p>", "tags": ["info"]}, {"location": "about/contributing/#indentation_1", "title": "Indentation", "text": "<p>Use <code>4 spaces</code> per indentation level.</p> <p> </p>", "tags": ["info"]}, {"location": "about/contributing/#style", "title": "Style", "text": "<p>For files that are not controlled by Prettier or ESLint; use <code>Allman Style</code>. Braces should be on their own lines, and any code inside the braces should be indented 4 spaces.</p> <p></p> <pre><code>return {\n status: \"failure\",\n user:\n {\n id: \"1aaa35aa-fb3a-62ae-ffec-a14g7fc401ac\",\n label: \"Test String\",\n }\n};\n\nwhile (x == y)\n{\n foo();\n bar();\n}\n</code></pre> <p> </p>", "tags": ["info"]}, {"location": "about/contributing/#line-length_1", "title": "Line Length", "text": "<p>Keep the maximum character count to <code>100 characters per line</code>. The configs on this page have prettier automatically set up to detect more than 100 characters per line.</p> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#commenting_1", "title": "Commenting", "text": "<p>Comment your code. It helps novice readers to better understand the process. You may use block style commenting, or single lines:</p> <pre><code>/*\n tests to decide if the end-user is running on Darwin or another platform.\n*/\n\ntest(`Return true if platform is Darwin`, () => {\n process.platform = 'darwin';\n expect(bIsDarwin()).toBe(true);\n});\n\ntest(`Return false if platform is not Darwin`, () => {\n process.platform = 'linux';\n expect(bIsDarwin()).toBe(false);\n});\n</code></pre> <p></p>", "tags": ["info"]}, {"location": "about/contributing/#casing_1", "title": "Casing", "text": "<p>Stick to <code>camelCase</code> as much as possible. </p> <pre><code>let myVar = 'one';\nlet secondVar = 'two';\n</code></pre> <p></p> <p>If you are defining a new environment variable; it must be in ALL CAPS in the <code>Dockerfile</code>:</p> <pre><code>ENV DIR_BUILD=/usr/src/app\nENV DIR_RUN=/usr/bin/app\nENV URL_REPO=\"https://git.binaryninja.net/binaryninja/\"\nENV WEB_IP=\"0.0.0.0\"\nENV WEB_PORT=4124\nENV STREAM_QUALITY=\"hd\"\nENV FILE_PLAYLIST=\"playlist.m3u8\"\nENV FILE_EPG=\"xmltv.xml\"\nENV LOG_LEVEL=4\nENV TZ=\"Etc/UTC\"\n</code></pre> <p></p> <p>Then you may call your new environment variable within the Javascript code; and ensure you define a default value to correct any user misconfigurations:</p> <pre><code>const envUrlRepo = process.env.URL_REPO || 'https://git.binaryninja.net/binaryninja';\nconst envStreamQuality = process.env.STREAM_QUALITY || 'hd';\nconst envFileM3U = process.env.FILE_PLAYLIST || 'playlist.m3u8';\nconst envFileXML = process.env.FILE_EPG || 'xmltv.xml';\nconst envFileTAR = process.env.FILE_TAR || 'xmltv.xml.gz';\n</code></pre> <p> </p> **[`^ back to top ^`](#about)** <p> </p> <p> </p>", "tags": ["info"]}, {"location": "about/conventions/", "title": "Conventions", "text": "<p>This documentation use some symbols for illustration purposes. Before you read on, please make sure you've made yourself familiar with the following list of conventions:</p> <p></p>"}, {"location": "about/conventions/#release-type", "title": "Release Type", "text": "The tag symbol in conjunction with a version number denotes when a specific feature or behavior was added. Make sure you're at least on this version if you want to use it. <p> default</p> <p> stable</p> <p> development</p> <p></p>"}, {"location": "about/conventions/#default", "title": "Controls", "text": "These icons define what type of control a specified setting uses. <p> toggle</p> <p> toggle on</p> <p> toggle off</p> <p> textbox</p> <p> dropdown</p> <p> button</p> <p> slider</p> <p> color wheel</p> <p></p>"}, {"location": "about/conventions/#default", "title": "\u2013 Default Value", "text": "This defines what the default value for a setting is. <p> Specified setting has a default value</p> <p> Specified setting has no default value and is empty</p> <p> Specified setting is automatically computed by the app</p> <p></p>"}, {"location": "about/conventions/#command", "title": "\u2013 Command", "text": "This defines a command <p> Specified setting has a default value</p> <p></p>"}, {"location": "about/conventions/#flags", "title": "\u2013 Flags", "text": "Default Experimental Required Customization Metadata Dangerous Multiple Setting <p>Anything listed with this icon are features or functionality that are still in development and may change in future versions.</p> <p></p>"}, {"location": "about/conventions/#3rd-party", "title": "\u2013 3<sup>rd</sup> Party", "text": "<p>This symbol denotes that the item described is classified as something that changes the overall functionality of the plugin.</p> <p></p>"}, {"location": "about/conventions/#setting", "title": "\u2013 Configurable Settings", "text": "<p>The following denotes a configurable setting. These can also be broken up into individual settings as shown below:</p>"}, {"location": "about/conventions/#example.setting.enabled", "title": "<code>enabled</code>", "text": "<p>1.0.0 <code>true</code></p> <p>This is an example setting</p>"}, {"location": "about/conventions/#example.setting.other", "title": "<code>other</code>", "text": "<p>1.0.0 <code>true</code></p> <p>This is another example setting</p> <p></p>"}, {"location": "about/conventions/#multiple-instances", "title": "\u2013 Multiple instances", "text": "<p>This symbol denotes that the plugin supports multiple instances, i.e, that it can be used multiple times in the <code>plugins</code> setting in <code>mkdocs.yml</code>.</p> <p></p>"}, {"location": "about/conventions/#feature", "title": "\u2013 Optional feature", "text": "<p>Some features may be hidden behind feature flags, which means they must be explicitly enabled first before they can be configured. This allows for the existence of potentially orthogonal features.</p> <p></p>"}, {"location": "about/conventions/#extension", "title": "\u2013 Markdown extension", "text": "<p>This symbol denotes that the thing described is a Markdown element.</p> <p></p>"}, {"location": "about/conventions/#danger", "title": "\u2013 Dangerous", "text": "<p>This symbol denotes that the item described is a metadata property, which can be used in Markdown documents as part of the front matter definition.</p> <p></p>"}, {"location": "about/conventions/#backers-only", "title": "\u2013 Backers only", "text": "<p>The pumping heart symbol denotes that a specific feature or behavior is only available to backers. Normal users will not have access to this particular item.</p> <p></p> <p></p>"}, {"location": "about/conventions/#other-tags", "title": "Other Tags", "text": ""}, {"location": "about/conventions/#example", "title": "Example Download", "text": "<p><code>.zip</code> </p> <p>The following denotes a downloadable file.</p> <p></p>"}, {"location": "about/conventions/#commands", "title": "Commands", "text": "<p><code>-s, --start</code></p> <p>The above denotes a command which can be executed in a terminal / command prompt.</p> <p></p>"}, {"location": "about/conventions/#options", "title": "Options", "text": "<p>Options are another form of setting which lists what the option does, and then examples of how it works.</p> <code>enabled</code> <p><code>true</code> This option specifies whether the plugin is enabled when building your project. If you want to speed up local builds, you can use an environment variable:</p> <pre><code>plugins:\n - rss:\n enabled: !ENV [CI, false]\n</code></pre> <code>match_path</code> <p><code>.*</code> This option specifies which pages should be included in the feed. For example, to only include blog posts in the feed, use the following regular expression:</p> <pre><code>plugins:\n - rss:\n match_path: blog/posts/.*\n</code></pre> <p></p> <p></p> <p> </p>"}, {"location": "about/license/", "title": "License", "text": "<p>MIT License</p> <p>Copyright \u00a9 2025 Aetherinox</p> <p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p> <p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p> <p>THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p> <p></p> <p></p>"}, {"location": "about/tags/", "title": "Tags", "text": "<p>Following is a list of relevant tags:</p> <p></p> <p></p>"}, {"location": "about/what_is_tvapp/", "title": "AboutTVApp2: M3U Playlist & Data Guides", "text": "TVApp2 Main Interface", "tags": ["info"]}, {"location": "about/what_is_tvapp/#what-is-tvapp2", "title": "What is TVApp2?", "text": "<p>TVApp2 is a docker image which allows you to download M3U playlists and EPG guide data from various online IPTV services such as TheTVApp, TVPass, and MoveOnJoy. The playlist and guide data files can be imported into your favorite IPTV applications such as Jellyfin, Plex, and Emby.</p> <p>Once the docker container is started; a fresh copy of the channel list and TV guide data will be downloaded and generated within your docker container. You can then visit the website URL associated with your docker container; which will give you direct links to the files that you can utilize with the above listed IPTV apps.</p> <p>All channels contain multiple sources so that you have a reliable streaming experience, and helps you combat moments when one channel source goes offline.</p> <p></p> <p></p>", "tags": ["info"]}, {"location": "about/what_is_tvapp/#image-sources", "title": "Image Sources", "text": "<p>This project contains several repositories which all share the same code; use them as backups:</p> <ul> <li>\ud83d\udd00 dockerhub:thebinaryninja/tvapp2</li> <li>\ud83d\udd00 github:thebinaryninja/tvapp2</li> <li>\ud83d\udd00 gitea:git.binaryninja.net/binaryninja/tvapp2</li> </ul> <p></p> Pull URL Registry Arch Version <code>ghcr.io/thebinaryninja/tvapp2:latest</code><code>ghcr.io/thebinaryninja/tvapp2:development</code> Github amd64arm64 <code>thebinaryninja/tvapp2:latest</code><code>thebinaryninja/tvapp2:development</code> Dockerhub amd64arm64 <code>git.binaryninja.net/binaryninja/tvapp2:latest</code><code>git.binaryninja.net/binaryninja/tvapp2:development</code> Gitea amd64arm64 <p></p> <p></p>", "tags": ["info"]}, {"location": "about/what_is_tvapp/#features", "title": "Features", "text": "<p>The following is a small list of the features available with the TVApp2 container:</p> <ul> <li>Multiple IPTV service sources:<ul> <li>TheTVApp</li> <li>TVPass</li> <li>MoveOnJoy</li> </ul> </li> <li>Channel playlists can be downloaded as a <code>.m38u</code> or a compressed <code>.gzip</code> archive.<ul> <li>Compressed gzip compatible with 3<sup>rd</sup> party apps like Cabernet and Jellyfin.</li> </ul> </li> <li>Tracking statistics which show the last update time, size, and a description for each file's purpose.</li> <li>API endpoints:<ul> <li>Resync All Files<ul> <li>http://127.0.0.1:4124/api/resync</li> <li>http://127.0.0.1:4124/api/restart</li> </ul> </li> <li>Health check<ul> <li>http://127.0.0.1:4124/api/health</li> <li>http://127.0.0.1:4124/api/status</li> </ul> </li> </ul> </li> <li>Direct access to download each of the generated files, including multiple easy-to-remember URLs for each file type.<ul> <li>M3U Playlist:<ul> <li>http://127.0.0.1:4124/playlist</li> <li>http://127.0.0.1:4124/m3u</li> <li>http://127.0.0.1:4124/m38u</li> </ul> </li> <li>EPG Guide Data (Uncompressed):<ul> <li>http://127.0.0.1:4124/guide</li> <li>http://127.0.0.1:4124/epg</li> <li>http://127.0.0.1:4124/xml</li> </ul> </li> <li>EPG Guide Data (Compressed):<ul> <li>http://127.0.0.1:4124/gzip</li> <li>http://127.0.0.1:4124/gz</li> </ul> </li> </ul> </li> <li>Video sources include both quality options <code>hd</code> and <code>sd</code>.</li> <li>Easily mountable docker volumes to access the generated files quickly.</li> <li>Wide variety of docker environment variables to change the binding IP, port, app root directory, quality, timezone, etc.</li> <li>Small docker image size; based on Alpine 3.x which averages <code>40MB</code>.</li> <li>Compatible with architectures <code>amd64</code> and <code>arm64/aarm64</code>.</li> <li>Example configurations for 3<sup>rd</sup> party apps such as Traefik and Authentik.</li> </ul> <p></p> <p></p>", "tags": ["info"]}, {"location": "about/what_is_tvapp/#contributors", "title": "\u2728 Contributors", "text": "<p>We are always looking for contributors. If you feel that you can provide something useful to Gistr, then we'd love to review your suggestion. Before submitting your contribution, please review the following resources:</p> <ul> <li>Pull Request Procedure</li> <li>Contributor Policy</li> </ul> <p></p> <p>Want to help but can't write code? - Review active questions by our community and answer the ones you know.</p> <p></p> <p></p> <p></p> <p>The following people have helped get this project going:</p> <p></p> <p></p> <sub>Aetherinox</sub>\ud83d\udcbb <sub>iFlip721</sub>\ud83d\udcbb <sub>Optx</sub>\ud83d\udcbb <p></p> <p></p>", "tags": ["info"]}, {"location": "blog/", "title": "Blog", "text": ""}, {"location": "config/env/", "title": "Environment Variables", "text": "<p>Environment variables allow you to modify how TVApp2 functions within a docker container. Ensure that you understand the setting you are changing before you modify these values, otherwise, TVApp2 may fail to start due to misconfigurations.</p> <p></p>", "tags": ["config"]}, {"location": "config/env/#tz", "title": "TZ", "text": "<p> 1.0.0 <code>Etc/UTC</code></p> <p>The <code>TZ</code> environment variable specifies the timezone that your docker container will utilize. This is useful for syncing your local time with console outputs such as our logging system.</p> ExampleTimezones docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - TZ=Etc/UTC # (1)\n</code></pre> <ol> <li> Changing this env variable will change the time for anything related to the TVApp2 docker container.</li> </ol> <pre><code> Etc/UTC\n Africa/Cairo\n Africa/Johannesburg\n Africa/Lagos\n America/Argentina/Buenos_Aires\n America/Bogota\n America/Caracas\n America/Chicago\n America/El_Salvador\n America/Juneau\n America/Lima\n America/Los_Angeles\n America/Mexico_City\n America/New_York\n America/Phoenix\n America/Santiago\n America/Sao_Paulo\n America/Toronto\n America/Vancouver\n Asia/Almaty\n Asia/Ashkhabad\n Asia/Bahrain\n Asia/Bangkok\n Asia/Chongqing\n Asia/Dubai\n Asia/Ho_Chi_Minh\n Asia/Hong_Kong\n Asia/Jakarta\n Asia/Jerusalem\n Asia/Kathmandu\n Asia/Kolkata\n Asia/Kuwait\n Asia/Muscat\n Asia/Qatar\n Asia/Riyadh\n Asia/Seoul\n Asia/Shanghai\n Asia/Singapore\n Asia/Taipei\n Asia/Tehran\n Asia/Tokyo\n Atlantic/Reykjavik\n Australia/ACT\n Australia/Adelaide\n Australia/Brisbane\n Australia/Sydney\n Europe/Athens\n Europe/Belgrade\n Europe/Berlin\n Europe/Copenhagen\n Europe/Helsinki\n Europe/Istanbul\n Europe/London\n Europe/Luxembourg\n Europe/Madrid\n Europe/Moscow\n Europe/Paris\n Europe/Riga\n Europe/Rome\n Europe/Stockholm\n Europe/Tallinn\n Europe/Vilnius\n Europe/Warsaw\n Europe/Zurich\n Pacific/Auckland\n Pacific/Chatham\n Pacific/Fakaofo\n Pacific/Honolulu\n Pacific/Norfolk\n US/Mountain\n</code></pre> <p></p>", "tags": ["config"]}, {"location": "config/env/#web_ip", "title": "WEB_IP", "text": "<p> 1.0.0 <code>0.0.0.0</code></p> <p>The <code>WEB_IP</code> environment variable allows you to define what IP address will be bound to the TVApp2 docker image.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - WEB_IP=0.0.0.0 # (1)\n</code></pre> <ol> <li> Specify <code>0.0.0.0</code> to bind to all local IP addresses.</li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#web_port", "title": "WEB_PORT", "text": "<p> 1.0.0 <code>4124</code></p> <p>The <code>WEB_PORT</code> environment variable allows you to define what port the TVApp2 docker container will listen to.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - WEB_IP=4124 # (1)\n</code></pre> <ol> <li> The default port is <code>4124</code></li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#web_encoding", "title": "WEB_ENCODING", "text": "<p> 1.3.0 <code>deflate, br</code></p> <p>The <code>WEB_ENCODING</code> environment variable allows you to customize the HTTP <code>Accept-Encoding</code> request and response header. This value specifies what content encoding the sender can understand when sending these requests.</p> <p>Most users will not need to modify this value unless you are running Jellyfin and receive the following error when attempting to sync EPG data between Jellyfin and the TVApp2 container:</p> <p>Jellyfin Error</p> <pre><code>[ERR] [27] Jellyfin.LiveTv.Guide.GuideManager: Error getting programs for channel \nXXXXXXXXXXXXXXX (Source 2) System.Xml.XmlException: '\u001f', hexadecimal value 0x1F, \nis an invalid character. Line 1, position 1.\n</code></pre> <p>If you receive the above error and you have already customized this environment variable to include <code>gzip</code>, you must remove it from your accepted encoders string to fix the error.</p> OldNew docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - WEB_ENCODING: 'gzip, deflate, br'\n</code></pre> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - WEB_ENCODING: 'deflate, br'\n</code></pre> <p></p>", "tags": ["config"]}, {"location": "config/env/#url_repo", "title": "URL_REPO", "text": "<p> 1.0.0 <code>https://git.binaryninja.net/binaryninja</code> </p> <p>The <code>URL_REPO</code> environment variable allows you to specify what Github repo is used to communicate with in order to fetch IPTV data. This is used as an internal environment variable by the developers and should not be changed by the end-user; otherwise you will be unable to fetch IPTV data.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - URL_REPO=https://git.binaryninja.net/binaryninja # (1)\n</code></pre> <ol> <li> It is highly recommended that you do not change this value otherwise you will not be able to download the latest M3U playlists and EPG guide data.</li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#file_url", "title": "FILE_URL", "text": "<p> 1.2.0 <code>urls.txt</code></p> <p>The <code>FILE_URL</code> environment variable allows you to specify what the name of the downloaded <code>urls.txt</code> cache file. This file is downloaded when you first spin up the TVApp2 container.</p> <p>There should be no need to utilize this environment variable unless you have a specific reason.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - FILE_URL=urls.txt # (1)\n</code></pre> <ol> <li> There is really no reason to modify this environment variable unless you have a specific purpose.</li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#file_m3u", "title": "FILE_M3U", "text": "<p> 1.1.0 <code>playlist.m3u8</code></p> <p>The <code>FILE_M3U</code> environment variable allows you to specify what the name of the downloaded <code>playlist.m3u8</code> file will be. This file is downloaded when you first spin up the TVApp2 container, and contains a list of what channels you can pick from.</p> <p>There should be no need to utilize this environment variable unless you have a specific reason.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - FILE_M3U=playlist.m3u8 # (1)\n</code></pre> <ol> <li> There is really no reason to modify this environment variable unless you have a specific purpose.</li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#file_epg", "title": "FILE_EPG", "text": "<p> 1.1.0 <code>xmltv.xml</code></p> <p>The <code>FILE_EPG</code> environment variable specifies the filename that will be utilized when your .xml EPG playlist file is generated.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - FILE_EPG=xmltv.xml # (1)\n</code></pre> <ol> <li> Changing this file only changes the filename locally; it does not affect the server-side fetching mechanism.</li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#file_gzip", "title": "FILE_GZIP", "text": "<p> 1.1.0 <code>xmltv.xml.gz</code></p> <p>The <code>FILE_GZIP</code> environment variable specifies the filename that will be utilized when a compressed <code>.gzip</code> is generated and when you download the file.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - FILE_GZIP=xmltv.xml.gz # (1)\n</code></pre> <ol> <li> Changing this file only changes the filename locally for generation and downloading. It does not affect the server-side fetching mechanism.</li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#stream_quality", "title": "STREAM_QUALITY", "text": "<p> 1.1.0 <code>hd</code></p> <p>The <code>STREAM_QUALITY</code> environment variable specifies the default stream quality that will be used when you initiate a new channel to view.</p> <p>Available Options:</p> <ul> <li><code>hd</code> High Definition</li> <li><code>sd</code> Standard Definition</li> </ul> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - STREAM_QUALITY=hd # (1)\n</code></pre> <ol> <li> This environment variable has the following options:<ul> <li>hd</li> <li>sd</li> </ul> </li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#dir_build", "title": "DIR_BUILD", "text": "<p> 1.0.0 <code>/usr/src/app</code> </p> <p>The <code>DIR_BUILD</code> environment variable specifies what local folder will be utilized by the TVApp2 docker container when the container builds the app.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - DIR_BUILD=/usr/src/app # (1)\n</code></pre> <ol> <li> You should not change this unless you are an advanced user.</li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#dir_run", "title": "DIR_RUN", "text": "<p> 1.0.0 <code>/usr/src/app</code> </p> <p>The <code>DIR_RUN</code> environment variable specifies what local folder will be utilized by the TVApp2 docker container when the container has built the app and placed it into a production folder.</p> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - DIR_RUN=/usr/bin/app # (1)\n</code></pre> <ol> <li> You should not change this unless you are an advanced user.</li> </ol> <p></p>", "tags": ["config"]}, {"location": "config/env/#log_level", "title": "LOG_LEVEL", "text": "<p> 1.1.0 <code>4</code></p> <p>The <code>LOG_LEVEL</code> environment variable allows you specify how deep logs should go when being output to your console.</p> ExampleLog Levels docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - LOG_LEVEL=4 # (1)\n</code></pre> <ol> <li> The default log level is <code>4</code> (info).</li> </ol> Log Level Name Description <code>6</code> Trace Displays all possible logs in console, along with anything below this line. <code>5</code> Debug Displays debug / developer logs, along with anything below this line. <code>4</code> Info Displays informative logs, along with anything below this line. <code>3</code> Notice Displays important notices, along with anything below this line. <code>2</code> Warn Displays warnings, along with anything below this line. <code>1</code> Error Displays only errors, none of the log levels above this line will be shown <p> </p>", "tags": ["config"]}, {"location": "config/volumes/", "title": "Mountable Volumes", "text": "<p>Mountable volumes in Docker allow you to share folders within a docker container with your host machine. This allows you to access these specific files without having to bash into the container and using the terminal to navigate around.</p> <p>The TVApp2 docker image provides a few different paths that you can mount to your host machine; as outlined below.</p> <p></p>", "tags": ["config"]}, {"location": "config/volumes/#usrbinapp", "title": "\ud83d\udcc1 /usr/bin/app", "text": "<p> 1.0.0</p> <p>The mountable volume <code>/usr/bin/app</code> is where TVApp2 files will be placed once the app has been built when your docker container spins up. The files in this folder include:</p> File Description <code>\ud83d\udcc1 node_modules</code> List of all NodeJS packages utilized by TVApp2 <code>\ud83d\udcc1 www</code> Main storage folder for TVApp2. Contains website files and M3U / EPG synced files <code>\ud83d\udcc4 package.json</code> NodeJS package file <code>\ud83d\udcc4 playlist.m3u8</code> Generated playlist containing channels <code>\ud83d\udcc4 urls.txt</code> List containing cached URLs utilized by TVApp2 <code>\ud83d\udcc4 xmltv.xml</code> EPG guide data in uncompressed XML format <code>\ud83d\udcc4 xmltv.xml.gz</code> EPG guide data in compressed GZ archive <code>\ud83d\udcc4 index.js</code> Main source code file for TVApp2 <p></p> Example docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - ./app:/usr/bin/app # (1)\n</code></pre> <ol> <li> Changing this env variable will change the time for anything related to the TVApp2 docker container.</li> </ol> <p></p> <p>This folder path can be changed by specifying a new path with the environment variable <code>DIR_RUN</code></p> Example docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - ./app:/usr/bin/app # (1) (2)\n</code></pre> <ol> <li> <p> Changing this env variable will change the folder within the docker container which stores the fully built TVApp2 files.</p> </li> <li> <p>This should not be used unless you know what you're doing</p> </li> </ol> <p></p> <p></p>", "tags": ["config"]}, {"location": "config/volumes/#config", "title": "\ud83d\udcc1 /config", "text": "<p> 1.0.0</p> <p>The mountable volume <code>/config</code> defines where the TVApp2 application will store SSL certificates related to the TVApp2 web interface being ran using https instead of http. The files in this folder include:</p> File Description <code>\ud83d\udcc1 keys</code> Folder which stores the SSL cert and keys <code>\ud83d\udcc4 keys/cert.crt</code> SSL public certificate <code>\ud83d\udcc4 keys/key.crt</code> SSL private key <p></p> Example docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - ./config:/config # (1) (2)\n</code></pre> <ol> <li> <p> Changing this env variable will change the folder within the docker container which stores the fully built TVApp2 files.</p> </li> <li> <p>This should not be used unless you know what you're doing</p> </li> </ol> <p> </p>", "tags": ["config"]}, {"location": "install/", "title": "Installing TVApp2", "text": "<p>To install TVApp2 using docker; you will need to use either the <code>\ud83d\uddd4 docker run</code> command, or create a <code>\ud83d\udcc4 docker-compose.yml</code> file which contains information about how to pull the latest image and spin the container up. We have provided instructions for both.</p> <p></p> <p>Select your desired option to bring up the TVApp2 container with:</p> <ul> <li> <p> docker run</p> <p>Spin up the TVApp2 container using the <code>docker run</code> command. This is useful for quick launches, but is not time efficient if you plan to use this container long-term.</p> <p>This requires a longer command that must be used each time you wish to bring the container up.</p> </li> <li> <p> docker compose</p> <p>Spin up the TVApp2 container by creating a <code>\ud83d\udcc4 docker-compose.yml</code> file which will store all of your options such as env variables, mounted volumes, and labels.</p> <p>To bring the container up, <code>cd</code> into the folder with the <code>\ud83d\udcc4 docker-compose.yml</code> file, and run the command <code>docker compose up -d</code>.</p> </li> </ul> <p> </p>", "tags": ["install"]}, {"location": "install/docker-run/", "title": "docker run", "text": "<p>Our documentation provides two ways that you may start up a TVApp2 docker container:</p> <ul> <li> <p> docker run</p> <p>Spin up the TVApp2 container using the <code>docker run</code> command. This is useful for quick launches, but is not time efficient if you plan to use this container long-term.</p> <p>This requires a longer command that must be used each time you wish to bring the container up.</p> </li> <li> <p> docker compose</p> <p>Spin up the TVApp2 container by creating a <code>\ud83d\udcc4 docker-compose.yml</code> file which will store all of your options such as env variables, mounted volumes, and labels.</p> <p>To bring the container up, <code>cd</code> into the folder with the <code>\ud83d\udcc4 docker-compose.yml</code> file, and run the command <code>docker compose up -d</code>.</p> </li> </ul> <p></p> <p>The <code>\ud83d\uddd4 docker run</code> command allows you to start up a docker container by providing a set of options which define how the container should operate, including the environment variables, mounted volumes, assigned IP address, etc.</p> <p></p> <p></p>", "tags": ["install"]}, {"location": "install/docker-run/#start-tvapp2", "title": "Start TVApp2", "text": "<p>Pulling the image if needed and starting the container. To spin up a TVApp2 container using this method; run a command similar to the below example. See the section Options below for a list of what you can specify.</p> Terminal <pre><code>docker run -d \\\n--restart=unless-stopped \\ # (1)!\n--name tvapp2 \\ # (2)!\n-p 4124:4124 \\ # (3)!\n-e \"TZ=Etc/UTC\" \\ # (4)!\n-v ${PWD}/app:/usr/bin/app \\ # (5)!\nghcr.io/thebinaryninja/tvapp2:latest # (6)!\n</code></pre> <ol> <li>Specifies what happens if the container becomes unresponsive or goes down.</li> <li>Name to assign the container; otherwise, a random id will be given.</li> <li>Port that will be used for the container</li> <li>Environment variable which specifies the timezone to use for the container.</li> <li>Mount the container volume <code>/usr/bin/app</code> to your host machine in the subfolder <code>./app</code></li> <li>Specifies what docker image to spin up.</li> </ol> <p></p> <p>To confirm that the container has been brought up, run the command <code>docker ps | grep tvapp2</code>. If you have the app Portainer, you can sign into your admin interface and view your TVApp2 container details, instead of using a command-line.</p> <pre><code>e95236c42b43 binaryninja/tvapp2:1.4.0 \"/init\" 3 seconds ago Up 3 seconds 4124/tcp tvapp2\n</code></pre> <p></p> <p></p>", "tags": ["install"]}, {"location": "install/docker-run/#options", "title": "Options", "text": "<p>Review the list of docker run options below. These allow you to define how a docker container will start up.</p> Official Docker Documentation <p>To view a full list of the available docker parameters, view the official docker documentation at:</p> <ul> <li>https://docs.docker.com/reference/cli/docker/container/run/</li> </ul> Parameter / Flag Description <code>-d, --detach</code> Run container in background and print container ID <code>-e, --env</code> Set environment variable <code>--env-file</code> Read in a file of environment variables <code>--expose</code> Expose a port or a range of ports <code>--health-cmd</code> Command to run to check health <code>--health-interval</code> Time between running the check<code>ms|s|m|h</code> (default 0s) <code>--health-retries</code> Consecutive failures needed to report unhealthy <code>--health-start-interval</code> Time between running the check during the start period<code>ms|s|m|h</code> (default 0s) <code>--health-start-period</code> Start period for the container to initialize before starting health-retries countdown<code>ms|s|m|h</code> (default 0s) <code>--health-timeout</code> Maximum time to allow one check to run<code>ms|s|m|h</code> (default 0s) <code>-h, --hostname</code> Container host name <code>--ip</code> IPv4 address (e.g., 172.30.100.104) <code>--ip6</code> IPv6 address (e.g., 2001:db8::33) <code>-l, --label</code> Set meta data on a container <code>--mount</code> Attach a filesystem mount to the container <code>--name</code> Assign a name to the container <code>--network</code> Connect a container to a network <code>--privileged</code> Give extended privileges to this container <code>-p, --publish</code> Publish a container's port(s) to the host <code>--pull</code> Pull image before running<code>always</code>, <code>missing</code>, <code>never</code> <code>--restart</code> Restart policy to apply when a container exits <code>on-failure[:max-retries]</code>, <code>always</code>, <code>unless-stopped</code> <code>-u, --user</code> Username or UID <code><name|uid>[:<group|gid>]</code> <code>-v, --volume</code> Bind mount a volume <code>-w, --workdir</code> Working directory inside the container <p></p> <p> </p>", "tags": ["install"]}, {"location": "usage/healthcheck/", "title": "Healthcheck", "text": "<p>This docker container includes the ability to run health checks between the container api and outside services such as Portainer, or any other app that has the ability to query the endpoint <code>api/health</code>.</p> <p></p> <p></p>", "tags": ["usage"]}, {"location": "usage/healthcheck/#api", "title": "API", "text": "<p>1.4.0</p> <p>This container includes the ability to run health checks utilizing the built-in API. You can directly access the health check and view a json formatted result with the url <code>https://tvapp2.domain.lan/api/health</code></p> Example /api/health<pre><code>{\n \"ip\": \"172.18.2.1\",\n \"gateway\": \"172.18.0.1\",\n \"uptime\": 5903.549082501,\n \"message\": \"healthy\",\n \"status\": \"healthy\",\n \"ref\": \"/api/health\",\n \"method\": \"GET\",\n \"code\": 200,\n \"timestamp\": 1744386346242\n}\n</code></pre> <p></p> <p>Numerous aliases have been added; you can use any of the following URLs to access the same health check results as they go to the same endpoint:</p> <ul> <li>https://tvapp2.domain.lan/api/health</li> <li>https://tvapp2.domain.lan/api/status</li> </ul> <p></p> <p></p>", "tags": ["usage"]}, {"location": "usage/healthcheck/#portainer", "title": "Portainer", "text": "<p>1.3.0</p> <p>To run a health check between TVApp2 and Portainer, apply the following lines of code to your TVApp2 <code>docker-compose.yml</code>. Two examples have been provided, you can use either one; <code>wget</code> or <code>curl</code>:</p> Using CURLUsing WGET docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - TZ=Etc/UTC\n health check:\n test: \"curl --fail --silent http://127.0.0.1:4124/api/health | grep -i healthy || exit 1\"\n interval: 15s\n timeout: 10s\n retries: 3\n</code></pre> docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - TZ=Etc/UTC\n health check:\n test: \"wget -qO- http://127.0.0.1:4124/api/health | grep -i healthy || exit 1\"\n interval: 15s\n timeout: 10s\n retries: 3\n</code></pre> <p></p> <p></p>", "tags": ["usage"]}, {"location": "usage/healthcheck/#web-interface", "title": "Web Interface", "text": "<p>1.4.0</p> <p>The TVApp2 web interface is equip with its own health check which is ran every <code>10 minutes</code> by default. Users will notice a health indicator in the top right of the header navigation bar which is represented by the icon.</p> <p>When the health check is ran every 10 minutes; a toast notification will appear in the lower-right side of the page:</p> Health check toast notification <p></p>", "tags": ["usage"]}, {"location": "usage/healthcheck/#health-check-duration", "title": "Health Check Duration", "text": "<p> 1.4.0 <code>600000</code></p> <p>By default, a health check between the TVApp2 container and the web interface is done every <code>10 minutes</code>, but you can change this duration to something less or more. Be aware that if you set the time too low, you will constantly be spammed with toast notifications. </p> <p>To change the health check delay, add the environment variable <code>HEALTH_TIMER</code> to your TVApp2 <code>docker-compose.yml</code>. Duration is in milliseconds.</p> <p></p> ExampleTime Chart docker-compose.yml<pre><code>services:\n tvapp2:\n container_name: tvapp2\n image: ghcr.io/thebinaryninja/tvapp2:latest\n restart: unless-stopped\n volumes:\n - /etc/timezone:/etc/timezone:ro\n - /etc/localtime:/etc/localtime:ro\n - /var/run/docker.sock:/var/run/docker.sock\n - ./config:/config\n - ./app:/usr/bin/app\n environment:\n - HEALTH_TIMER=600000 # (1)\n</code></pre> <ol> <li> Defines how often to perform health checks between the container and the web interface. Time is in milliseconds. Default value is <code>600000</code> (10 minutes)</li> </ol> HEALTH_TIMER Value Delay Between Checks <code>HEALTH_TIMER=300000</code> 5 minutes <code>HEALTH_TIMER=600000</code> 10 minutes <code>HEALTH_TIMER=1200000</code> 20 minutes <code>HEALTH_TIMER=1800000</code> 30 minutes <code>HEALTH_TIMER=3600000</code> 1 hour <p> </p>", "tags": ["usage"]}]} |