Source

The code

PEK TV lives in one repository on one branch, main: a C++ backend, a Flutter UI shared by every platform, and an Android host.

Repository layout

tree
backend/      C++ server + embedded Python (dev.sh builds it). API only, no web pages
flutter_ui/   the screens: the Flutter / Dart app shared by every platform
android/      Gradle project: Kotlin host, JNI, Python runner, resources
assets/       branding (icon, banner, splash) and screenshots
plugins/      bundled plugins: tmdb-discover, weather, skin-maker
plugin_packages/  plugin zips prepared for distribution
skins/        bundled skins: default (PEK Ember), green, neon
cloud/        Cloudflare Workers: PEK Cloud (sync, accounts, subtitles) and the PEK Store
tools/        sync_providers.js, make_skin.py, providers.json
.github/workflows/build_android.yml   the signed Android APK build

How the parts fit

architecture
Flutter UI (flutter_ui/)  <---- HTTP, port 8080 ---->  C++ backend (backend/)
  plugin screens (Python screen.py)                       scans folders and network shares
  are drawn natively by the app                           streams files, subtitles, trailers
  libmpv driven over pek/* channels                       runs plugin backends via embedded Python,
                                                          behind hesper_guard.py
                         PEK Cloud + PEK Store (Cloudflare Workers + D1), optional

The server answers only the device it runs on unless you set PEK_BIND and PEK_TOKEN. On Android, the Kotlin host starts the backend through JNI and plugin Python runs with Chaquopy.

Modules

Where to start reading.

PartFolderWhat it does
Flutter UIflutter_ui/lib/src/shell, home, layouts and focus (phone swipe pages, TV sidebar, D-pad); library, detail and dashboard pages; player, subtitles and skip; music; profiles and cloud; skins; the plugin host, install flow and store.
Backendbackend/server.cpp HTTP server and routes; media_scanner.cpp and nfo.h library scan; vfs_*.cpp one virtual file system over local, SMB, NFS, FTP, WebDAV and UPnP; music.cpp and music_tags.cpp; torrent.cpp; plugin_install.h, skin_install.h, github_install.h.
Plugin guardhesper_guard.pyDecides whether a plugin's Python may run: manifest check, import and attribute scan, audit hook and time limits.
Android hostandroid/Kotlin host (MainActivity, FlutterHostActivity), libmpv player (MpvController), Chaquopy for plugin Python, JNI into the backend.
Cloudcloud/Two Cloudflare Workers: PEK Cloud (accounts, sync, subtitle cache) and the PEK Store (plugin shelves).

Releases and in-app updates

PEK TV checks GitHub for a newer release every time it starts and offers to download and install it. Android always asks for confirmation.

publishing a release
# 1. raise pekBaseCode by 1 in android/app/build.gradle (18 -> 19)
# 2. push a tag; the workflow builds and publishes the release
git tag v2.2.0 && git push origin v2.2.0

# Result: PEK-TV-<version>-release-arm64-v8a.apk
#         PEK-TV-<version>-release-armeabi-v7a.apk
android/app/build.gradle
// each CPU build gets its own versionCode, so a 64-bit install stays 64-bit
versionCode pekBaseCode * 10 + (pekAbi == 'arm64-v8a' ? 2 : (pekAbi == 'armeabi-v7a' ? 1 : 0))
minSdk 26   // Android 8.0 or newer
  • The updater reads the release list, so pre-releases count; the newest tag with a matching apk wins.
  • The apk is checked against GitHub's SHA-256 when available, and Android refuses any apk signed with a different key.
  • Debug, -dev.N and local builds never show the update screen.

More reference docs

Each of these lives in the repository root.

PLUGINS.md

The plugin manifest, backend guard, permissions and publishing.

FLUTTER_PLUGINS.md

Python screens, the pek_ui API and effects.

SKINS.md

Skin format, installer and tools.

MUSIC.md

How the Music tab reads and plays your files.

SUBTITLES.md

Automatic subtitle lookup.

LOCAL_METADATA.md

NFO files and local artwork.

UPDATES.md

The in-app updater.

FLUTTER.md

The Flutter UI.