Last active
December 14, 2015 01:18
-
-
Save antonrogov/5004645 to your computer and use it in GitHub Desktop.
This file contains 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
addKiller("YouTube", { | |
"processItag": function(itag) { | |
if(itag === "38") return {"format": "4K MP4", "height": 2304, "isNative": true}; | |
if(itag === "37") return {"format": "1080p MP4", "height": 1080, "isNative": true}; | |
if(itag === "22") return {"format": "720p MP4", "height": 720, "isNative": true}; | |
if(itag === "18") return {"format": "360p MP4", "height": 360, "isNative": true}; | |
if(canPlayFLV) { | |
if(itag === "35") return {"format": "480p FLV", "height": 480, "isNative": false}; | |
if(itag === "5") return {"format": "240p FLV", "height": 240, "isNative": false}; | |
} | |
return false; | |
}, | |
"decode": function(s) { | |
switch(s.length) { | |
case 85: | |
s = s.split("").reverse().join(""); | |
return s.substring(1,60) + s.substring(0,1) + s.substring(61,82); | |
case 86: | |
return s.substring(6,7) + s.substring(1,3) + s.substring(62,63) + s.substring(7,43) + s.substring(0,1) + s.substring(56,57) + s.substring(45,56) + s.substring(43,44) + s.substring(57,62) + s.substring(3,4) + s.substring(63,84); | |
case 87: // TBI | |
return s; | |
} | |
}, | |
"canKill": function(data) { | |
if(/^https?:\/\/s\.ytimg\.com\//.test(data.src)) return true; | |
if(/^https?:\/\/(?:www\.)?youtube(?:-nocookie|\.googleapis)?\.com\//.test(data.src)) {data.embed = true; return true;} | |
return false; | |
}, | |
"process": function(data, callback) { | |
if(data.embed) { // old-style YT embed | |
var match = /\.com\/([vpe])\/+([^&?]+)/.exec(data.src); | |
if(match) { | |
if(match[1] === "p") this.processPlaylistID("PL" + match[2], {}, callback); | |
else this.processVideoID(match[2], callback); | |
} | |
return; | |
} | |
var flashvars = parseFlashVariables(data.params.flashvars); | |
var onsite = flashvars.t && flashvars.url_encoded_fmt_stream_map; | |
if(onsite) { | |
var match = /[#&?]t=(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?/.exec(data.location); | |
if (match) { | |
var hours = parseInt(match[1], 10) || 0; | |
var minutes = parseInt(match[2], 10) || 0; | |
var seconds = parseInt(match[3], 10) || 0; | |
flashvars.start = 3600 * hours + 60 * minutes + seconds; | |
} | |
flashvars.initScript = "\ | |
var tries = 0;\ | |
var intervalID = setInterval(function() {\ | |
try{\ | |
if(!mediaElement.parentNode) throw null;\ | |
yt.www.watch.player.oldSeekTo = yt.www.watch.player.seekTo;\ | |
yt.www.watch.player.seekTo = function(time) {\ | |
var seek = function() {\ | |
mediaElement.removeEventListener(\"loadeddata\", seek, false);\ | |
mediaElement.currentTime = time;\ | |
mediaElement.play();\ | |
};\ | |
if(mediaElement.readyState >= mediaElement.HAVE_CURRENT_DATA) {\ | |
mediaElement.pause();\ | |
seek();\ | |
} else {\ | |
mediaElement.preload = \"auto\";\ | |
mediaElement.addEventListener(\"loadeddata\", seek, false);\ | |
}\ | |
mediaElement.parentNode.focus();\ | |
};\ | |
clearInterval(intervalID);\ | |
} catch(e) {\ | |
if(++tries > 100 || e === null) clearInterval(intervalID);\ | |
}\ | |
}, 100);"; | |
flashvars.restoreScript = "\ | |
try{\ | |
if(yt.www.watch.player.oldSeekTo) yt.www.watch.player.seekTo = yt.www.watch.player.oldSeekTo;\ | |
} catch(e) {}"; | |
} | |
if(/^PL|^SP|^UL|^AL|^UU|^FL|^RD|^LL/.test(flashvars.list) && flashvars.feature !== "channel") this.processPlaylistID(flashvars.list, flashvars, callback); | |
else if(onsite) this.processFlashVars(flashvars, callback); | |
else if(flashvars.video_id) this.processVideoID(flashvars.video_id, function(mediaData) { | |
mediaData.startTime = parseInt(flashvars.start); | |
callback(mediaData); | |
}); | |
}, | |
"processFlashVars": function(flashvars, callback) { | |
if(flashvars.ps === "live") return; | |
var formatList = decodeURIComponent(flashvars.url_encoded_fmt_stream_map).split(","); | |
var sources = []; | |
var x; | |
for(var i = 0; i < formatList.length; i++) { | |
x = parseFlashVariables(formatList[i]); | |
var source = this.processItag(x.itag); | |
if(source) { | |
source.url = decodeURIComponent(x.url) + "&title=" + flashvars.title; | |
if(x.sig) source.url += "&signature=" + x.sig; | |
else if(x.s) source.url += "&signature=" + this.decode(x.s); | |
sources.push(source); | |
} | |
} | |
var posterURL; | |
if(flashvars.iurlmaxres) posterURL = decodeURIComponent(flashvars.iurlmaxres); | |
else if(flashvars.iurlsd) posterURL = decodeURIComponent(flashvars.iurlsd); | |
else posterURL = "https://i.ytimg.com/vi/" + flashvars.video_id + "/hqdefault.jpg"; | |
callback({ | |
"playlist": [{ | |
"title": decodeURIComponent(flashvars.title.replace(/\+/g, " ")), | |
"poster": posterURL, | |
"sources": sources | |
}], | |
"startTime": parseInt(flashvars.start), | |
"initScript": flashvars.initScript, | |
"restoreScript": flashvars.restoreScript | |
}); | |
}, | |
"processVideoID": function(videoID, 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", true); | |
xhr.addEventListener("load", function() { | |
var flashvars = parseFlashVariables(xhr.responseText); | |
if(flashvars.status === "ok" && flashvars.ps !== "live") { | |
var callbackForEmbed = function(videoData) { | |
videoData.playlist[0].siteInfo = {"name": "YouTube", "url": "http://www.youtube.com/watch?v=" + videoID}; | |
callback(videoData); | |
}; | |
_this.processFlashVars(flashvars, callbackForEmbed); | |
} else { // happens e.g. if YT just removed content and didn't update its playlists yet | |
callback({"playlist": [null]}); | |
} | |
}, false); | |
xhr.send(null); | |
}, | |
"processPlaylistID": function(playlistID, flashvars, callback) { | |
var videoIDList = []; | |
var _this = this; | |
var loadAPIList = function(playlistURL, startIndex, reverse) { | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", playlistURL + "?start-index=" + startIndex + "&max-results=50", true); | |
xhr.addEventListener("load", function() { | |
if(xhr.status !== 200) { | |
_this.processFlashVars(flashvars, callback); | |
return; | |
} | |
var entries = xhr.responseXML.getElementsByTagName("entry"); | |
for(var i = 0; i < entries.length; i++) { | |
try{ // being lazy | |
videoIDList[reverse ? "unshift" : "push"](/\?v=([^&?']+)/.exec(entries[i].getElementsByTagNameNS("http://search.yahoo.com/mrss/", "player")[0].getAttribute("url"))[1]); | |
} catch(e) {} | |
} | |
if(xhr.responseXML.querySelector("link[rel='next']") === null) processList(); | |
else loadAPIList(playlistURL, startIndex + 50, reverse); | |
}, false); | |
xhr.send(null); | |
}; | |
var processList = function() { | |
var track = 0; | |
var length = videoIDList.length; | |
if(flashvars.video_id) { // shift list so that videoID is first | |
while(videoIDList[0] !== flashvars.video_id && track < length) { | |
++track; | |
videoIDList.push(videoIDList.shift()); | |
} | |
if(track === length) { | |
videoIDList.unshift(flashvars.video_id); | |
++length; | |
track = 0; | |
} | |
} | |
var callbackForPlaylist = function(mediaData) { | |
mediaData.playlistLength = length; | |
mediaData.startTrack = track; | |
callback(mediaData); | |
}; | |
// load the first video at once | |
if(flashvars.url_encoded_fmt_stream_map) _this.processFlashVars(flashvars, callbackForPlaylist); | |
else _this.processVideoID(videoIDList[0], 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(), next); | |
}; | |
_this.processVideoID(videoIDList.shift(), next); | |
return; | |
}; | |
switch(playlistID.substring(0,2)) { | |
case "AL": | |
case "UU": | |
case "FL": | |
case "RD": | |
case "LL": | |
loadAPIList("https://gdata.youtube.com/feeds/api/playlists/" + playlistID, 1, false); | |
break; | |
case "PL": | |
case "SP": | |
loadAPIList("https://gdata.youtube.com/feeds/api/playlists/" + playlistID.substring(2), 1, false); | |
break; | |
case "UL": | |
if(flashvars.creator) loadAPIList("https://gdata.youtube.com/feeds/api/users/" + flashvars.creator + "/uploads", 1, true); | |
else if(flashvars.ptchn) loadAPIList("https://gdata.youtube.com/feeds/api/users/" + flashvars.ptchn + "/uploads", 1, true); | |
else { | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", "https://www.youtube.com/get_video_info?&video_id=" + playlistID.substring(2) + "&eurl=http%3A%2F%2Fwww%2Eyoutube%2Ecom%2F", true); | |
xhr.addEventListener("load", function() {loadAPIList("https://gdata.youtube.com/feeds/api/users/" + parseFlashVariables(xhr.responseText).author + "/uploads", 1, true);}, false); | |
xhr.send(null); | |
} | |
break; | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment