Compare commits
13
Commits
ios-backports
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c771aa01bd | ||
|
|
666a7eb8cd | ||
|
|
b2ca212c45 | ||
|
|
4044303764 | ||
|
|
04ac5ae725 | ||
|
|
084d7e9cad | ||
|
|
db1175d25c | ||
|
|
c673a0ba5d | ||
|
|
042364b45c | ||
|
|
bede72ed09 | ||
|
|
a4be0bab44 | ||
|
|
06a5c7078f | ||
|
|
10a2aa9ef5 |
No files matched your search
+5
-3
@@ -1,9 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- build.sh makes one APK per Android level from this file: it sets minSdkVersion and targetSdkVersion for each,
|
||||||
|
and versionCode = the one below x 100 + the level (13 -> 1308 for Android 2.2, 1316 for 4.1). -->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.miniabs"
|
package="com.miniabs"
|
||||||
android:versionCode="7"
|
android:versionCode="13"
|
||||||
android:versionName="1.6"
|
android:versionName="1.12"
|
||||||
android:installLocation="auto">
|
android:installLocation="internalOnly">
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10" />
|
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +1,37 @@
|
|||||||
# MiniABS
|
# Podlite
|
||||||
|
|
||||||
A tiny Audiobookshelf **podcast** client for the Samsung Galaxy Mini (GT-S5570) and other Android 2.2+ phones. Native Java, no libraries, ~130 KB. The interface is in Galician, with large text and touch targets sized for the Mini's 240×320 screen. Its purple colour scheme and launcher icon come from the Audiobookshelf icon pack (`art/icon_master_512.png`); `tools/make_icons.py` derives the notification and player icons from it.
|
A tiny Audiobookshelf **podcast** client for the Samsung Galaxy Mini (GT-S5570) and other Android 2.2+ phones, with a
|
||||||
|
second build for Android 4.1 and later (Xperia J, Galaxy S II…): see *Android 4.1 build*. Native Java; the APK is about 1.1 MB, nearly all of it the bundled TLS stack. Formerly MiniABS. The interface is in Galician, with large text and touch targets sized for the Mini's 240×320 screen. The launcher icon is the "Podcasts Radio" pack (master in `art/icon-master.png`); `tools/make_icons.py` draws the notification icon (a white radio silhouette) and the player icons. Its warm dark colours and amber accent come from the radio: brass and the glow of its dial.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
1. Copy `MiniABS.apk` to the phone (USB to the SD card, or download it in the browser).
|
1. Copy `Podlite.apk` (Android 4.1+: `Podlite-api16.apk`; Tenda picks the right one by itself) to the phone (USB to the SD card, or download it in the browser).
|
||||||
2. On the phone: **Settings → Applications → Unknown sources** → tick it.
|
2. On the phone: **Settings → Applications → Unknown sources** → tick it.
|
||||||
3. Open the APK from a file manager and install. It can be moved to the SD card (Settings → Applications → Manage applications → MiniABS → Move to SD card).
|
3. Open the APK from a file manager and install. Podlite installs to internal storage (about 1 MB): an app on the SD card is killed whenever the phone shares its SD card over USB, which stopped playback and broke HTTPS until a restart.
|
||||||
|
|
||||||
## Connecting
|
## Connecting
|
||||||
|
|
||||||
At home, the simplest option is your server's **local http:// address**, e.g. `http://192.168.1.10:13378`.
|
At home, the simplest option is your server's **local http:// address**, e.g. `http://192.168.1.10:13378`.
|
||||||
|
|
||||||
Sign in with your username and password, or tick "Use an API key instead". It works with both current servers (2.26+, short-lived access tokens that MiniABS refreshes automatically) and older ones (single long-lived token).
|
Sign in with your username and password, or tick "Use an API key instead". It works with both current servers (2.26+, short-lived access tokens that Podlite refreshes automatically) and older ones (single long-lived token).
|
||||||
|
|
||||||
## HTTPS (from outside your home)
|
## HTTPS (from outside your home)
|
||||||
|
|
||||||
Android 2.3 only speaks **TLS 1.0**, which modern servers refuse. So HTTPS needs one change on the server and is handled by the app from there.
|
Android 2.3 only speaks TLS 1.0, which modern servers refuse, so since 1.7 Podlite brings its own
|
||||||
|
**TLS 1.2** (Bouncy Castle, the same client as Plexamp Lite, with Mozilla's root certificates,
|
||||||
### Server: a legacy HTTPS port
|
keep-alive and session resumption). Sign in with your server's normal `https://` address, at
|
||||||
|
home or away; nothing changes on the server. (A legacy TLS 1.0 port set up for older versions
|
||||||
Add a second `server` block to nginx, on its own port, used only by the phone. Your normal HTTPS site stays strict.
|
keeps working too.)
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
|
||||||
listen 8443 ssl;
|
|
||||||
server_name abs.example.com;
|
|
||||||
ssl_certificate /etc/letsencrypt/live/abs.example.com/fullchain.pem; # must be an RSA certificate
|
|
||||||
ssl_certificate_key /etc/letsencrypt/live/abs.example.com/privkey.pem;
|
|
||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
|
||||||
# @SECLEVEL=0 is required: OpenSSL 3 refuses TLS 1.0 without it
|
|
||||||
ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA:AES128-SHA:@SECLEVEL=0";
|
|
||||||
ssl_prefer_server_ciphers on;
|
|
||||||
client_max_body_size 0;
|
|
||||||
location / {
|
|
||||||
proxy_pass http://127.0.0.1:13378;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_buffering off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then sign in with `https://abs.example.com:8443`.
|
|
||||||
|
|
||||||
- **RSA certificate:** Android 2.3 can't use ECDSA certificates. With certbot, request one with `--key-type rsa`.
|
|
||||||
- **Security:** TLS 1.0 with these ciphers is weak by today's standards, but much better than plain HTTP over the internet. Only open this port if you need it.
|
|
||||||
- **Caddy** can't serve TLS 1.0; put nginx (or HAProxy) in front for this port.
|
|
||||||
|
|
||||||
### App: certificates
|
### App: certificates
|
||||||
|
|
||||||
- **Built-in roots:** MiniABS trusts what the phone trusts, plus modern root certificates the phone's 2011-era list lacks: Let's Encrypt, Google Trust Services, Sectigo/ZeroSSL, DigiCert G2, Amazon and others. Most certificates just work.
|
- **Built-in roots:** Podlite checks certificates against Mozilla's current root list (`assets/roots`), so Let's Encrypt, Google Trust Services, Sectigo/ZeroSSL and the rest just work.
|
||||||
- **Anything else** (self-signed, a private CA, a new root): MiniABS shows the certificate's SHA-256 fingerprint and asks once. Compare it with the fingerprint your computer's browser shows for the site before tapping Trust. It then trusts the CA that issued it, so renewals keep working.
|
- **Anything else** (self-signed, a private CA, a new root): Podlite shows the certificate's SHA-256 fingerprint and asks once. Compare it with the fingerprint your computer's browser shows for the site before tapping Trust. It then trusts the CA that issued it, so renewals keep working.
|
||||||
- **Settings → Certificates you trusted** lets you forget them.
|
- **Settings → Certificates you trusted** lets you forget them.
|
||||||
|
|
||||||
### App: streaming
|
### App: streaming
|
||||||
|
|
||||||
Android 2.x's media player can't stream https:// URLs, so for HTTPS servers MiniABS runs a small proxy on the phone (127.0.0.1 only, random unguessable URLs). It forwards seeks and gets a fresh sign-in token for each request, so long episodes don't break when the token expires.
|
Android 2.x's media player can't stream modern https:// URLs, so for HTTPS servers Podlite runs a small proxy on the phone (127.0.0.1 only, random unguessable URLs). It forwards seeks and gets a fresh sign-in token for each request, so long episodes don't break when the token expires.
|
||||||
|
|
||||||
## Using it
|
## Using it
|
||||||
|
|
||||||
@@ -68,32 +39,57 @@ Android 2.x's media player can't stream https:// URLs, so for HTTPS servers Mini
|
|||||||
- **Shows**: every podcast; tap one for its episodes. Menu key → sort oldest/newest, hide played.
|
- **Shows**: every podcast; tap one for its episodes. Menu key → sort oldest/newest, hide played.
|
||||||
- **Saved**: episodes downloaded to the SD card, plus download progress.
|
- **Saved**: episodes downloaded to the SD card, plus download progress.
|
||||||
- **Tap** an episode to play. **Long-press** for Download, Delete download, Mark as played/unplayed, Go to show.
|
- **Tap** an episode to play. **Long-press** for Download, Delete download, Mark as played/unplayed, Go to show.
|
||||||
- **Player**: skip back/forward (set the amounts in Settings), seek bar, show notes. Menu key → sleep timer, mark as played, download, stop, close MiniABS.
|
- **Player**: skip back/forward (set the amounts in Settings), seek bar, show notes. Menu key → sleep timer, mark as played, download, stop, close Podlite.
|
||||||
- **Close**: Menu key → *Pechar MiniABS* (on the Latest/Shows/Saved screen or the player) saves the position, stops playback and closes the app.
|
- **Close**: Menu key → *Pechar Podlite* (on the Latest/Shows/Saved screen or the player) saves the position, stops playback and closes the app.
|
||||||
- **Headset buttons**: play/pause; next/previous skip forward/back. Playback pauses when headphones are unplugged and during calls.
|
- **Headset buttons**: play/pause; next/previous skip forward/back. Playback pauses when headphones are unplugged and during calls.
|
||||||
|
|
||||||
Colored dots: blue = new, amber = in progress (with a bar), grey = played.
|
Colored dots: blue = new, amber = in progress (with a bar), grey = played.
|
||||||
|
|
||||||
## Progress sync
|
## Progress sync
|
||||||
|
|
||||||
Playback opens an Audiobookshelf session and syncs every 15 seconds and on pause, so progress follows you to other apps. An episode only counts as played when playback gets within a minute of its end: a stream that drops or a saved file cut short is retried or reported, never marked as played. If playback says it's playing but stops moving for 12 seconds, MiniABS says so. Saved episodes play offline; their positions are kept on the phone and sent to the server next time you're online (or tap refresh on the Saved tab).
|
Playback opens an Audiobookshelf session and syncs every 15 seconds and on pause, so progress follows you to other apps. An episode only counts as played when playback gets within a minute of its end: a stream that drops or a saved file cut short is retried or reported, never marked as played. If playback says it's playing but stops moving for 12 seconds, Podlite says so. Saved episodes play offline; their positions are kept on the phone and sent to the server next time you're online (or tap refresh on the Saved tab).
|
||||||
|
|
||||||
|
## Android 4.1 build
|
||||||
|
|
||||||
|
One build per **Android level**, never per phone (the same pattern as Tenda and Plexamp Lite): `build/Podlite.apk`
|
||||||
|
for Android 2.2+ and `build/Podlite-api16.apk` for 4.1+, from the same source, package and key. `versionCode` is
|
||||||
|
the manifest's × 100 + the level (13 → 1308 and 1316), so a phone that moves up a level gets the newer build as an
|
||||||
|
ordinary update. What only one level can do is in `platform/api8/…/Platform.java` and `platform/api16/…/Platform.java`
|
||||||
|
(the same methods; keep them in step), plus `platform/api16/res` (Holo). The Android 4.1 build adds:
|
||||||
|
|
||||||
|
- **ExoPlayer 2.18** (`platform/api16/…/ExoEngine.java`) behind the small `Engine` interface the player service
|
||||||
|
uses (`MediaPlayerEngine` on Android 2.x), with **playback speed** (the button at the top of the player: 0,8× to 2×)
|
||||||
|
and **skip silences** (Settings → Reprodución). It keeps up to 3 minutes buffered. An episode ExoPlayer can't
|
||||||
|
decode is retried with Android's own player.
|
||||||
|
- A **notification** with the cover and −15 ⏯ +30 ✕ (pull it down for a larger one); swiping it away while paused stops.
|
||||||
|
- **Lock-screen controls** with the cover (⏮ ⏭ skip back and forward).
|
||||||
|
- Android 4's **Holo** dialogs, menus and Settings; a ⋮ button on phones without a Menu key.
|
||||||
|
- "Download on Wi-Fi only" means any network that doesn't cost: a phone's Wi-Fi hotspot counts as mobile data.
|
||||||
|
|
||||||
## Limits
|
## Limits
|
||||||
|
|
||||||
- Episodes are streamed with direct play. Formats Android 2.x can't decode (e.g. Opus) can't be played, since the transcoded HLS stream isn't supported on 2.x.
|
- Episodes are streamed with direct play. Formats Android 2.x can't decode (e.g. Opus) can't be played, since the transcoded HLS stream isn't supported on 2.x.
|
||||||
- No playback speed control: Android 2.x's media player doesn't support it.
|
- No playback speed control on Android 2.x (its media player doesn't support it); the Android 4.1 build has it.
|
||||||
- Downloads need an SD card. "Download on Wi-Fi only" is on by default.
|
- Downloads need an SD card. "Download on Wi-Fi only" is on by default.
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Needs a JDK, `aapt`, `dalvik-exchange` (dx), `zipalign`, `apksigner` (Ubuntu: `apt install aapt dalvik-exchange zipalign apksigner`) and an API 8 `android.jar`:
|
With the toolchain Plexamp Lite's `tools/setup_toolchain.sh` prepares (`~/android-toolchain`: aapt2, dx, the API 8
|
||||||
|
jar, Bouncy Castle renamed to `com.minamp.bc`, a Python venv with `cryptography`), plus for the Android 4.1 build the
|
||||||
|
API 16 jar, ExoPlayer (`tools/fetch_exoplayer.sh`), R8 (`d8.jar` from build-tools 34, in
|
||||||
|
`~/android-toolchain/calendar-tools/`) and a JDK 11+ (`build.sh` finds Homebrew's openjdk@17). No Gradle, no SDK:
|
||||||
|
|
||||||
ANDROID_JAR=/path/to/android-8/android.jar ./build.sh
|
./build.sh # -> build/Podlite.apk (Android 2.2+) and build/Podlite-api16.apk (4.1+)
|
||||||
|
./build.sh 16 # one level only
|
||||||
|
|
||||||
Compiling against the API 8 jar guarantees no newer Android APIs are used. The APK is signed with `miniabs.keystore` (password `miniabs`); keep it to install updates over the top.
|
Per level: aapt2 → javac (Java 8 bytecode against that level's `android.jar`) → for Android 2.x the Dalvik 2.x link
|
||||||
|
check and dx, for 4.1 R8 (`tools/r8-rules.pro`: keeps the app whole, shrinks ExoPlayer and Guava, one dex) →
|
||||||
|
`tools/signapk.py` (v1, SHA-1, the classic SignApk format Android ≤ 4.2 needs) → `tools/check_dex.py`. The APK is
|
||||||
|
signed with `miniabs.keystore` (JKS, password and alias `miniabs`; build.sh converts it to a PKCS#12 copy in `build/`
|
||||||
|
for the run); keep it to install updates over the top.
|
||||||
|
|
||||||
All sizes (text, rows, buttons, covers) are in `res/values/dimens.xml`; change them there and rebuild.
|
All sizes (text, rows, buttons, covers) are in `res/values/dimens.xml`; change them there and rebuild.
|
||||||
|
|
||||||
`tools/gen_roots.py` regenerates the bundled root certificates from a system CA store.
|
`src/com/miniabs/net/` is the bundled HTTP/TLS client shared with Plexamp Lite, Noticias Lite and Calendar Lite; `assets/roots/` holds Mozilla's roots (regenerate with Plexamp Lite's `tools/make_roots.py`).
|
||||||
|
|
||||||
`test/run_tests.sh` runs the API, JSON, progress, HTTPS-trust and streaming-proxy code on the desktop JVM against a mock Audiobookshelf server (`test/mock_abs.py`), over plain HTTP and over TLS with good, expired, wrong-host, forged and self-signed certificates (`test/make_pki.sh`).
|
`JSON_JAR=/path/to/json.jar test/run_tests.sh` (any org.json jar) runs the API, JSON, progress, HTTPS-trust and streaming-proxy code on the desktop JVM against a mock Audiobookshelf server (`test/mock_abs.py`), over plain HTTP and over TLS with good, expired, wrong-host, forged and self-signed certificates (`test/make_pki.sh`).
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 224 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loaded 100 of 193 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user