@@ -39,6 +39,22 @@ const log = function(message) {
39
39
! COMPILED && console . log ( 'PiPer: ' + message ) ;
40
40
} ;
41
41
42
+ /**
43
+ * Returns localized button title
44
+ *
45
+ * @return {string }
46
+ */
47
+ const localizedButtonTitle = function ( ) {
48
+ const language = navigator . language . substring ( 0 , 2 ) ;
49
+ switch ( language ) {
50
+ case 'de' :
51
+ return 'Bild-in-Bild starten' ;
52
+ case 'en' :
53
+ default :
54
+ return 'Open Picture in Picture mode' ;
55
+ }
56
+ } ;
57
+
42
58
/**
43
59
* Injects Picture in Picture button into webpage
44
60
*
@@ -52,7 +68,7 @@ const addButton = function(parent) {
52
68
53
69
// Set button properties
54
70
button . id = BUTTON_ID ;
55
- button . title = 'Open Picture in Picture mode' ;
71
+ button . title = localizedButtonTitle ( ) ;
56
72
if ( currentResource . buttonStyle ) button . style . cssText = currentResource . buttonStyle ;
57
73
if ( currentResource . buttonClassName ) button . className = currentResource . buttonClassName ;
58
74
@@ -97,11 +113,11 @@ const addButton = function(parent) {
97
113
/**
98
114
* Prepares video for captions
99
115
*
100
- * @param {HTMLVideoElement } video - an unprepared video element
116
+ * @param {HTMLVideoElement } video - video element that will display captions
101
117
*/
102
118
const prepareCaptions = function ( video ) {
103
119
104
- // Find existing caption track (if video element id changes function can be called twice)
120
+ // Find existing caption track
105
121
track = null ;
106
122
const allTracks = video . textTracks ;
107
123
for ( let trackId = allTracks . length ; trackId -- ; ) {
@@ -116,16 +132,27 @@ const prepareCaptions = function(video) {
116
132
// Otherwise create new caption track
117
133
log ( 'Caption track created' ) ;
118
134
track = video . addTextTrack ( 'captions' , TRACK_ID , 'en' ) ;
135
+ } ;
119
136
120
- // Toggle captions when Picture in Picture mode changes
121
- const toggleCaptions = function ( ) {
122
- showingCaptions = video . webkitPresentationMode == 'picture-in-picture' ;
123
- lastUnprocessedCaption = '' ;
124
- processCaptions ( ) ;
125
- log ( 'Video presentation mode changed (showingCaptions: ' + showingCaptions + ')' ) ;
126
- } ;
127
- video . addEventListener ( 'webkitbeginfullscreen' , toggleCaptions ) ;
128
- video . addEventListener ( 'webkitendfullscreen' , toggleCaptions ) ;
137
+ /**
138
+ * Toggles captions when video presentation mode changes
139
+ *
140
+ * @param {Event } event - a webkitpresentationmodechanged event
141
+ */
142
+ const videoPresentationModeChanged = function ( event ) {
143
+
144
+ // Ignore events from other video elements e.g. adverts
145
+ const video = /** @type {HTMLVideoElement } */ ( event . target ) ;
146
+ const expectedVideo = currentResource . videoElement ( true ) ;
147
+ if ( video != expectedVideo ) return ;
148
+
149
+ // Toggle display of the captions and prepare video if needed
150
+ showingCaptions = video . webkitPresentationMode == 'picture-in-picture' ;
151
+ if ( showingCaptions ) prepareCaptions ( video ) ;
152
+ lastUnprocessedCaption = '' ;
153
+ processCaptions ( ) ;
154
+
155
+ log ( 'Video presentation mode changed (showingCaptions: ' + showingCaptions + ')' ) ;
129
156
} ;
130
157
131
158
/**
@@ -225,7 +252,7 @@ const initialiseCaches = function() {
225
252
} ;
226
253
227
254
// Wraps a function that returns an element to provide faster lookups by id
228
- const cacheElementWrapper = function ( /** (function(): ?Element|undefined) */ elementFunction , elementChangedCallback ) {
255
+ const cacheElementWrapper = function ( elementFunction ) {
229
256
let cachedElementId = null ;
230
257
231
258
return function ( bypassCache ) {
@@ -242,23 +269,16 @@ const initialiseCaches = function() {
242
269
// Save the native id otherwise assign a unique id
243
270
if ( ! uncachedElement . id ) uncachedElement . id = uniqueId ( ) ;
244
271
cachedElementId = uncachedElement . id ;
245
-
246
- // Call the optional element changed callback if needed
247
- if ( cachedElement != uncachedElement && elementChangedCallback ) {
248
- elementChangedCallback ( uncachedElement ) ;
249
- }
250
272
}
251
273
return uncachedElement ;
252
274
} ;
253
275
} ;
254
276
255
277
// Performance optimisation - prepare captions when new video found
256
- let videoElementChanged = null ;
257
278
if ( currentResource . captionElement ) {
258
279
currentResource . captionElement = cacheElementWrapper ( currentResource . captionElement ) ;
259
- videoElementChanged = prepareCaptions ;
260
280
}
261
- currentResource . videoElement = cacheElementWrapper ( currentResource . videoElement , videoElementChanged ) ;
281
+ currentResource . videoElement = cacheElementWrapper ( currentResource . videoElement ) ;
262
282
currentResource . buttonParent = cacheElementWrapper ( currentResource . buttonParent ) ;
263
283
} ;
264
284
@@ -279,6 +299,27 @@ const bypassBackgroundTimerThrottling = function() {
279
299
/** @type {!IObject<string, PiperResource> } */
280
300
const resources = {
281
301
302
+ 'aktualne' : {
303
+ buttonClassName : 'jw-icon jw-icon-inline jw-button-color jw-reset jw-icon-logo' ,
304
+ buttonElementType : 'div' ,
305
+ buttonHoverStyle : /** CSS */ ( `
306
+ filter: brightness(50%) sepia(1) hue-rotate(311deg) saturate(550%) brightness(49%) !important;
307
+ ` ) ,
308
+ buttonInsertBefore : function ( /** Element */ parent ) {
309
+ return parent . lastChild ;
310
+ } ,
311
+ buttonParent : function ( ) {
312
+ return document . querySelector ( '.jw-controlbar-right-group' ) ;
313
+ } ,
314
+ buttonStyle : /** CSS */ ( `
315
+ width: 38px;
316
+ filter: brightness(80%);
317
+ ` ) ,
318
+ videoElement : function ( ) {
319
+ return document . querySelector ( 'video.jw-video' ) ;
320
+ } ,
321
+ } ,
322
+
282
323
'amazon' : {
283
324
buttonHoverStyle : /** CSS */ ( `opacity: 1 !important` ) ,
284
325
buttonInsertBefore : function ( /** Element */ parent ) {
@@ -481,6 +522,7 @@ const resources = {
481
522
'mixer' : {
482
523
buttonClassName : 'control' ,
483
524
buttonElementType : 'div' ,
525
+ buttonHoverStyle : /** CSS */ ( `background: rgba(255, 255, 255, 0.08)` ) ,
484
526
buttonInsertBefore : function ( /** Element */ parent ) {
485
527
return parent . lastChild . previousSibling ;
486
528
} ,
@@ -491,6 +533,7 @@ const resources = {
491
533
buttonStyle : /** CSS */ ( `
492
534
position: relative;
493
535
top: 2px;
536
+ border-radius: 50%;
494
537
cursor: pointer;
495
538
` ) ,
496
539
videoElement : function ( ) {
@@ -518,7 +561,7 @@ const resources = {
518
561
return e && e . parentElement . querySelector ( '.player-timedtext' ) ;
519
562
} ,
520
563
videoElement : function ( ) {
521
- return document . querySelector ( '.video-container video' ) ;
564
+ return document . querySelector ( '.VideoContainer video' ) ;
522
565
} ,
523
566
} ,
524
567
@@ -552,8 +595,7 @@ const resources = {
552
595
return parent . lastChild ;
553
596
} ,
554
597
buttonParent : function ( ) {
555
- const e = document . getElementById ( 'olvideo' ) ;
556
- return e && e . querySelector ( '.vjs-control-bar' ) ;
598
+ return document . querySelector ( '.vjs-control-bar' ) ;
557
599
} ,
558
600
buttonScale : 0.6 ,
559
601
buttonStyle : /** CSS */ ( `
@@ -595,6 +637,46 @@ const resources = {
595
637
} ,
596
638
} ,
597
639
640
+ 'pscp' : {
641
+ buttonClassName : 'Pill Pill--withIcon' ,
642
+ buttonElementType : 'span' ,
643
+ buttonHoverStyle : /** CSS */ ( `
644
+ opacity: 0.8 !important;
645
+ filter: brightness(125%) !important;
646
+ ` ) ,
647
+ buttonInsertBefore : function ( /** Element */ parent ) {
648
+ return parent . querySelector ( '.ShareBroadcast' ) . nextSibling ;
649
+ } ,
650
+ buttonParent : function ( ) {
651
+ return document . querySelector ( '.VideoOverlayRedesign-BottomBar-Right' ) ;
652
+ } ,
653
+ buttonScale : 0.6 ,
654
+ buttonStyle : /** CSS */ ( `
655
+ opacity: 0.5;
656
+ filter: brightness(200%);
657
+ ` ) ,
658
+ videoElement : function ( ) {
659
+ return document . querySelector ( '.vjs-tech video[src]' ) ;
660
+ } ,
661
+ } ,
662
+
663
+ 'seznam' : {
664
+ buttonClassName : 'sznp-ui-widget-box' ,
665
+ buttonElementType : 'div' ,
666
+ buttonHoverStyle : /** CSS */ ( `transform: scale(1.05)` ) ,
667
+ buttonInsertBefore : function ( /** Element */ parent ) {
668
+ return parent . lastChild ;
669
+ } ,
670
+ buttonParent : function ( ) {
671
+ return document . querySelector ( '.sznp-ui-ctrl-panel-layout-wrapper' ) ;
672
+ } ,
673
+ buttonScale : 0.75 ,
674
+ buttonStyle : /** CSS */ ( `cursor: pointer` ) ,
675
+ videoElement : function ( ) {
676
+ return document . querySelector ( '.sznp-ui-tech-video-wrapper video' ) ;
677
+ } ,
678
+ } ,
679
+
598
680
'streamable' : {
599
681
buttonDidAppear : function ( ) {
600
682
const progressBar = document . getElementById ( 'player-progress' ) ;
@@ -667,16 +749,17 @@ const resources = {
667
749
filter: brightness(50%) sepia(1) hue-rotate(219deg) saturate(117%) brightness(112%);
668
750
` ) ,
669
751
buttonInsertBefore : function ( /** Element */ parent ) {
670
- return parent . querySelector ( '.player-button-- fullscreen' ) ;
752
+ return parent . querySelector ( '.qa- fullscreen-button ' ) ;
671
753
} ,
672
754
buttonParent : function ( ) {
673
- const e = document . getElementById ( 'video-playback' ) || document . getElementById ( 'player' ) ;
674
- return e && e . querySelector ( '.player-buttons-right' ) ;
755
+ return document . querySelector ( '.player-buttons-right' ) ;
675
756
} ,
676
757
buttonScale : 0.8 ,
758
+ captionElement : function ( ) {
759
+ return document . querySelector ( '.player-captions-container' ) ;
760
+ } ,
677
761
videoElement : function ( ) {
678
- const e = document . getElementById ( 'video-playback' ) || document . getElementById ( 'player' ) ;
679
- return e && e . querySelector ( 'video' ) ;
762
+ return document . querySelector ( '.player-video video' ) ;
680
763
} ,
681
764
} ,
682
765
@@ -839,7 +922,10 @@ const resources = {
839
922
} ;
840
923
841
924
// Define domain name aliases and URL shorteners (e.g. youtu.be -> youtube.com)
925
+ resources [ 'oload' ] = resources [ 'openload' ] ;
926
+ resources [ 'periscope' ] = resources [ 'pscp' ] ;
842
927
resources [ 'primevideo' ] = resources [ 'amazon' ] ;
928
+ resources [ 'stream' ] = resources [ 'seznam' ] ;
843
929
resources [ 'youtu' ] = resources [ 'youtube' ] ;
844
930
845
931
@@ -851,13 +937,15 @@ if (domainName in resources) {
851
937
currentResource = resources [ domainName ] ;
852
938
853
939
initialiseCaches ( ) ;
940
+
941
+ document . addEventListener ( 'webkitpresentationmodechanged' , videoPresentationModeChanged , {
942
+ capture : true ,
943
+ } ) ;
854
944
855
945
const observer = new MutationObserver ( mutationObserver ) ;
856
-
857
946
observer . observe ( document , {
858
947
childList : true ,
859
948
subtree : true ,
860
949
} ) ;
861
-
862
950
mutationObserver ( ) ;
863
951
}
0 commit comments