(url: string)
| 369 | |
| 370 | // --- 核心查询逻辑 (Subinfo & Cha 共用) --- |
| 371 | private async processSubscription(url: string): Promise<{ |
| 372 | success: boolean; |
| 373 | configName: string; |
| 374 | status: string; |
| 375 | statusEmoji: string; |
| 376 | profileUrl: string | null; |
| 377 | used: number; |
| 378 | upload: number; |
| 379 | download: number; |
| 380 | total: number; |
| 381 | remain: number; |
| 382 | percent: number; |
| 383 | expireTs: number; |
| 384 | startTs: number; |
| 385 | websiteInfo: { website: string | null; websiteName: string | null }; |
| 386 | nodeInfo: { node_count: string | number; type_count: Record<string, number>; regions: Record<string, number> } | null; |
| 387 | errorMessage: string | null; |
| 388 | }> { |
| 389 | const websiteInfo = await getWebsiteInfo(url); |
| 390 | const result = { |
| 391 | success: false, |
| 392 | configName: '未知', |
| 393 | status: '失败', |
| 394 | statusEmoji: '❓', |
| 395 | profileUrl: null as string | null, |
| 396 | used: 0, upload: 0, download: 0, total: 0, remain: 0, percent: 0, |
| 397 | expireTs: 0, startTs: 0, |
| 398 | websiteInfo, |
| 399 | nodeInfo: null as { node_count: string | number; type_count: Record<string, number>; regions: Record<string, number> } | null, |
| 400 | errorMessage: null as string | null, |
| 401 | }; |
| 402 | |
| 403 | try { |
| 404 | let configName: string | null = this.getConfigNameFromMappings(url); |
| 405 | |
| 406 | const response = await axios.get(url, { |
| 407 | headers: { 'User-Agent': 'FlClash/v0.8.76 clash-verge Platform/android' }, |
| 408 | timeout: 15000, |
| 409 | maxRedirects: 5, |
| 410 | validateStatus: () => true |
| 411 | }); |
| 412 | |
| 413 | if (response.status !== 200) { |
| 414 | result.errorMessage = `无法访问(${response.status})`; |
| 415 | return result; |
| 416 | } |
| 417 | |
| 418 | // 尝试从 Content-Disposition 头获取配置名 |
| 419 | if (!configName) configName = this.getConfigNameFromHeader(response.headers['content-disposition']); |
| 420 | |
| 421 | // 使用网站标题作为名称补充 |
| 422 | if (!configName && websiteInfo.websiteName && websiteInfo.websiteName !== "连接失败") configName = websiteInfo.websiteName; |
| 423 | |
| 424 | result.configName = configName || '未知'; |
| 425 | |
| 426 | const userInfoHeader = response.headers['subscription-userinfo']; |
| 427 | result.profileUrl = (response.headers['profile-web-page-url'] as string | null) || null; |
| 428 |
no test coverage detected