Private
Public Access
Import minamp 1.0 source
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
0df8124629
194 files changed
+7319
No files matched your search
@@ -0,0 +1,283 @@
|
||||
package com.minamp.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Tiny JSON reader/writer. Plex responses are parsed into {@link Obj}/{@link Arr}, which offer
|
||||
* forgiving opt* accessors (Plex is loose about numbers vs strings).
|
||||
*/
|
||||
public final class Json {
|
||||
|
||||
private Json() {}
|
||||
|
||||
public static final class Obj {
|
||||
public final Map<String, Object> map;
|
||||
public Obj() { map = new HashMap<String, Object>(); }
|
||||
public Obj(Map<String, Object> m) { map = m; }
|
||||
|
||||
public Object get(String k) { return map.get(k); }
|
||||
public boolean has(String k) { return map.get(k) != null; }
|
||||
|
||||
public String optString(String k) { return optString(k, ""); }
|
||||
public String optString(String k, String def) {
|
||||
Object v = map.get(k);
|
||||
if (v == null) return def;
|
||||
if (v instanceof Double) {
|
||||
double d = ((Double) v).doubleValue();
|
||||
if (d == Math.floor(d) && Math.abs(d) < 1e15) return Long.toString((long) d);
|
||||
}
|
||||
return v.toString();
|
||||
}
|
||||
public long optLong(String k, long def) {
|
||||
Object v = map.get(k);
|
||||
if (v instanceof Number) return ((Number) v).longValue();
|
||||
if (v instanceof String) {
|
||||
try { return (long) Double.parseDouble((String) v); } catch (NumberFormatException e) { return def; }
|
||||
}
|
||||
if (v instanceof Boolean) return ((Boolean) v).booleanValue() ? 1 : 0;
|
||||
return def;
|
||||
}
|
||||
public int optInt(String k, int def) { return (int) optLong(k, def); }
|
||||
public double optDouble(String k, double def) {
|
||||
Object v = map.get(k);
|
||||
if (v instanceof Number) return ((Number) v).doubleValue();
|
||||
if (v instanceof String) {
|
||||
try { return Double.parseDouble((String) v); } catch (NumberFormatException e) { return def; }
|
||||
}
|
||||
return def;
|
||||
}
|
||||
public boolean optBool(String k) {
|
||||
Object v = map.get(k);
|
||||
if (v instanceof Boolean) return ((Boolean) v).booleanValue();
|
||||
if (v instanceof Number) return ((Number) v).intValue() != 0;
|
||||
if (v instanceof String) return "1".equals(v) || "true".equals(v);
|
||||
return false;
|
||||
}
|
||||
public Obj optObj(String k) {
|
||||
Object v = map.get(k);
|
||||
return v instanceof Obj ? (Obj) v : null;
|
||||
}
|
||||
public Arr optArr(String k) {
|
||||
Object v = map.get(k);
|
||||
return v instanceof Arr ? (Arr) v : null;
|
||||
}
|
||||
public Obj put(String k, Object v) { map.put(k, v); return this; }
|
||||
|
||||
@Override public String toString() { StringBuilder sb = new StringBuilder(); write(sb, this); return sb.toString(); }
|
||||
}
|
||||
|
||||
public static final class Arr {
|
||||
public final List<Object> list;
|
||||
public Arr() { list = new ArrayList<Object>(); }
|
||||
public int size() { return list.size(); }
|
||||
public Object get(int i) { return list.get(i); }
|
||||
public Obj optObj(int i) {
|
||||
Object v = i < list.size() ? list.get(i) : null;
|
||||
return v instanceof Obj ? (Obj) v : null;
|
||||
}
|
||||
public Arr add(Object v) { list.add(v); return this; }
|
||||
@Override public String toString() { StringBuilder sb = new StringBuilder(); write(sb, this); return sb.toString(); }
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ parsing
|
||||
|
||||
public static Object parse(String s) {
|
||||
P p = new P(s);
|
||||
p.ws();
|
||||
Object v = p.value();
|
||||
p.ws();
|
||||
if (p.i < s.length()) throw new IllegalArgumentException("Trailing data at " + p.i);
|
||||
return v;
|
||||
}
|
||||
|
||||
public static Obj parseObj(String s) {
|
||||
Object o = parse(s);
|
||||
if (!(o instanceof Obj)) throw new IllegalArgumentException("Expected JSON object");
|
||||
return (Obj) o;
|
||||
}
|
||||
|
||||
private static final class P {
|
||||
final String s; int i;
|
||||
P(String s) { this.s = s; }
|
||||
|
||||
void ws() {
|
||||
while (i < s.length()) {
|
||||
char c = s.charAt(i);
|
||||
if (c == ' ' || c == '\n' || c == '\r' || c == '\t') i++; else break;
|
||||
}
|
||||
}
|
||||
|
||||
IllegalArgumentException err(String m) { return new IllegalArgumentException(m + " at " + i); }
|
||||
|
||||
Object value() {
|
||||
if (i >= s.length()) throw err("Unexpected end");
|
||||
char c = s.charAt(i);
|
||||
switch (c) {
|
||||
case '{': return obj();
|
||||
case '[': return arr();
|
||||
case '"': return str();
|
||||
case 't': expect("true"); return Boolean.TRUE;
|
||||
case 'f': expect("false"); return Boolean.FALSE;
|
||||
case 'n': expect("null"); return null;
|
||||
default: return num();
|
||||
}
|
||||
}
|
||||
|
||||
void expect(String w) {
|
||||
if (!s.startsWith(w, i)) throw err("Expected " + w);
|
||||
i += w.length();
|
||||
}
|
||||
|
||||
Obj obj() {
|
||||
Obj o = new Obj();
|
||||
i++; ws();
|
||||
if (i < s.length() && s.charAt(i) == '}') { i++; return o; }
|
||||
while (true) {
|
||||
ws();
|
||||
if (i >= s.length() || s.charAt(i) != '"') throw err("Expected key");
|
||||
String k = str();
|
||||
ws();
|
||||
if (i >= s.length() || s.charAt(i) != ':') throw err("Expected :");
|
||||
i++; ws();
|
||||
o.map.put(k, value());
|
||||
ws();
|
||||
if (i >= s.length()) throw err("Unterminated object");
|
||||
char c = s.charAt(i++);
|
||||
if (c == '}') return o;
|
||||
if (c != ',') throw err("Expected , or }");
|
||||
}
|
||||
}
|
||||
|
||||
Arr arr() {
|
||||
Arr a = new Arr();
|
||||
i++; ws();
|
||||
if (i < s.length() && s.charAt(i) == ']') { i++; return a; }
|
||||
while (true) {
|
||||
ws();
|
||||
a.list.add(value());
|
||||
ws();
|
||||
if (i >= s.length()) throw err("Unterminated array");
|
||||
char c = s.charAt(i++);
|
||||
if (c == ']') return a;
|
||||
if (c != ',') throw err("Expected , or ]");
|
||||
}
|
||||
}
|
||||
|
||||
String str() {
|
||||
i++; // opening quote
|
||||
StringBuilder sb = null;
|
||||
int start = i;
|
||||
while (i < s.length()) {
|
||||
char c = s.charAt(i);
|
||||
if (c == '"') {
|
||||
String r = sb == null ? s.substring(start, i) : sb.append(s, start, i).toString();
|
||||
i++;
|
||||
return r;
|
||||
}
|
||||
if (c == '\\') {
|
||||
if (sb == null) sb = new StringBuilder();
|
||||
sb.append(s, start, i);
|
||||
i++;
|
||||
if (i >= s.length()) break;
|
||||
char e = s.charAt(i++);
|
||||
switch (e) {
|
||||
case 'n': sb.append('\n'); break;
|
||||
case 't': sb.append('\t'); break;
|
||||
case 'r': sb.append('\r'); break;
|
||||
case 'b': sb.append('\b'); break;
|
||||
case 'f': sb.append('\f'); break;
|
||||
case 'u':
|
||||
if (i + 4 > s.length()) throw err("Bad escape");
|
||||
sb.append((char) Integer.parseInt(s.substring(i, i + 4), 16));
|
||||
i += 4;
|
||||
break;
|
||||
default: sb.append(e);
|
||||
}
|
||||
start = i;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
throw err("Unterminated string");
|
||||
}
|
||||
|
||||
Object num() {
|
||||
int start = i;
|
||||
while (i < s.length()) {
|
||||
char c = s.charAt(i);
|
||||
if ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.' || c == 'e' || c == 'E') i++;
|
||||
else break;
|
||||
}
|
||||
if (start == i) throw err("Unexpected character");
|
||||
String n = s.substring(start, i);
|
||||
try {
|
||||
if (n.indexOf('.') < 0 && n.indexOf('e') < 0 && n.indexOf('E') < 0 && n.length() < 18) {
|
||||
return Long.valueOf(n);
|
||||
}
|
||||
return Double.valueOf(n);
|
||||
} catch (NumberFormatException e) {
|
||||
throw err("Bad number");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ writing
|
||||
|
||||
public static void write(StringBuilder sb, Object v) {
|
||||
if (v == null) { sb.append("null"); return; }
|
||||
if (v instanceof String) { quote(sb, (String) v); return; }
|
||||
if (v instanceof Number || v instanceof Boolean) { sb.append(v.toString()); return; }
|
||||
if (v instanceof Obj) {
|
||||
sb.append('{');
|
||||
boolean first = true;
|
||||
for (Iterator<Map.Entry<String, Object>> it = ((Obj) v).map.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry<String, Object> e = it.next();
|
||||
if (e.getValue() == null) continue;
|
||||
if (!first) sb.append(',');
|
||||
first = false;
|
||||
quote(sb, e.getKey());
|
||||
sb.append(':');
|
||||
write(sb, e.getValue());
|
||||
}
|
||||
sb.append('}');
|
||||
return;
|
||||
}
|
||||
if (v instanceof Arr) {
|
||||
sb.append('[');
|
||||
List<Object> l = ((Arr) v).list;
|
||||
for (int i = 0; i < l.size(); i++) {
|
||||
if (i > 0) sb.append(',');
|
||||
write(sb, l.get(i));
|
||||
}
|
||||
sb.append(']');
|
||||
return;
|
||||
}
|
||||
quote(sb, v.toString());
|
||||
}
|
||||
|
||||
private static void quote(StringBuilder sb, String s) {
|
||||
sb.append('"');
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
switch (c) {
|
||||
case '"': sb.append("\\\""); break;
|
||||
case '\\': sb.append("\\\\"); break;
|
||||
case '\n': sb.append("\\n"); break;
|
||||
case '\r': sb.append("\\r"); break;
|
||||
case '\t': sb.append("\\t"); break;
|
||||
default:
|
||||
if (c < 0x20) {
|
||||
String h = Integer.toHexString(c);
|
||||
sb.append("\\u");
|
||||
for (int k = h.length(); k < 4; k++) sb.append('0');
|
||||
sb.append(h);
|
||||
} else sb.append(c);
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user