iptv-app/ui/src/storage/adapters/androidStorage.js
2026-02-24 23:00:33 +08:00

202 lines
4.8 KiB
JavaScript

import { IStorage } from "./implement";
export class AndroidStorage extends IStorage {
constructor() {
super();
this.memoryCache = new Map(); // 内存缓存
}
// 检查 Android 接口是否可用
isAvailable() {
return typeof window.AndroidAsset !== "undefined";
}
// 调用原生接口
async callNative(method, ...args) {
if (!this.isAvailable()) {
throw new Error("AndroidAsset not available");
}
return window.AndroidAsset[method](...args);
}
// 基础操作 (使用 localStorage 作为后备)
async get(key) {
try {
const value = await this.callNative("getItem", key);
return value ? JSON.parse(value) : null;
} catch {
return this.memoryCache.get(key) || null;
}
}
async set(key, value) {
this.memoryCache.set(key, value);
try {
await this.callNative("setItem", key, JSON.stringify(value));
} catch {
// 忽略原生存储失败
}
}
async remove(key) {
this.memoryCache.delete(key);
try {
await this.callNative("removeItem", key);
} catch {}
}
async clear() {
this.memoryCache.clear();
try {
await this.callNative("clear");
} catch {}
}
// 频道数据 (使用专用接口)
async getChannels() {
try {
const data = await this.callNative("readChannelData");
if (data && !data.startsWith("ERROR:")) {
// 解析频道数据并缓存
const channels = this.parseChannelData(data);
this.memoryCache.set("channels", channels);
return channels;
}
} catch {}
return this.memoryCache.get("channels") || [];
}
async setChannels(channels) {
this.memoryCache.set("channels", channels);
// 原生端通过文件存储,这里只更新内存缓存
await this.setCacheMeta(
"channels",
new CacheMeta({
key: "channels",
updatedAt: Date.now(),
size: channels.length,
}),
);
}
parseChannelData(text) {
// 简单的 TXT 格式解析
const channels = [];
const lines = text.split("\n");
let currentGroup = "";
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
if (trimmed.includes("#genre#")) {
currentGroup = trimmed.split(",")[0];
} else if (trimmed.includes(",")) {
const [name, url] = trimmed.split(",").map((s) => s.trim());
if (name && url) {
const existing = channels.find(
(c) => c.name === name && c.group === currentGroup,
);
if (existing) {
existing.urls.push(url);
} else {
channels.push(
new Channel({
id: `${currentGroup}_${name}`,
name,
group: currentGroup,
urls: [url],
}),
);
}
}
}
}
return channels;
}
async getGroups() {
const channels = await this.getChannels();
const groups = new Set(channels.map((c) => c.group));
return Array.from(groups);
}
// 订阅源
async getSubscriptions() {
return (await this.get("subscriptions")) || [];
}
async setSubscriptions(subs) {
await this.set("subscriptions", subs);
}
// 线路有效性 (使用 SharedPreferences)
async getValidity(url) {
const all = await this.getAllValidity();
return all.find((v) => v.url === url);
}
async setValidity(url, validity) {
const all = await this.getAllValidity();
const index = all.findIndex((v) => v.url === url);
if (index >= 0) {
all[index] = { ...validity, url };
} else {
all.push({ ...validity, url });
}
await this.set("validity", all);
}
async getAllValidity() {
return (await this.get("validity")) || [];
}
// 用户偏好
async getPreferences() {
return (await this.get("preferences")) || new Preferences();
}
async setPreferences(prefs) {
await this.set("preferences", prefs);
}
// 播放历史
async getHistory(limit = 50) {
const all = (await this.get("history")) || [];
return all.slice(-limit).reverse();
}
async addHistory(item) {
const all = (await this.get("history")) || [];
all.push(item);
// 保留最近 500 条
if (all.length > 500) {
all.splice(0, all.length - 500);
}
await this.set("history", all);
}
async clearHistory() {
await this.remove("history");
}
// 缓存元数据
async getCacheMeta(key) {
const all = (await this.get("cacheMeta")) || {};
return all[key];
}
async setCacheMeta(key, meta) {
const all = (await this.get("cacheMeta")) || {};
all[key] = { ...meta, key };
await this.set("cacheMeta", all);
}
async isCacheValid(key, ttl) {
const meta = await this.getCacheMeta(key);
if (!meta || !meta.updatedAt) return false;
return Date.now() - meta.updatedAt < ttl;
}
}