feat: admin api cookie

This commit is contained in:
shinya
2025-07-09 22:42:53 +08:00
parent 7edc673c9f
commit 2bbb67ac9c
16 changed files with 215 additions and 384 deletions

57
src/lib/auth.ts Normal file
View File

@@ -0,0 +1,57 @@
import { NextRequest } from 'next/server';
// 从cookie获取认证信息 (服务端使用)
export function getAuthInfoFromCookie(request: NextRequest): {
password?: string;
username?: string;
signature?: string;
timestamp?: number;
} | null {
const authCookie = request.cookies.get('auth');
if (!authCookie) {
return null;
}
try {
const decoded = decodeURIComponent(authCookie.value);
const authData = JSON.parse(decoded);
return authData;
} catch (error) {
return null;
}
}
// 从cookie获取认证信息 (客户端使用)
export function getAuthInfoFromBrowserCookie(): {
password?: string;
username?: string;
signature?: string;
timestamp?: number;
} | null {
if (typeof window === 'undefined') {
return null;
}
try {
// 解析 document.cookie
const cookies = document.cookie.split(';').reduce((acc, cookie) => {
const [key, value] = cookie.trim().split('=');
if (key && value) {
acc[key] = value;
}
return acc;
}, {} as Record<string, string>);
const authCookie = cookies['auth'];
if (!authCookie) {
return null;
}
const decoded = decodeURIComponent(authCookie);
const authData = JSON.parse(decoded);
return authData;
} catch (error) {
return null;
}
}

View File

@@ -24,27 +24,11 @@ export interface PlayRecord {
play_time: number; // 播放进度(秒)
total_time: number; // 总进度(秒)
save_time: number; // 记录保存时间(时间戳)
user_id: number; // 用户 ID本地存储情况下恒为 0
}
// ---- 常量 ----
const PLAY_RECORDS_KEY = 'moontv_play_records';
// +++ 新增:获取当前用户名工具函数 +++
/**
* 从 localStorage 中读取当前用户名
* 如果不存在则返回 undefined
*/
function getUsername(): string | undefined {
if (typeof window === 'undefined') return undefined;
try {
const name = localStorage.getItem('username')?.trim();
return name || undefined;
} catch {
return undefined;
}
}
// ---- 环境变量 ----
const STORAGE_TYPE = (() => {
const raw =
@@ -84,10 +68,7 @@ export function generateStorageKey(source: string, id: string): string {
export async function getAllPlayRecords(): Promise<Record<string, PlayRecord>> {
// 若配置标明使用数据库,则从后端 API 拉取
if (STORAGE_TYPE !== 'localstorage') {
const user = getUsername();
return fetchFromApi<Record<string, PlayRecord>>(
`/api/playrecords?user=${encodeURIComponent(user ?? '')}`
);
return fetchFromApi<Record<string, PlayRecord>>(`/api/playrecords`);
}
// 默认 / localstorage 流程
@@ -112,21 +93,19 @@ export async function getAllPlayRecords(): Promise<Record<string, PlayRecord>> {
export async function savePlayRecord(
source: string,
id: string,
record: Omit<PlayRecord, 'user_id'>
record: PlayRecord
): Promise<void> {
const key = generateStorageKey(source, id);
const fullRecord: PlayRecord = { ...record, user_id: 0 };
// 若配置标明使用数据库,则通过 API 保存
if (STORAGE_TYPE !== 'localstorage') {
try {
const user = getUsername();
const res = await fetch('/api/playrecords', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ user, key, record: fullRecord }),
body: JSON.stringify({ key, record }),
});
if (!res.ok) throw new Error(`保存播放记录失败: ${res.status}`);
} catch (err) {
@@ -144,7 +123,7 @@ export async function savePlayRecord(
try {
const allRecords = await getAllPlayRecords();
allRecords[key] = fullRecord;
allRecords[key] = record;
localStorage.setItem(PLAY_RECORDS_KEY, JSON.stringify(allRecords));
} catch (err) {
console.error('保存播放记录失败:', err);
@@ -165,9 +144,7 @@ export async function deletePlayRecord(
if (STORAGE_TYPE !== 'localstorage') {
try {
const res = await fetch(
`/api/playrecords?key=${encodeURIComponent(
key
)}&user=${encodeURIComponent(getUsername() ?? '')}`,
`/api/playrecords?key=${encodeURIComponent(key)}`,
{
method: 'DELETE',
}
@@ -206,10 +183,7 @@ export async function getSearchHistory(): Promise<string[]> {
// 如果配置为使用数据库,则从后端 API 获取
if (STORAGE_TYPE !== 'localstorage') {
try {
const user = getUsername();
return fetchFromApi<string[]>(
`/api/searchhistory?user=${encodeURIComponent(user ?? '')}`
);
return fetchFromApi<string[]>(`/api/searchhistory`);
} catch (err) {
console.error('获取搜索历史失败:', err);
return [];
@@ -243,13 +217,12 @@ export async function addSearchHistory(keyword: string): Promise<void> {
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
try {
const user = getUsername();
await fetch('/api/searchhistory', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ keyword: trimmed, user: user ?? '' }),
body: JSON.stringify({ keyword: trimmed }),
});
} catch (err) {
console.error('保存搜索历史失败:', err);
@@ -280,8 +253,7 @@ export async function clearSearchHistory(): Promise<void> {
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
try {
const user = getUsername();
await fetch(`/api/searchhistory?user=${encodeURIComponent(user ?? '')}`, {
await fetch(`/api/searchhistory`, {
method: 'DELETE',
});
} catch (err) {
@@ -305,15 +277,9 @@ export async function deleteSearchHistory(keyword: string): Promise<void> {
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
try {
const user = getUsername();
await fetch(
`/api/searchhistory?user=${encodeURIComponent(
user ?? ''
)}&keyword=${encodeURIComponent(trimmed)}`,
{
method: 'DELETE',
}
);
await fetch(`/api/searchhistory?keyword=${encodeURIComponent(trimmed)}`, {
method: 'DELETE',
});
} catch (err) {
console.error('删除搜索历史失败:', err);
}
@@ -342,7 +308,6 @@ export interface Favorite {
cover: string;
total_episodes: number;
save_time: number;
user_id: number; // 本地存储情况下恒为 0
}
// 收藏在 localStorage 中使用的 key
@@ -354,10 +319,7 @@ const FAVORITES_KEY = 'moontv_favorites';
export async function getAllFavorites(): Promise<Record<string, Favorite>> {
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
const user = getUsername();
return fetchFromApi<Record<string, Favorite>>(
`/api/favorites?user=${encodeURIComponent(user ?? '')}`
);
return fetchFromApi<Record<string, Favorite>>(`/api/favorites`);
}
// localStorage 模式
@@ -381,21 +343,19 @@ export async function getAllFavorites(): Promise<Record<string, Favorite>> {
export async function saveFavorite(
source: string,
id: string,
favorite: Omit<Favorite, 'user_id'>
favorite: Favorite
): Promise<void> {
const key = generateStorageKey(source, id);
const fullFavorite: Favorite = { ...favorite, user_id: 0 };
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
try {
const user = getUsername();
const res = await fetch('/api/favorites', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ user, key, favorite: fullFavorite }),
body: JSON.stringify({ key, favorite }),
});
if (!res.ok) throw new Error(`保存收藏失败: ${res.status}`);
} catch (err) {
@@ -413,7 +373,7 @@ export async function saveFavorite(
try {
const allFavorites = await getAllFavorites();
allFavorites[key] = fullFavorite;
allFavorites[key] = favorite;
localStorage.setItem(FAVORITES_KEY, JSON.stringify(allFavorites));
} catch (err) {
console.error('保存收藏失败:', err);
@@ -433,15 +393,9 @@ export async function deleteFavorite(
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
try {
const user = getUsername();
const res = await fetch(
`/api/favorites?key=${encodeURIComponent(
key
)}&user=${encodeURIComponent(user ?? '')}`,
{
method: 'DELETE',
}
);
const res = await fetch(`/api/favorites?key=${encodeURIComponent(key)}`, {
method: 'DELETE',
});
if (!res.ok) throw new Error(`删除收藏失败: ${res.status}`);
} catch (err) {
console.error('删除收藏到数据库失败:', err);
@@ -478,12 +432,7 @@ export async function isFavorited(
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
try {
const user = getUsername();
const res = await fetch(
`/api/favorites?key=${encodeURIComponent(
key
)}&user=${encodeURIComponent(user ?? '')}`
);
const res = await fetch(`/api/favorites?key=${encodeURIComponent(key)}`);
if (!res.ok) return false;
const data = await res.json();
return !!data;
@@ -505,7 +454,7 @@ export async function isFavorited(
export async function toggleFavorite(
source: string,
id: string,
favoriteData?: Omit<Favorite, 'user_id'>
favoriteData?: Favorite
): Promise<boolean> {
const already = await isFavorited(source, id);
@@ -528,9 +477,8 @@ export async function toggleFavorite(
export async function clearAllPlayRecords(): Promise<void> {
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
const user = getUsername();
try {
await fetch(`/api/playrecords?user=${encodeURIComponent(user ?? '')}`, {
await fetch(`/api/playrecords`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
});
@@ -551,9 +499,8 @@ export async function clearAllPlayRecords(): Promise<void> {
export async function clearAllFavorites(): Promise<void> {
// 数据库模式
if (STORAGE_TYPE !== 'localstorage') {
const user = getUsername();
try {
await fetch(`/api/favorites?user=${encodeURIComponent(user ?? '')}`, {
await fetch(`/api/favorites`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
});

View File

@@ -63,8 +63,7 @@ export class DbManager {
record: Omit<PlayRecord, 'user_id'>
): Promise<void> {
const key = generateStorageKey(source, id);
const fullRecord: PlayRecord = { ...record, user_id: 0 };
await this.storage.setPlayRecord(userName, key, fullRecord);
await this.storage.setPlayRecord(userName, key, record);
}
async getAllPlayRecords(userName: string): Promise<{
@@ -96,11 +95,10 @@ export class DbManager {
userName: string,
source: string,
id: string,
favorite: Omit<Favorite, 'user_id'>
favorite: Favorite
): Promise<void> {
const key = generateStorageKey(source, id);
const fullFavorite: Favorite = { ...favorite, user_id: 0 };
await this.storage.setFavorite(userName, key, fullFavorite);
await this.storage.setFavorite(userName, key, favorite);
}
async getAllFavorites(

View File

@@ -10,7 +10,6 @@ export interface PlayRecord {
play_time: number; // 播放进度(秒)
total_time: number; // 总进度(秒)
save_time: number; // 记录保存时间(时间戳)
user_id: number; // 用户IDlocalStorage情况下全部为0
}
// 收藏数据结构
@@ -19,7 +18,6 @@ export interface Favorite {
total_episodes: number; // 总集数
title: string;
cover: string;
user_id: number; // 用户IDlocalStorage情况下全部为0
save_time: number; // 记录保存时间(时间戳)
}