Renames the app (label, texts, Audiobookshelf client name, User-Agent, APK). The package name, preferences and signing key stay, so it installs over MiniABS and keeps its settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
96 lines
3.6 KiB
Java
96 lines
3.6 KiB
Java
package com.miniabs;
|
|
|
|
import org.json.JSONException;
|
|
import org.json.JSONObject;
|
|
|
|
/** One podcast episode, trimmed down to what Podlite needs. */
|
|
final class Episode {
|
|
String itemId = ""; // library item (the podcast) id
|
|
String id = ""; // episode id
|
|
String title = "";
|
|
String show = ""; // podcast title
|
|
String author = "";
|
|
String desc = "";
|
|
String ino = ""; // audio file inode, used for downloads
|
|
String ext = ".mp3";
|
|
String mime = "";
|
|
long published; // ms since epoch
|
|
double duration; // seconds
|
|
long size; // bytes
|
|
|
|
/** Builds an episode from an Audiobookshelf episode object. Returns null if it has no audio. */
|
|
static Episode fromApi(JSONObject e, String itemId, String show, String author) {
|
|
if (e == null) return null;
|
|
Episode ep = new Episode();
|
|
ep.id = Util.str(e, "id");
|
|
ep.itemId = itemId != null && itemId.length() > 0 ? itemId : Util.str(e, "libraryItemId");
|
|
ep.title = Util.str(e, "title");
|
|
ep.show = show == null ? "" : show;
|
|
ep.author = author == null ? "" : author;
|
|
ep.desc = Util.str(e, "description");
|
|
if (ep.desc.length() == 0) ep.desc = Util.str(e, "subtitle");
|
|
ep.published = e.optLong("publishedAt", 0);
|
|
JSONObject af = e.optJSONObject("audioFile");
|
|
if (af != null) {
|
|
ep.duration = af.optDouble("duration", 0);
|
|
ep.ino = Util.str(af, "ino");
|
|
ep.mime = Util.str(af, "mimeType");
|
|
JSONObject meta = af.optJSONObject("metadata");
|
|
if (meta != null) {
|
|
String x = Util.str(meta, "ext");
|
|
if (x.length() > 0) ep.ext = x;
|
|
ep.size = meta.optLong("size", 0);
|
|
}
|
|
}
|
|
if (ep.duration <= 0) ep.duration = e.optDouble("duration", 0);
|
|
if (ep.id.length() == 0 || ep.itemId.length() == 0 || af == null) return null;
|
|
ep.ext = safeExt(ep.ext);
|
|
// The podcast object (when the API sends it) carries the show name
|
|
JSONObject pod = e.optJSONObject("podcast");
|
|
if (pod != null && ep.show.length() == 0) {
|
|
JSONObject md = pod.optJSONObject("metadata");
|
|
if (md != null) {
|
|
ep.show = Util.str(md, "title");
|
|
ep.author = Util.str(md, "author");
|
|
}
|
|
}
|
|
return ep;
|
|
}
|
|
|
|
private static String safeExt(String x) {
|
|
x = x.toLowerCase();
|
|
if (!x.startsWith(".")) x = "." + x;
|
|
if (!x.matches("\\.[a-z0-9]{1,5}")) x = ".mp3";
|
|
return x;
|
|
}
|
|
|
|
JSONObject toJson() {
|
|
JSONObject o = new JSONObject();
|
|
try {
|
|
o.put("itemId", itemId).put("id", id).put("title", title).put("show", show)
|
|
.put("author", author).put("desc", desc).put("ino", ino).put("ext", ext)
|
|
.put("mime", mime).put("published", published).put("duration", duration)
|
|
.put("size", size);
|
|
} catch (JSONException ignored) {
|
|
}
|
|
return o;
|
|
}
|
|
|
|
static Episode fromStored(JSONObject o) {
|
|
Episode e = new Episode();
|
|
e.itemId = Util.str(o, "itemId");
|
|
e.id = Util.str(o, "id");
|
|
e.title = Util.str(o, "title");
|
|
e.show = Util.str(o, "show");
|
|
e.author = Util.str(o, "author");
|
|
e.desc = Util.str(o, "desc");
|
|
e.ino = Util.str(o, "ino");
|
|
e.ext = safeExt(o.optString("ext", ".mp3"));
|
|
e.mime = Util.str(o, "mime");
|
|
e.published = o.optLong("published", 0);
|
|
e.duration = o.optDouble("duration", 0);
|
|
e.size = o.optLong("size", 0);
|
|
return e;
|
|
}
|
|
}
|