/* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ import { AdminConfig } from './admin.types'; import { Favorite, IStorage, PlayRecord } from './types'; // 搜索历史最大条数 const SEARCH_HISTORY_LIMIT = 20; // D1 数据库接口 interface D1Database { prepare(sql: string): D1PreparedStatement; exec(sql: string): Promise; batch(statements: D1PreparedStatement[]): Promise; } interface D1PreparedStatement { bind(...values: any[]): D1PreparedStatement; first(colName?: string): Promise; run(): Promise; all(): Promise>; } interface D1Result { results: T[]; success: boolean; error?: string; meta: { changed_db: boolean; changes: number; last_row_id: number; duration: number; }; } interface D1ExecResult { count: number; duration: number; } // 获取全局D1数据库实例 function getD1Database(): D1Database { return (process.env as any).DB as D1Database; } export class D1Storage implements IStorage { private db: D1Database | null = null; private async getDatabase(): Promise { if (!this.db) { this.db = getD1Database(); } return this.db; } // 播放记录相关 async getPlayRecord( userName: string, key: string ): Promise { try { const db = await this.getDatabase(); const result = await db .prepare('SELECT * FROM play_records WHERE username = ? AND key = ?') .bind(userName, key) .first(); if (!result) return null; return { title: result.title, source_name: result.source_name, cover: result.cover, year: result.year, index: result.index_episode, total_episodes: result.total_episodes, play_time: result.play_time, total_time: result.total_time, save_time: result.save_time, search_title: result.search_title || undefined, }; } catch (err) { console.error('Failed to get play record:', err); throw err; } } async setPlayRecord( userName: string, key: string, record: PlayRecord ): Promise { try { const db = await this.getDatabase(); await db .prepare( ` INSERT OR REPLACE INTO play_records (username, key, title, source_name, cover, year, index_episode, total_episodes, play_time, total_time, save_time, search_title) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ` ) .bind( userName, key, record.title, record.source_name, record.cover, record.year, record.index, record.total_episodes, record.play_time, record.total_time, record.save_time, record.search_title || null ) .run(); } catch (err) { console.error('Failed to set play record:', err); throw err; } } async getAllPlayRecords( userName: string ): Promise> { try { const db = await this.getDatabase(); const result = await db .prepare( 'SELECT * FROM play_records WHERE username = ? ORDER BY save_time DESC' ) .bind(userName) .all(); const records: Record = {}; result.results.forEach((row: any) => { records[row.key] = { title: row.title, source_name: row.source_name, cover: row.cover, year: row.year, index: row.index_episode, total_episodes: row.total_episodes, play_time: row.play_time, total_time: row.total_time, save_time: row.save_time, search_title: row.search_title || undefined, }; }); return records; } catch (err) { console.error('Failed to get all play records:', err); throw err; } } async deletePlayRecord(userName: string, key: string): Promise { try { const db = await this.getDatabase(); await db .prepare('DELETE FROM play_records WHERE username = ? AND key = ?') .bind(userName, key) .run(); } catch (err) { console.error('Failed to delete play record:', err); throw err; } } // 收藏相关 async getFavorite(userName: string, key: string): Promise { try { const db = await this.getDatabase(); const result = await db .prepare('SELECT * FROM favorites WHERE username = ? AND key = ?') .bind(userName, key) .first(); if (!result) return null; return { title: result.title, source_name: result.source_name, cover: result.cover, year: result.year, total_episodes: result.total_episodes, save_time: result.save_time, search_title: result.search_title, }; } catch (err) { console.error('Failed to get favorite:', err); throw err; } } async setFavorite( userName: string, key: string, favorite: Favorite ): Promise { try { const db = await this.getDatabase(); await db .prepare( ` INSERT OR REPLACE INTO favorites (username, key, title, source_name, cover, year, total_episodes, save_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ` ) .bind( userName, key, favorite.title, favorite.source_name, favorite.cover, favorite.year, favorite.total_episodes, favorite.save_time ) .run(); } catch (err) { console.error('Failed to set favorite:', err); throw err; } } async getAllFavorites(userName: string): Promise> { try { const db = await this.getDatabase(); const result = await db .prepare( 'SELECT * FROM favorites WHERE username = ? ORDER BY save_time DESC' ) .bind(userName) .all(); const favorites: Record = {}; result.results.forEach((row: any) => { favorites[row.key] = { title: row.title, source_name: row.source_name, cover: row.cover, year: row.year, total_episodes: row.total_episodes, save_time: row.save_time, search_title: row.search_title, }; }); return favorites; } catch (err) { console.error('Failed to get all favorites:', err); throw err; } } async deleteFavorite(userName: string, key: string): Promise { try { const db = await this.getDatabase(); await db .prepare('DELETE FROM favorites WHERE username = ? AND key = ?') .bind(userName, key) .run(); } catch (err) { console.error('Failed to delete favorite:', err); throw err; } } // 用户相关 async registerUser(userName: string, password: string): Promise { try { const db = await this.getDatabase(); await db .prepare('INSERT INTO users (username, password) VALUES (?, ?)') .bind(userName, password) .run(); } catch (err) { console.error('Failed to register user:', err); throw err; } } async verifyUser(userName: string, password: string): Promise { try { const db = await this.getDatabase(); const result = await db .prepare('SELECT password FROM users WHERE username = ?') .bind(userName) .first<{ password: string }>(); return result?.password === password; } catch (err) { console.error('Failed to verify user:', err); throw err; } } async checkUserExist(userName: string): Promise { try { const db = await this.getDatabase(); const result = await db .prepare('SELECT 1 FROM users WHERE username = ?') .bind(userName) .first(); return result !== null; } catch (err) { console.error('Failed to check user existence:', err); throw err; } } async changePassword(userName: string, newPassword: string): Promise { try { const db = await this.getDatabase(); await db .prepare('UPDATE users SET password = ? WHERE username = ?') .bind(newPassword, userName) .run(); } catch (err) { console.error('Failed to change password:', err); throw err; } } async deleteUser(userName: string): Promise { try { const db = await this.getDatabase(); const statements = [ db.prepare('DELETE FROM users WHERE username = ?').bind(userName), db .prepare('DELETE FROM play_records WHERE username = ?') .bind(userName), db.prepare('DELETE FROM favorites WHERE username = ?').bind(userName), db .prepare('DELETE FROM search_history WHERE username = ?') .bind(userName), ]; await db.batch(statements); } catch (err) { console.error('Failed to delete user:', err); throw err; } } // 搜索历史相关 async getSearchHistory(userName: string): Promise { try { const db = await this.getDatabase(); const result = await db .prepare( 'SELECT keyword FROM search_history WHERE username = ? ORDER BY created_at DESC LIMIT ?' ) .bind(userName, SEARCH_HISTORY_LIMIT) .all<{ keyword: string }>(); return result.results.map((row) => row.keyword); } catch (err) { console.error('Failed to get search history:', err); throw err; } } async addSearchHistory(userName: string, keyword: string): Promise { try { const db = await this.getDatabase(); // 先删除可能存在的重复记录 await db .prepare( 'DELETE FROM search_history WHERE username = ? AND keyword = ?' ) .bind(userName, keyword) .run(); // 添加新记录 await db .prepare('INSERT INTO search_history (username, keyword) VALUES (?, ?)') .bind(userName, keyword) .run(); // 保持历史记录条数限制 await db .prepare( ` DELETE FROM search_history WHERE username = ? AND id NOT IN ( SELECT id FROM search_history WHERE username = ? ORDER BY created_at DESC LIMIT ? ) ` ) .bind(userName, userName, SEARCH_HISTORY_LIMIT) .run(); } catch (err) { console.error('Failed to add search history:', err); throw err; } } async deleteSearchHistory(userName: string, keyword?: string): Promise { try { const db = await this.getDatabase(); if (keyword) { await db .prepare( 'DELETE FROM search_history WHERE username = ? AND keyword = ?' ) .bind(userName, keyword) .run(); } else { await db .prepare('DELETE FROM search_history WHERE username = ?') .bind(userName) .run(); } } catch (err) { console.error('Failed to delete search history:', err); throw err; } } // 用户列表 async getAllUsers(): Promise { try { const db = await this.getDatabase(); const result = await db .prepare('SELECT username FROM users ORDER BY created_at ASC') .all<{ username: string }>(); return result.results.map((row) => row.username); } catch (err) { console.error('Failed to get all users:', err); throw err; } } // 管理员配置相关 async getAdminConfig(): Promise { try { const db = await this.getDatabase(); const result = await db .prepare('SELECT config FROM admin_config WHERE id = 1') .first<{ config: string }>(); if (!result) return null; return JSON.parse(result.config) as AdminConfig; } catch (err) { console.error('Failed to get admin config:', err); throw err; } } async setAdminConfig(config: AdminConfig): Promise { try { const db = await this.getDatabase(); await db .prepare( 'INSERT OR REPLACE INTO admin_config (id, config) VALUES (1, ?)' ) .bind(JSON.stringify(config)) .run(); } catch (err) { console.error('Failed to set admin config:', err); throw err; } } }