Import miniabs 1.0 source

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xockoandClaude Opus 5.5 committed 2026-10-14 19:26:04 +02:00
commit 4fe9eed870
78 files changed
+5800

No files matched your search

+146
View File
@@ -0,0 +1,146 @@
package com.miniabs;
import java.util.UUID;
import org.json.JSONObject;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Base64;
/** Settings and sign-in state. */
final class Prefs {
static final String MODE_JWT = "jwt"; // ABS 2.26+: short access token + refresh token
static final String MODE_LEGACY = "legacy"; // older servers: one long-lived token
static final String MODE_KEY = "key"; // API key pasted by the user
private static Prefs instance;
final SharedPreferences sp;
private Prefs(Context c) {
sp = PreferenceManager.getDefaultSharedPreferences(c);
}
static synchronized Prefs get(Context c) {
if (instance == null) instance = new Prefs(c.getApplicationContext());
return instance;
}
private String s(String k) {
return sp.getString(k, "");
}
String server() { return s("server"); }
String username() { return s("username"); }
String token() { return s("access"); }
String refreshToken() { return s("refresh"); }
String mode() { return s("mode"); }
boolean trustAll() { return sp.getBoolean("trust_all", false); }
boolean wifiOnly() { return sp.getBoolean("wifi_only", true); }
boolean covers() { return sp.getBoolean("covers", true); }
String libraryId() { return s("library_id"); }
String libraryName() { return s("library_name"); }
int skipBack() { return num("skip_back", 15); }
int skipFwd() { return num("skip_fwd", 30); }
private int num(String k, int def) {
try {
return Integer.parseInt(sp.getString(k, String.valueOf(def)));
} catch (Exception e) {
return def;
}
}
boolean loggedIn() {
return server().length() > 0 && token().length() > 0;
}
boolean canRefresh() {
return MODE_JWT.equals(mode()) && refreshToken().length() > 0;
}
void setServer(String server, boolean trustAll) {
sp.edit().putString("server", server).putBoolean("trust_all", trustAll).commit();
}
synchronized void setAuth(String user, String mode, String access, String refresh) {
SharedPreferences.Editor e = sp.edit()
.putString("username", user)
.putString("mode", mode)
.putString("refresh", refresh == null ? "" : refresh);
putToken(e, access);
e.commit();
}
synchronized void setTokens(String access, String refresh) {
SharedPreferences.Editor e = sp.edit();
if (refresh != null && refresh.length() > 0) e.putString("refresh", refresh);
putToken(e, access);
e.commit();
}
/** Stores the token with its lifetime measured on this phone's clock (old phones' clocks drift). */
private void putToken(SharedPreferences.Editor e, String access) {
long lifetime = 0;
try {
String[] parts = access.split("\\.");
if (parts.length == 3) {
JSONObject p = new JSONObject(new String(Base64.decode(parts[1], Base64.URL_SAFE), "UTF-8"));
long exp = p.optLong("exp", 0), iat = p.optLong("iat", 0);
if (exp > 0 && iat > 0 && exp > iat) lifetime = exp - iat;
}
} catch (Exception ignored) {
// not a JWT, or unreadable: treat as non-expiring
}
e.putString("access", access)
.putLong("token_lifetime", lifetime)
.putLong("token_obtained", System.currentTimeMillis());
}
/** Seconds left on the access token; Long.MAX_VALUE when it doesn't expire. */
long tokenSecondsLeft() {
long life = sp.getLong("token_lifetime", 0);
if (life <= 0) return Long.MAX_VALUE;
long age = (System.currentTimeMillis() - sp.getLong("token_obtained", 0)) / 1000;
if (age < 0) return 0; // clock went backwards; be safe and refresh
return life - age;
}
long tokenObtainedAt() {
return sp.getLong("token_obtained", 0);
}
void logout() {
sp.edit().remove("access").remove("refresh").remove("mode")
.remove("library_id").remove("library_name").remove("last_episode").commit();
}
void setLibrary(String id, String name) {
sp.edit().putString("library_id", id).putString("library_name", name).commit();
}
String deviceId() {
String id = s("device_id");
if (id.length() == 0) {
id = UUID.randomUUID().toString();
sp.edit().putString("device_id", id).commit();
}
return id;
}
void setLastEpisode(Episode e) {
sp.edit().putString("last_episode", e == null ? "" : e.toJson().toString()).commit();
}
Episode lastEpisode() {
String j = s("last_episode");
if (j.length() == 0) return null;
try {
return Episode.fromStored(new JSONObject(j));
} catch (Exception e) {
return null;
}
}
}