Private
Public Access
Plexamp Lite 1.14: Android 4.1 build with ExoPlayer, lyrics, home-screen widget
- One build per Android level, as in Tenda: build/PlexampLite.apk (Android 2.2+, versionCode 1508) and build/PlexampLite-api16.apk (Android 4.1+, 1516), from shared src/ plus platform/api8 or platform/api16. - Android 4.1 build: ExoPlayer 2.18.7 behind a small Engine interface (gapless hand-over to read-ahead and downloaded files, a longer buffer, MediaPlayer fallback for tracks it can't decode), a notification and lock screen with art and buttons, a resizable widget, Holo, a menu button without a Menu key, metered networks. R8 shrinks ExoPlayer and Guava (tools/fetch_exoplayer.sh, tools/r8-rules.pro). - Both builds: lyrics in Now Playing as in the Mac app (timed lyrics follow and seek), a home-screen widget, media play/pause keys, the moon icon drawn without clipPath. - PlexampLite-noreport on the SD card stops play reports, for tests against a real server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2e7476669e
commit
13f29e26c4
39 files changed
+1685
-119
No files matched your search
@@ -6,6 +6,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import com.minamp.net.Http;
|
||||
import com.minamp.util.Json;
|
||||
|
||||
/** Paths into one music library section, plus the playback-URL decisions. */
|
||||
@@ -150,6 +151,35 @@ public final class Library {
|
||||
if (t.partKey.length() == 0) throw new IOException(com.minamp.util.Tr.t("no_media", "Track has no playable media"));
|
||||
}
|
||||
|
||||
/** The track's lyrics text, "" when it has none: timed (LRC) if there are, else the longest plain text (a
|
||||
* local .txt can be a broken copy of LyricFind's). Blocking. */
|
||||
public String lyrics(Item t) throws IOException {
|
||||
List<Item> l = server.items("/library/metadata/" + t.ratingKey); // lists leave the streams out
|
||||
if (l.isEmpty()) return "";
|
||||
Item full = l.get(0);
|
||||
String best = "";
|
||||
for (int i = 0; i < full.lyricsKeys.size(); i++) {
|
||||
String text = lyricsStream(full.lyricsKeys.get(i));
|
||||
if (i < full.lyricsTimed && text.trim().length() > 0) return text;
|
||||
if (text.trim().length() > best.trim().length()) best = text;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
private String lyricsStream(String key) throws IOException {
|
||||
Http.Response r = Http.get(server.url(key), server.mediaHeaders(), 20000);
|
||||
try {
|
||||
if (r.code == 404) return "";
|
||||
if (r.code != 200) throw new IOException("HTTP " + r.code);
|
||||
byte[] d = r.readAll();
|
||||
String text = new String(d, "UTF-8");
|
||||
if (text.indexOf('\uFFFD') >= 0) text = new String(d, "ISO-8859-1"); // not UTF-8 after all
|
||||
return text;
|
||||
} finally {
|
||||
r.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void shuffle(List<Item> l) {
|
||||
Collections.shuffle(l, new Random());
|
||||
}
|
||||
@@ -295,7 +325,12 @@ public final class Library {
|
||||
|
||||
// ------------------------------------------------------------------ reporting
|
||||
|
||||
/** For testing against a real server: report no plays or positions (App sets it when the SD card has a file
|
||||
* named PlexampLite-noreport), so the account's play counts and history stay as they were. */
|
||||
public static boolean noReport;
|
||||
|
||||
public void timeline(Item t, String state, long timeMs) {
|
||||
if (noReport) return;
|
||||
try {
|
||||
server.fetchQuiet("/:/timeline?ratingKey=" + t.ratingKey
|
||||
+ "&key=" + Plex.enc("/library/metadata/" + t.ratingKey)
|
||||
@@ -305,6 +340,7 @@ public final class Library {
|
||||
}
|
||||
|
||||
public void scrobble(Item t) {
|
||||
if (noReport) return;
|
||||
try {
|
||||
server.fetchQuiet("/:/scrobble?identifier=com.plexapp.plugins.library&key=" + Plex.enc(t.ratingKey));
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
Reference in new issue
Block a user