Private
Public Access
Replace jarsigner + zipalign.py with tools/signapk.py, which writes the v1 signature the way old JarUtils expects and aligns the APK. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
94 lines
5.0 KiB
Markdown
94 lines
5.0 KiB
Markdown
# Minamp
|
||
|
||
A small Plexamp-style music player for Plex, built for the Samsung Galaxy Mini (GT-S5570:
|
||
Android 2.2/2.3, 240×320 ldpi screen, 600 MHz ARMv6, 384 MB RAM). Runs on any Android 2.2+ phone.
|
||
|
||
## Install
|
||
|
||
1. On the phone: **Settings → Applications → Unknown sources** (tick it).
|
||
2. Copy `Minamp.apk` to the SD card (USB cable, or download it in the browser) and open it
|
||
with a file manager, or from a computer: `adb install Minamp.apk`.
|
||
3. The app can live on the SD card (Settings → Applications → Manage → Minamp → Move to SD card),
|
||
which helps with the Mini's tiny internal storage.
|
||
|
||
## Sign in
|
||
|
||
Open Minamp → **Sign in with Plex**. It shows a 4-character code; on any other device go to
|
||
**plex.tv/link** and type it in. Minamp then lists your servers (owned and shared) and music libraries.
|
||
|
||
*Connect to a server address* is the manual fallback: an IP/hostname plus an optional X-Plex-Token.
|
||
|
||
## Streaming from anywhere
|
||
|
||
After sign-in Minamp knows every address Plex advertises for your server and picks the best
|
||
working one, re-checking whenever the phone switches network:
|
||
|
||
| Order | Connection | When it's used |
|
||
|---|---|---|
|
||
| 1 | Home network, HTTPS (`*.plex.direct`) | On your Wi-Fi |
|
||
| 2 | Home network, plain HTTP | Same, if your router blocks plex.direct DNS (rebind protection) |
|
||
| 3 | Remote, HTTPS | Away, if Remote Access is set up on the server |
|
||
| 4 | Plex Relay | Away, when the server isn't reachable directly (bandwidth-capped; Minamp caps itself at 192 kbps) |
|
||
|
||
For the best remote experience enable **Settings → Remote Access** on your Plex Media Server.
|
||
Without it, Relay still works.
|
||
|
||
Android 2.x can't do modern TLS, so Minamp bundles its own TLS 1.2/1.3 stack (Bouncy Castle,
|
||
renamed to `com.minamp.bc` so it doesn't clash with the old copy inside Android) and verifies
|
||
certificates against Mozilla's root store (from `certifi`). A tiny loopback proxy feeds the
|
||
phone's media player, so HTTPS streams and relay work the same as local ones. If the phone's
|
||
clock has been reset to before 2024 the certificate date check is skipped rather than failing.
|
||
|
||
## Playback and quality
|
||
|
||
* MP3, AAC (M4A) and Ogg Vorbis play directly. FLAC, ALAC etc. are transcoded to MP3 by the
|
||
server (Android 2.2/2.3 can't decode FLAC).
|
||
* **Menu → Settings**: separate quality for home Wi-Fi (default *Original*) and for away/mobile
|
||
data (default *192 kbps MP3*); 320/256/192/128/96 kbps available.
|
||
* Seeking in a transcoded track restarts the transcode at the new position.
|
||
* If a stream fails, Minamp re-picks the connection and resumes; if it fails again it downloads
|
||
the whole track first and plays from the SD card. "Download tracks before playing" forces that
|
||
mode (useful on flaky mobile data).
|
||
* Plays are reported to Plex (Now Playing in the Plex dashboard, play counts, resume position).
|
||
|
||
## Features
|
||
|
||
* Home: Library radio, Loved radio (rated 4★+ / loved), Time-travel radio (pick a decade),
|
||
Random album, Recently added and Recently played shelves.
|
||
* Artists / Albums (5 sort orders) / Playlists tabs with paging and fast scroll; Search.
|
||
* Artist page with *Play all* and *Artist radio*; album and playlist pages with *Play*/*Shuffle*.
|
||
* Long-press anything: Play next, Add to queue, Go to album/artist, Love.
|
||
* Now Playing: big art on a backdrop coloured from the cover, seek bar, shuffle, repeat
|
||
(queue/track), love, sleep timer (15–90 min or end of track), where it's streaming from.
|
||
* Up Next queue: jump, play next, remove, clear; the queue and position survive restarts.
|
||
* Wired headset button: 1 click play/pause, 2 next, 3 previous; Bluetooth media keys;
|
||
pauses for calls and when headphones are unplugged.
|
||
|
||
## Building (no Android SDK needed)
|
||
|
||
```
|
||
tools/setup_toolchain.sh # once: fetches aapt2, the API 8 android.jar, builds dx, renames Bouncy Castle
|
||
./build.sh # -> build/Minamp.apk
|
||
```
|
||
|
||
`build.sh` runs `aapt2` (resources), `javac` (Java 8 bytecode checked against the API 8
|
||
`android.jar`), `dx` (dex 035) and `tools/signapk.py`, which writes the v1 signature in the
|
||
classic Android SignApk format and aligns the APK. (Modern `jarsigner` output does *not* install on
|
||
Android 4.2 and older: it names digests `SHA-1-Digest` and labels the PKCS#7 signer algorithm in a
|
||
way old `JarUtils` can't read, so the phone treats the APK as unsigned.) The debug key in `signing/` (password `minamp123`) is what this APK is
|
||
signed with, so rebuilt APKs install over it.
|
||
|
||
Tests (desktop JVM, no device):
|
||
|
||
* `test/PlexTest.java` + `test/mock_plex.py`: PIN sign-in, server discovery, connection
|
||
picking/fallback, TLS with a wildcard plex.direct-style certificate (ECDSA leaf, RSA root),
|
||
untrusted-root rejection, browsing, search, artwork, and the stream proxy (Range requests over
|
||
TLS, de-chunking transcodes, aborting).
|
||
* `test/QueueTest.java`: shuffle/unshuffle, repeat modes, play next, remove, move, clear.
|
||
|
||
## Limits
|
||
|
||
* No gapless playback (Android 2.2/2.3 have no API for it).
|
||
* Notification has no playback buttons (pre-Android 3 can't); tap it to open Now Playing.
|
||
* Downloads for offline listening aren't implemented.
|