🏗️ Build and Test JellyTau / Run Tests (push) Successful in 20m34s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 6m6s
Traceability Validation / Check Requirement Traces (push) Successful in 18s
Build & Release / Run Tests (push) Successful in 20m26s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 10m3s
Build & Release / Build Linux (push) Successful in 37m59s
Build & Release / Build Windows (push) Successful in 23m0s
Build & Release / Build Android (push) Successful in 40m26s
Build & Release / Create Release (push) Successful in 1m20s
Bundles this session's work plus the concurrent search/offline/player changes.
Every gate passes on the combined tree: 885 frontend tests, 610 Rust tests,
clippy clean, boundary clean, trace coverage 86%.
Offline video playback — four separate defects, each of which alone stopped it:
DR-133 A completed download's file_path is already absolute (the worker
rewrites it on completion), but the player rooted it a second time and
handed the webview /data/user/0/app//data/user/0/app/videos/x.mp4.
DR-134 The asset protocol was never enabled: no protocol-asset feature and no
assetProtocol config, so convertFileSrc produced URLs nothing answered.
Also silently defeated the cached-thumbnail path, which fails soft to
the server copy and hid it whenever the server was reachable.
DR-137 Tauri's asset protocol answers a range-less request by reading the
whole file into memory, and only advertises Accept-Ranges from inside
its range branch, so the first request never learns ranges exist.
Chromium gave up with PIPELINE_ERROR_READ after ~31s. Local media is
now served by a loopback HTTP server: bounded 4 MiB chunks streamed
from the file handle, every response length-delimited, and a range-less
request answered with one chunk rather than the file. Confined by a
per-session token and to the app data directory, because loopback is
shared between apps on Android.
DR-138 Release builds set usesCleartextTraffic=false, so Android rejected the
request to that server before any I/O. A network-security-config
exempts 127.0.0.1 only; a remote server must still be HTTPS.
Downloads:
DR-135 download_item never records media_type and the reconnect resolver read
that NULL as 'audio', so a movie queued from a media card had its URL
resolved by get_audio_stream_url and completed as an audio-only
transcode. The item's own type now decides.
DR-136 Rows already downloaded that way are requeued on reconnect, since
prevention alone leaves them reading "downloaded" and still unplayable.
Known limitation: a download taken at `original` quality is a byte copy of the
source, so it can be any container. One such file is an AVI holding XVID, which
the webview cannot play in any case — the media server serves it correctly and
Chromium refuses it. That needs either a transcoded download preset or the
native ExoPlayer surface work, and is not addressed here.
Also fixes two ID collisions between concurrent work: DR-143 defined twice
(search vs offline gate) and UT-131 defined twice (Episode Focus hero vs channel
cap). The search requirement is now DR-147 and the channel-cap test UT-141, with
their code references and matrix rows updated.
122 lines
5.3 KiB
Bash
Executable File
122 lines
5.3 KiB
Bash
Executable File
#!/bin/bash
|
|
# Sync Android source files from src-tauri/android to src-tauri/gen/android
|
|
# This ensures the generated build directory has the latest source files
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
SOURCE_DIR="$PROJECT_ROOT/src-tauri/android/src/main/java/com/dtourolle/jellytau"
|
|
TARGET_DIR="$PROJECT_ROOT/src-tauri/gen/android/app/src/main/java/com/dtourolle/jellytau"
|
|
|
|
echo "Syncing Android sources..."
|
|
echo " From: $SOURCE_DIR"
|
|
echo " To: $TARGET_DIR"
|
|
|
|
# Create target directory if it doesn't exist
|
|
mkdir -p "$TARGET_DIR"
|
|
|
|
# Remove old copies of player and security directories
|
|
rm -rf "$TARGET_DIR/player" "$TARGET_DIR/security"
|
|
|
|
# Copy the directories
|
|
cp -r "$SOURCE_DIR/player" "$TARGET_DIR/"
|
|
cp -r "$SOURCE_DIR/security" "$TARGET_DIR/"
|
|
|
|
# Copy individual Kotlin files (like VideoOverlayManager.kt)
|
|
for kt_file in "$SOURCE_DIR"/*.kt; do
|
|
if [ -f "$kt_file" ]; then
|
|
cp "$kt_file" "$TARGET_DIR/"
|
|
echo " Copied: $(basename "$kt_file")"
|
|
fi
|
|
done
|
|
|
|
# Restore the app module build.gradle.kts (media3 deps + release signing config).
|
|
# gen/android is regenerated by `tauri android init`, so this tracked template is
|
|
# the source of truth and must be copied back after any (re)generation.
|
|
APP_GRADLE_SRC="$PROJECT_ROOT/src-tauri/android/app/build.gradle.kts"
|
|
APP_GRADLE_DST="$PROJECT_ROOT/src-tauri/gen/android/app/build.gradle.kts"
|
|
if [ -f "$APP_GRADLE_SRC" ]; then
|
|
cp "$APP_GRADLE_SRC" "$APP_GRADLE_DST"
|
|
echo " Copied: app/build.gradle.kts"
|
|
fi
|
|
|
|
# AndroidManifest.xml. `tauri android init` regenerates gen/android from
|
|
# tauri.conf.json and would drop our hand-maintained entries (media playback
|
|
# service + permissions, hardware acceleration, picture-in-picture attributes
|
|
# on MainActivity), so this tracked copy is the source of truth and must be
|
|
# restored after a regen. Gradle reads ONLY the gen/ copy - there is no
|
|
# manifest-merger hook here, so this must be the complete manifest.
|
|
MANIFEST_SRC="$PROJECT_ROOT/src-tauri/android/src/main/AndroidManifest.xml"
|
|
MANIFEST_DST="$PROJECT_ROOT/src-tauri/gen/android/app/src/main/AndroidManifest.xml"
|
|
if [ -f "$MANIFEST_SRC" ]; then
|
|
cp "$MANIFEST_SRC" "$MANIFEST_DST"
|
|
echo " Copied: app/src/main/AndroidManifest.xml"
|
|
fi
|
|
|
|
# Custom ProGuard/R8 keep rules. Required for minified release builds:
|
|
# the player/ and security/ Kotlin classes are loaded by name via JNI from
|
|
# Rust, so R8 can't see the references and would strip them without this.
|
|
# build.gradle.kts globs **/*.pro, so dropping it in app/ is enough.
|
|
PROGUARD_SRC="$PROJECT_ROOT/src-tauri/android/app/proguard-jellytau.pro"
|
|
PROGUARD_DST="$PROJECT_ROOT/src-tauri/gen/android/app/proguard-jellytau.pro"
|
|
if [ -f "$PROGUARD_SRC" ]; then
|
|
cp "$PROGUARD_SRC" "$PROGUARD_DST"
|
|
echo " Copied: app/proguard-jellytau.pro"
|
|
fi
|
|
|
|
# Launcher icons / adaptive-icon mipmaps. `tauri android init` generates
|
|
# low-quality launcher icons from tauri.conf.json (which has no high-res
|
|
# Android source), so overwrite them with the real committed mipmaps.
|
|
RES_SRC="$PROJECT_ROOT/src-tauri/android/src/main/res"
|
|
RES_DST="$PROJECT_ROOT/src-tauri/gen/android/app/src/main/res"
|
|
if [ -d "$RES_SRC" ]; then
|
|
for dir in "$RES_SRC"/mipmap-*; do
|
|
[ -d "$dir" ] || continue
|
|
name="$(basename "$dir")"
|
|
mkdir -p "$RES_DST/$name"
|
|
cp "$dir"/* "$RES_DST/$name/"
|
|
echo " Copied res: $name"
|
|
done
|
|
|
|
# values/ (themes.xml): status-bar styling that `tauri android init` does
|
|
# not generate. Previously this directory was tracked but never copied, so
|
|
# the theme customizations below never reached a build.
|
|
if [ -d "$RES_SRC/values" ]; then
|
|
mkdir -p "$RES_DST/values"
|
|
cp "$RES_SRC"/values/*.xml "$RES_DST/values/"
|
|
echo " Copied res: values"
|
|
fi
|
|
|
|
# xml/ (network_security_config.xml): referenced from the manifest, so a
|
|
# missing copy fails the resource link rather than degrading quietly.
|
|
# Merged into Tauri's generated xml/ (which holds file_paths.xml) rather
|
|
# than replacing it.
|
|
if [ -d "$RES_SRC/xml" ]; then
|
|
mkdir -p "$RES_DST/xml"
|
|
cp "$RES_SRC"/xml/*.xml "$RES_DST/xml/"
|
|
echo " Copied res: xml"
|
|
fi
|
|
# We ship only the color adaptive icon (background + foreground). Drop any
|
|
# monochrome layer Tauri may generate: the themed-icon monochrome doesn't
|
|
# render well, and our adaptive-icon xml no longer references it, so a stray
|
|
# ic_launcher_monochrome.png would just be dead weight.
|
|
rm -f "$RES_DST"/mipmap-*/ic_launcher_monochrome.png
|
|
|
|
# `tauri android init` also emits the Android Studio DEFAULT adaptive icon
|
|
# as API-qualified VECTOR drawables:
|
|
# drawable/ic_launcher_background.xml (solid #3DDC84 green)
|
|
# drawable-v24/ic_launcher_foreground.xml (the Android robot)
|
|
# Because drawable-v24 is a more specific match than our unqualified
|
|
# mipmap-*/ic_launcher_*.png, on API 24+ the vector WINS and the app ships
|
|
# the green square robot instead of our jellyfish. Remove them so the
|
|
# adaptive-icon xml resolves @mipmap/ic_launcher_{background,foreground}
|
|
# to the real committed PNGs.
|
|
rm -f "$RES_DST"/drawable/ic_launcher_background.xml \
|
|
"$RES_DST"/drawable-v24/ic_launcher_foreground.xml \
|
|
"$RES_DST"/drawable*/ic_launcher_foreground.xml \
|
|
"$RES_DST"/drawable*/ic_launcher_background.xml
|
|
fi
|
|
|
|
echo "✓ Android sources synced successfully"
|