fix: clear persistent Laya warning and apply language selection immediately (#12)

Two fixes: the ChannelList local-AI warning kept showing after the
runtime became available because status changes were not re-evaluated
on refresh; and selecting a language in the player did not switch the
stream variant immediately. Refresh warning visibility from the
latest laya status and apply the chosen variant/language on
selection, with tests for both behaviors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
blomios
2026-10-02 15:15:06 +02:00
parent cb4939daae
commit 4d662369c9
7 changed files with 63 additions and 8 deletions

View File

@ -1184,9 +1184,9 @@
<script src="/js/components/VideoPlayer.js?v=5"></script>
<script src="/js/services/channelLanguageDetection.js?v=1"></script>
<script src="/js/services/channelLanguageFusion.js?v=1"></script>
<script src="/js/services/layaStatusPresentation.js?v=3"></script>
<script src="/js/services/channelVariantGrouping.js?v=4"></script>
<script src="/js/components/ChannelList.js?v=9"></script>
<script src="/js/services/layaStatusPresentation.js?v=4"></script>
<script src="/js/services/channelVariantGrouping.js?v=5"></script>
<script src="/js/components/ChannelList.js?v=10"></script>
<script src="/js/components/SourceManager.js?v=2"></script>
<script src="/js/components/EpgGuide.js?v=2"></script>
<script src="/js/pages/HomePage.js?v=2"></script>
@ -1194,7 +1194,7 @@
<script src="/js/pages/Guide.js?v=2"></script>
<script src="/js/pages/MoviesPage.js?v=4"></script>
<script src="/js/pages/SeriesPage.js?v=1"></script>
<script src="/js/pages/Settings.js?v=6"></script>
<script src="/js/pages/Settings.js?v=7"></script>
<script src="/js/pages/WatchPage.js?v=1"></script>
<script src="/js/app.js?v=4"></script>
<script>

View File

@ -346,9 +346,11 @@ class ChannelList {
async refreshLayaLanguages(mode = window.app?.player?.settings?.languageDetectionMode || 'algo') {
const requestId = ++this._languageDetectionRequest;
if (mode === 'algo') {
const hadWarning = Boolean(this.languageDetectionNotice || this.languageDetectionFallback);
this.layaLanguageResults.clear();
this.languageDetectionNotice = '';
this.languageDetectionFallback = false;
if (hadWarning) this.render();
return;
}
@ -1403,10 +1405,17 @@ class ChannelList {
this.render();
const logicalChannel = this.logicalChannels.find(channel => channel.fingerprint === fingerprint);
if (!logicalChannel) return;
const variant = ChannelVariantGrouping.selectVariantByLanguage(logicalChannel, languageCode, {
isFavorite: item => this.isFavorite(item.sourceId, item.id),
isHidden: item => this.isHidden('channel', item.sourceId, item.streamId || item.id)
});
if (!variant) return;
await this.selectChannel({
logicalId: fingerprint,
variantId: logicalChannel.preferredVariant.id,
sourceId: logicalChannel.preferredVariant.sourceId
variantId: variant.id,
sourceId: variant.sourceId,
renderId: this.currentRenderId,
renderGroup: this.currentRenderGroup
});
}

View File

@ -145,6 +145,11 @@ class SettingsPage {
this.layaStatus = { runtimeAvailable: false, modelPresent: false, error: err.message };
}
this.renderLayaStatus(this.layaStatus);
const mode = this.app.player?.settings?.languageDetectionMode || 'algo';
if (mode !== 'algo' && this.layaStatus?.modelPresent && this.layaStatus?.runtimeAvailable &&
this.app.channelList?.languageDetectionNotice) {
void this.app.channelList.refreshLayaLanguages(mode);
}
if (this.layaStatus?.downloading) this.startLayaStatusPolling();
return this.layaStatus;
}

View File

@ -170,6 +170,24 @@
return listMode === 'grouped';
}
function selectVariantByLanguage(logicalChannel, languageCode, options = {}) {
const isFavorite = options.isFavorite || (() => false);
const isHidden = options.isHidden || (() => false);
const visible = (logicalChannel?.variants || []).filter(variant => !isHidden(variant));
if (!visible.length) return null;
const preferredVisible = visible.find(variant => getVariantKey(variant) === getVariantKey(logicalChannel.preferredVariant));
if (!languageCode || languageCode === 'auto') return preferredVisible || visible[0];
const matching = languageCode && languageCode !== 'auto'
? visible.filter(variant => variant.language?.code === languageCode)
: visible;
const candidates = matching.length ? matching : (preferredVisible ? [preferredVisible] : visible);
return candidates.map((variant, index) => ({ variant, index })).sort((a, b) =>
Number(isFavorite(b.variant)) - Number(isFavorite(a.variant)) ||
qualityScore(b.variant) - qualityScore(a.variant) ||
a.index - b.index
)[0].variant;
}
return {
normalizeChannelName,
displayNameForFingerprint,
@ -177,6 +195,7 @@
getQuality,
groupChannels,
orderFlatChannels,
selectVariantByLanguage,
shouldUseFavoritesGroup
};
});

View File

@ -79,7 +79,10 @@
function channelListWarning(mode, status = {}, batchFailed = false) {
if (mode === 'algo') return '';
if (batchFailed || status.modelPresent !== true || status.runtimeAvailable !== true) {
if (batchFailed) {
return 'Local AI language matching failed. Standard channel matching is being used.';
}
if (status.modelPresent !== true || status.runtimeAvailable !== true) {
return 'Local AI service is unavailable. Standard channel matching is being used.';
}
return '';