Skip to content

Commit 8fb4ea3

Browse files
authored
Merge pull request #39 from amarcu5/develop
v0.2.4
2 parents 7326d9d + c98b96c commit 8fb4ea3

File tree

5 files changed

+139
-33
lines changed

5 files changed

+139
-33
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,18 @@ Get the latest release from the [Safari Extension Gallery](https://safari-extens
2828
* [Netflix](http://www.netflix.com)
2929
* [OCS](http://www.ocs.fr)
3030
* [Openload](http://www.openload.co)
31+
* [Periscope](http://www.periscope.tv)
3132
* [Plex](http://www.plex.tv)
33+
* [Seznam Zprávy](http://www.seznam.cz/zpravy)
34+
* [Stream.cz](http://www.stream.cz)
3235
* [Streamable](http://streamable.com)
3336
* [The Onion](http://www.theonion.com)
3437
* [Twitch](http://www.twitch.tv)
3538
* [Udemy](http://www.udemy.com)
3639
* [Vevo](http://www.vevo.com)
3740
* [Vice](http://www.vice.com)
3841
* [Vid.me](http://www.vid.me)
42+
* [Video Aktálně](http://video.aktualne.cz)
3943
* [VRV](http://www.vrv.co)
4044
* [YouTube](http://www.youtube.com)
4145

out/PiPer.safariextz

406 Bytes
Binary file not shown.

src/Info.plist

+14
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
<dict>
3939
<key>Allowed Domains</key>
4040
<array>
41+
<string>aktualne.cz</string>
42+
<string>*.aktualne.cz</string>
4143
<string>amazon.co.uk</string>
4244
<string>*.amazon.co.uk</string>
4345
<string>amazon.com</string>
@@ -72,10 +74,22 @@
7274
<string>*.ocs.fr</string>
7375
<string>openload.co</string>
7476
<string>*.openload.co</string>
77+
<string>oload.stream</string>
78+
<string>*.oload.stream</string>
79+
<string>oload.tv</string>
80+
<string>*.oload.tv</string>
81+
<string>periscope.tv</string>
82+
<string>*.periscope.tv</string>
7583
<string>plex.tv</string>
7684
<string>*.plex.tv</string>
7785
<string>primevideo.com</string>
7886
<string>*.primevideo.com</string>
87+
<string>pscp.tv</string>
88+
<string>*.pscp.tv</string>
89+
<string>seznam.cz</string>
90+
<string>*.seznam.cz</string>
91+
<string>stream.cz</string>
92+
<string>*.stream.cz</string>
7993
<string>streamable.com</string>
8094
<string>*.streamable.com</string>
8195
<string>theonion.com</string>

src/scripts/main.js

+119-31
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ const log = function(message) {
3939
!COMPILED && console.log('PiPer: ' + message);
4040
};
4141

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+
4258
/**
4359
* Injects Picture in Picture button into webpage
4460
*
@@ -52,7 +68,7 @@ const addButton = function(parent) {
5268

5369
// Set button properties
5470
button.id = BUTTON_ID;
55-
button.title = 'Open Picture in Picture mode';
71+
button.title = localizedButtonTitle();
5672
if (currentResource.buttonStyle) button.style.cssText = currentResource.buttonStyle;
5773
if (currentResource.buttonClassName) button.className = currentResource.buttonClassName;
5874

@@ -97,11 +113,11 @@ const addButton = function(parent) {
97113
/**
98114
* Prepares video for captions
99115
*
100-
* @param {HTMLVideoElement} video - an unprepared video element
116+
* @param {HTMLVideoElement} video - video element that will display captions
101117
*/
102118
const prepareCaptions = function(video) {
103119

104-
// Find existing caption track (if video element id changes function can be called twice)
120+
// Find existing caption track
105121
track = null;
106122
const allTracks = video.textTracks;
107123
for (let trackId = allTracks.length; trackId--;) {
@@ -116,16 +132,27 @@ const prepareCaptions = function(video) {
116132
// Otherwise create new caption track
117133
log('Caption track created');
118134
track = video.addTextTrack('captions', TRACK_ID, 'en');
135+
};
119136

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 + ')');
129156
};
130157

131158
/**
@@ -225,7 +252,7 @@ const initialiseCaches = function() {
225252
};
226253

227254
// 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) {
229256
let cachedElementId = null;
230257

231258
return function(bypassCache) {
@@ -242,23 +269,16 @@ const initialiseCaches = function() {
242269
// Save the native id otherwise assign a unique id
243270
if (!uncachedElement.id) uncachedElement.id = uniqueId();
244271
cachedElementId = uncachedElement.id;
245-
246-
// Call the optional element changed callback if needed
247-
if (cachedElement != uncachedElement && elementChangedCallback) {
248-
elementChangedCallback(uncachedElement);
249-
}
250272
}
251273
return uncachedElement;
252274
};
253275
};
254276

255277
// Performance optimisation - prepare captions when new video found
256-
let videoElementChanged = null;
257278
if (currentResource.captionElement) {
258279
currentResource.captionElement = cacheElementWrapper(currentResource.captionElement);
259-
videoElementChanged = prepareCaptions;
260280
}
261-
currentResource.videoElement = cacheElementWrapper(currentResource.videoElement, videoElementChanged);
281+
currentResource.videoElement = cacheElementWrapper(currentResource.videoElement);
262282
currentResource.buttonParent = cacheElementWrapper(currentResource.buttonParent);
263283
};
264284

@@ -279,6 +299,27 @@ const bypassBackgroundTimerThrottling = function() {
279299
/** @type {!IObject<string, PiperResource>} */
280300
const resources = {
281301

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+
282323
'amazon': {
283324
buttonHoverStyle: /** CSS */ (`opacity: 1 !important`),
284325
buttonInsertBefore: function(/** Element */ parent) {
@@ -481,6 +522,7 @@ const resources = {
481522
'mixer': {
482523
buttonClassName: 'control',
483524
buttonElementType: 'div',
525+
buttonHoverStyle: /** CSS */ (`background: rgba(255, 255, 255, 0.08)`),
484526
buttonInsertBefore: function(/** Element */ parent) {
485527
return parent.lastChild.previousSibling;
486528
},
@@ -491,6 +533,7 @@ const resources = {
491533
buttonStyle: /** CSS */ (`
492534
position: relative;
493535
top: 2px;
536+
border-radius: 50%;
494537
cursor: pointer;
495538
`),
496539
videoElement: function() {
@@ -518,7 +561,7 @@ const resources = {
518561
return e && e.parentElement.querySelector('.player-timedtext');
519562
},
520563
videoElement: function() {
521-
return document.querySelector('.video-container video');
564+
return document.querySelector('.VideoContainer video');
522565
},
523566
},
524567

@@ -552,8 +595,7 @@ const resources = {
552595
return parent.lastChild;
553596
},
554597
buttonParent: function() {
555-
const e = document.getElementById('olvideo');
556-
return e && e.querySelector('.vjs-control-bar');
598+
return document.querySelector('.vjs-control-bar');
557599
},
558600
buttonScale: 0.6,
559601
buttonStyle: /** CSS */ (`
@@ -595,6 +637,46 @@ const resources = {
595637
},
596638
},
597639

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+
598680
'streamable': {
599681
buttonDidAppear: function() {
600682
const progressBar = document.getElementById('player-progress');
@@ -667,16 +749,17 @@ const resources = {
667749
filter: brightness(50%) sepia(1) hue-rotate(219deg) saturate(117%) brightness(112%);
668750
`),
669751
buttonInsertBefore: function(/** Element */ parent) {
670-
return parent.querySelector('.player-button--fullscreen');
752+
return parent.querySelector('.qa-fullscreen-button');
671753
},
672754
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');
675756
},
676757
buttonScale: 0.8,
758+
captionElement: function() {
759+
return document.querySelector('.player-captions-container');
760+
},
677761
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');
680763
},
681764
},
682765

@@ -839,7 +922,10 @@ const resources = {
839922
};
840923

841924
// Define domain name aliases and URL shorteners (e.g. youtu.be -> youtube.com)
925+
resources['oload'] = resources['openload'];
926+
resources['periscope'] = resources['pscp'];
842927
resources['primevideo'] = resources['amazon'];
928+
resources['stream'] = resources['seznam'];
843929
resources['youtu'] = resources['youtube'];
844930

845931

@@ -851,13 +937,15 @@ if (domainName in resources) {
851937
currentResource = resources[domainName];
852938

853939
initialiseCaches();
940+
941+
document.addEventListener('webkitpresentationmodechanged', videoPresentationModeChanged, {
942+
capture: true,
943+
});
854944

855945
const observer = new MutationObserver(mutationObserver);
856-
857946
observer.observe(document, {
858947
childList: true,
859948
subtree: true,
860949
});
861-
862950
mutationObserver();
863951
}

update.plist

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
<key>CFBundleIdentifier</key>
99
<string>com.amarcus.safari.piper</string>
1010
<key>CFBundleShortVersionString</key>
11-
<string>0.2.3</string>
11+
<string>0.2.4</string>
1212
<key>CFBundleVersion</key>
13-
<string>100</string>
13+
<string>115</string>
1414
<key>Developer Identifier</key>
1515
<string>BQ6Q24MF9X</string>
1616
<key>URL</key>

0 commit comments

Comments
 (0)