-
Notifications
You must be signed in to change notification settings - Fork 23
VP-211: subtitlesFinder component for a VideoPlayer #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
02560be
c1450b7
53d215f
c93087d
4ce84ac
8cd58ed
349b267
b384b92
f4f6e43
4eb8e6d
abe30ff
f07847c
82b22ec
0488d2f
81f19fe
f9b89a6
544a360
c37ebf0
95a94f5
57fb6b3
c645cbc
a7b2da5
e907342
12d1a5f
4d8e90a
a9f073b
4bf4f2e
5d024dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| Copyright 2012 OCAD University | ||
|
|
||
| Licensed under the Educational Community License (ECL), Version 2.0 or the New | ||
| BSD license. You may not use this file except in compliance with one these | ||
| Licenses. | ||
|
|
||
| You may obtain a copy of the ECL 2.0 License and BSD License at | ||
| https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt | ||
| */ | ||
|
|
||
| /*global jQuery, window, fluid*/ | ||
|
|
||
| // JSLint options | ||
| /*jslint white: true, funcinvoke: true, undef: true, newcap: true, nomen: true, regexp: true, bitwise: true, browser: true, forin: true, maxerr: 100, indent: 4 */ | ||
|
|
||
| (function () { | ||
|
|
||
| fluid.defaults("fluid.dataSource", { | ||
| gradeNames: ["autoInit", "fluid.eventedComponent", "fluid.modelComponent"], | ||
| events: { | ||
| onError: null, | ||
| onSuccess: null | ||
| }, | ||
| invokers: { | ||
| get: "fluid.dataSource.get", | ||
| dataParse: { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can be written simply as: |
||
| funcName: "fluid.dataSource.dataParse", | ||
| args: ["{arguments}.0"] | ||
| } | ||
| }, | ||
| model: { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure why these are in a model, instead of plain default options.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because those values could be changed potentially. There could be the case when the same dataSource would be used to query 2 different webservices. In that case we want to change those values and according to our conventions options block has settings which do not change when state of the component changes |
||
| dataType: "jsonp", // Default ajax data type | ||
| params: {}, // parameters which will be added to the url | ||
| baseURL: null // url where the call will be made | ||
| }, | ||
| timeout: 10000 // do not allow jsonp to halt. max timeout request | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is nice.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is mandatory for jsonp requests. By default they could query indefinitely.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be in members then. |
||
| }); | ||
|
|
||
| fluid.dataSource.dataParse = function (data) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if this is how the function looks like, default invoker implementation should be fluid.identity. |
||
| return data; | ||
| }; | ||
|
|
||
| fluid.dataSource.get = function (that) { | ||
| var events = that.events, | ||
| model = that.model; | ||
|
|
||
| $.ajax({ | ||
| dataType: /* "jsonp", */model.dataType, | ||
| url: model.baseURL, | ||
| data: model.params, | ||
| timeout : that.options.timeout | ||
| }).done(function (data) { | ||
| events.onSuccess.fire(that.dataParse(data)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps we should parse on a separate line to have a possibility of seeing the result. |
||
| }).fail(function () { | ||
| events.onError.fire(); | ||
| }); | ||
| }; | ||
|
|
||
| })(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,7 +34,6 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| postInitFunction: "fluid.videoPlayer.languageMenu.postInit", | ||
| finalInitFunction: "fluid.videoPlayer.languageMenu.finalInit", | ||
| produceTree: "fluid.videoPlayer.languageMenu.produceTree", | ||
| languages: [], | ||
| currentLanguagePath: "activeLanguages", | ||
| showHidePath: "showLanguage", | ||
| model: {}, | ||
|
|
@@ -48,7 +47,8 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| }, | ||
| activated: null, | ||
| hiddenByKeyboard: null, | ||
| onControlledElementReady: null | ||
| onControlledElementReady: null, | ||
| onLanguageListUpdated: null | ||
| }, | ||
| listeners: { | ||
| onControlledElementReady: { | ||
|
|
@@ -80,14 +80,12 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| // TODO: Could this be specified declaratively, in a "protoTree" option? | ||
| // Ans: not very effectively... the renderer still needs to be burned to the ground | ||
| fluid.videoPlayer.languageMenu.produceTree = function (that) { | ||
| // Silly damn renderer with its crazy JSON idiolect! | ||
| that.model.languages = that.options.languages; | ||
| var tree = { | ||
| // create a menu item for each language in the model | ||
| expander: { | ||
| type: "fluid.renderer.repeat", | ||
| repeatID: "language", | ||
| controlledBy: "languages", | ||
| controlledBy: that.options.languageListPath, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be a meaningful default, even if it's an empty array.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. languageListPath points to an empty arrays in the model of a VideoPlayer for transcripts and captions |
||
| pathAs: "lang", | ||
| tree: { | ||
| value: "${{lang}.label}", | ||
|
|
@@ -216,6 +214,12 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| fluid.videoPlayer.languageMenu.bindEventListeners(that); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most if not all contents of this final init function should be eliminated. We can use default component events such as onCreate or onAttach to finish up initialization. |
||
| fluid.videoPlayer.languageMenu.setUpKeyboardA11y(that); | ||
|
|
||
| that.events.onLanguageListUpdated.addListener(function () { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be defined in defaults rather than in final init function. |
||
| that.refreshView(); | ||
| fluid.videoPlayer.languageMenu.bindEventListeners(that); | ||
| fluid.videoPlayer.languageMenu.setUpKeyboardA11y(that); | ||
| }); | ||
|
|
||
| that.container.attr("role", "menu"); | ||
| that.container.css("z-index", 9999); | ||
| that.hideMenu(); | ||
|
|
@@ -243,6 +247,8 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| onReady: null, | ||
| onRenderingComplete: null, | ||
| onControlledElementReady: null, | ||
| onLanguageListUpdated: null, | ||
|
|
||
| afterFetchResources: null | ||
| }, | ||
| listeners: { | ||
|
|
@@ -251,9 +257,9 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| priority: "last" | ||
| } | ||
| }, | ||
| languages: [], | ||
| currentLanguagePath: "", | ||
| showHidePath: "", | ||
| languageListPath: "", | ||
| strings: { | ||
| showLanguage: "Show Language", | ||
| hideLanguage: "Hide Language" | ||
|
|
@@ -286,13 +292,14 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| container: "{languageControls}.dom.menu", | ||
| options: { | ||
| model: "{languageControls}.model", | ||
| languages: "{languageControls}.options.languages", | ||
| applier: "{languageControls}.applier", | ||
| showHidePath: "{languageControls}.options.showHidePath", | ||
| currentLanguagePath: "{languageControls}.options.currentLanguagePath", | ||
| languageListPath: "{languageControls}.options.languageListPath", | ||
| strings: "{languageControls}.options.strings", | ||
| events: { | ||
| onControlledElementReady: "{languageControls}.events.onControlledElementReady" | ||
| onControlledElementReady: "{languageControls}.events.onControlledElementReady", | ||
| onLanguageListUpdated: "{languageControls}.events.onLanguageListUpdated" | ||
| } | ||
| } | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -96,7 +96,8 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| model: "{videoPlayer}.model", | ||
| applier: "{videoPlayer}.applier", | ||
| events: { | ||
| onLoadedMetadata: "{videoPlayer}.events.onLoadedMetadata" | ||
| onLoadedMetadata: "{videoPlayer}.events.onLoadedMetadata", | ||
| onTimeUpdate: "{intervalEventsConductor}.events.onTimeUpdate" | ||
| }, | ||
| listeners: { | ||
| onExitFullScreen: { | ||
|
|
@@ -165,7 +166,9 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| onScrub: "{videoPlayer}.events.onScrub", | ||
| afterScrub: "{videoPlayer}.events.afterScrub", | ||
| onTranscriptsReady: "{videoPlayer}.events.canBindTranscriptMenu", | ||
| onCaptionsReady: "{videoPlayer}.events.canBindCaptionMenu" | ||
| onCaptionsReady: "{videoPlayer}.events.canBindCaptionMenu", | ||
| onCaptionListUpdated: "{videoPlayer}.events.onCaptionListUpdated", | ||
| onTranscriptListUpdated: "{videoPlayer}.events.onTranscriptListUpdated" | ||
| }, | ||
| listeners: { | ||
| onReady: "{videoPlayer}.events.onControllersReady" | ||
|
|
@@ -178,7 +181,19 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| html5Captionator: { | ||
| type: "fluid.videoPlayer.captionator", | ||
| container: "{videoPlayer}.dom.videoPlayer", | ||
| createOnEvent: "onMediaReady" | ||
| createOnEvent: "onSubtitlesFinderReady" | ||
| }, | ||
| subtitlesFinder: { | ||
| type: "fluid.subtitlesFinder", | ||
| createOnEvent: "onMediaReady", | ||
| options: { | ||
| sources: "{videoPlayer}.options.video.sources", | ||
| serviceURL: "https://www.universalsubtitles.org/api2/partners/videos/", | ||
| languagesPath: "objects.0.languages", | ||
| events: { | ||
| onReady: "{videoPlayer}.events.onSubtitlesFinderReady" | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| preInitFunction: "fluid.videoPlayer.preInit", | ||
|
|
@@ -209,6 +224,15 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| args: ["{videoPlayer}"] | ||
| }, | ||
|
|
||
| onCaptionListUpdated: null, | ||
| onTranscriptListUpdated: null, | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The user is probably interested in |onSubtitlesFinderReadyBoiled| event rather than |onSubtitlesFinderReady| we should probably rename this to have something like this: |
||
| onSubtitlesFinderReady: null, | ||
| onSubtitlesFinderReadyBoiled: { | ||
| event: "onSubtitlesFinderReady", | ||
| args: ["{videoPlayer}", "{arguments}.0"] | ||
| }, | ||
|
|
||
| // public, time events | ||
| onTimeUpdate: null, | ||
|
|
||
|
|
@@ -281,7 +305,9 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| volume: 60, | ||
| muted: false, | ||
| canPlay: false, | ||
| play: false | ||
| play: false, | ||
| captions: [], | ||
| transcripts: [] | ||
| }, | ||
| templates: { | ||
| videoPlayer: { | ||
|
|
@@ -465,6 +491,12 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| that.toggleFullscreen = function () { | ||
| that.applier.requestChange("fullscreen", !that.model.fullscreen); | ||
| }; | ||
|
|
||
| // This is the place when we move integrator specified captions and transcripts into the model of a VideoPlayer | ||
| // This model could be potentially extended by some other components like subtitlesFinder | ||
| // Also we agreed on keeping things simple for an integrator where an integrator lists options without touching videoPlayer model. | ||
| that.model.captions = fluid.copy(that.options.video.captions); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps this can go into members. If not, we can express these two lines with a mergePolicy. |
||
| that.model.transcripts = fluid.copy(that.options.video.transcripts); | ||
| }; | ||
|
|
||
| fluid.videoPlayer.postInit = function (that) { | ||
|
|
@@ -500,9 +532,49 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| }; | ||
| }; | ||
|
|
||
| fluid.videoPlayer.uniqueMergeArray = function(firstArray, secondArray, elPath) { | ||
| var languageArray = [], i; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should use makeArray here. |
||
| firstArray = firstArray || []; | ||
| secondArray = secondArray || []; | ||
|
|
||
| var result = firstArray.concat(secondArray); | ||
| result = fluid.remove_if(result, function (elem) { | ||
| var srclang = fluid.get(elem, elPath); | ||
| if (srclang === undefined) { | ||
| return; | ||
| } | ||
|
|
||
| if (languageArray.indexOf(srclang) > -1) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only supported in IE9+. Should use $.inArray |
||
| return elem; | ||
| } | ||
| languageArray.push(srclang); | ||
| }); | ||
|
|
||
| return result; | ||
| }; | ||
|
|
||
| fluid.videoPlayer.extendLanguages = function(that, captionData) { | ||
| captionData = captionData || []; | ||
| if (captionData.length === 0) { | ||
| return; | ||
| } | ||
|
|
||
| // Apply uniqueMergeArray for captions and transcripts based on the captionData returned from the subtitlesFinder component | ||
| fluid.each(["captions", "transcripts"], function (type) { | ||
| var tempData = fluid.copy(captionData); | ||
| fluid.videoPlayer.addDefaultKind(tempData, fluid.get(that.options.defaultKinds, type)); | ||
| tempData = fluid.videoPlayer.uniqueMergeArray(fluid.get(that.model, type), tempData, "srclang"); | ||
| that.applier.requestChange(type, tempData); | ||
| }); | ||
| }; | ||
|
|
||
| fluid.videoPlayer.finalInit = function (that) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This final init function should only contain model/applier binding material. Everything else should be moved out into onCreate or onAttach. The fetchResources call should result in an event firing and the callback should be registered through the defaults and bind to a global function. |
||
| that.container.attr("role", "application"); | ||
|
|
||
| that.applier.modelChanged.addListener("captions", that.events.onCaptionListUpdated.fire); | ||
| that.applier.modelChanged.addListener("transcripts", that.events.onTranscriptListUpdated.fire); | ||
| that.events.onSubtitlesFinderReadyBoiled.addListener(fluid.videoPlayer.extendLanguages); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be defined in defaults. |
||
|
|
||
| // Render each media source with its custom renderer, registered by type. | ||
| // If we aren't on an HTML 5 video-enabled browser, don't bother setting up the controller, captions or transcripts. | ||
|
|
||
|
|
@@ -662,16 +734,5 @@ var fluid_1_5 = fluid_1_5 || {}; | |
| funcName: "fluid.videoPlayer.hideControllersSimple", | ||
| args: ["{videoPlayer}"] | ||
| }); | ||
|
|
||
| /*************************************************************************************************** | ||
| * The wiring up of the onTimeUpdate event btw timer component "media" and intervalEventsConductor * | ||
| ***************************************************************************************************/ | ||
| fluid.demands("fluid.videoPlayer.media", ["fluid.videoPlayer.intervalEventsConductor", "fluid.videoPlayer"], { | ||
| options: { | ||
| events: { | ||
| onTimeUpdate: "{intervalEventsConductor}.events.onTimeUpdate" | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| })(jQuery, fluid_1_5); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,7 +83,7 @@ https://source.fluidproject.org/svn/LICENSE.txt | |
| var display = that.readIndirect("elPaths.displayCaptions"); | ||
| if (display) { | ||
| fluid.videoPlayer.html5Captionator.showCurrentTrack(that.readIndirect("elPaths.currentCaptions"), | ||
| tracks, that.options.captions); | ||
| tracks, that.options.model.captions); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, should probably be in members and be referred to as that.captions |
||
| } else { | ||
| fluid.videoPlayer.html5Captionator.hideAllTracks(tracks); | ||
| } | ||
|
|
@@ -92,7 +92,7 @@ https://source.fluidproject.org/svn/LICENSE.txt | |
| }; | ||
|
|
||
| fluid.videoPlayer.html5Captionator.finalInit = function (that) { | ||
| var captions = that.options.captions; | ||
| var captions = that.options.model.captions; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, should probably be in members and be referred to as that.captions |
||
|
|
||
| // Need to know when all the tracks have been created so we can trigger captionator | ||
| that.tracksToCreate = captions.length; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copyright data should be 2013