From 9720d10ba791a5a7db8a16094f1825a6eb837540 Mon Sep 17 00:00:00 2001 From: aaa bbb Date: Mon, 11 May 2026 23:46:16 +0800 Subject: [PATCH] fix: check all sources and repair first-run guide --- CHANGELOG.md | 11 ++++++ README.md | 2 +- VERSION.txt | 2 +- diagnostics.html | 4 +-- index.html | 3 +- js/config.js | 2 +- js/diagnostics.js | 2 +- js/onboarding.js | 2 +- js/source-health.js | 28 ++++++++++++--- package-lock.json | 4 +-- package.json | 2 +- test/libretv-defaults.test.mjs | 66 ++++++++++++++++++++++++++++++---- 12 files changed, 105 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7007e9672b..4aad08a13d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ All notable changes to this maintained LibreTV fork are documented here. +## 1.2.7 - 2026-05-11 + +### Changed + +- Source health checks now cover all built-in and custom sources instead of only the default selected sources. +- Renamed the settings action from `检测默认源` to `检测源`. + +### Fixed + +- Loaded the shared modal stylesheet on the home page so the first-run guide opens as a centered overlay instead of appearing in page flow. + ## 1.2.6 - 2026-05-11 ### Changed diff --git a/README.md b/README.md index 318620e702..0f11b5c1b8 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ PWA 相关文件: ## 源健康与诊断 -设置面板可以检测默认源的搜索、详情和 m3u8 可访问性,并缓存一份本地报告。诊断页位于 `/diagnostics.html`,用于检查密码保护、代理状态、PWA 状态和源状态,不显示密钥、令牌或密码。 +设置面板可以检测全部内置源和自定义源的搜索、详情和 m3u8 可访问性,并缓存一份本地报告。诊断页位于 `/diagnostics.html`,用于检查密码保护、代理状态、PWA 状态和源状态,不显示密钥、令牌或密码。 配置导出格式当前为 `LibreTV-Settings` `2.0.0`。导入旧版 `1.0.0` 配置时会校验哈希、过滤未知字段,并提示迁移结果。 diff --git a/VERSION.txt b/VERSION.txt index eccd097e97..805d8ea949 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -202605112321 +202605112332 diff --git a/diagnostics.html b/diagnostics.html index 78300f1a90..fc6816409a 100644 --- a/diagnostics.html +++ b/diagnostics.html @@ -32,11 +32,11 @@

LibreTV 诊断

-

默认源健康

+

源健康

源健康:尚未检测

最近检测:尚未检测

- +
diff --git a/index.html b/index.html index 275f147280..ed458af59c 100644 --- a/index.html +++ b/index.html @@ -18,6 +18,7 @@ + @@ -100,7 +101,7 @@

设置

源健康:尚未检测 - +
最近检测:尚未检测
diff --git a/js/config.js b/js/config.js index b87b95dde6..2fe21f27ae 100644 --- a/js/config.js +++ b/js/config.js @@ -17,7 +17,7 @@ const SITE_CONFIG = { url: '', description: '免费在线视频搜索与观看平台', logo: 'image/logo.png', - version: '1.2.6' + version: '1.2.7' }; const DEFAULT_SELECTED_APIS = ['ysgc', 'jszy', 'wujin', 'maoyan']; diff --git a/js/diagnostics.js b/js/diagnostics.js index 150deabd91..f3fa28c748 100644 --- a/js/diagnostics.js +++ b/js/diagnostics.js @@ -60,7 +60,7 @@ function getSourceDiagnostic() { const state = report.summary.failed > 0 ? 'warn' : 'ok'; return { state, - detail: `${report.summary.successRate}% 成功,${report.summary.ok}/${report.summary.total} 个默认源完全可用` + detail: `${report.summary.successRate}% 成功,${report.summary.ok}/${report.summary.total} 个源完全可用` }; } diff --git a/js/onboarding.js b/js/onboarding.js index ee1610b1c2..890748a400 100644 --- a/js/onboarding.js +++ b/js/onboarding.js @@ -27,7 +27,7 @@ function showFirstRunGuide(force = false) {
数据源 - 默认源会随健康检查调整,自定义源可通过导出配置备份。 + 源健康检查会覆盖全部内置源和自定义源,自定义源可通过导出配置备份。
PWA diff --git a/js/source-health.js b/js/source-health.js index 362b994260..d8d1ea62c8 100644 --- a/js/source-health.js +++ b/js/source-health.js @@ -3,12 +3,29 @@ const SOURCE_HEALTH_CHECKED_AT_KEY = 'sourceHealthCheckedAt'; const SOURCE_HEALTH_TTL_MS = 24 * 60 * 60 * 1000; const SOURCE_HEALTH_PROBE_QUERY = '阿凡达'; -function getDefaultHealthSourceIds() { - const defaults = Array.isArray(window.DEFAULT_SELECTED_APIS) ? window.DEFAULT_SELECTED_APIS : []; - return defaults.filter(sourceId => window.API_SITES?.[sourceId] && !window.API_SITES[sourceId].adult); +function getCustomHealthSourceIds() { + try { + const customSources = JSON.parse(localStorage.getItem('customAPIs') || '[]'); + if (!Array.isArray(customSources)) return []; + return customSources + .map((source, index) => source?.url ? `custom_${index}` : '') + .filter(Boolean); + } catch (error) { + console.warn('读取自定义源失败:', error); + return []; + } +} + +function getHealthSourceIds() { + const builtInSourceIds = Object.keys(window.API_SITES || {}); + return [...builtInSourceIds, ...getCustomHealthSourceIds()]; } function getHealthSourceName(sourceId) { + if (sourceId.startsWith('custom_')) { + const customApi = window.getCustomApiInfo?.(sourceId.replace('custom_', '')); + return customApi?.name || sourceId; + } return window.API_SITES?.[sourceId]?.name || sourceId; } @@ -165,7 +182,7 @@ function summarizeSourceHealth(sources) { return { total, ok, degraded, failed, successRate }; } -async function runSourceHealthCheck(sourceIds = getDefaultHealthSourceIds()) { +async function runSourceHealthCheck(sourceIds = getHealthSourceIds()) { const checkedAt = new Date().toISOString(); const sources = []; const button = document.getElementById('sourceHealthButton'); @@ -193,7 +210,7 @@ async function runSourceHealthCheck(sourceIds = getDefaultHealthSourceIds()) { } finally { if (button) { button.disabled = false; - button.textContent = '检测默认源'; + button.textContent = '检测源'; } } } @@ -254,6 +271,7 @@ document.addEventListener('DOMContentLoaded', () => { window.SOURCE_HEALTH_STORAGE_KEY = SOURCE_HEALTH_STORAGE_KEY; window.loadSourceHealthReport = loadSourceHealthReport; window.saveSourceHealthReport = saveSourceHealthReport; +window.getHealthSourceIds = getHealthSourceIds; window.probeSourceHealth = probeSourceHealth; window.runSourceHealthCheck = runSourceHealthCheck; window.renderSourceHealthSummary = renderSourceHealthSummary; diff --git a/package-lock.json b/package-lock.json index 5e45b222f9..57db4b4e46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "libretv", - "version": "1.2.6", + "version": "1.2.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "libretv", - "version": "1.2.6", + "version": "1.2.7", "license": "Apache-2.0", "dependencies": { "axios": "^1.9.0", diff --git a/package.json b/package.json index 5254ec1f17..f8bccb9533 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "libretv", "type": "module", - "version": "1.2.6", + "version": "1.2.7", "private": true, "description": "免费在线视频搜索与观看平台", "author": "bestZwei", diff --git a/test/libretv-defaults.test.mjs b/test/libretv-defaults.test.mjs index 9e839db105..4cad20591d 100644 --- a/test/libretv-defaults.test.mjs +++ b/test/libretv-defaults.test.mjs @@ -293,13 +293,14 @@ test('maintenance automation avoids direct main pushes and public preview workfl assert.doesNotMatch(workflowText, /git push origin main|target_sync_branch:\s*main|pull_request_target/); }); -test('source health checks probe default sources and expose a UI report', async () => { +test('source health checks probe sources and expose a UI report', async () => { const sourceHealth = await readProjectFile('js/source-health.js'); const index = await readProjectFile('index.html'); const sw = await readProjectFile('service-worker.js'); assert.match(sourceHealth, /SOURCE_HEALTH_STORAGE_KEY/); assert.match(sourceHealth, /runSourceHealthCheck/); + assert.match(sourceHealth, /getHealthSourceIds/); assert.match(sourceHealth, /probeSourceHealth/); assert.match(sourceHealth, /handleApiRequest/); assert.match(sourceHealth, /searchOk/); @@ -312,10 +313,56 @@ test('source health checks probe default sources and expose a UI report', async assert.match(index, /sourceHealthSummary/); assert.match(index, /sourceHealthList/); assert.match(index, /runSourceHealthCheck/); + assert.match(index, />检测源 { + const sandbox = { + console, + URL, + window: {}, + localStorage: { + getItem(key) { + if (key === 'customAPIs') { + return JSON.stringify([ + { name: '自定义一', url: 'https://custom-one.example/api.php/provide/vod' }, + { name: '自定义二', url: 'https://custom-two.example/api.php/provide/vod' } + ]); + } + return null; + }, + setItem() {} + }, + document: { + addEventListener() {}, + getElementById() { + return null; + } + }, + performance: { + now() { + return 0; + } + }, + setTimeout, + clearTimeout, + AbortController + }; + vm.createContext(sandbox); + vm.runInContext(await readProjectFile('js/config.js'), sandbox); + vm.runInContext(await readProjectFile('js/customer_site.js'), sandbox); + vm.runInContext(await readProjectFile('js/source-health.js'), sandbox); + + const builtInSourceIds = Object.keys(sandbox.window.API_SITES); + const sourceIds = Array.from(sandbox.window.getHealthSourceIds()); + + assert.deepEqual(sourceIds, [...builtInSourceIds, 'custom_0', 'custom_1']); + assert.ok(sourceIds.some(sourceId => sandbox.window.API_SITES[sourceId]?.adult)); +}); + test('playback errors are classified and offer one-click source switching', async () => { const playerErrors = await readProjectFile('js/player-errors.js'); const player = await readProjectFile('js/player.js'); @@ -348,10 +395,15 @@ test('first-run guidance and diagnostics page support public self-hosting', asyn assert.match(onboarding, /PWA/); assert.match(onboarding, /导出配置/); assert.match(index, /js\/onboarding\.js/); + assert.match(index, /css\/modals\.css/); + assert.ok(index.indexOf('css/modals.css') < index.indexOf('css/styles.css')); assert.match(index, /showFirstRunGuide\(true\)/); assert.match(diagnosticsHtml, /diagnostics-root/); assert.match(diagnosticsHtml, /js\/diagnostics\.js/); + assert.match(diagnosticsHtml, /源健康/); + assert.match(diagnosticsHtml, />检测源 { const changelog = await readProjectFile('CHANGELOG.md'); - assert.equal(packageJson.version, '1.2.6'); - assert.equal(lockJson.version, '1.2.6'); - assert.equal(lockJson.packages[''].version, '1.2.6'); - assert.match(config, /version:\s*'1\.2\.6'/); - assert.match(changelog, /1\.2\.6/); - assert.match(changelog, /read-only/); + assert.equal(packageJson.version, '1.2.7'); + assert.equal(lockJson.version, '1.2.7'); + assert.equal(lockJson.packages[''].version, '1.2.7'); + assert.match(config, /version:\s*'1\.2\.7'/); + assert.match(changelog, /1\.2\.7/); + assert.match(changelog, /检测源|Source health checks/); assert.match(versionTxt, /^\d{12}$/); assert.ok(Number(versionTxt) > 202508060117); });