Files
SleppyOwl/tools/tv/env.sh
2026-10-27 13:23:58 +03:00

65 lines
5.3 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Helpers for driving the test TV over adb. Usage: source tools/tv/env.sh
# TV_ADB (адрес ТВ), JF_URL (сервер), ADB, JAVA_HOME, PROFILE_SERIES — из local/dev.env (шаблон tools/dev.env.example).
source "$(dirname "${BASH_SOURCE[0]}")/../devenv.sh"
: "${TV_ADB:?set TV_ADB in local/dev.env}"
ADB=${ADB:-$(command -v adb || echo "$HOME/Android/Sdk/platform-tools/adb")}
A="$ADB -s $TV_ADB"
OUT=${OUT:-/tmp/movies-tv}; mkdir -p "$OUT"
k() { for x in "$@"; do $A shell input keyevent "$x"; sleep 0.7; done; }
shot() { $A exec-out screencap -p > "$OUT/$1.png"; echo "$OUT/$1.png"; }
install_debug() { ./gradlew :app:assembleDebug -q && $A install -r app/build/outputs/apk/debug/app-debug.apk; }
# Открыть карточку (и сразу играть, если указан движок или play=1): play <itemId> [exo|vlc]
play() {
if [ -n "$2" ]; then $A shell am start -S -n ru.stenfredd.sleepyowl/.MainActivity --es item "$1" --es engine "$2" >/dev/null
else $A shell am start -S -n ru.stenfredd.sleepyowl/.MainActivity --es item "$1" --ez play true >/dev/null; fi
}
# Журнал решений сессии воспроизведения
plog() { $A logcat -d | grep -E " (I|W|E) PlaybackSession" | sed 's/^.*PlaybackSession: //' | cut -c1-300; }
# Токен с ТВ (только debug-сборка: run-as читает DataStore приложения)
# (текущий аккаунт: первый в списке — последний использованный)
tv_token() { $A exec-out run-as ru.stenfredd.sleepyowl cat files/datastore/jellyfin_session.preferences_pb | grep -aoE '"token":"[0-9a-f]{32}"' | head -1 | grep -oE '[0-9a-f]{32}'; }
# Что играет на ТВ по данным сервера: название, позиция (с), PlayMethod. X-Emby-Token сервер 12.x не принимает.
sess() {
curl -s -H "Authorization: MediaBrowser Token=\"${TV_TOKEN:=$(tv_token)}\"" "${JF_URL:?set JF_URL in local/dev.env}/Sessions?activeWithinSeconds=60" |
python3 -c 'import json,sys
for s in json.load(sys.stdin):
n=s.get("NowPlayingItem")
if n and s.get("Client","").startswith("Movies"): print(n["Name"], round(s["PlayState"].get("PositionTicks",0)/1e7,1), s["PlayState"].get("PlayMethod"), "paused" if s["PlayState"].get("IsPaused") else "")'
}
# Реально ли звук уходит на выход: потоки AudioFlinger, число записей и активные треки
aout() { $A shell dumpsys media.audio_flinger | grep -E "^Output thread|Total writes|Tracks of which"; }
# Журнал локального прокси VLC (диапазоны, кэш, сколько скачано с сервера)
vproxy() { $A logcat -d | grep "VLC proxy" | sed -E 's/^[0-9-]+ ([0-9:.]+).*VLC proxy/\1/' | cut -c1-170; }
# Замер плавности интерфейса (только на release-сборке!): ui_bench [right|down] [N]
# Листает ряд (или экран) вперёд и назад N раз и печатает перцентили кадра и GPU, затем разбивку по фазам.
ui_bench() {
local dir=${1:-right} n=${2:-8} back P=ru.stenfredd.sleepyowl
[ "$dir" = right ] && back=left || back=up
$A shell dumpsys gfxinfo $P reset >/dev/null
for i in $(seq 1 $n); do $A shell input keyevent DPAD_${dir^^}; sleep 0.35; done
for i in $(seq 1 $n); do $A shell input keyevent DPAD_${back^^}; sleep 0.35; done
$A shell dumpsys gfxinfo $P | grep -E 'Janky frames:|50th percentile|90th percentile|99th percentile|50th gpu|90th gpu'
$A shell dumpsys gfxinfo $P framestats | python3 tools/tv/framestats.py
}
# Release + сразу компиляция по baseline profile (иначе ТВ скомпилирует его только при фоновом обслуживании).
install_release() {
./gradlew :app:assembleRelease -q && $A install -r app/build/outputs/apk/release/app-release.apk || return
$A shell am broadcast -a androidx.profileinstaller.action.INSTALL_PROFILE ru.stenfredd.sleepyowl/androidx.profileinstaller.ProfileInstallReceiver >/dev/null
$A shell cmd package compile -f -m speed-profile ru.stenfredd.sleepyowl
}
# Снять baseline profile заново на ТВ (~8 мин, ТВ должен быть с выполненным входом) и положить в app/src/release.
# Gradle может закончить с «failing tests» при успешном прогоне — тогда профиль копируется вручную.
# PROFILE_SERIES — id сериала для прохода по странице сериала.
gen_profile() {
: "${PROFILE_SERIES:?set PROFILE_SERIES in local/dev.env}"
ANDROID_SERIAL=$TV_ADB ./gradlew :app:generateReleaseBaselineProfile -Pandroid.injected.androidTest.leaveApksInstalledAfterRun=true \
-Pandroid.testInstrumentationRunnerArguments.seriesId=$PROFILE_SERIES
local src="baselineprofile/build/outputs/connected_android_test_additional_output/nonMinifiedRelease/connected"
src=$(find "$src" -name 'BaselineProfileGenerator_generate-startup-prof.txt' | head -1)
[ -n "$src" ] || { echo "профиль не найден"; return 1; }
cp "$src" app/src/release/generated/baselineProfiles/baseline-prof.txt
cp "$src" app/src/release/generated/baselineProfiles/startup-prof.txt
echo "профиль: $(wc -l < "$src") правил"
}