diff --git a/README.md b/README.md
index b5ebeec..7e93fc9 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,9 @@ For developement: Xcode 8
4. Enable 'Run PiPifier'
5. Select 'Run PiPifier' on a website with a video
+# Userscript
+https://greasyfork.org/scripts/374160-pipifier
+
# How can I help?
If you are a developer feel free to make any addition to improve PiPifier.
@@ -57,4 +60,5 @@ If you are user and want a native PiP button in any video player please make a r
The code is a bit dirty and there are some unused parts in it (Tried to add more features before I needed to focus on other things). If you want to help me clean it up feel free to do so :)
# Contact
-Made by [@arno_app](https://twitter.com/arno_app) with an important bug fix by [@Cacauu_de](https://twitter.com/Cacauu_de).
+Made by [@arno_app](https://twitter.com/arno_app) with an important bug fix by [@Cacauu_de](https://twitter.com/Cacauu_de)
+Userscript port & Chrome support: [Willian](https://github.com/willian-zhang)
diff --git a/userscript/all.user.js b/userscript/all.user.js
new file mode 100644
index 0000000..45f8e56
--- /dev/null
+++ b/userscript/all.user.js
@@ -0,0 +1,250 @@
+// ==UserScript==
+// @name PiPifier
+// @namespace https://github.com/Willian-Zhang/PiPifier
+// @version 0.3
+// @description PiPifier is an extension that lets you use every HTML5 video in Picture in Picture mode
+// @author @arno_app , @Cacauu_de , @Willian
+// @match */*
+// @grant none
+// ==/UserScript==
+
+//image URLs
+var whiteSVG_Icon = `data:image/svg+xml;utf8,
+`;
+var blackSVG_Icon = `data:image/svg+xml;utf8,
+`;
+
+//safari.self.addEventListener("message", messageHandler); // Message recieved from Swift code
+window.onfocus = function() {
+ previousResult = null;
+ checkForVideo();
+}; // Tab selected
+new MutationObserver(checkForVideo).observe(document, {subtree: true, childList: true}); // DOM changed
+
+//function dispatchMessage(messageName, parameters) {
+// safari.extension.dispatchMessage(messageName, parameters);
+//}
+
+function messageHandler(event) {
+ if (event.name === "enablePiP" && getVideo() != null) {
+ enablePiP();
+ } else if (event.name === "addCustomPiPButtonToPlayer") {
+ addCustomPiPButtonToPlayer(event.message)
+ }
+}
+function addCustomPiPButtonToPlayer(message){
+ message.callback();
+}
+
+var previousResult = null;
+var videoCheck = {found: true}
+function checkForVideo() {
+ if (getVideo() != null) {
+ addCustomPiPButtons();
+ if (previousResult === null || previousResult === false) {
+ //dispatchMessage("videoCheck", {found: true});
+ console.warn("videoCheck", {found: true})
+ videoCheck = {found: true}
+ // enablePiP();
+ }
+ previousResult = true;
+ } else if (window == window.top) {
+ if (previousResult === null || previousResult === true) {
+ //dispatchMessage("videoCheck", {found: false});
+ console.warn("videoCheck", {found: false})
+ videoCheck = {found: false}
+ }
+ previousResult = false;
+ }
+}
+
+function getVideo() {
+ return document.getElementsByTagName('video')[0];
+}
+
+async function action(video) {
+ if (video.hasAttribute('__pip__')) {
+ await document.exitPictureInPicture();
+ } else {
+ await video.requestPictureInPicture();
+ video.setAttribute('__pip__', true);
+ video.addEventListener('leavepictureinpicture', event => {
+ video.removeAttribute('__pip__');
+ }, {
+ once: true
+ });
+ }
+}
+
+function enablePiP() {
+ let video = getVideo()
+ if(video.webkitSetPresentationMode){
+ // safari
+ video.webkitSetPresentationMode('picture-in-picture');
+ }else{
+ //chrome
+ action(video);
+ }
+}
+
+//----------------- Custom Button Methods -----------------
+
+var players = [
+ {name: "YouTube", shouldAddButton: shouldAddYouTubeButton, addButton: addYouTubeButton},
+ {name: "VideoJS", shouldAddButton: shouldAddVideoJSButton, addButton: addVideoJSButton},
+ {name: "Netflix", shouldAddButton: shouldAddNetflixButton, addButton: addNetflixButton},
+ {name: "Wistia", shouldAddButton: shouldAddWistiaButton, addButton: addWistiaButton},
+ //TODO: add other players here
+ ];
+
+let pipCheck = function pipCheck(message){
+ addCustomPiPButtonToPlayer(message);
+}
+function addCustomPiPButtons() {
+ for (const player of players) {
+ if (player.shouldAddButton()) {
+ //dispatchMessage("pipCheck", {callback: player.addButton.name}) //Sets the callback to the player's addButton
+ pipCheck({callback: player.addButton});
+ }
+ }
+}
+
+//----------------- Player Implementations -------------------------
+
+function shouldAddYouTubeButton() {
+ //check if on youtube or player is embedded
+ return (location.hostname.match(/^(www\.)?youtube\.com$/)
+ || document.getElementsByClassName("ytp-right-controls").length > 0)
+ && document.getElementsByClassName('PiPifierButton').length == 0;
+}
+
+function addYouTubeButton() {
+ if (!shouldAddYouTubeButton()) return;
+ var button = document.createElement("button");
+ button.className = "ytp-button PiPifierButton";
+ button.title = "PiP (by PiPifier)";
+ button.onclick = enablePiP;
+ //TODO add style
+ //button.style.backgroundImage = 'url('+ whiteSVG_Icon + ')';
+ var buttonImage = document.createElement("img");
+ buttonImage.src = whiteSVG_Icon;
+ buttonImage.width = 22;
+ buttonImage.height = 36;
+ button.appendChild(buttonImage);
+
+ document.getElementsByClassName("ytp-right-controls")[0].appendChild(button);
+}
+
+
+function shouldAddVideoJSButton() {
+ return document.getElementsByClassName('vjs-control-bar').length > 0
+ && document.getElementsByClassName('PiPifierButton').length == 0;
+}
+
+
+function addVideoJSButton() {
+ if (!shouldAddVideoJSButton()) return;
+ var button = document.createElement("button");
+ button.className = "PiPifierButton vjs-control vjs-button";
+ button.title = "PiP (by PiPifier)";
+ button.onclick = enablePiP;
+ var buttonImage = document.createElement("img");
+ buttonImage.src = whiteSVG_Icon;
+ buttonImage.width = 16;
+ buttonImage.height = 30;
+ button.appendChild(buttonImage);
+ var fullscreenButton = document.getElementsByClassName("vjs-fullscreen-control")[0];
+ fullscreenButton.parentNode.insertBefore(button, fullscreenButton);
+}
+
+function shouldAddWistiaButton() {
+ return document.getElementsByClassName('wistia_playbar').length > 0
+ && document.getElementsByClassName('PiPifierButton').length == 0;
+}
+
+function addWistiaButton() {
+ if (!shouldAddWistiaButton()) return;
+ var button = document.createElement("button");
+ button.className = "PiPifierButton w-control w-control--fullscreen w-is-visible";
+ button.alt = "Picture in Picture";
+ button.title = "PiP (by PiPifier)";
+ button.onclick = enablePiP;
+ var buttonImage = document.createElement("img");
+ buttonImage.src = whiteSVG_Icon;
+ buttonImage.width = 28;
+ buttonImage.height = 18;
+ buttonImage.style.verticalAlign = "middle";
+ button.appendChild(buttonImage);
+ document.getElementsByClassName("w-control-bar__region--airplay")[0].appendChild(button);
+}
+
+
+function shouldAddNetflixButton() {
+ return location.hostname.match('netflix')
+ && document.getElementsByClassName('PiPifierButton').length == 0;
+}
+
+function addNetflixButton(timeOutCounter) {
+ if (!shouldAddNetflixButton()) return;
+ if (timeOutCounter == null) timeOutCounter = 0;
+ var button = document.createElement("button");
+ button.className = "PiPifierButton";
+ button.title = "PiP (by PiPifier)";
+ button.onclick = enablePiP;
+ button.style.backgroundColor = "transparent";
+ button.style.border = "none";
+ button.style.maxHeight = "inherit";
+ button.style.width = "70px";
+ button.style.marginRight = "2px";
+ var buttonImage = document.createElement("img");
+ buttonImage.src = whiteSVG_Icon;
+ buttonImage.style.verticalAlign = "middle";
+ buttonImage.style.maxHeight = "40%";
+ button.appendChild(buttonImage);
+ var playerStatusDiv = document.getElementsByClassName("player-status")[0];
+ if (playerStatusDiv == null && timeOutCounter < 3) {
+ //this is needed because the div is sometimes not reachable on the first load
+ //also necessary to count up and stop at some time to avoid endless loop on main netflix page
+ setTimeout(function() {addNetflixButton(timeOutCounter+1);}, 3000);
+ return;
+ }
+ playerStatusDiv.insertBefore(button, playerStatusDiv.firstChild);
+}
\ No newline at end of file