Private
Public Access
Backport from the iOS version: offline downloads, home-first reconnect, stall warning, Close
- Downloads for offline listening: long-press a track, album, artist or playlist -> Download; Menu -> Downloads lists them (progress, space used/free, play/shuffle, retry, remove). Saved on the SD card (Android/data/com.minamp/ files/downloads). MP3 originals kept as they are unless above a lower download quality; the rest transcoded to MP3 (320 kbps by default). One at a time, Range resume for originals, retried when the server is back, Wi-Fi lock. - Downloaded tracks play from the SD card, offline too; plays made offline are reported to Plex when a connection works again. - Server.pick: when last time's connection was remote, give the plain home addresses 2 s first (a hairpinned remote address kept us encrypted and capped at home). test/PreferHomeTest.java. - Playback "playing" but not moving for 12 s: say so instead of staying silent. - Menu -> Close Minamp: stop the music and close every screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f7f49ecfbb
commit
f9050bbac0
15 files changed
+933
-43
No files matched your search
@@ -89,6 +89,7 @@ public class PlayerService extends Service implements MediaPlayer.OnPreparedList
|
||||
public static String sourceLabel() {
|
||||
PlayerService s = instance;
|
||||
if (s == null || s.track == null) return "";
|
||||
if (s.localFile) return s.getString(R.string.downloaded);
|
||||
App app = App.get();
|
||||
String where = app.server == null || app.server.active() == null ? "" : com.minamp.plex.Server.kindLabel(app.server.active().kind);
|
||||
String q = s.transcoding ? s.kbps + " kbps MP3" : (s.track.codec.toUpperCase() + (s.track.bitrate > 0 ? " " + s.track.bitrate + " kbps" : ""));
|
||||
@@ -134,6 +135,10 @@ public class PlayerService extends Service implements MediaPlayer.OnPreparedList
|
||||
private long lastTimeline;
|
||||
private long lastSave;
|
||||
private long lastPos; // last position seen while playing (getCurrentPosition is unreliable after completion)
|
||||
private boolean localFile; // playing a download from the SD card
|
||||
private long stallPos = -1; // position last seen moving
|
||||
private long stallSince;
|
||||
private boolean stallWarned;
|
||||
|
||||
private AudioManager audio;
|
||||
private boolean hasFocus;
|
||||
@@ -265,6 +270,17 @@ public class PlayerService extends Service implements MediaPlayer.OnPreparedList
|
||||
setState(BUFFERING, getString(R.string.connecting));
|
||||
goForeground();
|
||||
if (play) requestFocus();
|
||||
// Downloaded: play the file on the SD card, no network needed (offline too)
|
||||
final File saved = Downloads.get().fileFor(it);
|
||||
localFile = saved != null;
|
||||
if (saved != null) {
|
||||
transcoding = false;
|
||||
session = null;
|
||||
variantOrder = null;
|
||||
kbps = 0;
|
||||
begin(new java.util.ArrayList<String>(), "mp3", saved, 0, posMs);
|
||||
return;
|
||||
}
|
||||
final boolean download = forceDownload || app.downloadFirst();
|
||||
worker.execute(new Runnable() {
|
||||
public void run() {
|
||||
@@ -605,6 +621,16 @@ public class PlayerService extends Service implements MediaPlayer.OnPreparedList
|
||||
if (state == PLAYING && track != null) {
|
||||
long pos = currentPosition();
|
||||
lastPos = pos;
|
||||
// "playing" but not moving for 12 s: say so instead of staying silent
|
||||
if (pos != stallPos) {
|
||||
stallPos = pos;
|
||||
stallSince = now;
|
||||
stallWarned = false;
|
||||
} else if (!stallWarned && now - stallSince > 12000) {
|
||||
stallWarned = true;
|
||||
com.minamp.net.DiagLog.log("playback stalled at " + pos / 1000 + "s");
|
||||
toast(getString(R.string.stalled));
|
||||
}
|
||||
if (!scrobbled && track.duration > 0 && pos > track.duration * 9 / 10) scrobble(track);
|
||||
if (now - lastTimeline > 10000) report(false);
|
||||
if (now - lastSave > 15000) { lastSave = now; PlayQueue.get().resumePositionMs = pos; }
|
||||
@@ -631,7 +657,16 @@ public class PlayerService extends Service implements MediaPlayer.OnPreparedList
|
||||
scrobbled = true;
|
||||
final App app = App.get();
|
||||
reporter.execute(new Runnable() {
|
||||
public void run() { if (app.library != null) app.library.scrobble(it); }
|
||||
public void run() {
|
||||
if (app.library == null) return;
|
||||
// offline (a download): keep the play and report it when the server is back
|
||||
boolean online = app.library.server.active() != null;
|
||||
if (!online) {
|
||||
try { app.library.server.base(); online = true; } catch (Exception ignored) {}
|
||||
}
|
||||
if (online) app.library.scrobble(it);
|
||||
else app.addPendingScrobble(it.ratingKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user