Minamp 1.3

- Fix NoSuchMethodError on Android 2.x: Dalvik before 4.0 can't link Object
  methods (toString/equals/...) called through an interface. Patch the bundled
  Bouncy Castle (tools/patch_bc_dalvik.py) and our own CertVerifier, and make
  build.sh fail if tools/scan_dalvik.py finds any such call
- Treat a manually entered private address (10.x, 172.16-31.x, 192.168.x,
  .local) as home, so LAN servers that allow access without sign-in work
- Send Plex client headers on media requests (files and transcodes)
- Explain a 503 on a file as the server being unable to open it (drive or
  folder not available)
- Connection log: home/away, token presence, Plex's file check and a direct
  file request in the streaming test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xockoandClaude Opus 5.5 committed 2026-10-14 20:56:27 +02:00
1 parent a4b875ef34
commit 58d21b6d68
14 files changed
+218 -13

No files matched your search

+2 -1
View File
@@ -160,7 +160,8 @@ public final class CertVerifier {
GeneralName n = arr[i];
if (n.getTagNo() == GeneralName.dNSName) {
sawDns = true;
if (!ip && dnsMatch(n.getName().toString(), host)) return true;
// String.valueOf, not getName().toString(): Dalvik < 4.0 can't call Object methods via an interface
if (!ip && dnsMatch(String.valueOf(n.getName()), host)) return true;
} else if (n.getTagNo() == GeneralName.iPAddress && ip) {
byte[] a = ASN1OctetString.getInstance(n.getName()).getOctets();
if (ipString(a).equals(host)) return true;
+12 -1
View File
@@ -50,6 +50,7 @@ public final class StreamProxy implements Runnable {
final String id;
final List<String> urls;
final boolean buffered;
Map<String, String> headers; // sent upstream with every request
int chosen = -1; // index that worked
final List<Http.Response> live = new ArrayList<Http.Response>();
// buffered state (guarded by this)
@@ -95,8 +96,14 @@ public final class StreamProxy implements Runnable {
/** @return the local URL to give MediaPlayer, ending in an extension it may sniff. */
public String register(String id, List<String> remoteUrls, String ext, boolean buffered) {
return register(id, remoteUrls, ext, buffered, null);
}
public String register(String id, List<String> remoteUrls, String ext, boolean buffered, Map<String, String> headers) {
Route r = new Route(id, new ArrayList<String>(remoteUrls), buffered);
r.headers = headers;
synchronized (routes) {
routes.put(id, new Route(id, new ArrayList<String>(remoteUrls), buffered));
routes.put(id, r);
}
return "http://127.0.0.1:" + port() + "/s/" + id + "/stream." + ext;
}
@@ -198,6 +205,7 @@ public final class StreamProxy implements Runnable {
/** Tries the route's URLs in order; returns the accepted response or throws with the server's words. */
private Http.Response openUpstream(Route route, String method, String range, int first, int last) throws IOException {
Map<String, String> h = new LinkedHashMap<String, String>();
if (route.headers != null) h.putAll(route.headers);
h.put("Accept", "*/*");
if (range != null) h.put("Range", range);
String refusal = null;
@@ -216,6 +224,9 @@ public final class StreamProxy implements Runnable {
up.close();
code = up.code;
refusal = "Server refused the stream (" + up.code + ")" + (body.trim().length() > 0 ? ": " + com.minamp.plex.Plex.snippet(body) : "");
if (up.code == 503 && route.urls.get(i).indexOf("/library/parts/") >= 0) {
refusal = "Plex couldn't open this file (503). Is the drive or folder with your music available to the server?";
}
DiagLog.log("stream variant " + i + " refused: " + refusal);
}
throw new RefusedException(code, refusal);