Merge branch 'fix/t12-warning-language-apply' into develop (#12)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -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>
|
||||
|
||||
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
};
|
||||
});
|
||||
|
||||
@ -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 '';
|
||||
|
||||
@ -75,3 +75,22 @@ test('Laya language results participate in variant selection', () => {
|
||||
assert.equal(logical.preferredVariant.id, '1');
|
||||
assert.deepEqual(logical.availableLanguages.map(item => item.code), ['fr', 'en']);
|
||||
});
|
||||
|
||||
test('language selection immediately resolves the best visible matching variant', () => {
|
||||
const frenchSd = channel('fr-sd', 'Sports One SD');
|
||||
const frenchHd = channel('fr-hd', 'Sports One HD');
|
||||
const english4k = channel('en-4k', 'Sports One 4K');
|
||||
const languageResults = new Map([
|
||||
[grouping.getVariantKey(frenchSd), { language: 'fr', confidence: 0.9 }],
|
||||
[grouping.getVariantKey(frenchHd), { language: 'fr', confidence: 0.9 }],
|
||||
[grouping.getVariantKey(english4k), { language: 'en', confidence: 0.95 }]
|
||||
]);
|
||||
const logical = grouping.groupChannels([frenchSd, frenchHd, english4k], {
|
||||
languageMode: 'laya',
|
||||
languageResults
|
||||
})[0];
|
||||
const selected = grouping.selectVariantByLanguage(logical, 'fr', {
|
||||
isHidden: variant => variant.id === 'fr-hd'
|
||||
});
|
||||
assert.equal(selected.id, 'fr-sd');
|
||||
});
|
||||
|
||||
@ -55,7 +55,7 @@ test('ChannelList warning only appears for active Laya modes when unavailable or
|
||||
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.');
|
||||
assert.equal(channelListWarning('laya', ready, true), 'Local AI language matching failed. Standard channel matching is being used.');
|
||||
});
|
||||
|
||||
test('installed model with unavailable service is not reported ready', () => {
|
||||
|
||||
Reference in New Issue
Block a user