From 4bc83ef5a37fde28f359dffc0b71c072ed07c0b3 Mon Sep 17 00:00:00 2001 From: stschr <92983372+stschr@users.noreply.github.com> Date: Tue, 20 Sep 2022 11:35:09 +0200 Subject: [PATCH] make language matching more robust (#4015) * make language matching more robust * adding BCP-47 module * use BCP-47 extended filter in settings matcher * remove commented code * downgrade version of bcp-47 modules to v1 as they are compatibel with CommonJS (not ESmodule only); add differentiation between string and RegExp in settings.lang * enhancing language selection tests, making them more sensitive, adding case with 3-letter code, using RegExp object instead of string with RegExp * refine documentation of possible data types with langValue in setInitialMediaSettingsFor API --- src/streaming/MediaPlayer.js | 2 +- src/streaming/controllers/MediaController.js | 6 +- .../streaming.controllers.MediaController.js | 119 +++++++++--------- 3 files changed, 66 insertions(+), 61 deletions(-) diff --git a/src/streaming/MediaPlayer.js b/src/streaming/MediaPlayer.js index 97bfcf922a..414954402d 100644 --- a/src/streaming/MediaPlayer.js +++ b/src/streaming/MediaPlayer.js @@ -1515,7 +1515,7 @@ function MediaPlayer() { /** * This method allows to set media settings that will be used to pick the initial track. Format of the settings * is following:
- * {lang: langValue (can be either a string or a regex to match), + * {lang: langValue (can be either a string primitive, a string object, or a RegExp object to match), * index: indexValue, * viewpoint: viewpointValue, * audioChannelConfiguration: audioChannelConfigurationValue, diff --git a/src/streaming/controllers/MediaController.js b/src/streaming/controllers/MediaController.js index 5bd59bbe69..b2c2e44a9f 100644 --- a/src/streaming/controllers/MediaController.js +++ b/src/streaming/controllers/MediaController.js @@ -33,6 +33,8 @@ import Events from '../../core/events/Events'; import EventBus from '../../core/EventBus'; import FactoryMaker from '../../core/FactoryMaker'; import Debug from '../../core/Debug'; +var bcp47Normalize = require('bcp-47-normalize') +import {extendedFilter} from 'bcp-47-match'; function MediaController() { @@ -309,7 +311,9 @@ function MediaController() { } function matchSettings(settings, track, isTrackActive = false) { - const matchLang = !settings.lang || (track.lang.match(settings.lang)); + const matchLang = !settings.lang || ( + (settings.lang instanceof RegExp)?(track.lang.match(settings.lang)):( extendedFilter(track.lang, bcp47Normalize(settings.lang) ).length>0 ) + ); const matchIndex = (settings.index === undefined) || (settings.index === null) || (track.index === settings.index); const matchViewPoint = !settings.viewpoint || (settings.viewpoint === track.viewpoint); const matchRole = !settings.role || !!track.roles.filter(function (item) { diff --git a/test/unit/streaming.controllers.MediaController.js b/test/unit/streaming.controllers.MediaController.js index b08684543e..e1f3927b62 100644 --- a/test/unit/streaming.controllers.MediaController.js +++ b/test/unit/streaming.controllers.MediaController.js @@ -334,99 +334,100 @@ describe('MediaController', function () { }); describe('Initial Track Management', function () { + let streamInfo = { + id: 'id' + }; + let frTrack = { + type: trackType, + streamInfo: streamInfo, + lang: 'fr', + viewpoint: 'viewpoint', + roles: 1, + accessibility: 1, + audioChannelConfiguration: 1 + }; + const qtzTrack = { + type: trackType, + streamInfo: streamInfo, + lang: 'qtz', + viewpoint: 'viewpoint', + roles: 1, + accessibility: 1, + audioChannelConfiguration: 1 + }; it('should check initial media settings to choose initial track', function () { - let streamInfo = { - id: 'id' - }; - let track = { - type: trackType, - streamInfo: streamInfo, - lang: 'fr', - viewpoint: 'viewpoint', - roles: 1, - accessibility: 1, - audioChannelConfiguration: 1 - }; + mediaController.addTrack(frTrack); + mediaController.addTrack(qtzTrack); - mediaController.addTrack(track); + let trackList = mediaController.getTracksFor(trackType, streamInfo.id); + expect(trackList).to.have.lengthOf(2); + expect(objectUtils.areEqual(trackList[0], frTrack)).to.be.true; // jshint ignore:line + expect(objectUtils.areEqual(trackList[1], qtzTrack)).to.be.true; // jshint ignore:line + + let currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo.id); + expect(objectUtils.areEqual(currentTrack, frTrack)).to.be.false; // jshint ignore:line + + // call to setInitialMediaSettingsForType + mediaController.setInitialSettings(trackType, { + lang: 'qtz', + viewpoint: 'viewpoint' + }); + mediaController.setInitialMediaSettingsForType(trackType, streamInfo); + + currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo.id); + expect(objectUtils.areEqual(currentTrack, qtzTrack)).to.be.true; // jshint ignore:line + + }); + + it('should check initial media settings to choose initial track with 639-2 3-letter code', function () { + mediaController.addTrack(qtzTrack); + mediaController.addTrack(frTrack); let trackList = mediaController.getTracksFor(trackType, streamInfo.id); - expect(trackList).to.have.lengthOf(1); - expect(objectUtils.areEqual(trackList[0], track)).to.be.true; // jshint ignore:line + expect(trackList).to.have.lengthOf(2); + expect(objectUtils.areEqual(trackList[0], qtzTrack)).to.be.true; // jshint ignore:line + expect(objectUtils.areEqual(trackList[1], frTrack)).to.be.true; // jshint ignore:line let currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo.id); - expect(objectUtils.areEqual(currentTrack, track)).to.be.false; // jshint ignore:line + expect(objectUtils.areEqual(currentTrack, frTrack)).to.be.false; // jshint ignore:line // call to setInitialMediaSettingsForType mediaController.setInitialSettings(trackType, { - lang: 'fr', + lang: 'fre', viewpoint: 'viewpoint' }); mediaController.setInitialMediaSettingsForType(trackType, streamInfo); currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo.id); - expect(objectUtils.areEqual(currentTrack, track)).to.be.true; // jshint ignore:line + expect(objectUtils.areEqual(currentTrack, frTrack)).to.be.true; // jshint ignore:line }); it('should check initial media settings to choose initial track with a string/regex lang', function () { - const streamInfo = { - id: 'id' - }; - const track = { - type: trackType, - streamInfo: streamInfo, - lang: 'fr', - viewpoint: 'viewpoint', - roles: 1, - accessibility: 1, - audioChannelConfiguration: 1 - }; - - mediaController.addTrack(track); + mediaController.addTrack(frTrack); + mediaController.addTrack(qtzTrack); let trackList = mediaController.getTracksFor(trackType, streamInfo.id); - expect(trackList).to.have.lengthOf(1); - expect(objectUtils.areEqual(trackList[0], track)).to.be.true; // jshint ignore:line + expect(trackList).to.have.lengthOf(2); + expect(objectUtils.areEqual(trackList[0], frTrack)).to.be.true; // jshint ignore:line + expect(objectUtils.areEqual(trackList[1], qtzTrack)).to.be.true; // jshint ignore:line let currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo.id); - expect(objectUtils.areEqual(currentTrack, track)).to.be.false; // jshint ignore:line + expect(objectUtils.areEqual(currentTrack, frTrack)).to.be.false; // jshint ignore:line // call to setInitialMediaSettingsForType mediaController.setInitialSettings(trackType, { - lang: 'fr|en|qtz', + lang: /fr|en|qtz/, viewpoint: 'viewpoint' }); mediaController.setInitialMediaSettingsForType(trackType, streamInfo); currentTrack = mediaController.getCurrentTrackFor(trackType, streamInfo.id); - expect(objectUtils.areEqual(currentTrack, track)).to.be.true; // jshint ignore:line + expect(objectUtils.areEqual(currentTrack, frTrack)).to.be.true; // jshint ignore:line }); it('should check initial media settings to choose initial track with a regex lang', function () { - const streamInfo = { - id: 'id' - }; - const frTrack = { - type: trackType, - streamInfo: streamInfo, - lang: 'fr', - viewpoint: 'viewpoint', - roles: 1, - accessibility: 1, - audioChannelConfiguration: 1 - }; - const qtzTrack = { - type: trackType, - streamInfo: streamInfo, - lang: 'qtz', - viewpoint: 'viewpoint', - roles: 1, - accessibility: 1, - audioChannelConfiguration: 1 - }; - mediaController.addTrack(frTrack); mediaController.addTrack(qtzTrack);