From 4f655888937436f57a335f4fa866fed31885bdfb Mon Sep 17 00:00:00 2001 From: blomios Date: Fri, 2 Oct 2026 14:34:30 +0200 Subject: [PATCH] fix: correct Settings actions in Laya ready state and clear stale AI warning (#12) Offer the right actions in Settings when Laya is ready/available instead of leaving irrelevant ones, and stop showing the ChannelList local-AI warning once the runtime is actually available. Derive both from layaStatusPresentation and cover the ready/available action set with tests. Co-Authored-By: Claude Opus 4.8 --- public/css/main.css | 4 ++++ public/index.html | 6 +++--- public/js/components/ChannelList.js | 12 +++++++++--- public/js/services/layaStatusPresentation.js | 10 +++++++++- test/layaStatusPresentation.test.js | 20 ++++++++++++++++++-- 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/public/css/main.css b/public/css/main.css index e0bf2fe..2c41682 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -768,6 +768,10 @@ h4 { background: var(--color-bg-tertiary); } +.laya-model-panel [hidden] { + display: none !important; +} + .laya-model-heading, .laya-model-actions { display: flex; diff --git a/public/index.html b/public/index.html index d7f983d..bb4c2d2 100644 --- a/public/index.html +++ b/public/index.html @@ -10,7 +10,7 @@ nodecast-tv | IPTV Player - + - + - + diff --git a/public/js/components/ChannelList.js b/public/js/components/ChannelList.js index 6ee47a7..d985acd 100644 --- a/public/js/components/ChannelList.js +++ b/public/js/components/ChannelList.js @@ -363,14 +363,19 @@ class ChannelList { const results = new Map(); try { const status = await API.laya.getStatus(); - if (!status?.modelPresent || !status?.runtimeAvailable) { + const statusWarning = LayaStatusPresentation.channelListWarning(mode, status); + if (statusWarning) { if (requestId !== this._languageDetectionRequest) return; this.layaLanguageResults.clear(); this.languageDetectionFallback = true; - this.languageDetectionNotice = 'Local AI service is unavailable. Standard channel matching is being used.'; + this.languageDetectionNotice = statusWarning; this.render(); return; } + if (requestId !== this._languageDetectionRequest) return; + this.languageDetectionNotice = ''; + this.languageDetectionFallback = false; + this.render(); for (let index = 0; index < descriptors.length; index += 64) { const response = await API.laya.detectLanguages(descriptors.slice(index, index + 64)); (response.results || []).forEach(result => results.set(String(result.id), result)); @@ -383,7 +388,7 @@ class ChannelList { if (requestId !== this._languageDetectionRequest) return; this.layaLanguageResults.clear(); this.languageDetectionFallback = true; - this.languageDetectionNotice = 'Local AI service is unavailable. Standard channel matching is being used.'; + this.languageDetectionNotice = LayaStatusPresentation.channelListWarning(mode, {}, true); console.warn('[ChannelList] Local AI language detection unavailable:', err.message); } this.render(); @@ -442,6 +447,7 @@ class ChannelList { window.app?.navigateTo?.('settings'); window.app?.pages?.settings?.switchTab?.('player'); }); + notice.appendChild(document.createTextNode(' ')); notice.appendChild(settingsButton); this.container.appendChild(notice); } diff --git a/public/js/services/layaStatusPresentation.js b/public/js/services/layaStatusPresentation.js index 86327fe..e846bdf 100644 --- a/public/js/services/layaStatusPresentation.js +++ b/public/js/services/layaStatusPresentation.js @@ -77,5 +77,13 @@ }; } - return { presentLayaStatus }; + function channelListWarning(mode, status = {}, batchFailed = false) { + if (mode === 'algo') return ''; + if (batchFailed || status.modelPresent !== true || status.runtimeAvailable !== true) { + return 'Local AI service is unavailable. Standard channel matching is being used.'; + } + return ''; + } + + return { channelListWarning, presentLayaStatus }; }); diff --git a/test/layaStatusPresentation.test.js b/test/layaStatusPresentation.test.js index 685a7bf..e216067 100644 --- a/test/layaStatusPresentation.test.js +++ b/test/layaStatusPresentation.test.js @@ -1,6 +1,6 @@ const test = require('node:test'); const assert = require('node:assert/strict'); -const { presentLayaStatus } = require('../public/js/services/layaStatusPresentation.js'); +const { channelListWarning, presentLayaStatus } = require('../public/js/services/layaStatusPresentation.js'); test('presents unknown-size downloads as indeterminate with downloaded bytes', () => { const view = presentLayaStatus({ @@ -37,9 +37,25 @@ test('failed downloads expose retry, safe details and Standard fallback', () => }); test('ready models expose removal without download actions', () => { - const view = presentLayaStatus({ phase: 'ready', modelPresent: true, runtimeAvailable: true }); + const view = presentLayaStatus({ phase: 'idle', modelPresent: true, runtimeAvailable: true, sizeBytes: 678323814 }); + assert.equal(view.statusLabel, 'Ready'); assert.equal(view.showRemove, true); assert.equal(view.showDownload, false); + assert.equal(view.showCheckAgain, false); + assert.equal(view.showStartCommand, false); + assert.equal(view.availabilityMessage, ''); +}); + +test('ChannelList warning only appears for active Laya modes when unavailable or failed', () => { + const ready = { modelPresent: true, runtimeAvailable: true }; + assert.equal(channelListWarning('hybrid', ready), ''); + assert.equal(channelListWarning('laya', ready), ''); + assert.equal(channelListWarning('algo', { modelPresent: false, runtimeAvailable: false }), ''); + assert.equal( + channelListWarning('hybrid', { modelPresent: true, runtimeAvailable: false }), + 'Local AI service is unavailable. Standard channel matching is being used.' + ); + assert.equal(channelListWarning('laya', ready, true), 'Local AI service is unavailable. Standard channel matching is being used.'); }); test('installed model with unavailable service is not reported ready', () => {