记录清理机制
This commit is contained in:
@@ -437,6 +437,7 @@ dockge/komodo 等 docker compose UI 也有自动更新功能
|
||||
| VIDEOINFO_CACHE_MINUTES | 私人影库视频信息在内存中的缓存时长(分钟) | 正整数 | 1440(1天) |
|
||||
| NEXT_PUBLIC_ENABLE_SOURCE_SEARCH | 是否开启源站寻片功能 | true/false | true |
|
||||
| MAX_PLAY_RECORDS_PER_USER | 单个用户播放记录清理阈值(超过此数量将自动清理旧记录) | 正整数 | 100 |
|
||||
| MAX_MANGA_HISTORY_PER_USER | 单个用户漫画阅读历史保留上限 | 正整数 | 100 |
|
||||
| INIT_CONFIG | 初始配置(JSON 格式,包含 api_site、custom_category、lives 等) | JSON 字符串 | (空) |
|
||||
| CONFIG_SUBSCRIPTION_URL | 配置订阅 URL(Base58 编码的配置文件地址,优先级高于 INIT_CONFIG) | URL | (空) |
|
||||
| TMDB_API_KEY | TMDB API 密钥 | 任意字符串 | (空) |
|
||||
|
||||
+2
-1
@@ -2068,13 +2068,14 @@ export class D1Storage implements IStorage {
|
||||
async cleanupOldMangaReadRecords(userName: string): Promise<void> {
|
||||
try {
|
||||
const maxRecords = parseInt(process.env.MAX_MANGA_HISTORY_PER_USER || '100', 10);
|
||||
const threshold = maxRecords + 10;
|
||||
const countResult = await this.db
|
||||
.prepare('SELECT COUNT(*) as count FROM manga_read_records WHERE username = ?')
|
||||
.bind(userName)
|
||||
.first();
|
||||
|
||||
const count = Number(countResult?.count || 0);
|
||||
if (count <= maxRecords) return;
|
||||
if (count <= threshold) return;
|
||||
|
||||
await this.db
|
||||
.prepare(`
|
||||
|
||||
+19
-4
@@ -95,6 +95,8 @@ const PLAY_RECORDS_KEY = 'moontv_play_records';
|
||||
const FAVORITES_KEY = 'moontv_favorites';
|
||||
const MANGA_SHELF_KEY = 'moontv_manga_shelf';
|
||||
const MANGA_HISTORY_KEY = 'moontv_manga_history';
|
||||
const DEFAULT_MAX_MANGA_HISTORY_RECORDS = 100;
|
||||
const DEFAULT_MAX_MANGA_HISTORY_THRESHOLD = DEFAULT_MAX_MANGA_HISTORY_RECORDS + 10;
|
||||
const SEARCH_HISTORY_KEY = 'moontv_search_history';
|
||||
const MUSIC_PLAY_RECORDS_KEY = 'moontv_music_play_records';
|
||||
|
||||
@@ -1701,6 +1703,17 @@ export async function clearAllMangaShelf(): Promise<void> {
|
||||
window.dispatchEvent(new CustomEvent('mangaShelfUpdated', { detail: {} }));
|
||||
}
|
||||
|
||||
function trimMangaReadRecords(records: Record<string, MangaReadRecord>): Record<string, MangaReadRecord> {
|
||||
const entries = Object.entries(records);
|
||||
if (entries.length <= DEFAULT_MAX_MANGA_HISTORY_THRESHOLD) return records;
|
||||
|
||||
return Object.fromEntries(
|
||||
entries
|
||||
.sort(([, a], [, b]) => b.saveTime - a.saveTime)
|
||||
.slice(0, DEFAULT_MAX_MANGA_HISTORY_RECORDS)
|
||||
);
|
||||
}
|
||||
|
||||
export async function getAllMangaReadRecords(): Promise<Record<string, MangaReadRecord>> {
|
||||
if (typeof window === 'undefined') return {};
|
||||
|
||||
@@ -1748,8 +1761,9 @@ export async function saveMangaReadRecord(sourceId: string, mangaId: string, rec
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
const cached = cacheManager.getCachedMangaReadRecords() || {};
|
||||
cached[key] = record;
|
||||
cacheManager.cacheMangaReadRecords(cached);
|
||||
window.dispatchEvent(new CustomEvent('mangaHistoryUpdated', { detail: cached }));
|
||||
const trimmedRecords = trimMangaReadRecords(cached);
|
||||
cacheManager.cacheMangaReadRecords(trimmedRecords);
|
||||
window.dispatchEvent(new CustomEvent('mangaHistoryUpdated', { detail: trimmedRecords }));
|
||||
|
||||
try {
|
||||
await fetchWithAuth('/api/manga/history', {
|
||||
@@ -1766,8 +1780,9 @@ export async function saveMangaReadRecord(sourceId: string, mangaId: string, rec
|
||||
|
||||
const allRecords = await getAllMangaReadRecords();
|
||||
allRecords[key] = record;
|
||||
localStorage.setItem(MANGA_HISTORY_KEY, JSON.stringify(allRecords));
|
||||
window.dispatchEvent(new CustomEvent('mangaHistoryUpdated', { detail: allRecords }));
|
||||
const trimmedRecords = trimMangaReadRecords(allRecords);
|
||||
localStorage.setItem(MANGA_HISTORY_KEY, JSON.stringify(trimmedRecords));
|
||||
window.dispatchEvent(new CustomEvent('mangaHistoryUpdated', { detail: trimmedRecords }));
|
||||
}
|
||||
|
||||
export async function deleteMangaReadRecord(sourceId: string, mangaId: string): Promise<void> {
|
||||
|
||||
@@ -2037,13 +2037,14 @@ export class PostgresStorage implements IStorage {
|
||||
async cleanupOldMangaReadRecords(userName: string): Promise<void> {
|
||||
try {
|
||||
const maxRecords = parseInt(process.env.MAX_MANGA_HISTORY_PER_USER || '100', 10);
|
||||
const threshold = maxRecords + 10;
|
||||
const countResult = await this.db
|
||||
.prepare('SELECT COUNT(*) as count FROM manga_read_records WHERE username = $1')
|
||||
.bind(userName)
|
||||
.first();
|
||||
|
||||
const count = Number(countResult?.count || 0);
|
||||
if (count <= maxRecords) return;
|
||||
if (count <= threshold) return;
|
||||
|
||||
await this.db
|
||||
.prepare(`
|
||||
|
||||
@@ -1557,6 +1557,8 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
async cleanupOldMangaReadRecords(userName: string): Promise<void> {
|
||||
const records = await this.getAllMangaReadRecords(userName);
|
||||
const maxRecords = parseInt(process.env.MAX_MANGA_HISTORY_PER_USER || '100', 10);
|
||||
const threshold = maxRecords + 10;
|
||||
if (Object.keys(records).length <= threshold) return;
|
||||
const keys = Object.entries(records)
|
||||
.sort(([, a], [, b]) => b.saveTime - a.saveTime)
|
||||
.slice(maxRecords)
|
||||
|
||||
Reference in New Issue
Block a user