订阅式legado

This commit is contained in:
mtvpls
2026-05-19 21:03:11 +08:00
parent da1be9a07c
commit 79fe582f17
8 changed files with 550 additions and 1071 deletions
@@ -0,0 +1,45 @@
import { NextRequest, NextResponse } from 'next/server';
import { getAuthInfoFromCookie } from '@/lib/auth';
import { getConfig, setCachedConfig } from '@/lib/config';
import { db } from '@/lib/db';
import { legadoSubscriptionStore } from '@/lib/legado/subscription-store';
export const runtime = 'nodejs';
async function ensureAdmin(request: NextRequest) {
const authInfo = getAuthInfoFromCookie(request);
if (!authInfo?.username) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
if (authInfo.username !== process.env.USERNAME) {
const userInfo = await db.getUserInfoV2(authInfo.username);
if (!userInfo || (userInfo.role !== 'admin' && userInfo.role !== 'owner') || userInfo.banned) return NextResponse.json({ error: '权限不足' }, { status: 401 });
}
return authInfo.username;
}
export async function POST(request: NextRequest, context: { params: Promise<{ id: string }> }) {
const ensured = await ensureAdmin(request);
if (ensured instanceof NextResponse) return ensured;
const { id } = await context.params;
try {
const config = await getConfig();
const opds = config.OPDSConfig || { Enabled: false, Sources: [], LegadoSubscriptions: [], CacheTTL: 10 * 60 * 1000 };
const current = (opds.LegadoSubscriptions || []).find((item) => item.id === id);
if (!current) return NextResponse.json({ success: false, error: '订阅不存在' }, { status: 404 });
const meta = await legadoSubscriptionStore.sync({ id: current.id, name: current.name, url: current.url });
const nextConfig = legadoSubscriptionStore.mergeMeta(config, { ...current, ...meta, enabled: current.enabled !== false });
await db.saveAdminConfig(nextConfig);
await setCachedConfig(nextConfig);
return NextResponse.json({ success: true, subscription: { ...current, ...meta, enabled: current.enabled !== false } });
} catch (error) {
const config = await getConfig();
const opds = config.OPDSConfig || { Enabled: false, Sources: [], LegadoSubscriptions: [], CacheTTL: 10 * 60 * 1000 };
const now = Date.now();
const message = error instanceof Error ? error.message : '刷新 Legado 订阅失败';
const nextSubscriptions = (opds.LegadoSubscriptions || []).map((item) => item.id === id ? { ...item, lastSyncAt: now, lastError: message } : item);
const nextConfig = { ...config, OPDSConfig: { ...opds, LegadoSubscriptions: nextSubscriptions } };
await db.saveAdminConfig(nextConfig);
await setCachedConfig(nextConfig);
return NextResponse.json({ success: false, error: message }, { status: 400 });
}
}
@@ -0,0 +1,35 @@
import { NextRequest, NextResponse } from 'next/server';
import { getAuthInfoFromCookie } from '@/lib/auth';
import { getConfig, setCachedConfig } from '@/lib/config';
import { db } from '@/lib/db';
import { legadoSubscriptionStore } from '@/lib/legado/subscription-store';
export const runtime = 'nodejs';
async function ensureAdmin(request: NextRequest) {
const authInfo = getAuthInfoFromCookie(request);
if (!authInfo?.username) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
if (authInfo.username !== process.env.USERNAME) {
const userInfo = await db.getUserInfoV2(authInfo.username);
if (!userInfo || (userInfo.role !== 'admin' && userInfo.role !== 'owner') || userInfo.banned) return NextResponse.json({ error: '权限不足' }, { status: 401 });
}
return authInfo.username;
}
export async function DELETE(request: NextRequest, context: { params: Promise<{ id: string }> }) {
const ensured = await ensureAdmin(request);
if (ensured instanceof NextResponse) return ensured;
const { id } = await context.params;
try {
const config = await getConfig();
const opds = config.OPDSConfig || { Enabled: false, Sources: [], LegadoSubscriptions: [], CacheTTL: 10 * 60 * 1000 };
const nextConfig = { ...config, OPDSConfig: { ...opds, LegadoSubscriptions: (opds.LegadoSubscriptions || []).filter((item) => item.id !== id) } };
await legadoSubscriptionStore.delete(id);
await db.saveAdminConfig(nextConfig);
await setCachedConfig(nextConfig);
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json({ success: false, error: error instanceof Error ? error.message : '删除 Legado 订阅失败' }, { status: 400 });
}
}
@@ -0,0 +1,36 @@
import { NextRequest, NextResponse } from 'next/server';
import { getAuthInfoFromCookie } from '@/lib/auth';
import { getConfig, setCachedConfig } from '@/lib/config';
import { db } from '@/lib/db';
import { legadoSubscriptionStore } from '@/lib/legado/subscription-store';
export const runtime = 'nodejs';
async function ensureAdmin(request: NextRequest) {
const authInfo = getAuthInfoFromCookie(request);
if (!authInfo?.username) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
if (authInfo.username !== process.env.USERNAME) {
const userInfo = await db.getUserInfoV2(authInfo.username);
if (!userInfo || (userInfo.role !== 'admin' && userInfo.role !== 'owner') || userInfo.banned) return NextResponse.json({ error: '权限不足' }, { status: 401 });
}
return authInfo.username;
}
export async function POST(request: NextRequest) {
const ensured = await ensureAdmin(request);
if (ensured instanceof NextResponse) return ensured;
try {
const body = await request.json();
const url = String(body?.url || '').trim();
const name = String(body?.name || '').trim() || 'Legado 订阅';
const meta = await legadoSubscriptionStore.sync({ name, url });
const config = await getConfig();
const nextConfig = legadoSubscriptionStore.mergeMeta(config, meta);
await db.saveAdminConfig(nextConfig);
await setCachedConfig(nextConfig);
return NextResponse.json({ success: true, subscription: meta });
} catch (error) {
return NextResponse.json({ success: false, error: error instanceof Error ? error.message : '导入 Legado 订阅失败' }, { status: 400 });
}
}