Created
April 19, 2017 09:06
-
-
Save send2moran/b7d31abfdf60cd38621e1e8268a18adf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if(window.safari) { | |
// YOUTUBE HACKS for ClickToPlugin | |
var script = "var s = document.createElement('script'); s.textContent = 'if(!/[?&]html5=1/.test(location.search)){"; | |
// Disable SPF | |
script += "ytspf={};Object.defineProperty(ytspf,\"enabled\",{\"value\":false});"; | |
// Disable HTML5 | |
script += "HTMLMediaElement.prototype.canPlayType=function(){return\"\";};HTMLMediaElement.prototype.nativePlay=HTMLMediaElement.prototype.play;HTMLMediaElement.prototype.play=function(){if(this.className===\"CTPmediaElement\")this.nativePlay();else{this.removeAttribute(\"src\");this.load();}};"; | |
// Disable Flash version checking... | |
// ... on /watch pages | |
script += "ytplayer={};Object.defineProperty(ytplayer,\"config\",{\"get\":function(){return ytplayer.$;},\"set\":function($){$.min_version=\"0.0.0\";$.url_v9as2=$.url;ytplayer.$=$;}});"; | |
// ... on /embed pages | |
script += "yt={\"config_\":{}};Object.defineProperty(yt.config_,\"PLAYER_CONFIG\",{\"get\":function(){return yt.config_.$;},\"set\":function($){$.min_version=\"0.0.0\";$.url_v9as2=$.url;yt.config_.$=$;}});"; | |
// ... on /user pages | |
script += "document.addEventListener(\"DOMContentLoaded\",function(){var v=document.getElementById(\"upsell-video\");if(v)v.dataset.swfConfig=v.dataset.swfConfig.replace(/(min_version[^\\\\d]*)\\\\d+\\\\.\\\\d+\\\\.\\\\d+/,\"$10.0.0\").replace(/(url_v9as2\\\":\\\")\\\"/,\"$1\"+ytplayer.config.url.replace(/\\\\//g,\"\\\\\\\\/\")+\"\\\\\"\");},true);"; | |
script += "}'; document.documentElement.appendChild(s);"; | |
safari.extension.addContentScript(script, ["http://www.youtube.com/*", "https://www.youtube.com/*"], [], false); | |
} | |
addKiller("YouTube", { | |
"canKill": function(data) { | |
if(/^https?:\/\/s\.ytimg\.com\//.test(data.src)) return true; | |
if(/^https?:\/\/(?:www\.)?youtube(?:-nocookie|\.googleapis)?\.com\/[vpe]\//.test(data.src)) {data.embed = true; return true;} | |
return false; | |
}, | |
"process": function(data, callback) { | |
var videoID, playlistID, startTime; | |
var onsite = /^https?:\/\/www\.youtube\.com\/watch\?/.test(data.location); | |
if(data.embed) { // old-style YT embed | |
var match = /\.com\/([vpe])\/+([^&?]+)/.exec(data.src); | |
if(match) { | |
if(match[1] === "p") playlistID = "PL" + match[2]; | |
else videoID = match[2]; | |
} else return; | |
match = /[?&]start=([\d]+)/.exec(data.src); | |
if(match) startTime = parseInt(match[1]); | |
} else { | |
var flashvars = parseFlashVariables(data.params.flashvars); | |
videoID = flashvars.video_id; | |
if(!videoID) return; | |
if(/^PL|^FL|^SP|^AL/.test(flashvars.list)) playlistID = flashvars.list; | |
if(onsite) { | |
var match = /[#&?]t=(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?/.exec(data.location); | |
if(match) { | |
var hours = parseInt(match[1]) || 0; | |
var minutes = parseInt(match[2]) || 0; | |
var seconds = parseInt(match[3]) || 0; | |
startTime = 3600 * hours + 60 * minutes + seconds; | |
} | |
} else startTime = parseInt(flashvars.start); | |
} | |
var mainCallback = function(mediaData) { | |
mediaData.startTime = startTime; | |
if(onsite) { | |
mediaData.initScript = "try{var _this=this;var seekTo=function(time){var seek=function(){_this.removeEventListener(\"loadeddata\",seek,false);_this.play();_this.currentTime=time;};if(_this.readyState>=_this.HAVE_CURRENT_DATA)seek();else{_this.preload=\"auto\";_this.addEventListener(\"loadeddata\",seek,false);}_this.parentNode.focus();};window.yt=window.yt||{};yt.www=yt.www||{};yt.www.watch=yt.www.watch||{};yt.www.watch.player=yt.www.watch.player||{};yt.www.watch.player.flashSeekTo=yt.www.watch.player.seekTo;Object.defineProperty(yt.www.watch.player,\"seekTo\",{\"get\":function(){return seekTo;},\"set\":function(x){yt.www.watch.player.flashSeekTo=x;},\"enumerable\":false,\"configurable\":false});}catch(e){}"; | |
mediaData.restoreScript = "try{var player={\"seekTo\":yt.www.watch.player.flashSeekTo};for(var e in yt.www.watch.player){if(e!==\"flashSeekTo\")player[e]=yt.www.watch.player[e];}yt.www.watch.player=player;}catch(e){}"; | |
} | |
callback(mediaData); | |
}; | |
if(playlistID) this.processPlaylist(playlistID, videoID, mainCallback, callback); | |
else if(videoID) this.processVideoID(videoID, !onsite, mainCallback); | |
}, | |
"processVideoID": function(videoID, isEmbed, callback) { | |
var _this = this; | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", "https://www.youtube.com/get_video_info?&video_id=" + videoID + "&eurl=http%3A%2F%2Fwww%2Eyoutube%2Ecom%2F&sts=135957536242", true); | |
xhr.addEventListener("load", function() { | |
var flashvars = parseFlashVariables(xhr.responseText); | |
if(flashvars.status === "ok") { | |
_this.processFlashVars(flashvars, isEmbed ? function(mediaData) { | |
mediaData.playlist[0].siteInfo = {"name": "YouTube", "url": "http://www.youtube.com/watch?v=" + videoID}; | |
callback(mediaData); | |
} : callback); | |
} else { // e.g. region-blocked video | |
callback({"playlist": [null]}); | |
} | |
}, false); | |
xhr.send(null); | |
}, | |
"processFlashVars": function(flashvars, callback) { | |
if(flashvars.ps === "live" && !flashvars.hlsvp) return; | |
var sources = []; | |
var title = flashvars.title.replace(/%22/g, "%5C%22"); | |
// Get video URLs | |
if(flashvars.url_encoded_fmt_stream_map) { // Get 240p, 360p, and 720p | |
var fmtList = decodeURIComponent(flashvars.url_encoded_fmt_stream_map).split(","); | |
var fmt, source; | |
for(var i = 0; i < fmtList.length; i++) { | |
fmt = parseFlashVariables(fmtList[i]); | |
if(!fmt.url) continue; | |
if(fmt.itag === "22") { | |
source = {"format": "720p MP4", "height": 720, "isNative": true}; | |
} else if(fmt.itag === "18") { | |
source = {"format": "360p MP4", "height": 360, "isNative": true}; | |
} else if(canPlayFLV && fmt.itag === "5") { | |
source = {"format": "240p FLV", "height": 240, "isNative": false}; | |
} else continue; | |
source.url = decodeURIComponent(fmt.url); | |
if(fmt.sig) source.url += "&signature=" + fmt.sig; | |
else if(fmt.s) source.url += "&signature=" + this.decodeSignature(fmt.s); | |
// title parameter cannot be more than 228 unescaped characters | |
if(unescape(title + source.height).length < 225) source.url += "&title=" + title + "%20%5B" + source.height + "p%5D"; | |
sources.push(source); | |
} | |
} else if(flashvars.hlsvp) { | |
sources.push({"url": decodeURIComponent(flashvars.hlsvp), "format": "HLS", "isNative": true}); | |
} | |
var poster, title; | |
if(flashvars.iurlmaxres) poster = decodeURIComponent(flashvars.iurlmaxres); | |
else if(flashvars.iurlsd) poster = decodeURIComponent(flashvars.iurlsd); | |
else poster = "https://i.ytimg.com/vi/" + flashvars.video_id + "/hqdefault.jpg"; | |
if(flashvars.title) title = decodeURIComponent(flashvars.title.replace(/\+/g, " ")); | |
sources.sort(function(s, t) { | |
return s.height < t.height ? 1 : -1; | |
}); | |
callback({ | |
"playlist": [{ | |
"title": title, | |
"poster": poster, | |
"sources": sources | |
}] | |
}); | |
}, | |
"decodeSignature": function(s) { | |
s = s.split(""); | |
s = s.slice(3); | |
s = s.reverse(); | |
s = s.slice(2); | |
s = s.reverse(); | |
s = s.slice(1); | |
s = s.reverse(); | |
var t = s[0]; | |
s[0] = s[67%s.length]; | |
s[67] = t; | |
return s.join(""); | |
}, | |
"processPlaylist": function(playlistID, videoID, mainCallback, callback) { | |
var videoIDList = []; | |
var _this = this; | |
var loadPlaylist = function(url) { | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", url ? url : "https://www.youtube.com/playlist?list=" + playlistID, true); | |
xhr.addEventListener("load", function() { | |
if(xhr.status === 200) { | |
var regex = /\bdata-video-id=\\?"([^\\"]*)\\?"/g; | |
var match; | |
while(match = regex.exec(xhr.responseText)) { | |
videoIDList.push(match[1]); | |
} | |
match = /\bdata-uix-load-more-href=\\?"([^"]*)\\?"/.exec(xhr.responseText); | |
if(match === null) processList(); | |
else loadPlaylist("https://www.youtube.com" + unescapeUnicode(match[1]).replace(/\\/g, "").replace(/&/g, "&")); | |
} else if(videoID) _this.processVideoID(videoID, false, mainCallback); | |
}, false); | |
xhr.send(null); | |
}; | |
var processList = function() { | |
var track = 0; | |
var length = videoIDList.length; | |
if(videoID) { // shift list so that videoID is first | |
while(videoIDList[0] !== videoID && track < length) { | |
++track; | |
videoIDList.push(videoIDList.shift()); | |
} | |
if(track === length) { | |
videoIDList.unshift(videoID); | |
++length; | |
track = 0; | |
} | |
} | |
var callbackForPlaylist = function(mediaData) { | |
mediaData.playlistLength = length; | |
mediaData.startTrack = track; | |
mainCallback(mediaData); | |
}; | |
// load the first video at once | |
_this.processVideoID(videoIDList[0], !videoID, callbackForPlaylist); | |
videoIDList.shift(); | |
unloadList(); | |
}; | |
var unloadList = function() { | |
if(videoIDList.length === 0) return; | |
var i = 0; | |
var imax = videoIDList.length; | |
if(imax > 3) imax = 3; // load by groups of 3 | |
var mediaData = {"loadAfter": true, "playlist": []}; | |
var next = function(data) { | |
mediaData.playlist.push(data.playlist[0]); | |
++i; | |
if(i === imax) { | |
callback(mediaData); | |
unloadList(); | |
} else _this.processVideoID(videoIDList.shift(), true, next); | |
}; | |
_this.processVideoID(videoIDList.shift(), true, next); | |
}; | |
loadPlaylist(); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment