(url: string)
| 369 | } catch (error) { |
| 370 | // 忽略加载失败 |
| 371 | return 0; |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | // 从映射中获取配置名称 |
| 376 | private getConfigNameFromMappings(url: string): string | null { |
| 377 | for (const [key, name] of Object.entries(REMOTE_CONFIG_MAPPINGS)) { |
| 378 | if (url.includes(key)) return name; |
| 379 | } |
| 380 | return null; |
| 381 | } |
| 382 | |
| 383 | // 从 Content-Disposition 头获取配置名称 |
| 384 | private getConfigNameFromHeader(contentDisposition: string | null): string | null { |
| 385 | if (!contentDisposition) return null; |
| 386 | |
| 387 | try { |
| 388 | const parts = contentDisposition.split(';'); |
| 389 | for (const part of parts) { |
| 390 | const trimmed = part.trim(); |
| 391 | if (trimmed.startsWith('filename*=')) { |
| 392 | const namePart = trimmed.split("''").pop(); |
| 393 | if (namePart) return decodeURIComponent(namePart); |
| 394 | } else if (trimmed.startsWith('filename=')) { |
| 395 | let namePart = trimmed.split('=').slice(1).join('=').trim().replace(/^["']|["']$/g, ''); |
| 396 | if (namePart) return decodeURIComponent(Buffer.from(namePart, 'binary').toString('utf-8')); |
| 397 | } |
| 398 | } |
| 399 | } catch { |
| 400 | // 忽略解析错误 |
| 401 | } |
| 402 | return null; |
| 403 | } |
| 404 | |
| 405 | // --- 核心查询逻辑 (Subinfo & Cha 共用) --- |
| 406 | private async processSubscription(url: string): Promise<{ |
| 407 | success: boolean; |
| 408 | configName: string; |
| 409 | status: string; |
| 410 | statusEmoji: string; |
| 411 | profileUrl: string | null; |
| 412 | used: number; |
| 413 | upload: number; |
| 414 | download: number; |
| 415 | total: number; |
| 416 | remain: number; |
| 417 | percent: number; |
| 418 | expireTs: number; |
| 419 | startTs: number; |
| 420 | websiteInfo: { website: string | null; websiteName: string | null }; |
| 421 | nodeInfo: NodeInfoResult | null; |
| 422 | errorMessage: string | null; |
| 423 | }> { |
| 424 | const websiteInfo = await getWebsiteInfo(url); |
| 425 | const result = { |
| 426 | success: false, |
| 427 | configName: '未知', |
| 428 | status: '失败', |
no test coverage detected