feat: DSL 磁力聚合 — 搜索/解析/预览/投递 + cilisousuo 源 + 中英双语 + Docker 部署

This commit is contained in:
ice-a
2026-10-16 18:53:45 +08:00
commit d6999104bf
64 changed files with 16524 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
import { loadSettings, type BtClientConfig } from '../../utils/appconfig'
import { ADAPTERS, listClientStatuses } from '../../utils/clients'
/** 客户端配置 + 实时在线状态 */
export default defineEventHandler(async () => {
const settings = await loadSettings()
const statuses = await listClientStatuses()
return {
adapters: ADAPTERS.map((a) => ({
type: a.type,
label: a.label,
defaultPort: a.defaultPort,
defaultPath: a.defaultPath || null
})),
configs: settings.btClients as BtClientConfig[],
statuses,
online: statuses.filter((s) => s.online).length,
total: statuses.length,
settings: {
searchProxy: settings.searchProxy,
searchTimeout: settings.searchTimeout,
metadataTimeout: settings.metadataTimeout,
enabledProviders: settings.enabledProviders
}
}
})
+32
View File
@@ -0,0 +1,32 @@
import { normalizeClient, saveSettings, type AppSettings, type BtClientConfig } from '../../utils/appconfig'
/** 保存客户端配置 / 搜索源配置 */
export default defineEventHandler(async (event) => {
const body = await readBody(event).catch(() => ({}))
const patch: Partial<AppSettings> = {}
if (Array.isArray(body?.btClients)) {
patch.btClients = (body.btClients as Partial<BtClientConfig>[]).map((raw, i) => normalizeClient(raw, i))
}
if (typeof body?.searchProxy === 'string') patch.searchProxy = body.searchProxy.trim()
if (body?.searchTimeout != null) patch.searchTimeout = Math.min(Math.max(Number(body.searchTimeout) || 12000, 1000), 60000)
if (body?.metadataTimeout != null) patch.metadataTimeout = Math.min(Math.max(Number(body.metadataTimeout) || 30000, 3000), 180000)
if (Array.isArray(body?.enabledProviders) && body.enabledProviders.length) {
patch.enabledProviders = body.enabledProviders.map((p: unknown) => String(p))
}
if (!Object.keys(patch).length) {
throw createError({ statusCode: 400, statusMessage: '没有可保存的字段' })
}
let settings: AppSettings
try {
settings = await saveSettings(patch)
} catch (err) {
throw createError({
statusCode: 503,
statusMessage: `MongoDB 不可用,配置无法保存:${err instanceof Error ? err.message : err}`
})
}
return { ok: true, settings }
})
+10
View File
@@ -0,0 +1,10 @@
import { listAllTasks } from '../../utils/clients'
export default defineEventHandler(async () => {
const groups = await listAllTasks()
return {
groups,
totalCount: groups.reduce((sum, g) => sum + g.tasks.length, 0),
onlineCount: groups.filter((g) => g.online).length
}
})
+22
View File
@@ -0,0 +1,22 @@
import { normalizeClient, type BtClientConfig } from '../../utils/appconfig'
import { endpointOf, friendlyClientError, getAdapter } from '../../utils/clients'
/** 保存前先试连一次,确认地址 / 账号可用 */
export default defineEventHandler(async (event) => {
const body = await readBody(event).catch(() => ({}))
const cfg: BtClientConfig = normalizeClient((body?.client || body) as Partial<BtClientConfig>)
const adapter = getAdapter(cfg.type)
if (!adapter) throw createError({ statusCode: 400, statusMessage: `不支持的客户端类型:${cfg.type}` })
try {
const result = await adapter.probe(cfg)
return { ok: true, online: result.online, version: result.version || null, endpoint: endpointOf(cfg) }
} catch (err) {
return {
ok: false,
online: false,
endpoint: endpointOf(cfg),
error: friendlyClientError(err)
}
}
})