Start here

Building PEK TV

Build the C++ backend and the Android app, environment variables, signing and CI.

View source on GitHub

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++ or clang), Python 3 with its development files (python3-config), and OpenSSL headers. The search-site fetcher needs HTTPS, so OpenSSL is required.
  • httplib.h in backend/ (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 binary

Use 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 #

  1. Works out the version name: the tag without its v, or the versionName in android/app/build.gradle plus -dev.<run number>.
  2. Runs flutter pub get in flutter_ui/, which generates the Flutter module the Gradle build includes, then copies plugins and skins into the app's assets (without caches or plugin data/ folders).
  3. Builds OpenSSL and SQLite (both cached), clones libsmb2 for SMB and libnfs for NFS, and optionally libtorrent and Boost headers.
  4. Builds the APK. If the full build fails it retries without the optional native libraries (SMB, NFS, torrent).
  5. 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) or release (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_BASE64

In 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