Import miniabs 1.0 source
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
4fe9eed870
78 files changed
+5800
No files matched your search
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user