test prod emby
This commit is contained in:
@@ -9,7 +9,10 @@ export const runtime = 'nodejs';
|
|||||||
*/
|
*/
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
|
console.log('[Emby Sources API] 开始获取Emby源列表');
|
||||||
const sources = await embyManager.getEnabledSources();
|
const sources = await embyManager.getEnabledSources();
|
||||||
|
console.log('[Emby Sources API] 获取到的源数量:', sources.length);
|
||||||
|
console.log('[Emby Sources API] 源详情:', JSON.stringify(sources, null, 2));
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
sources: sources.map(s => ({
|
sources: sources.map(s => ({
|
||||||
|
|||||||
@@ -45,11 +45,18 @@ export async function PATCH(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const storage = getStorage();
|
const storage = getStorage();
|
||||||
const userInfo = await storage.getUserInfoV2(authInfo.username);
|
|
||||||
|
|
||||||
// 检查权限:只有管理员和站长可以操作
|
// 检查权限:只有管理员和站长可以操作
|
||||||
if (userInfo?.role !== 'admin' && userInfo?.role !== 'owner') {
|
if (storage.getUserInfoV2) {
|
||||||
return NextResponse.json({ error: '无权限操作' }, { status: 403 });
|
const userInfo = await storage.getUserInfoV2(authInfo.username);
|
||||||
|
if (userInfo?.role !== 'admin' && userInfo?.role !== 'owner') {
|
||||||
|
return NextResponse.json({ error: '无权限操作' }, { status: 403 });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果不支持 getUserInfoV2,只允许站长操作
|
||||||
|
if (authInfo.username !== process.env.USERNAME) {
|
||||||
|
return NextResponse.json({ error: '无权限操作' }, { status: 403 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
@@ -116,11 +123,18 @@ export async function DELETE(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const storage = getStorage();
|
const storage = getStorage();
|
||||||
const userInfo = await storage.getUserInfoV2(authInfo.username);
|
|
||||||
|
|
||||||
// 检查权限:只有管理员和站长可以删除
|
// 检查权限:只有管理员和站长可以删除
|
||||||
if (userInfo?.role !== 'admin' && userInfo?.role !== 'owner') {
|
if (storage.getUserInfoV2) {
|
||||||
return NextResponse.json({ error: '无权限操作' }, { status: 403 });
|
const userInfo = await storage.getUserInfoV2(authInfo.username);
|
||||||
|
if (userInfo?.role !== 'admin' && userInfo?.role !== 'owner') {
|
||||||
|
return NextResponse.json({ error: '无权限操作' }, { status: 403 });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果不支持 getUserInfoV2,只允许站长操作
|
||||||
|
if (authInfo.username !== process.env.USERNAME) {
|
||||||
|
return NextResponse.json({ error: '无权限操作' }, { status: 403 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const movieRequest = await storage.getMovieRequest(params.id);
|
const movieRequest = await storage.getMovieRequest(params.id);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
// 列表页不返回 requestedBy
|
// 列表页不返回 requestedBy
|
||||||
if (!detail) {
|
if (!detail) {
|
||||||
requests = requests.map(r => ({ ...r, requestedBy: undefined }));
|
requests = requests.map(r => ({ ...r, requestedBy: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按求片人数和时间排序
|
// 按求片人数和时间排序
|
||||||
@@ -92,15 +92,17 @@ export async function POST(request: NextRequest) {
|
|||||||
const cooldownSeconds = config.SiteConfig.MovieRequestCooldown ?? 3600;
|
const cooldownSeconds = config.SiteConfig.MovieRequestCooldown ?? 3600;
|
||||||
const rateLimit = cooldownSeconds * 1000;
|
const rateLimit = cooldownSeconds * 1000;
|
||||||
|
|
||||||
const userInfo = await storage.getUserInfoV2(authInfo.username);
|
if (storage.getUserInfoV2) {
|
||||||
if (userInfo?.last_movie_request_time) {
|
const userInfo = await storage.getUserInfoV2(authInfo.username);
|
||||||
const elapsed = Date.now() - userInfo.last_movie_request_time;
|
if (userInfo?.last_movie_request_time) {
|
||||||
if (elapsed < rateLimit) {
|
const elapsed = Date.now() - userInfo.last_movie_request_time;
|
||||||
const remaining = Math.ceil((rateLimit - elapsed) / 60000);
|
if (elapsed < rateLimit) {
|
||||||
return NextResponse.json(
|
const remaining = Math.ceil((rateLimit - elapsed) / 60000);
|
||||||
{ error: `操作太频繁,请${remaining}分钟后再试` },
|
return NextResponse.json(
|
||||||
{ status: 429 }
|
{ error: `操作太频繁,请${remaining}分钟后再试` },
|
||||||
);
|
{ status: 429 }
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,15 +175,17 @@ export async function POST(request: NextRequest) {
|
|||||||
await storage.addUserMovieRequest(authInfo.username, newRequest.id);
|
await storage.addUserMovieRequest(authInfo.username, newRequest.id);
|
||||||
|
|
||||||
// 更新频率限制 - 保存到用户信息的 hash 中
|
// 更新频率限制 - 保存到用户信息的 hash 中
|
||||||
await storage.client.hSet(
|
if ('client' in storage && storage.client && typeof (storage.client as any).hSet === 'function') {
|
||||||
`user:${authInfo.username}:info`,
|
await (storage.client as any).hSet(
|
||||||
'last_movie_request_time',
|
`user:${authInfo.username}:info`,
|
||||||
Date.now().toString()
|
'last_movie_request_time',
|
||||||
);
|
Date.now().toString()
|
||||||
|
);
|
||||||
|
|
||||||
// 清除用户信息缓存,确保下次读取到最新数据
|
// 清除用户信息缓存,确保下次读取到最新数据
|
||||||
const { userInfoCache } = await import('@/lib/user-cache');
|
const { userInfoCache } = await import('@/lib/user-cache');
|
||||||
userInfoCache?.delete(authInfo.username);
|
userInfoCache?.delete(authInfo.username);
|
||||||
|
}
|
||||||
|
|
||||||
// 给站长发送通知
|
// 给站长发送通知
|
||||||
const ownerUsername = process.env.USERNAME;
|
const ownerUsername = process.env.USERNAME;
|
||||||
|
|||||||
@@ -302,11 +302,18 @@ async function getInitConfig(configFile: string, subConfig: {
|
|||||||
export async function getConfig(): Promise<AdminConfig> {
|
export async function getConfig(): Promise<AdminConfig> {
|
||||||
// 直接使用内存缓存
|
// 直接使用内存缓存
|
||||||
if (cachedConfig) {
|
if (cachedConfig) {
|
||||||
|
console.log('[Config] 使用缓存的配置');
|
||||||
|
console.log('[Config] 缓存中EmbyConfig存在:', !!cachedConfig.EmbyConfig);
|
||||||
|
console.log('[Config] 缓存中EmbyConfig.Sources存在:', !!cachedConfig.EmbyConfig?.Sources);
|
||||||
|
if (cachedConfig.EmbyConfig?.Sources) {
|
||||||
|
console.log('[Config] 缓存中Sources长度:', cachedConfig.EmbyConfig.Sources.length);
|
||||||
|
}
|
||||||
return cachedConfig;
|
return cachedConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果正在初始化,等待初始化完成
|
// 如果正在初始化,等待初始化完成
|
||||||
if (configInitPromise) {
|
if (configInitPromise) {
|
||||||
|
console.log('[Config] 等待配置初始化完成');
|
||||||
return configInitPromise;
|
return configInitPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -43,14 +43,24 @@ class EmbyManager {
|
|||||||
*/
|
*/
|
||||||
private async getSources(): Promise<EmbySourceConfig[]> {
|
private async getSources(): Promise<EmbySourceConfig[]> {
|
||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
|
console.log('[EmbyManager] 获取配置完成');
|
||||||
|
console.log('[EmbyManager] EmbyConfig存在:', !!config.EmbyConfig);
|
||||||
|
console.log('[EmbyManager] EmbyConfig.Sources存在:', !!config.EmbyConfig?.Sources);
|
||||||
|
console.log('[EmbyManager] EmbyConfig.Sources是数组:', Array.isArray(config.EmbyConfig?.Sources));
|
||||||
|
if (config.EmbyConfig?.Sources) {
|
||||||
|
console.log('[EmbyManager] Sources长度:', config.EmbyConfig.Sources.length);
|
||||||
|
console.log('[EmbyManager] Sources内容:', JSON.stringify(config.EmbyConfig.Sources, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
// 如果是新格式(Sources数组)
|
// 如果是新格式(Sources数组)
|
||||||
if (config.EmbyConfig?.Sources && Array.isArray(config.EmbyConfig.Sources)) {
|
if (config.EmbyConfig?.Sources && Array.isArray(config.EmbyConfig.Sources)) {
|
||||||
|
console.log('[EmbyManager] 使用新格式Sources,返回', config.EmbyConfig.Sources.length, '个源');
|
||||||
return config.EmbyConfig.Sources;
|
return config.EmbyConfig.Sources;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是旧格式(单源配置),转换为数组格式
|
// 如果是旧格式(单源配置),转换为数组格式
|
||||||
if (config.EmbyConfig?.ServerURL) {
|
if (config.EmbyConfig?.ServerURL) {
|
||||||
|
console.log('[EmbyManager] 使用旧格式配置,转换为数组');
|
||||||
return [{
|
return [{
|
||||||
key: 'default',
|
key: 'default',
|
||||||
name: 'Emby',
|
name: 'Emby',
|
||||||
@@ -68,6 +78,7 @@ class EmbyManager {
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[EmbyManager] 没有找到任何Emby配置,返回空数组');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,8 +141,12 @@ class EmbyManager {
|
|||||||
* 获取所有启用的Emby源配置
|
* 获取所有启用的Emby源配置
|
||||||
*/
|
*/
|
||||||
async getEnabledSources(): Promise<EmbySourceConfig[]> {
|
async getEnabledSources(): Promise<EmbySourceConfig[]> {
|
||||||
|
console.log('[EmbyManager] getEnabledSources 被调用');
|
||||||
const sources = await this.getSources();
|
const sources = await this.getSources();
|
||||||
return sources.filter(s => s.enabled);
|
console.log('[EmbyManager] 获取到所有源:', sources.length, '个');
|
||||||
|
const enabledSources = sources.filter(s => s.enabled);
|
||||||
|
console.log('[EmbyManager] 过滤后启用的源:', enabledSources.length, '个');
|
||||||
|
return enabledSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -127,6 +127,20 @@ export interface IStorage {
|
|||||||
getUserMovieRequests(userName: string): Promise<string[]>;
|
getUserMovieRequests(userName: string): Promise<string[]>;
|
||||||
addUserMovieRequest(userName: string, requestId: string): Promise<void>;
|
addUserMovieRequest(userName: string, requestId: string): Promise<void>;
|
||||||
removeUserMovieRequest(userName: string, requestId: string): Promise<void>;
|
removeUserMovieRequest(userName: string, requestId: string): Promise<void>;
|
||||||
|
|
||||||
|
// 新版用户存储(V2)- 可选方法
|
||||||
|
getUserInfoV2?(userName: string): Promise<{
|
||||||
|
role: 'owner' | 'admin' | 'user';
|
||||||
|
banned: boolean;
|
||||||
|
tags?: string[];
|
||||||
|
oidcSub?: string;
|
||||||
|
enabledApis?: string[];
|
||||||
|
created_at: number;
|
||||||
|
playrecord_migrated?: boolean;
|
||||||
|
favorite_migrated?: boolean;
|
||||||
|
skip_migrated?: boolean;
|
||||||
|
last_movie_request_time?: number;
|
||||||
|
} | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索结果数据结构
|
// 搜索结果数据结构
|
||||||
|
|||||||
Reference in New Issue
Block a user