Merge branch 'fix/t12-laya-ready-actions' into develop (#12)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -768,6 +768,10 @@ h4 {
|
|||||||
background: var(--color-bg-tertiary);
|
background: var(--color-bg-tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.laya-model-panel [hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
.laya-model-heading,
|
.laya-model-heading,
|
||||||
.laya-model-actions {
|
.laya-model-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
<title>nodecast-tv | IPTV Player</title>
|
<title>nodecast-tv | IPTV Player</title>
|
||||||
<meta name="description" content="Stream live TV, movies, and series with EPG support">
|
<meta name="description" content="Stream live TV, movies, and series with EPG support">
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||||
<link rel="stylesheet" href="css/main.css?v=5">
|
<link rel="stylesheet" href="css/main.css?v=6">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@800&display=swap"
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@800&display=swap"
|
||||||
@ -1184,9 +1184,9 @@
|
|||||||
<script src="/js/components/VideoPlayer.js?v=5"></script>
|
<script src="/js/components/VideoPlayer.js?v=5"></script>
|
||||||
<script src="/js/services/channelLanguageDetection.js?v=1"></script>
|
<script src="/js/services/channelLanguageDetection.js?v=1"></script>
|
||||||
<script src="/js/services/channelLanguageFusion.js?v=1"></script>
|
<script src="/js/services/channelLanguageFusion.js?v=1"></script>
|
||||||
<script src="/js/services/layaStatusPresentation.js?v=2"></script>
|
<script src="/js/services/layaStatusPresentation.js?v=3"></script>
|
||||||
<script src="/js/services/channelVariantGrouping.js?v=4"></script>
|
<script src="/js/services/channelVariantGrouping.js?v=4"></script>
|
||||||
<script src="/js/components/ChannelList.js?v=8"></script>
|
<script src="/js/components/ChannelList.js?v=9"></script>
|
||||||
<script src="/js/components/SourceManager.js?v=2"></script>
|
<script src="/js/components/SourceManager.js?v=2"></script>
|
||||||
<script src="/js/components/EpgGuide.js?v=2"></script>
|
<script src="/js/components/EpgGuide.js?v=2"></script>
|
||||||
<script src="/js/pages/HomePage.js?v=2"></script>
|
<script src="/js/pages/HomePage.js?v=2"></script>
|
||||||
|
|||||||
@ -363,14 +363,19 @@ class ChannelList {
|
|||||||
const results = new Map();
|
const results = new Map();
|
||||||
try {
|
try {
|
||||||
const status = await API.laya.getStatus();
|
const status = await API.laya.getStatus();
|
||||||
if (!status?.modelPresent || !status?.runtimeAvailable) {
|
const statusWarning = LayaStatusPresentation.channelListWarning(mode, status);
|
||||||
|
if (statusWarning) {
|
||||||
if (requestId !== this._languageDetectionRequest) return;
|
if (requestId !== this._languageDetectionRequest) return;
|
||||||
this.layaLanguageResults.clear();
|
this.layaLanguageResults.clear();
|
||||||
this.languageDetectionFallback = true;
|
this.languageDetectionFallback = true;
|
||||||
this.languageDetectionNotice = 'Local AI service is unavailable. Standard channel matching is being used.';
|
this.languageDetectionNotice = statusWarning;
|
||||||
this.render();
|
this.render();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (requestId !== this._languageDetectionRequest) return;
|
||||||
|
this.languageDetectionNotice = '';
|
||||||
|
this.languageDetectionFallback = false;
|
||||||
|
this.render();
|
||||||
for (let index = 0; index < descriptors.length; index += 64) {
|
for (let index = 0; index < descriptors.length; index += 64) {
|
||||||
const response = await API.laya.detectLanguages(descriptors.slice(index, index + 64));
|
const response = await API.laya.detectLanguages(descriptors.slice(index, index + 64));
|
||||||
(response.results || []).forEach(result => results.set(String(result.id), result));
|
(response.results || []).forEach(result => results.set(String(result.id), result));
|
||||||
@ -383,7 +388,7 @@ class ChannelList {
|
|||||||
if (requestId !== this._languageDetectionRequest) return;
|
if (requestId !== this._languageDetectionRequest) return;
|
||||||
this.layaLanguageResults.clear();
|
this.layaLanguageResults.clear();
|
||||||
this.languageDetectionFallback = true;
|
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);
|
console.warn('[ChannelList] Local AI language detection unavailable:', err.message);
|
||||||
}
|
}
|
||||||
this.render();
|
this.render();
|
||||||
@ -442,6 +447,7 @@ class ChannelList {
|
|||||||
window.app?.navigateTo?.('settings');
|
window.app?.navigateTo?.('settings');
|
||||||
window.app?.pages?.settings?.switchTab?.('player');
|
window.app?.pages?.settings?.switchTab?.('player');
|
||||||
});
|
});
|
||||||
|
notice.appendChild(document.createTextNode(' '));
|
||||||
notice.appendChild(settingsButton);
|
notice.appendChild(settingsButton);
|
||||||
this.container.appendChild(notice);
|
this.container.appendChild(notice);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 };
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
const test = require('node:test');
|
const test = require('node:test');
|
||||||
const assert = require('node:assert/strict');
|
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', () => {
|
test('presents unknown-size downloads as indeterminate with downloaded bytes', () => {
|
||||||
const view = presentLayaStatus({
|
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', () => {
|
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.showRemove, true);
|
||||||
assert.equal(view.showDownload, false);
|
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', () => {
|
test('installed model with unavailable service is not reported ready', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user