22function sepiaFW_build_ui_cards_embed ( ) {
33 var Embed = { } ;
44
5- //TODO: add MediaPlayer
6- /*
7- - Controls : start, pause/stop, resume, next, previous
8- - Implement async. callback with msgId and timeout
5+ //MediaPlayer
6+ /* TODO:
7+ - Test and finish controls : start, pause/stop, resume, next, previous, vol...
8+ - Implement async. callback with msgId and timeout?
99 - Get media info and use SepiaFW.audio.setPlayerTitle('', '') + setMediaSessionState (SepiaFW.audio)
1010 */
1111 var playerWidgets = {
1212 default : "<assist_server>/widgets/mp-default.html" ,
1313 embedded : "<assist_server>/widgets/mp-default.html" ,
1414 spotify : "<assist_server>/widgets/mp-spotify.html" ,
1515 apple_music : "<assist_server>/widgets/mp-apple-music.html" ,
16- youtube : "<assist_server>/widgets/mp-youtube.html"
16+ youtube : "<assist_server>/widgets/mp-youtube.html" ,
17+ soundcloud : "<assist_server>/widgets/mp-soundcloud.html"
1718 }
1819
1920 var activeMediaPlayers = { } ;
2021 var lastActiveMediaPlayer = undefined ;
22+ var maxActiveMediaPlayers = 5 ; //NOTE: "active" does not mean "playing" but "exists" with event listeners
2123
2224 function getNewMediaPlayerId ( ) {
2325 mediaPlayerLastId ++ ;
2426 var overflow = false ;
25- if ( mediaPlayerLastId > 5 ) {
27+ if ( mediaPlayerLastId > maxActiveMediaPlayers ) {
2628 mediaPlayerLastId = 1 ;
2729 overflow = true ;
2830 }
@@ -31,7 +33,7 @@ function sepiaFW_build_ui_cards_embed(){
3133 //remove old players
3234 var oldMp = activeMediaPlayers [ newId ] ;
3335 if ( oldMp && oldMp . exists ( ) ) {
34- oldMp . release ( ) ;
36+ oldMp . cardItem . sepiaCardOnBeforeRemove ( ) ;
3537 $ ( oldMp . cardItem ) . remove ( ) ;
3638 }
3739 //console.error("RELEASED and REMOVED", newId, activeMediaPlayers[newId]); //DEBUG
@@ -69,6 +71,7 @@ function sepiaFW_build_ui_cards_embed(){
6971 allowIframe = 'encrypted-media *;' ;
7072 }
7173 var iframe = document . createElement ( "iframe" ) ;
74+ iframe . className = "cardItemBlock onlyBlock" ;
7275 iframe . src = contentUrl ;
7376 iframe . width = "100%" ;
7477 iframe . height = 50 ; //can be set via postMessage interface
@@ -79,7 +82,7 @@ function sepiaFW_build_ui_cards_embed(){
7982 mediaPlayerDiv . appendChild ( iframe ) ;
8083 //loading overlay
8184 var loadOverlay = document . createElement ( 'div' ) ;
82- loadOverlay . className = "cardItemOverlay" ;
85+ loadOverlay . className = "cardItemOverlay cardItemBlock " ;
8386 loadOverlay . innerHTML = "<p>Loading</p>" ;
8487 mediaPlayerDiv . appendChild ( loadOverlay ) ;
8588 return {
@@ -152,7 +155,7 @@ function sepiaFW_build_ui_cards_embed(){
152155 //options
153156 //required: parentElement, widget or widgetUrl
154157 //optional: brand
155- //events: onready
158+ //events: onready (NOTE: will trigger only once)
156159
157160 var thisPlayer = this ;
158161 //console.error("Embedded MediaPlayer", options); //DEBUG
@@ -172,17 +175,27 @@ function sepiaFW_build_ui_cards_embed(){
172175 //Widget URL
173176 var widgetUrl = ( options . widgetUrl || playerWidgets [ options . widget ] ) . trim ( ) ;
174177 widgetUrl = SepiaFW . config . replacePathTagWithActualPath ( widgetUrl ) ;
175- var widgetIsSameOrigin = SepiaFW . tools . isSameOrigin ( widgetUrl ) ;
176- var widgetIsSepiaFileHost = SepiaFW . config . urlIsSepiaFileHost ( widgetUrl ) ;
177- var widgetIsRemote = ( widgetUrl . indexOf ( "http:" ) == 0 ) || ( widgetUrl . indexOf ( "https:" ) == 0 ) || ( widgetUrl . indexOf ( "ftp:" ) == 0 ) ;
178- var widgetIsTrusted = widgetIsSameOrigin || widgetIsSepiaFileHost || ! widgetIsRemote ;
178+ //check URL - NOTE: currently we do not allow unknown URLs
179+ var isValidLocalURL = SepiaFW . tools . isRelativeFileUrl ( widgetUrl , "html" ) ;
180+ var isTrustedRemoteUrl = SepiaFW . tools . isRemoteFileUrl ( widgetUrl , "html" )
181+ && ( SepiaFW . tools . isSameOrigin ( widgetUrl ) || SepiaFW . config . urlIsSepiaFileHost ( widgetUrl ) ) ;
182+ var widgetIsTrusted = isValidLocalURL || isTrustedRemoteUrl ;
183+ if ( ! widgetIsTrusted ) {
184+ SepiaFW . debug . error ( "WARNING: Widget URL has remote location and was BLOCKED due to security restrictions! - URL: " + widgetUrl ) ;
185+ SepiaFW . ui . showSafeWarningPopup ( "Warning" , [
186+ "SEPIA was asked to open a widget with an untrusted remote URL. The request has been blocked due to security restrictions." ,
187+ "If you want to use this widget please ask an admin to move it to a secure location (e.g. the SEPIA file server)." ,
188+ "URL:"
189+ ] , widgetUrl ) ;
190+ return ;
191+ }
179192
180193 //URL parameters (so we have the data during loading)
181194 widgetUrl = SepiaFW . tools . setParameterInURL ( widgetUrl , "skinStyle" , SepiaFW . ui . getSkinStyle ( ) ) ;
182195 widgetUrl = SepiaFW . tools . setParameterInURL ( widgetUrl , "skinId" , SepiaFW . ui . getSkin ( ) ) ;
183- //add more: language, isMobile, env, ...?
184-
185- console . error ( "Media Player URL" , widgetUrl , "isTrusted" , widgetIsTrusted ) ; //DEBUG
196+ widgetUrl = SepiaFW . tools . setParameterInURL ( widgetUrl , "lang" , SepiaFW . config . appLanguage ) ;
197+ widgetUrl = SepiaFW . tools . setParameterInURL ( widgetUrl , "mobile" , SepiaFW . ui . isMobile ) ;
198+ SepiaFW . debug . info ( "Embedded MediaPlayer - Loading widget URL: " + widgetUrl ) ;
186199
187200 //Create card (DOM element)
188201 var mpObj = createMediaPlayerDomElement ( playerId , widgetUrl , widgetIsTrusted , function ( ) {
@@ -191,23 +204,25 @@ function sepiaFW_build_ui_cards_embed(){
191204 } ) ;
192205 thisPlayer . iframe = mpObj . iframe ;
193206 thisPlayer . cardItem = mpObj . card ;
207+ thisPlayer . overlay = mpObj . overlay ;
194208 thisPlayer . exists = function ( ) {
195209 var ex = thisPlayer . cardItem && document . body . contains ( thisPlayer . cardItem ) ;
196- if ( ! ex && state != 11 ) {
197- thisPlayer . release ( ) ;
198- }
210+ /* if (!ex && state != 11){
211+ thisPlayer.release(); //this should be used but it can lead to null pointer in sync. follow-up checks :-/
212+ }*/
199213 return ex ;
200214 }
201215 options . parentElement . appendChild ( mpObj . card ) ;
202216
203217 //Card move and delete actions
204- mpObj . card . sepiaCardOnBeforeMove = function ( ) {
205- console . error ( "MOVE EVENT" , playerId ) ; //DEBUG
206- //TODO: rescue state - anything else? (note: onready is a one-time event now)
207- }
208- mpObj . card . sepiaCardOnBeforeRemove = function ( ) {
209- //TODO: currently called nowhere
210- console . error ( "REMOVE EVENT" , playerId ) ; //DEBUG
218+ thisPlayer . cardItem . sepiaCardOnBeforeMove = function ( ) {
219+ //TODO: no reliable way to call it atm (can we use MutationObserver? But on what parent?)
220+ //console.error("BEFORE MOVE EVENT", playerId); //DEBUG
221+ //anything? (note: onready is a one-time event now, settings will restore automatically)
222+ }
223+ thisPlayer . cardItem . sepiaCardOnBeforeRemove = function ( ) {
224+ //TODO: no reliable way to call it atm (too many events: history clear, parent list remove, etc...)
225+ //console.error("BEFORE REMOVE EVENT", playerId); //DEBUG
211226 thisPlayer . release ( ) ;
212227 }
213228
@@ -238,8 +253,14 @@ function sepiaFW_build_ui_cards_embed(){
238253 if ( ev . state != undefined ) {
239254 stateHandler ( ev ) ;
240255 }
256+ if ( ev . settings ) {
257+ widgetSettings = ev . settings ;
258+ }
241259 }
242260
261+ //Settings backup
262+ var widgetSettings ; //settings specific to widget that will be submitted e.g. after move or reload
263+
243264 //States
244265 var state = 0 ; //0: created, 1: ready, 2: playing, 3: paused, 10: error, 11: closed
245266 var isOnHold = false ; //will start to play after next idle event (usually)
@@ -248,34 +269,42 @@ function sepiaFW_build_ui_cards_embed(){
248269
249270 function stateHandler ( ev ) {
250271 var data = ev . data || { } ;
272+
273+ //on-ready
251274 if ( ev . state == 1 ) {
252- //on-ready
253275 state = ev . state ;
254276 if ( data . size && data . size . height ) {
255277 thisPlayer . iframe . style . height = data . size . height ;
256278 }
257- setTimeout ( function ( ) { $ ( mpObj . overlay ) . hide ( ) ; } , 500 ) ;
279+ setTimeout ( function ( ) { $ ( thisPlayer . overlay ) . hide ( ) ; } , 500 ) ;
280+ //settings stored?
281+ if ( widgetSettings ) {
282+ thisPlayer . restoreSettings ( widgetSettings ) ;
283+ }
258284 //callback (only once)
259285 if ( options . onready ) {
260286 options . onready ( ) ;
261287 options . onready = undefined ;
262288 }
263289
290+ //on-play
264291 } else if ( ev . state == 2 ) {
265- //on-play
266292 state = ev . state ;
267293 SepiaFW . audio . broadcastAudioEvent ( "embedded-media-player" , "start" ) ;
268- lastActiveMediaPlayer = thisPlayer ; //TODO: use?
294+ lastActiveMediaPlayer = thisPlayer ;
269295 SepiaFW . debug . info ( "Embedded MediaPlayer - Last active player switched to: " + playerId ) ;
270296 //Embed.stopAllMediaPlayers(thisPlayer) //this should be handled globally for ALL media
297+ if ( ev . data && ev . data . meta ) {
298+ console . error ( "META" , ev . data . meta ) ; //DEBUG
299+ }
271300
301+ //on-pause
272302 } else if ( ev . state == 3 ) {
273- //on-pause
274303 state = ev . state ;
275304 SepiaFW . audio . broadcastAudioEvent ( "embedded-media-player" , "pause" ) ;
276305
306+ //on-error
277307 } else if ( ev . state == 10 ) {
278- //on-error
279308 var lastWasError = ( state == 10 ) ;
280309 state = ev . state ;
281310 //ev.code-ev.name: 1-UnknownEvent, 2-NoMediaMatch, 3-PlayerErrorNotAllowed, 4-PlayerError (any), ... tbd
@@ -292,6 +321,8 @@ function sepiaFW_build_ui_cards_embed(){
292321 }
293322 SepiaFW . debug . error ( "Embedded MediaPlayer - Error:" , ev . name , ev . message , ev . code ) ;
294323 SepiaFW . audio . broadcastAudioEvent ( "embedded-media-player" , "error" ) ;
324+
325+ //other
295326 } else {
296327 SepiaFW . debug . error ( "Embedded MediaPlayer - Unknown state: " + ev . state ) ;
297328 return ;
@@ -326,14 +357,15 @@ function sepiaFW_build_ui_cards_embed(){
326357 //include 'isOnHold'? (atm we don't check this for internal player)
327358 }
328359
329- //Controls - TODO: implement callbacks?! more?
360+ //Controls
330361 thisPlayer . play = function ( doneCallback , errorCallback ) {
331362 sendEvent ( { controls : "play" } ) ;
332363 isWaitingForPlay = true ;
333364 }
334365 thisPlayer . pause = function ( doneCallback , errorCallback ) {
335366 sendEvent ( { controls : "pause" } ) ;
336367 isWaitingForPause = true ;
368+ isWaitingForPlay = false ;
337369 isOnHold = false ;
338370 }
339371 thisPlayer . fadeOut = function ( doneCallback , errorCallback ) {
@@ -351,6 +383,7 @@ function sepiaFW_build_ui_cards_embed(){
351383 thisPlayer . next = function ( doneCallback , errorCallback ) {
352384 sendEvent ( { controls : "next" } ) ;
353385 }
386+ //TODO: implement callbacks?! more?
354387 thisPlayer . previous = function ( doneCallback , errorCallback ) {
355388 sendEvent ( { controls : "previous" } ) ;
356389 }
@@ -360,6 +393,7 @@ function sepiaFW_build_ui_cards_embed(){
360393 thisPlayer . volumeDown = function ( doneCallback , errorCallback ) {
361394 sendEvent ( { controls : "volumeDown" } ) ;
362395 }
396+
363397 //Content
364398 thisPlayer . mediaRequest = function ( type , request , autoplay , safeRequest , doneCallback , errorCallback ) {
365399 SepiaFW . audio . broadcastAudioEvent ( "embedded-media-player" , "prepare" ) ;
@@ -381,10 +415,22 @@ function sepiaFW_build_ui_cards_embed(){
381415 safeRequest : safeRequest //came from assistant or private channel?
382416 } ) ;
383417 }
418+ //Settings
419+ thisPlayer . restoreSettings = function ( data ) {
420+ sendEvent ( {
421+ settings : data
422+ } ) ;
423+ }
424+
425+ //Specials
426+ thisPlayer . openInExternalPage = function ( ) {
427+ //TODO: implement
428+ SepiaFW . ui . showPopup ( SepiaFW . local . g ( "cant_execute" ) + " (Coming Soon)" ) ;
429+ }
384430
385- //stop, release resources and remove handle
431+ //Release resources and remove handler
386432 thisPlayer . release = function ( doneCallback , errorCallback ) {
387- // - remove from active players, block incoming events
433+ //remove from active players, block incoming events
388434 state = 11 ;
389435 if ( lastActiveMediaPlayer == thisPlayer ) lastActiveMediaPlayer = undefined ;
390436 delete activeMediaPlayers [ playerId ] ;
0 commit comments