Files
SleppyOwl/docs/development.md
StenFredd 3ef78bd49c
All checks were successful
release / release (push) Successful in 12m40s
Add CI
2026-10-27 17:38:55 +03:00

11 KiB
Raw Permalink Blame History

Разработка

Сборка

Нужны JDK 21 и Android SDK (compileSdk 37). Gradle — через обёртку ./gradlew (9.8.1).

Что Команда
ТВ, debug ./gradlew :app:assembleDebug → app/build/outputs/apk/debug/app-debug.apk
ТВ, release ./gradlew :app:assembleRelease — R8 без обфускации, ключ — ниже; ABI armeabi-v7a + arm64-v8a
ПК, запуск ./gradlew :desktop:run или tools/linux/desktop.sh (без Gradle вокруг процесса)
ПК, пакет ./gradlew :desktop:packageDeb → desktop/build/deb/sleepyowl_<версия>_amd64.deb (зависит от libmpv2)
Тесты ./gradlew test (в т.ч. рендер-тесты экранов ПК и ui:shared без дисплея)

Производительность интерфейса на ТВ мерить только на release-сборке (см. ui-performance.md). Baseline profile лежит в app/src/release/generated/baselineProfiles/ и снимается заново на ТВ (gen_profile, ниже).

Версия обоих приложений — sleepyowl.versionName в gradle.properties (или -Psleepyowl.versionName=…); versionCode APK следует за ней (1.2.3 → 1002003). Release-APK подписывается ключом из ANDROID_KEYSTORE (+ ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, по умолчанию sleepyowl), без него — debug-ключом машины.

CI: релизы в Gitea

.gitea/workflows/release.yaml: на пуш в master APK и .deb собираются в Docker и выкладываются на страницу Releases репозитория как тег v<версия> (APK sleepyowl-<версия>.apk, .deb как его назвал packageDeb).

  • Версия. Каждый релиз — patch на единицу выше прошлого тега (v0.1.1 → 0.1.2). Чтобы начать новую minor или major, поднять sleepyowl.versionName в gradle.properties выше последнего релиза — следующий релиз возьмёт её. Первый релиз — версия из gradle.properties. Пуш, который не менял приложения (только docs/, tools/, .gitea/, baselineprofile/, тесты, *.md), релиза не делает.

  • Сборка. tools/ci/Dockerfile — образ с JDK 21 и Android SDK; tools/ci/release.Dockerfile собирает в нём :app:assembleRelease :desktop:packageDeb (tools/ci/release.sh) целиком внутри BuildKit: исходники — контекст сборки, ключ — BuildKit-секреты (в слои не попадает), кэш Gradle — cache mount, который живёт между сборками, результат — --output. Так раннеру не нужны bind mount'ы.

  • Раннер. Нужен Gitea Actions runner с меткой ubuntu-latest, видящий этот репозиторий (на уровне репозитория, организации StenFreddSoft или всего сервера) и с доступом к Docker.

  • Секреты (Settings → Actions → Secrets):

    • ANDROID_KEYSTORE_BASE64 — base64 -w0 <keystore>;
    • ANDROID_KEYSTORE_PASSWORD — его пароль (у PKCS12 он же пароль ключа);
    • ANDROID_KEY_ALIAS — alias ключа, если не sleepyowl;
    • RELEASE_TOKEN — только если автоматический токен Actions не может создавать релизы: токен с write:repository.

    Без ключа джоба падает: APK на ключе, придуманном в контейнере, не встанет поверх ни одной установленной версии. Ключ должен быть один и тот же навсегда — APK на другом ключе ставится только после удаления приложения (с его настройками и входом). Свой ключ: keytool -genkeypair -keystore sleepyowl.jks -alias sleepyowl -keyalg RSA -keysize 4096 -validity 36500, хранить вне репозитория и с резервной копией.

  • Переменные (Settings → Actions → Variables, необязательные): RELEASES_KEEP (10) — сколько релизов остаётся на странице (старые удаляются вместе с файлами, теги остаются); BUILD_CACHE_KEEP (10GB) — потолок кэша сборки Docker на раннере.

Локально то же самое (команды — в шапке tools/ci/release.Dockerfile):

docker build -t sleepyowl-ci tools/ci
docker build --no-cache -f tools/ci/release.Dockerfile --secret id=keystore,src=<keystore> \
  --secret id=keystore_password,src=<файл с паролем> --secret id=key_alias,src=<файл с alias> -o out .

Личные настройки инструментов: local/

Папка local/ целиком в .gitignore: там всё, что относится к конкретной машине, серверу и аккаунтам — настройки инструментов, рабочие заметки, тестовые данные, резервные копии. В git она не попадает.

Инструменты в tools/ берут адреса и идентификаторы из local/dev.env. Шаблон с описанием каждой переменной — tools/dev.env.example:

mkdir -p local && cp tools/dev.env.example local/dev.env   # и заполнить

Формат — строки KEY=value без кавычек и подстановок; переменная, уже заданная в окружении, важнее файла. Shell-скрипты подключают файл через tools/devenv.sh, Python-скрипты — через tools/devenv.py. Если нужной переменной нет, скрипт останавливается и говорит, какую задать.

Переменная Для чего
JAVA_HOME, ADB JDK 21 и adb, если не из окружения/PATH
TV_ADB адрес ТВ для adb (<ip-тв>:5555)
JF_URL сервер Jellyfin по адресу в LAN
JF_USER тестовый аккаунт на сервере: тестовые прогоны меняют его данные просмотра
PROFILE_SERIES id сериала для прохода по странице сериала при съёмке baseline profile
K2_EPISODES три подряд идущие серии одного сезона для tools/linux/k2.py
L0_FLOAT_ITEM, L0_CASES файл и список файлов для проверок mpv в tools/linux/l0/

Debug-тур (app/src/debug/assets/tour.json, список файлов для обхода всех форматов из отладочного экрана) тоже не в git: он собирается со своего сервера.

Инструменты

tools/tv/ — тестовый ТВ по adb

source tools/tv/env.sh даёт функции:

  • install_debug, install_release (release сразу компилируется по baseline profile);
  • play <itemId> [exo|vlc] — открыть карточку и играть (debug deep-link --es item, --es engine, --el start <мс>);
  • k KEY… — нажатия пульта, shot NAME — скриншот в $OUT;
  • plog — журнал решений сессии воспроизведения, vproxy — журнал локального прокси VLC, aout — что реально идёт на аудиовыход;
  • tv_token — токен текущего аккаунта (только debug-сборка, через run-as), sess — что играет на ТВ по данным сервера;
  • ui_bench [right|down] [N] — замер плавности (перцентили кадра и GPU, разбивка по фазам через framestats.py);
  • gen_profile — снять baseline profile на ТВ (~8 мин, на ТВ должен быть выполнен вход).

tools/tv/run-case.sh <name> <itemId> [exo|vlc] — прогон одного файла: скриншот и журнал.

tools/tour/build_tour.py

Собирает debug-тур: минимальный набор файлов медиатеки, покрывающий все форматные признаки сервера (контейнер, кодеки, HDR, частоты, чересстрочность, субтитры) и важные для выбора движка пары.

tools/logo/make_assets.py

Все растровые логотипы (баннер ТВ, адаптивная иконка, сова и надпись в интерфейсе, иконки ПК 16…512) генерируются из design/logo/sleepyowl.png. PNG не править руками — перезапускать скрипт.

tools/linux/ — версия для ПК

  • desktop.sh — запуск приложения без Gradle (DESKTOP_NOBUILD=1 — без сборки, SLEEPYOWL_SCALE — масштаб).
  • stand.sh — тестовый стенд: свой виртуальный дисплей Xvfb :87 с оконным менеджером Muffin и своей сессией D-Bus, звук в ao=null. Окна, мышь, MPRIS и хранитель экрана проверяются, не трогая рабочий стол. Файлы приложения стенда — отдельно от обычных ($STAND).
  • xinput.py — ввод на дисплей стенда; fake_screensaver.py — заглушка org.freedesktop.ScreenSaver на шине стенда.
  • k2.py — сквозная проверка плеера и интеграции с системой на стенде (PASS/FAIL по пунктам, скриншоты).
  • watchdata.py snapshot|diff|restore — снимок данных просмотра тестового аккаунта до прогона и возврат после.
  • l0/ — проверка, как сам mpv играет файлы медиатеки (версии 0.37 и 0.41, vo=gpu/gpu-next), и поведение плавающего окна mpv.

Подробности о стенде и его ограничениях — в desktop.md.