Building PEK TV
Build the C++ backend and the Android app, environment variables, signing and CI.
PEK TV lives on one branch, main. The same checkout builds every part, so there is nothing to switch or keep in step. Pick the part you need.
| Part | Folder | How | Output |
|---|---|---|---|
| Backend (C++) | backend/ |
backend/dev.sh on Termux, Linux or MSYS2 / WSL |
bin/pek, the API on http://localhost:8080 |
| Android app (APK) | android/ + flutter_ui/ |
GitHub Actions, .github/workflows/build_android.yml |
PEK-TV-<version>-<type>.apk |
Android is the only app build today. The Flutter screens in flutter_ui/ and the backend in backend/ are shared, so another platform is added to this same branch as its own folder and workflow file next to android/ and build_android.yml.
The backend #
There is no web page to build any more: the screens are the Flutter app in flutter_ui/ (see FLUTTER.md), and the server only answers API requests. Only the C++ backend in backend/ is compiled.
You need #
- A C++17 compiler (
g++orclang), Python 3 with its development files (python3-config), and OpenSSL headers. The search-site fetcher needs HTTPS, so OpenSSL is required. httplib.hinbackend/(already in the repo).- Termux:
pkg install clang python openssl
Build and run #
cd backend
bash dev.sh # build to bin/pek, then run it
./dev.sh --run # skip the build, run the last binaryUse bash dev.sh on Android shared storage, where files cannot be made executable. The script runs the binary from a copy in your home folder because Android blocks executing files on shared storage. bin/ is created in the nearest parent folder that already has one, otherwise next to the script.
The server then listens on http://localhost:8080 for the app. Edits to a plugin only need a restart; rebuild only when a .cpp file changes.
Optional libraries (auto-detected) #
Discovery, FTP, WebDAV and DLNA / UPnP always work. SMB, NFS and torrents are built in only when their headers are found, so the same script behaves the same on Termux, Linux and Windows.
| Feature | Library | Switch |
|---|---|---|
| SMB | libsmb2 | PEK_SMB=0 or 1 |
| NFS | libnfs | PEK_NFS=0 or 1 |
| Torrent playback | libtorrent-rasterbar | PEK_TORRENT=0 or 1 |
1 means required (the build fails if it is missing) and 0 means skip. The old HESPER_* names still work. Without libtorrent, searching still works and playing a torrent reports that it is not built in.
Environment variables #
| Variable | What it does |
|---|---|
TMDB_API_KEY |
Your own TMDb key, if you do not use PEK's built-in access |
TMDB_PROXY_URL |
Use a different TMDb proxy address |
PEK_BIND / PEK_TOKEN |
Open PEK TV to other devices, for example PEK_BIND=0.0.0.0 PEK_TOKEN=choose-a-secret, then other devices can reach the server's API on http://<device-ip>:8080 by sending that token (there is no web page to open). By default it only answers the device it runs on |
PEK_TRUSTED_PLUGINS |
Comma-separated plugin ids you wrote yourself and want to run unguarded while developing |
PEK_ALLOW_PLUGIN_BACKEND=0 |
Refuse plugin .py files (for a store build) |
PEK_ALLOW_GITHUB=0 |
Disable install-from-GitHub |
PEK_SUBS_URL |
Address of the subtitle worker, if it is not on the sync address |
The Android app #
The Android app is a Kotlin host around the same backend. It starts the C++ server through JNI, shows the Flutter UI from flutter_ui/, uses libmpv as its only video player and Chaquopy to run the plugin Python backends. Targets: minSdk 26, compileSdk and targetSdk 36, ABIs armeabi-v7a and arm64-v8a, application id com.pektv.app.
It is built by GitHub Actions, so you do not need Android Studio. The repository has no Gradle wrapper; the workflow installs Gradle 8.14.3 and JDK 17, and the exact NDK named by ndkVersion in android/app/build.gradle (it reads that file, so the two cannot drift apart).
What the workflow does #
- Works out the version name: the tag without its
v, or theversionNameinandroid/app/build.gradleplus-dev.<run number>. - Runs
flutter pub getinflutter_ui/, which generates the Flutter module the Gradle build includes, then copiespluginsandskinsinto the app's assets (without caches or plugindata/folders). - Builds OpenSSL and SQLite (both cached), clones libsmb2 for SMB and libnfs for NFS, and optionally libtorrent and Boost headers.
- Builds the APK. If the full build fails it retries without the optional native libraries (SMB, NFS, torrent).
- Verifies the signature, uploads the APK as an artifact (kept 30 days), and can publish a GitHub pre-release.
Run a build #
Manual: repository Actions tab, Build PEK TV (Android), Run workflow. Choose
debug(fast, installs next to your release because its id ends in.debug) orrelease(signed). Tick torrent to build libtorrent in (slower, experimental) and publish to also make a pre-release (release builds only).Release: push a tag that starts with
v. That builds a signed release APK and a GitHub pre-release.git tag v0.1.4-beta.1 git push origin v0.1.4-beta.1
Signing secrets (release builds) #
Create a keystore once and keep it safe. If you lose it you cannot update installed copies.
keytool -genkeypair -v -keystore pek-release.jks -alias pek \
-keyalg RSA -keysize 2048 -validity 10000
base64 -w0 pek-release.jks # paste the output into PEK_KEYSTORE_BASE64In the repository go to Settings → Secrets and variables → Actions and add:
| Secret | Value |
|---|---|
PEK_KEYSTORE_BASE64 |
the base64 text of the keystore |
PEK_KEYSTORE_PASSWORD |
the keystore password |
PEK_KEY_ALIAS |
the alias (pek above) |
PEK_KEY_PASSWORD |
the key password |
Never commit the keystore. The repository's .gitignore already excludes *.jks, *.keystore and keystore.b64.
When you add or edit a streaming service, change tools/providers.json and run node tools/sync_providers.js from the project root. It regenerates the package allow-list in FlutterHostActivity.kt, the <queries> in AndroidManifest.xml and the Python provider table in pek_providers.py.
PEK Cloud (optional) #
Accounts, sync, subtitles and the PEK Store run on Cloudflare Workers with a D1 database, and email codes are sent through Brevo. A phone browser is enough to deploy it. The full step-by-step guides are cloud/DEPLOY.md and cloud/STORE-DEPLOY.md in the repository. Sign-up can be made invite-only with single-use codes (INVITE_ONLY=1 and an ADMIN_KEY); accounts that already exist are not affected.
Checks before you push #
for f in cloud/*.js tools/*.js; do node --check "$f"; done
python3 -m py_compile backend/hesper_guard.py plugins/*/*.py
cd flutter_ui && flutter analyze && flutter test