├── .gitignore ├── BBC.js ├── BIM.js ├── Bild.js ├── Blip.js ├── Break.js ├── Brightcove.js ├── CSSfix.js ├── CollegeHumor.js ├── Dailymotion.js ├── Eurogamer.js ├── Facebook.js ├── Flash.js ├── Flowplayer.js ├── Gamestar.js ├── Gametrailers.js ├── Generic.js ├── Golem.js ├── IGN.js ├── ImbcNews.js ├── Katu.js ├── MTVNetworks.js ├── Megavideo.js ├── Metacafe.js ├── Myspass.js ├── NYTimes.js ├── NaverVideo.js ├── Novamov.js ├── RaiTv.js ├── SKCommsVideo.js ├── Sevenone.js ├── Silverlight.js ├── Spiegel.js ├── TED.js ├── ThemisMedia.js ├── Tumblr.js ├── TvPot.js ├── Veoh.js ├── Vimeo.js ├── Vodpod.js ├── Welt.js ├── XinMSN.js ├── YouTube-embed-only.js ├── YouTube-force-flash.js ├── YouTube-no-hack.js ├── YouTube.js ├── YouTubeF.js ├── YouTubeS.js ├── YouTubeXHR.js ├── Zeit.js ├── mediaTypes.js ├── support.js └── ВКонтакте.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /BBC.js: -------------------------------------------------------------------------------- 1 | addKiller("BBC", { 2 | 3 | "canKill": function(data) { 4 | return /^http:\/\/emp\.bbci\.co\.uk\/.*\.swf/.test(data.src); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var flashvars = parseFlashVariables(data.params.flashvars); 9 | var playlistURL; 10 | if(flashvars.playlist) playlistURL = decodeURIComponent(flashvars.playlist); 11 | else playlistURL = data.location.replace(/^https?:\/\/[^\/]*\//, "http://playlists.bbc.co.uk/").replace(/[#?].*$/, "") + "A/playlist.sxml"; 12 | 13 | var xhr = new XMLHttpRequest(); 14 | xhr.open("GET", playlistURL, true); 15 | xhr.addEventListener("load", function(event) { 16 | var xml = event.target.responseXML; 17 | var mediator = xml.getElementsByTagName("mediator")[0]; 18 | if(!mediator) return; 19 | 20 | var track = {}; 21 | var title = xml.getElementsByTagName("title")[0]; 22 | if(title) track.title = title.textContent; 23 | 24 | var links = xml.getElementsByTagName("link"); 25 | for(var i = 0; i < links.length; i++) { 26 | if(links[i].getAttribute("rel") === "holding") { 27 | track.poster = links[i].getAttribute("href"); 28 | break; 29 | } 30 | } 31 | 32 | var xhr = new XMLHttpRequest(); 33 | xhr.open("GET", "http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/mediaset/journalism-http-tablet/vpid/" + mediator.getAttribute("identifier") + "/format/json/", true); 34 | // Can also use /xml instead of /json to get an XML response; JSON should be marginally faster 35 | xhr.addEventListener("load", function() { 36 | var data = JSON.parse(xhr.responseText); 37 | var sources = []; 38 | data.media.forEach(function(media) { 39 | var connection = media.connection[0]; 40 | if(!connection || connection.protocol !== "http" || !connection.href) return; 41 | sources.unshift({ 42 | "url": connection.href, 43 | "format": media.bitrate + "k MP4", 44 | "height": parseInt(media.height), 45 | "isNative": true 46 | }); 47 | }); 48 | if(sources.length === 0) return; 49 | track.sources = sources; 50 | callback({"playlist": [track]}); 51 | }, false); 52 | xhr.send(null); 53 | }, false); 54 | xhr.send(null); 55 | } 56 | 57 | }); 58 | -------------------------------------------------------------------------------- /BIM.js: -------------------------------------------------------------------------------- 1 | // BIM killer (2011-09-16) 2 | 3 | addKiller("BIM", { 4 | 5 | "canKill": function(data) { 6 | return (/bimVideoPlayer[^\/.]*\.swf$/.test(data.src) && /(?:^|&)mediaXML=/.test(data.params.flashvars)); 7 | }, 8 | 9 | "process": function(data, callback) { 10 | var url = decodeURIComponent(parseFlashVariables(data.params.flashvars).mediaXML); 11 | var title, posterURL, videoURL; 12 | 13 | var xhr = new XMLHttpRequest(); 14 | xhr.open('GET', url, true); 15 | xhr.onload = function() { 16 | var xml = xhr.responseXML; 17 | 18 | if(xml.getElementsByTagName("h264").length > 0) { 19 | videoURL = xml.getElementsByTagName("h264")[0].textContent; 20 | } else return; 21 | if(xml.getElementsByTagName("image").length > 0) { 22 | posterURL = xml.getElementsByTagName("image")[0].textContent; 23 | } 24 | if(xml.getElementsByTagName("title").length > 0) { 25 | title = xml.getElementsByTagName("title")[0].textContent; 26 | } 27 | 28 | callback({ 29 | "playlist": [{ 30 | "poster": posterURL, 31 | "title": title, 32 | "sources": [{"url": videoURL, "format": "MP4", "isNative": true}] 33 | }] 34 | }); 35 | }; 36 | xhr.send(null); 37 | } 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /Bild.js: -------------------------------------------------------------------------------- 1 | // Bild killer (2011-09-16) 2 | 3 | addKiller("Bild", { 4 | 5 | "canKill": function(data) { 6 | return data.src.indexOf('http://www.bild.de/media/') !== -1; 7 | }, 8 | 9 | "process": function(data, callback) { 10 | var params = parseFlashVariables(data.params.flashvars); 11 | var _this = this; 12 | var xhr = new XMLHttpRequest(); 13 | xhr.open('GET', 'http://www.bild.de' + params.xmlsrc, true); 14 | xhr.onload = function(event) { 15 | _this.parseResponse(event.target.responseXML, callback); 16 | } 17 | xhr.send(null); 18 | }, 19 | 20 | "parseResponse": function(response, callback) { 21 | if(response === null) return; 22 | var videos = response.getElementsByTagName('video'); 23 | if(videos.length < 1) { 24 | return false; 25 | } 26 | callback({ 27 | playlist: [{ 28 | poster: videos[0].getAttribute('img'), 29 | sources: [{ 30 | url: videos[0].getAttribute('src'), 31 | format: 'H.264', 32 | isNative: true 33 | }] 34 | }], 35 | isAudio: false 36 | }); 37 | } 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /Blip.js: -------------------------------------------------------------------------------- 1 | addKiller("Blip", { 2 | 3 | "canKill": function(data) { 4 | return data.src.indexOf("blip.tv/") !== -1; 5 | }, 6 | 7 | "process": function(data, callback) { 8 | if(/^https?:\/\/blip\.tv\/players\/xplayer/.test(data.location)) { 9 | var videoID = parseFlashVariables(data.location.split(/\?/)[1]).id; 10 | var url = "http://blip.tv/rss/flash/" + videoID; 11 | this.processXML(url, false, callback); 12 | } else if(/stratos\.swf/.test(data.src)) { 13 | var match = /[?&#]file=([^&]*)/.exec(data.src); 14 | if(!match) return; 15 | url = match[1]; 16 | this.processXML(decodeURIComponent(url), !/^http:\/\/blip\.tv/.test(data.location), callback); 17 | } else { 18 | var match = /blip\.tv\/play\/([^%]*)/.exec(data.src); 19 | if(match) this.processOldVideoID(match[1], callback); 20 | } 21 | }, 22 | 23 | "processXML": function(url, isEmbed, callback) { 24 | var xhr = new XMLHttpRequest(); 25 | xhr.open("GET", url, true); 26 | xhr.addEventListener("load", function() { 27 | var xml = xhr.responseXML; 28 | var media = xml.getElementsByTagNameNS("http://search.yahoo.com/mrss/", "content"); 29 | var sources = []; 30 | var url, info, height, audioOnly = true; 31 | 32 | for(var i = 0; i < media.length; i++) { 33 | url = media[i].getAttribute("url"); 34 | info = extInfo(getExt(url)); 35 | if(!info) continue; 36 | if(!info.isAudio) audioOnly = false; 37 | height = media[i].getAttribute("height"); 38 | info.url = url; 39 | info.format = media[i].getAttributeNS("http://blip.tv/dtd/blip/1.0", "role") + " " + info.format; 40 | info.height = parseInt(height); 41 | sources.push(info); 42 | } 43 | 44 | var siteInfo; 45 | if(isEmbed) { 46 | var itemId = xml.getElementsByTagNameNS("http://blip.tv/dtd/blip/1.0", "item_id")[0]; 47 | if(itemId) siteInfo = {"name": "Blip.tv", "url": "http://www.blip.tv/file/" + itemId.textContent}; 48 | } 49 | 50 | callback({ 51 | "playlist": [{ 52 | "title": xml.getElementsByTagName("item")[0].getElementsByTagName("title")[0].textContent, 53 | "poster": xml.getElementsByTagNameNS("http://search.yahoo.com/mrss/", "thumbnail")[0].getAttribute("url"), 54 | "sources": sources, 55 | "siteInfo": siteInfo 56 | }], 57 | "audioOnly": audioOnly 58 | }); 59 | }, false); 60 | xhr.send(null); 61 | }, 62 | 63 | "processOldVideoID": function(videoID, callback) { 64 | var xhr = new XMLHttpRequest(); 65 | xhr.open("GET", "http://blip.tv/players/episode/" + videoID + "?skin=api", true); 66 | var _this = this; 67 | xhr.addEventListener("load", function() { 68 | _this.processXML("http://blip.tv/rss/flash/" + xhr.responseXML.getElementsByTagName("id")[0].textContent, true, callback); 69 | }, false); 70 | xhr.send(null); 71 | } 72 | 73 | }); 74 | -------------------------------------------------------------------------------- /Break.js: -------------------------------------------------------------------------------- 1 | addKiller("Break", { 2 | 3 | "canKill": function(data) { 4 | if(/s\.brkmd\.com\/content\/swf\/|media1\.break\.com\/break\/swf\//.test(data.src)) return true; 5 | return false; 6 | }, 7 | 8 | "process": function(data, callback) { 9 | var flashvars = parseFlashVariables(data.params.flashvars); 10 | if(flashvars.videoPath) this.processFlashVars(flashvars, callback); 11 | }, 12 | 13 | "processFlashVars": function(flashvars, callback) { 14 | var videoURL = decodeURIComponent(flashvars.videoPath).replace(/\.flv$|\.mp4$/, ""); 15 | var videoHash = ".mp4?" + flashvars.icon; 16 | 17 | var poster = flashvars.sThumbLoc || flashvars.thumbnailURL; 18 | 19 | var sources = []; 20 | sources.push({"url": videoURL + videoHash, "format": "360p MP4", "height": 360, "isNative": true}); 21 | 22 | var call = function() { 23 | callback({"playlist": [{ 24 | "title": unescape(flashvars.sVidTitle), 25 | "poster": decodeURIComponent(poster), 26 | "sources": sources 27 | }]}); 28 | }; 29 | 30 | var isNewURL = /-360$/.test(videoURL); 31 | videoURL = videoURL.replace(/-360$|_1$/, ""); 32 | var hqURL = videoURL + (isNewURL ? "-480" : "_2") + videoHash; 33 | getMIMEType(hqURL, function(type) { 34 | if(type === "video/mp4") { 35 | sources.unshift({"url": hqURL, "format": "480p MP4", "height": 480, "isNative": true}); 36 | var hdURL = videoURL + (isNewURL ? "-720" : "_3") + videoHash; 37 | getMIMEType(hdURL, function(type) { 38 | if(type === "video/mp4") sources.unshift({"url": hdURL, "format": "720p MP4", "height": 720, "isNative": true}); 39 | call(); 40 | }); 41 | } else call(); 42 | }); 43 | } 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /Brightcove.js: -------------------------------------------------------------------------------- 1 | addKiller("Brightcove", { 2 | 3 | "canKill": function(data) { 4 | return /^https?:\/\/(?:c|secure)\.brightcove\.com\/services\/viewer\/federated_f9/.test(data.src); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var isSecure = data.src.charAt(4) === "s"; 9 | var flashvars = parseFlashVariables(data.params.flashvars); 10 | 11 | var url; 12 | if(/[&?]playerID=/.test(data.src)) { 13 | url = data.src.replace("federated_f9", "htmlFederated"); 14 | } else { 15 | url = (isSecure ? "https://secure" : "http://c") + ".brightcove.com/services/viewer/htmlFederated?playerID=" + flashvars.playerID + "&playerKey=" + flashvars.playerKey + "&%40videoPlayer=" + flashvars.videoId; 16 | } 17 | 18 | var xhr = new XMLHttpRequest(); 19 | xhr.open("GET", url, true); 20 | xhr.addEventListener("load", function() { 21 | var i = xhr.responseText.indexOf("experienceJSON"); 22 | if(i === -1) return; 23 | 24 | var s = xhr.responseText.substring(i + 17); 25 | s = s.substring(0, s.indexOf("\n") - 2); 26 | 27 | try { 28 | var media = JSON.parse(s).data.programmedContent.videoPlayer.mediaDTO; 29 | } catch(e) { 30 | return; 31 | } 32 | 33 | var sources = []; 34 | var processRendition = function(source) { 35 | // videoCodec can be H264, SORENSON, or ON2 36 | if(source.videoCodec !== "H264" || !source.defaultURL) return; 37 | var bitrate = Math.round(parseInt(source.encodingRate)/100000); 38 | var format = bitrate === 0 ? source.frameHeight + "p " : bitrate + "00k "; 39 | var ext = getExt(source.defaultURL); 40 | format += ext ? ext.toUpperCase() : "MP4"; 41 | sources.unshift({"url": source.defaultURL, "format": format, "height": parseInt(source.frameHeight), "isAudio": source.audioOnly, "isNative": true}); 42 | }; 43 | 44 | media.renditions.forEach(processRendition); 45 | if(sources.length === 0) { 46 | media.IOSRenditions.forEach(processRendition); 47 | if(sources.length === 0) { 48 | var source = extInfo(getExt(media.FLVFullLengthURL)); 49 | if(source && !media.FLVFullLengthStreamed) { 50 | source.url = media.FLVFullLengthURL; 51 | sources.push(source); 52 | } else return; 53 | } 54 | } 55 | 56 | callback({"playlist": [{ 57 | "sources": sources, 58 | "poster": media.videoStillURL, 59 | "title": media.displayName 60 | }]}); 61 | }, false); 62 | xhr.send(null); 63 | } 64 | 65 | }); 66 | -------------------------------------------------------------------------------- /CSSfix.js: -------------------------------------------------------------------------------- 1 | var script = "MediaPlayer.prototype.initShadowDOM = function() {\r\n\tvar sheet = this.container.appendChild(document.createElement(\"style\")).sheet;\r\n\t\r\n\tsheet.insertRule(\"#\" + this.mediaElement.id + \":-webkit-full-screen::-webkit-media-controls-status-display{display:none;}\", 0);\r\n\t\r\n\tvar pseudoElements = {\"controlsPanel\": \"-webkit-media-controls-panel\", \"statusDisplay\": \"-webkit-media-controls-status-display\", \"playButton\": \"-webkit-media-controls-play-button\", \"muteButton\": \"-webkit-media-controls-mute-button\", \"volumeSliderContainer\": \"-webkit-media-controls-volume-slider-container\", \"rewindButton\": \"-webkit-media-controls-rewind-button\", \"fullscreenButton\": \"-webkit-media-controls-fullscreen-button\", \"timelineContainer\": \"-webkit-media-controls-timeline-container\"};\r\n\t\r\n\tvar shadowDOM = {};\r\n\tfor(var e in pseudoElements) {\r\n\t\tsheet.insertRule(\"#\" + this.mediaElement.id + \":not(:-webkit-full-screen)::\" + pseudoElements[e] + \"{}\", 0);\r\n\t\tshadowDOM[e] = sheet.cssRules[0];\r\n\t}\r\n\t\r\n\tshadowDOM.controlsPanel.style.position = \"absolute\";\r\n\tif(settings.hideRewindButton) shadowDOM.rewindButton.style.display = \"none\";\r\n\t\r\n\tshadowDOM.update = function() {};\r\n\t\r\n\tthis.shadowDOM = shadowDOM;\r\n};"; 2 | safari.extension.addContentScript(script, [], [], true); 3 | -------------------------------------------------------------------------------- /CollegeHumor.js: -------------------------------------------------------------------------------- 1 | addKiller("CollegeHumor", { 2 | 3 | "canKill": function(data) { 4 | return data.src.indexOf("collegehumor.cvcdn.com/moogaloop/") !== -1; 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var videoID = parseFlashVariables(data.params.flashvars).clip_id; 9 | if(!videoID) { 10 | var match = /[?&]clip_id=([^&]*)/.exec(data.src); 11 | if(match) videoID = match[1]; 12 | else return; 13 | } 14 | 15 | var xhr = new XMLHttpRequest(); 16 | xhr.open("GET", "http://www.collegehumor.com/moogaloop/video/" + videoID, true); 17 | xhr.addEventListener("load", function() { 18 | var video = xhr.responseXML.querySelector("video"); 19 | 20 | // YouTube redirection 21 | var provider = video.querySelector("provider"); 22 | if(provider) { 23 | if(provider.textContent === "youtube" && hasKiller("YouTube")) { 24 | getKiller("YouTube").processVideoID(video.querySelector("youtubeID").textContent, callback); 25 | } 26 | return; 27 | } 28 | 29 | var videoURL = video.querySelector("file").textContent; 30 | if(!/\.mp4$/.test(videoURL)) return; 31 | 32 | var sources = [{ 33 | "url": videoURL, 34 | "format": "360p MP4", 35 | "height": 360, 36 | "isNative": true 37 | }]; 38 | 39 | var hq = video.querySelector("hq"); 40 | if(hq) { 41 | sources.unshift({ 42 | "url": hq.textContent, 43 | "format": "HQ MP4", 44 | "height": 480, 45 | "isNative": true 46 | }); 47 | } 48 | 49 | callback({"playlist": [{ 50 | "title": video.querySelector("caption").textContent, 51 | "poster": video.querySelector("thumbnail").textContent, 52 | "sources": sources 53 | }]}); 54 | }, false); 55 | xhr.send(null); 56 | } 57 | 58 | }); 59 | -------------------------------------------------------------------------------- /Dailymotion.js: -------------------------------------------------------------------------------- 1 | addKiller("Dailymotion", { 2 | 3 | "canKill": function(data) { 4 | return /dmcdn\.net\/playerv5\/|www\.dailymotion\.com/.test(data.src); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var config = parseFlashVariables(data.params.flashvars).config; 9 | if(config) this.processConfig(decodeURIComponent(config), !/^https?:\/\/www\.dailymotion\.com\/video/.test(data.location), callback); 10 | else { 11 | var match = /\/swf\/(?:video\/)?([^&?#]+)/.exec(data.src); 12 | if(match) this.processVideoID(match[1], callback); 13 | } 14 | }, 15 | 16 | "processConfig": function(config, isEmbed, callback) { 17 | var metadata = JSON.parse(config).metadata; 18 | 19 | var siteInfo; 20 | if(isEmbed) siteInfo = {"name": "Dailymotion", "url": "http://www.dailymotion.com/video/" + metadata.id}; 21 | 22 | var sources = []; 23 | for(var res in metadata.qualities) { 24 | if(!/\d+/.test(res)) continue; 25 | sources.unshift({"url": metadata.qualities[res][0].url, "format": res + "p MP4", "height": res === "380" ? 360 : parseInt(res), "isNative": true}); 26 | } 27 | if(sources.length === 0) return; 28 | 29 | callback({"playlist": [{ 30 | "title": metadata.title, 31 | "poster": metadata.poster_url, 32 | "sources": sources, 33 | "siteInfo": siteInfo 34 | }]}); 35 | }, 36 | 37 | "processVideoID": function(videoID, callback) { 38 | var _this = this; 39 | var xhr = new XMLHttpRequest(); 40 | xhr.open("GET", "http://www.dailymotion.com/embed/video/" + videoID, true); 41 | xhr.addEventListener("load", function() { 42 | var match = /\bdmp\.create\(document\.getElementById\('player'\), (\{.*\})\);\n/.exec(xhr.responseText); 43 | if(match) _this.processConfig(match[1], true, callback); 44 | }, false); 45 | xhr.send(null); 46 | } 47 | 48 | }); 49 | -------------------------------------------------------------------------------- /Eurogamer.js: -------------------------------------------------------------------------------- 1 | addKiller("Eurogamer", { 2 | 3 | "canKill": function(data) { 4 | return data.src.indexOf("eurogamer.net/scripts") !== -1; 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var flashvars = parseFlashVariables(data.params.flashvars); 9 | var matches = /\[\[JSON\]\]\[(.*?)\]/.exec(decodeURIComponent(flashvars.playlist)); 10 | 11 | if( !matches || matches < 2 ) 12 | return; 13 | 14 | var payload = JSON.parse(matches[1]); 15 | 16 | var sources = []; 17 | 18 | if( payload['hd.file'] ) 19 | sources.push({"url": payload['hd.file'] , "format": "HD", "height": 720, "isNative": true}); 20 | 21 | if( payload['hd.original'] ) 22 | sources.push({"url": payload['hd.original'] , "format": "SD", "height": 406, "isNative": true}); 23 | 24 | callback({ 25 | "playlist": [{ 26 | "title": data.title, 27 | "poster": payload.image, 28 | "sources": sources 29 | }]}); 30 | } 31 | 32 | }); -------------------------------------------------------------------------------- /Facebook.js: -------------------------------------------------------------------------------- 1 | addKiller("Facebook", { 2 | 3 | "canKill": function(data) { 4 | return data.src.indexOf("www.facebook.com/v/") !== -1 || /^https?:\/\/(?:fbstatic-a\.akamaihd\.net|static\.[a-z]*\.fbcdn\.net|s-static\.[a-z]*\.facebook\.com|b\.static\.[a-z]*\.fbcdn\.net)\/rsrc\.php\/v[1-9]\/[a-zA-Z0-9_-]{2}\/r\/[a-zA-Z0-9_-]*\.swf/.test(data.src); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var flashvars = parseFlashVariables(data.params.flashvars); 9 | if(flashvars.params) { 10 | this.processParams(flashvars.params, callback); 11 | } else { // Embedded video 12 | var match = /facebook\.com\/v\/([^&?]+)/.exec(data.src); 13 | if(!match) match = /\.swf.*[?&]v=([^&]*)/.exec(data.src); 14 | if(match) this.processVideoID(match[1], callback); 15 | } 16 | }, 17 | 18 | "processParams": function(params, callback) { 19 | var sources = []; 20 | var video = JSON.parse(decodeURIComponent(params)).video_data[0]; 21 | if(video.hd_src) sources.push({"url": video.hd_src.replace(/\\\//g,"/"), "format": "HD MP4", "height": 720, "isNative": true}); 22 | if(video.sd_src) sources.push({"url": video.sd_src.replace(/\\\//g,"/"), "format": "SD MP4", "height": 240, "isNative": true}); 23 | if(sources.length === 0) return; 24 | 25 | var posterURL; 26 | if(video.thumbnail_src) posterURL = video.thumbnail_src.replace(/\\\//g,"/"); 27 | 28 | callback({"playlist": [{"poster": posterURL, "sources": sources}]}); 29 | }, 30 | 31 | "processVideoID": function(videoID, callback) { 32 | var _this = this; 33 | var xhr = new XMLHttpRequest(); 34 | var url = "https://www.facebook.com/video/video.php?v=" + videoID; 35 | xhr.open("GET", url, true); 36 | xhr.addEventListener("load", function() { 37 | var callbackForEmbed = function(videoData) { 38 | videoData.playlist[0].siteInfo = {"name": "Facebook", "url": url}; 39 | callback(videoData); 40 | }; 41 | var match = /\[\"params\",\s*\"([^"]*)\"\]/.exec(xhr.responseText); 42 | if(match) _this.processParams(match[1].replace(/\\u0025/g, "%"), callbackForEmbed); 43 | }, false); 44 | xhr.send(null); 45 | } 46 | 47 | }); 48 | -------------------------------------------------------------------------------- /Flash.js: -------------------------------------------------------------------------------- 1 | addKiller("Flash", { 2 | 3 | "canKill": function(data) { 4 | if(data.type !== "application/x-shockwave-flash") return false; 5 | var match = /(?:^|&)(real_file|file|filename|load|playlistfile|src|source|video|mp3|mp3url|soundFile|soundUrl|url|content|mediaUrl|file_url|sampleURL|wmvUrl|flvUrl)=/.exec(data.params.flashvars); 6 | if(match) {data.file = match[1]; return true;} 7 | match = /[?&](file|mp3|playlist_url)=/.exec(data.src); 8 | if(match) {data.hash = match[1]; return true;} 9 | return false; 10 | }, 11 | 12 | "process": function(data, callback) { 13 | var flashvars = parseFlashVariables(data.params.flashvars); 14 | 15 | if(flashvars.config) { 16 | var xhr = new XMLHttpRequest(); 17 | xhr.open("GET", makeAbsoluteURL(decodeURIComponent(flashvars.config), data.baseURL), true); 18 | var _this = this; 19 | xhr.addEventListener("load", function() { 20 | var config = xhr.responseXML.getElementsByTagName("config")[0]; 21 | var node; 22 | for(var i = 0; i < config.childNodes.length; i++) { 23 | node = config.childNodes[i]; 24 | flashvars[node.nodeName] = node.textContent; 25 | } 26 | _this.processFlashVars(data, flashvars, callback); 27 | }, false); 28 | xhr.send(null); 29 | } else this.processFlashVars(data, flashvars, callback); 30 | }, 31 | 32 | "processFlashVars": function(data, flashvars, callback) { 33 | if(/^rtmp/.test(flashvars.streamer)) return; 34 | 35 | // Get media and poster URL 36 | var sourceURL, posterURL; 37 | if(data.file) { 38 | sourceURL = decodeURIComponent(flashvars[data.file].replace(/\+/g, " ")); 39 | posterURL = decodeURIComponent(flashvars.image || flashvars.preloadImage || flashvars.poster_url || flashvars.icon || flashvars.thumb || flashvars.sScreenshotUrl || ""); 40 | } else { 41 | sourceURL = new RegExp("[?&]" + data.hash + "=([^&]*)").exec(data.src); 42 | if(sourceURL) { 43 | sourceURL = decodeURIComponent(sourceURL[1]); 44 | posterURL = /[?&]image=([^&]*)/.exec(data.src); 45 | if(posterURL) posterURL = decodeURIComponent(posterURL[1]); 46 | } 47 | } 48 | 49 | if(/^[a-z]+:\/\//.test(sourceURL) && !/^http/.test(sourceURL)) return; 50 | 51 | // YouTube redirection 52 | // (sometimes with flashvars.provider === "youtube") 53 | if(/^http:\/\/(?:www.)?youtube.com/.test(sourceURL)) { 54 | var match = /[?&\/]v[=\/]([^?&\/]*)/.exec(sourceURL); 55 | if(match) { 56 | if(!hasKiller("YouTube")) return; 57 | var YTcallback = callback; 58 | if(posterURL) YTcallback = function(mediaData) { 59 | mediaData.playlist[0].poster = posterURL; 60 | callback(mediaData); 61 | }; 62 | getKiller("YouTube").processVideoID(match[1], YTcallback); 63 | return; 64 | } 65 | } 66 | 67 | // Site-specific hacks 68 | if(/^https?:\/\/www\.tvn24\.pl/.test(data.location)) sourceURL = sourceURL.replace(".flv", ".mp4"); 69 | 70 | if(!sourceURL) return; 71 | var ext = getExt(sourceURL); 72 | var isPlaylist = data.file === "playlistfile" || data.hash === "playlist_url" || ext === "xml" || ext === "xspf"; 73 | 74 | var baseURL = data.src; // used to resolve video URLs 75 | if(flashvars.netstreambasepath) baseURL = decodeURIComponent(flashvars.netstreambasepath); 76 | 77 | if(isPlaylist) { 78 | parseXSPlaylist(makeAbsoluteURL(sourceURL, data.baseURL), baseURL, posterURL, flashvars.item, callback); 79 | return; 80 | } 81 | 82 | sourceURL = makeAbsoluteURL(sourceURL, baseURL); 83 | 84 | var sources = []; 85 | var audioOnly = true; 86 | var call = function(info) { 87 | if(info) { 88 | info.url = sourceURL; 89 | sources.push(info); 90 | if(!info.isAudio) audioOnly = false; 91 | } 92 | if(sources.length !== 0 || posterURL !== undefined) callback({ 93 | "playlist": [{"poster": posterURL, "sources": sources}], 94 | "audioOnly": audioOnly 95 | }); 96 | }; 97 | 98 | if(flashvars["hd.file"]) { 99 | var hdURL = decodeURIComponent(flashvars["hd.file"]); 100 | var info = extInfo(getExt(hdURL)); 101 | if(info) { 102 | info.url = makeAbsoluteURL(hdURL, baseURL); 103 | info.format = "HD " + info.format; 104 | info.height = 720; 105 | sources.push(info); 106 | audioOnly = false; 107 | } 108 | } 109 | 110 | if(ext === "php" || !ext) { 111 | getMIMEType(sourceURL, function(type) { 112 | call(typeInfo(type)); 113 | }); 114 | } else call(extInfo(ext)); 115 | } 116 | 117 | }); 118 | -------------------------------------------------------------------------------- /Flowplayer.js: -------------------------------------------------------------------------------- 1 | addKiller("Flowplayer", { 2 | 3 | "canKill": function(data) { 4 | return /(?:^|&)config=/.test(data.params.flashvars); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | try { 9 | var config = JSON.parse(parseFlashVariables(data.params.flashvars).config.replace(/\n/g, " ")); 10 | } catch(e) { 11 | return; 12 | } 13 | 14 | var baseURL; 15 | if(config.clip) baseURL = config.clip.baseUrl; 16 | 17 | var playlist = []; 18 | var audioOnly = true; 19 | var splash; 20 | 21 | var parseTitle = function(title) {return title;}; 22 | if(/bimvid_player/.test(data.src)) parseTitle = function(title) {return unescapeHTML(title.replace(/\+/g, " "));}; 23 | 24 | if(config.playList) config.playlist = config.playList; 25 | if(typeof config.playlist !== "object") { 26 | if(config.clip) config.playlist = [config.clip]; 27 | else if(data.params.href) config.playlist = [data.params.href]; 28 | else return; 29 | } 30 | 31 | config.playlist.forEach(function(clip) { 32 | if(typeof clip === "string") clip = {"url": clip}; 33 | 34 | if(!clip.url) return; 35 | if(clip.live) return; 36 | if(clip.provider === "rtmp") return; 37 | 38 | clip.url = decodeURIComponent(clip.url); 39 | var source = extInfo(getExt(clip.url)); 40 | if(source) { 41 | var base = clip.baseUrl ? clip.baseUrl : baseURL; 42 | if(base && !/^https?:/.test(clip.url)) { 43 | base = decodeURIComponent(base); 44 | if(!/\/$/.test(base) && !/^\//.test(clip.url)) base += "/"; 45 | source.url = base + clip.url; 46 | } else { 47 | source.url = clip.url; 48 | } 49 | 50 | var poster; 51 | if(clip.coverImage) poster = decodeURIComponent(clip.coverImage.url); 52 | else if(clip.overlay) poster = decodeURIComponent(clip.overlay); 53 | else poster = splash; 54 | splash = undefined; 55 | 56 | playlist.push({ 57 | "title": parseTitle(clip.title), 58 | "poster": poster, 59 | "sources": [source] 60 | }); 61 | if(!source.isAudio) audioOnly = false; 62 | } else { 63 | var ext = getExt(clip.url); 64 | if(ext === "jpg" || ext === "png") splash = clip.url; 65 | else splash = undefined; 66 | } 67 | }); 68 | 69 | if(playlist.length !== 0) callback({ 70 | "playlist": playlist, 71 | "audioOnly": audioOnly 72 | }); 73 | } 74 | 75 | }); 76 | -------------------------------------------------------------------------------- /Gamestar.js: -------------------------------------------------------------------------------- 1 | // Gamestar killer (2011-09-16) 2 | 3 | addKiller("Gamestar", { 4 | 5 | "canKill": function(data) { 6 | return data.src.indexOf('http://www.gamestar.de/jw') !== -1; 7 | }, 8 | 9 | "process": function(data, callback) { 10 | var params = parseFlashVariables(data.params.flashvars); 11 | callback({ 12 | playlist: [{ 13 | sources: [{ 14 | url: decodeURIComponent(params.file), 15 | format: 'H.264', 16 | isNative: true 17 | }] 18 | }], 19 | isAudio: false 20 | }); 21 | } 22 | 23 | }); 24 | -------------------------------------------------------------------------------- /Gametrailers.js: -------------------------------------------------------------------------------- 1 | // Gametrailers killer (2011-09-16) 2 | 3 | addKiller("Gametrailers", { 4 | 5 | "canKill": function(data) { 6 | return data.src.indexOf(':video:gametrailers.com:') !== -1; 7 | }, 8 | 9 | "process": function(data, callback) { 10 | var match = /:([0-9]*)$/.exec(data.src); 11 | if(!match) return; 12 | var _this = this; 13 | var xhr = new XMLHttpRequest(); 14 | xhr.open('GET', 'http://www.gametrailers.com/neo/?page=xml.mediaplayer.Mediagen&movieId=' + match[1], true); 15 | xhr.onload = function(event) { 16 | // Gametrailers send xml as text/html 17 | var xml = (new DOMParser()).parseFromString(event.target.responseText, "text/xml"); 18 | _this.parseResponse(xml, callback); 19 | } 20 | xhr.send(null); 21 | }, 22 | 23 | "parseResponse": function(xml, callback) { 24 | var elements = xml.getElementsByTagName('src'); 25 | if(elements.length < 1) { 26 | return false; 27 | } 28 | var src = elements[0].textContent; 29 | var info = extInfo(getExt(src)); 30 | if(!info) return; 31 | info.url = src; 32 | var rendition = xml.getElementsByTagName('rendition'); 33 | if(rendition.length > 0) { 34 | info.height = parseInt(rendition[0].getAttribute("height")); 35 | if(info.height >= 720) info.format = "HD " + info.format; 36 | } 37 | callback({ 38 | playlist: [{ 39 | sources: [info] 40 | }] 41 | }); 42 | } 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /Generic.js: -------------------------------------------------------------------------------- 1 | addKiller("Generic", { 2 | 3 | "canKill": function(data) { 4 | // Streaming is not supported 5 | if(/^rts?p/.test(data.src) || data.params.href) return false; 6 | return (data.info = typeInfo(data.type)) || (data.info = extInfo(getExt(data.src))); 7 | }, 8 | 9 | "process": function(data, callback) { 10 | data.info.url = data.src; 11 | callback({ 12 | "playlist": [{ 13 | "poster": data.params.previewimage, 14 | "sources": [data.info] 15 | }], 16 | "audioOnly": data.info.isAudio 17 | }); 18 | } 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /Golem.js: -------------------------------------------------------------------------------- 1 | // Golem killer (2011-09-16) 2 | 3 | addKiller("Golem", { 4 | 5 | "canKill": function(data) { 6 | return data.src.indexOf('http://video.golem.de/nvplayer/') !== -1; 7 | }, 8 | 9 | "process": function(data, callback) { 10 | var params = parseFlashVariables(data.params.flashvars) 11 | callback({ 12 | playlist: [{ 13 | poster: params.image_src, 14 | sources: [{ 15 | url: 'http://video.golem.de/download/' + params.id + '?q=high', 16 | format: 'HD MP4', 17 | height: 720, 18 | isNative: true 19 | }, 20 | { 21 | url: 'http://video.golem.de/download/' + params.id, 22 | format: 'SD MP4', 23 | height: 360, 24 | isNative: true 25 | }] 26 | }] 27 | }); 28 | } 29 | 30 | }); 31 | -------------------------------------------------------------------------------- /IGN.js: -------------------------------------------------------------------------------- 1 | addKiller("IGN", { 2 | 3 | "canKill": function(data) { 4 | return /\/IGNPlayer\.swf/.test(data.src); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var configURL = decodeURIComponent(parseFlashVariables(data.params.flashvars).url).replace(/[?#].*/, ""); 9 | if(!/\.config$/.test(configURL)) configURL += ".config"; 10 | 11 | var _this = this; 12 | var xhr = new XMLHttpRequest(); 13 | xhr.open("GET", configURL, true); 14 | xhr.addEventListener("load", function() { 15 | _this.processConfig(JSON.parse(xhr.responseText), !/^http:\/\/www\.ign\.com\/videos\//.test(data.location), callback); 16 | }, false); 17 | xhr.send(null); 18 | }, 19 | 20 | "processConfig": function(config, isEmbed, callback) { 21 | var media = config.playlist.media; 22 | 23 | var siteInfo; 24 | if(isEmbed) siteInfo = {"name": "IGN", "url": media.metadata.url.replace(/\\\//g, "/")}; 25 | 26 | var videoURL = media.url.replace(/\\\//g, "/"); 27 | var source = extInfo(getExt(videoURL)); 28 | if(!source) return; 29 | source.url = videoURL; 30 | source.height = 720; 31 | var poster = media.poster[0].url.replace(/\\\//g, "/").replace(/\{size\}/, "large"); 32 | 33 | callback({ 34 | "playlist": [{ 35 | "title": media.metadata.title, 36 | "sources": [source], 37 | "poster": poster, 38 | "siteInfo": siteInfo 39 | }] 40 | }); 41 | } 42 | 43 | }); 44 | -------------------------------------------------------------------------------- /ImbcNews.js: -------------------------------------------------------------------------------- 1 | addKiller("ImbcNews", { 2 | "canKill": function(data) { 3 | if(data.src.indexOf("ImbcNewsPlayer.swf") !== -1) return true; 4 | return false; 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var flashvars = parseFlashVariables(data.params.flashvars); 9 | var match = flashvars.vodUrl.match(/^rtmp:\/\/(.+)\.mp4$/i); 10 | if(match) { 11 | var start_time = flashvars.startTime; 12 | var end_time = flashvars.endTime; 13 | var img_url = flashvars.imgUrl; 14 | var url = "http://"+ match[1] +".mp4/playlist.m3u8?wowzaplaystart="+ start_time +"&wowzaplayduration="+ (end_time - start_time); 15 | callback({ 16 | "playlist": [{ 17 | "poster": img_url, 18 | "sources": [{ 19 | "url": url, 20 | "format": "MP4", 21 | "isNative": true 22 | }] 23 | }] 24 | }); 25 | 26 | } 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /Katu.js: -------------------------------------------------------------------------------- 1 | addKiller("Katu", { 2 | 3 | "canKill": function(data) { 4 | return /^https?:\/\/www.katu.com\//.test(data.location) && /^fin_videoplayer_/.test(data.params.id); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var videoID = /^fin_videoplayer_([\d_]*)/.exec(data.params.id)[1]; 9 | var xhr = new XMLHttpRequest(); 10 | xhr.open("GET", data.location, true); 11 | xhr.addEventListener("load", function() { 12 | try{ 13 | var config = new RegExp("fin_story_media\\['" + videoID + "'\\] = ([^;]*)").exec(xhr.responseText)[1]; 14 | var file = /file: '([^']*)',/.exec(config)[1]; 15 | var image = /image: '([^']*)',/.exec(config)[1]; 16 | } catch(e) { 17 | return; 18 | } 19 | 20 | callback({"playlist": [{ 21 | "sources": [{"url": file, "format": "MP4", "isNative": true}], 22 | "poster": image 23 | }]}); 24 | },false); 25 | xhr.send(); 26 | } 27 | }); -------------------------------------------------------------------------------- /MTVNetworks.js: -------------------------------------------------------------------------------- 1 | addKiller("MTVNetworks", { 2 | 3 | "contexts": { 4 | "arc:video:thedailyshow.com:": "4", 5 | "arc:episode:thedailyshow.com:": "5", 6 | "arc:playlist:thedailyshow.com:": "8", 7 | "arc:video:colbertnation.com:": "5", 8 | // "arc:episode:colbertnation.com:": "", // no feed 9 | "arc:video:gametrailers.com:": "", 10 | "arc:video:southparkstudios.com:": "", 11 | "arc:episode:southparkstudios.com:": "4", 12 | "arc:episode:southpark.nl:": "2", 13 | "arc:video:comedycentral.com:": "", 14 | "arc:playlist:comedycentral.com:": "9", 15 | "arc:episode:comedycentral.com:": "4", 16 | "arc:promo:tosh.comedycentral.com:": "", 17 | "arc:video:tosh.comedycentral.com:": "", 18 | "arc:episode:tosh.comedycentral.com:": "2"// 19 | // "uma:video:mtv.com:": "", // only rtmpe 20 | // "uma:videolist:mtv.com:": "" // only rtmpe 21 | }, 22 | 23 | "aliases": { 24 | "arc:episode:colbertnation.com:": "arc:video:colbertnation.com:", 25 | "arc:playlist:colbertnation.com:": "arc:video:colbertnation.com:", 26 | "arc:episode:southpark.de:": "arc:episode:southparkstudios.com:" 27 | }, 28 | 29 | "canKill": function(data) { 30 | if(data.src.indexOf("media.mtvnservices.com") !== -1) return true; 31 | if(/^http:\/\/southpark\.cc\.com/.test(data.location)) {data.hulu = true; return true;} 32 | return false; 33 | }, 34 | 35 | "process": function(data, callback) { 36 | if(data.hulu) { 37 | var _this = this; 38 | var xhr = new XMLHttpRequest(); 39 | xhr.open("GET", data.location, true); 40 | xhr.addEventListener("load", function() { 41 | var mgid = /\bdata-mgid=\"(mgid:([^.]*[.\w]+:)[-\w]+)\"/.exec(xhr.responseText); 42 | if(!mgid) return; 43 | mgid.shift(); 44 | _this.processMGID(mgid, callback); 45 | }, false); 46 | xhr.send(null); 47 | } else if(/adbridge/.test(data.src) && /^https?:\/\/www\.cc\.com/.test(data.location)) { 48 | var _this = this; 49 | var xhr = new XMLHttpRequest(); 50 | xhr.open("GET", data.location, true); 51 | xhr.addEventListener("load", function() { 52 | var mgid = /data-mgid=\"(mgid:([^.]*[.\w]+:)[-\w]+)/.exec(xhr.responseText); 53 | if(mgid) _this.processMGID([mgid[1], mgid[2]], callback); 54 | }, false); 55 | xhr.send(null); 56 | } else { 57 | var mgid = /mgid:([^.]*[.\w]+:)[-\w]+/.exec(data.src); 58 | if(mgid) this.processMGID(mgid, callback); 59 | } 60 | }, 61 | 62 | "processMGID": function(mgid, callback) { 63 | var context = ""; 64 | if(this.aliases[mgid[1]]) mgid[1] = this.aliases[mgid[1]]; 65 | if(this.contexts[mgid[1]]) context = "/context" + this.contexts[mgid[1]]; 66 | 67 | var _this = this; 68 | var xhr = new XMLHttpRequest(); 69 | xhr.open("GET", "http://media.mtvnservices.com/pmt-arc/e1/players/mgid:" + mgid[1] + context + "/config.xml", true); 70 | xhr.addEventListener("load", function() { 71 | var xml = xhr.responseXML; 72 | var feedURL = xml.getElementsByTagName("feed")[0].textContent.replace(/\n/g, "").replace("{uri}", mgid[0]); 73 | if(feedURL) _this.processFeedURL(feedURL, callback); 74 | }, false); 75 | xhr.send(null); 76 | }, 77 | 78 | "processFeedURL": function(feedURL, callback) { 79 | var xhr = new XMLHttpRequest(); 80 | xhr.open("GET", feedURL, true); 81 | xhr.addEventListener("load", function() { 82 | var xml = new DOMParser().parseFromString(xhr.responseText.replace(/^\s+/,""), "text/xml"); 83 | var channels = xml.getElementsByTagName("channel"); 84 | if(channels.length !== 0) xml = channels[0]; 85 | var items = xml.getElementsByTagName("item"); 86 | 87 | var list = []; 88 | var playlist = []; 89 | 90 | for(var i = 0; i < items.length; i++) { 91 | var element = items[i].getElementsByTagNameNS("http://search.yahoo.com/mrss/", "content")[0]; 92 | if(!element) continue; 93 | var track = {"content": element.getAttribute("url")}; 94 | 95 | element = items[i].getElementsByTagNameNS("http://search.yahoo.com/mrss/", "thumbnail")[0]; 96 | if(element) track.poster = element.getAttribute("url"); 97 | 98 | element = items[i].getElementsByTagName("title")[0]; 99 | if(element) track.title = element.textContent; 100 | 101 | list.push(track); 102 | } 103 | 104 | var length = list.length - 1; 105 | 106 | var next = function() { 107 | if(list.length === 0) callback({"playlist": playlist}); 108 | else addToPlaylist(list.shift()); 109 | }; 110 | 111 | var addToPlaylist = function(track) { 112 | var xhr = new XMLHttpRequest(); 113 | xhr.open("GET", track.content, true); 114 | delete track.content; 115 | xhr.addEventListener("load", function() { 116 | var renditions = xhr.responseXML.getElementsByTagName("rendition"); 117 | 118 | var sources = []; 119 | var src, index; 120 | for(var i = renditions.length -1 ; i >= 0; i--) { 121 | var source = typeInfo(renditions[i].getAttribute("type")); 122 | if(source === null) continue; 123 | 124 | src = renditions[i].getElementsByTagName("src")[0].textContent; 125 | index = src.indexOf("/gsp."); 126 | if(index === -1) continue; 127 | source.url = "http://viacommtvstrmfs.fplive.net" + src.substring(index); 128 | 129 | source.format = renditions[i].getAttribute("bitrate") + "k " + source.format; 130 | source.height = parseInt(renditions[i].getAttribute("height")); 131 | sources.push(source); 132 | } 133 | 134 | if(sources.length === 0) { 135 | if(list.length === length) return; 136 | } else { 137 | track.sources = sources; 138 | playlist.push(track); 139 | } 140 | 141 | next(); 142 | }, false); 143 | xhr.send(null); 144 | }; 145 | next(); 146 | }, false); 147 | xhr.send(null); 148 | } 149 | 150 | }); 151 | -------------------------------------------------------------------------------- /Megavideo.js: -------------------------------------------------------------------------------- 1 | // Megavideo killer (2011-09-16) 2 | 3 | addKiller("Megavideo", { 4 | 5 | "canKill": function(data) { 6 | if(!canPlayFLV) return false; 7 | if(/^http:\/\/wwwstatic\.megavideo\.com\/mv_player[2-9]?\.swf/.test(data.src)) {data.onsite = true; return true;}; 8 | if(data.src.indexOf("megavideo.com/v/") !== -1) {data.onsite = false; return true;} 9 | return false; 10 | }, 11 | 12 | "process": function(data, callback) { 13 | if(data.onsite) { 14 | this.processFlashVars(parseFlashVariables(data.params.flashvars), callback); 15 | return; 16 | } 17 | 18 | // embedded video 19 | var match = /megavideo\.com\/v\/([A-Z0-9]{8})/.exec(data.src); 20 | if(!match) return; 21 | 22 | var url = "http://megavideo.com/?v=" + match[1]; 23 | 24 | var xhr = new XMLHttpRequest(); 25 | xhr.open('GET', url, true); 26 | var _this = this; 27 | xhr.onload = function() { 28 | var callbackForEmbed = function(videoData) { 29 | videoData.playlist[0].siteInfo = {"name": "Megavideo", "url": url}; 30 | callback(videoData); 31 | }; 32 | var regex = new RegExp("flashvars\\.([0-9a-z_]*)\\s=\\s\\\"([^\"]*)\\\";", "g"); 33 | _this.processFlashVars(parseWithRegExp(xhr.responseText, regex), callbackForEmbed); 34 | }; 35 | xhr.send(null); 36 | }, 37 | 38 | "processFlashVars": function(flashvars, callback) { 39 | var sources = []; 40 | 41 | var title; 42 | if(flashvars.title) title = decodeURIComponent(flashvars.title.replace(/\+/g, "%20")).toUpperCase(); 43 | 44 | if(flashvars.hd === "1") { 45 | sources.push({"url": "http://www" + flashvars.hd_s + ".megavideo.com/files/" + this.decrypt(flashvars.hd_un, flashvars.hd_k1, flashvars.hd_k2) + "/" + title + ".flv", "format": "HD FLV", "resolution": 720, "isNative": false}); 46 | } 47 | sources.push({"url": "http://www" + flashvars.s + ".megavideo.com/files/" + this.decrypt(flashvars.un, flashvars.k1, flashvars.k2) + "/" + title + ".flv", "format": "SD FLV", "resolution": 360, "isNative": false}); 48 | 49 | callback({ 50 | "playlist": [{"title": title, "sources": sources}] 51 | }); 52 | }, 53 | 54 | // taken from http://userscripts.org/scripts/review/87011 55 | "decrypt": function(str, key1, key2) { 56 | var loc1 = []; 57 | for(var loc3 = 0; loc3 < str.length; ++loc3) { 58 | loc1.push(("000" + parseInt(str.charAt(loc3), 16).toString(2)).slice(-4)); 59 | } 60 | loc1 = loc1.join("").split(""); 61 | var loc6 = []; 62 | for(var loc3 = 0; loc3 < 384; ++loc3) { 63 | key1 = (key1 * 11 + 77213) % 81371; 64 | key2 = (key2 * 17 + 92717) % 192811; 65 | loc6[loc3] = (key1 + key2) % 128; 66 | } 67 | for(var loc3 = 256; loc3 >= 0; --loc3) { 68 | var loc5 = loc6[loc3]; 69 | var loc4 = loc3 % 128; 70 | var loc8 = loc1[loc5]; 71 | loc1[loc5] = loc1[loc4]; 72 | loc1[loc4] = loc8; 73 | } 74 | for(var loc3 = 0; loc3 < 128; ++loc3) { 75 | loc1[loc3] = loc1[loc3] ^ loc6[loc3 + 256] & 1; 76 | } 77 | var loc12 = loc1.join(""); 78 | var loc7 = []; 79 | for(var loc3 = 0; loc3 < loc12.length; loc3 = loc3 + 4) { 80 | var loc9 = loc12.substr(loc3, 4); 81 | loc7.push(loc9); 82 | } 83 | var loc2 = []; 84 | for(var loc3 = 0; loc3 < loc7.length; ++loc3) { 85 | loc2.push(parseInt(loc7[loc3], 2).toString(16)); 86 | } 87 | return loc2.join(""); 88 | } 89 | 90 | }); 91 | -------------------------------------------------------------------------------- /Metacafe.js: -------------------------------------------------------------------------------- 1 | addKiller("Metacafe", { 2 | 3 | "canKill": function(data) { 4 | return (data.src.indexOf(".mcstatic.com/Flash/vp/") !== -1 || data.src.indexOf("metacafe.com/fplayer/") !== -1); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | if(/(?:^|&)mediaData=/.test(data.params.flashvars)) { 9 | this.processFlashVars(parseFlashVariables(data.params.flashvars), callback); 10 | } else { 11 | var match = /metacafe\.com\/fplayer\/([0-9]*)\//.exec(data.src); 12 | if(match) this.processVideoID(match[1], callback); 13 | return; 14 | } 15 | }, 16 | 17 | "processFlashVars": function(flashvars, callback) { 18 | if(!flashvars.mediaData) return; 19 | var mediaList = JSON.parse(decodeURIComponent(flashvars.mediaData)); 20 | for(var type in mediaList) { 21 | mediaList[type] = mediaList[type].mediaURL + "?__gda__=" + mediaList[type].key; 22 | } 23 | var sources = []; 24 | 25 | if(mediaList.highDefinitionMP4) { 26 | sources.push({"url": mediaList.highDefinitionMP4, "format": "HD MP4", "height": 720, "isNative": true}); 27 | } 28 | if(mediaList.MP4) { 29 | sources.push({"url": mediaList.MP4, "format": "SD MP4", "height": 360, "isNative": true}); 30 | } 31 | if(canPlayFLV && mediaList.flv) { 32 | sources.push({"url": mediaList.flv, "format": "SD FLV", "height": 360, "isNative": false}); 33 | } 34 | 35 | var title; 36 | if(flashvars.title) title = decodeURIComponent(flashvars.title); 37 | 38 | callback({"playlist": [{"title": title, "sources": sources}]}); 39 | }, 40 | 41 | "processVideoID": function(videoID, callback) { 42 | var _this = this; 43 | var xhr = new XMLHttpRequest(); 44 | var url = "http://www.metacafe.com/watch/" + videoID; 45 | xhr.open("GET", url, true); 46 | xhr.addEventListener("load", function() { 47 | var match = /name=\"flashvars\"\svalue=\"([^"]*)\"/.exec(xhr.responseText); 48 | if(match) { 49 | var callbackForEmbed = function(videoData) { 50 | videoData.playlist[0].siteInfo = {"name": "Metacafe", "url": url}; 51 | callback(videoData); 52 | }; 53 | _this.processFlashVars(match[1], callbackForEmbed); 54 | } 55 | }, false); 56 | xhr.send(null); 57 | } 58 | 59 | }); 60 | -------------------------------------------------------------------------------- /Myspass.js: -------------------------------------------------------------------------------- 1 | // Myspass killer (2011-09-16) 2 | 3 | addKiller("Myspass", { 4 | 5 | "canKill": function(data) { 6 | return data.src === "http://www.myspass.de/myspass/includes/apps/player/standard/player_core.swf"; 7 | }, 8 | 9 | "process": function(data, callback) { 10 | var params = parseFlashVariables(data.params.flashvars); 11 | if(!params.asf) { 12 | return false; 13 | } 14 | var xhr = new XMLHttpRequest(); 15 | xhr.open('GET', 'http://www.myspass.de/myspass/includes/apps/video/getvideometadataxml.php?id=' + params.asf, true); 16 | xhr.onload = function() { 17 | // Send xml as text/html 18 | var xml = (new DOMParser()).parseFromString(xhr.responseText, "text/xml"); 19 | callback({ 20 | playlist: [{ 21 | poster: xml.getElementsByTagName('imagePreview')[0].textContent, 22 | sources: [{ 23 | url: xml.getElementsByTagName('url_flv')[0].textContent, 24 | format: 'FLV', 25 | isNative: false 26 | }] 27 | }] 28 | }); 29 | } 30 | xhr.send(null); 31 | } 32 | 33 | }); -------------------------------------------------------------------------------- /NYTimes.js: -------------------------------------------------------------------------------- 1 | addKiller("NYTimes", { 2 | 3 | "canKill": function(data) { 4 | return /^https?:\/\/static\d*\.nyt\.com\/video\//.test(data.src); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var flashvars = parseFlashVariables(data.params.flashvars); 9 | var url = "http://www.nytimes.com/svc/video/api/v2/video/" + flashvars.id; 10 | 11 | var xhr = new XMLHttpRequest(); 12 | xhr.open("GET", url, true); 13 | xhr.addEventListener("load", function() { 14 | var media = JSON.parse(xhr.responseText); 15 | 16 | var sources = media.renditions.filter(function(e) { 17 | return e.video_codec === "H264" && /video_\d*p_mp4/.test(e.type); 18 | }); 19 | 20 | sources.sort(function(a, b) { 21 | if(a.height < b.height) return 1; 22 | else return -1; 23 | }); 24 | for(var i = 0; i < sources.length; i++) { 25 | sources[i].format = sources[i].height + " MP4"; 26 | sources[i].isNative = true; 27 | } 28 | 29 | var poster = media.images[0].url; 30 | for(var i = 0; i < media.images.length; i++) { 31 | if(media.images[i].type === "videoSixteenByNine768") { 32 | poster = media.images[i].url; 33 | break; 34 | } 35 | } 36 | 37 | var mediaData = {"playlist": [{ 38 | "sources": sources, 39 | "poster": "http://www.nytimes.com/" + poster, 40 | "title": media.headline 41 | }]}; 42 | 43 | mediaData.initScript = "try{\ 44 | var container = this.parentNode.parentNode;\ 45 | var sheet = container.insertBefore(document.createElement(\"style\"), container.firstChild).sheet;\ 46 | sheet.insertRule(\".video-player-container object,.vhs-loader,.nytd-player-controls{display:none !important;}\", 0);\ 47 | } catch(e) {}"; 48 | mediaData.restoreScript = "try{\ 49 | var container = this.parentNode.parentNode;\ 50 | container.removeChild(container.getElementsByTagName(\"style\")[0]);\ 51 | } catch(e) {}"; 52 | 53 | callback(mediaData); 54 | }, false); 55 | xhr.send(null); 56 | } 57 | 58 | }); 59 | -------------------------------------------------------------------------------- /NaverVideo.js: -------------------------------------------------------------------------------- 1 | addKiller("NaverVideo", { 2 | "canKill": function(data) { 3 | if(data.src.indexOf("inKey") !== -1) data.onsite = true; 4 | else data.onsite = false; 5 | if(data.src.indexOf("serviceapi.nmv.naver.com/flash/NFPlayer.swf") !== -1) return true; 6 | return false; 7 | }, 8 | 9 | "process": function(data, callback) { 10 | // in & out 11 | var match = data.src.match(/vid=([0-9A-F]+)&(in|out)Key=([0-9a-fV]+)/); 12 | if(match) { 13 | var videoid = match[1]; 14 | var key = match[3]; 15 | var inout = (data.onsite) ? "in" : "out"; 16 | var videoxml = "http://serviceapi.nmv.naver.com/flash/play.nhn?vid=" + videoid + "&"+ inout +"Key=" + key; 17 | var infoxml = "http://serviceapi.nmv.naver.com/flash/videoInfo.nhn?vid=" + videoid + "&"+ inout +"Key=" + key; 18 | 19 | var xhr = new XMLHttpRequest(); 20 | xhr.open('GET', videoxml, false); 21 | xhr.send(null); 22 | 23 | var videoUrl = xhr.responseXML.getElementsByTagName("Result")[0].getElementsByTagName("FlvUrl")[0].textContent; 24 | this.processVideoInfo(videoUrl, infoxml, callback); 25 | } 26 | }, 27 | 28 | "processVideoInfo": function(videoUrl, infoxml, callback) { 29 | var xhr = new XMLHttpRequest(); 30 | xhr.open('GET', infoxml, true); 31 | xhr.onload = function(event) { 32 | var result = event.target.responseXML.getElementsByTagName("Result")[0]; 33 | 34 | var link = result.getElementsByTagName("Link")[0].textContent; 35 | var title = result.getElementsByTagName("Subject")[0].textContent; 36 | var posterurl = result.getElementsByTagName("CoverImage")[0].textContent; 37 | var type = result.getElementsByTagName("VideoType")[0].textContent; 38 | 39 | callback({ 40 | "playlist": [{ 41 | "siteinfo": [{ 42 | "name": "Naver", 43 | "url": link 44 | }], 45 | "title": title, 46 | "poster": posterurl, 47 | "sources": [{ 48 | "url": videoUrl, 49 | "format": type, 50 | "isNative": (type == "MP4") ? true : false 51 | }] 52 | }] 53 | }); 54 | }; 55 | xhr.send(null); 56 | } 57 | 58 | }); 59 | -------------------------------------------------------------------------------- /Novamov.js: -------------------------------------------------------------------------------- 1 | // novamov killer (2012-01-03) 2 | 3 | addKiller("novamov", { 4 | 5 | "canKill": function(data) { 6 | if(!canPlayFLV) return false; 7 | if(/novaplayerv3\.swf/.test(data.src)) {return true;}; 8 | return false; 9 | }, 10 | 11 | "process": function(data, callback) { 12 | var flashvars = parseFlashVariables(data.params.flashvars); 13 | var url = "http://www.novamov.com/api/player.api.php?key=" + flashvars.filekey + "&pass=undefined&codes=" + flashvars.cid + "&file=" + flashvars.file; 14 | var xhr = new XMLHttpRequest(); 15 | var _this = this; 16 | xhr.open('GET', url, true); 17 | xhr.onload = function(event) { 18 | _this.parseResponse(parseFlashVariables(event.target.responseText), callback); 19 | }; 20 | xhr.send(null); 21 | }, 22 | 23 | "parseResponse": function(response, callback) { 24 | if (response.url && response.title) { 25 | callback({ 26 | "playlist": [{ 27 | "title": decodeURIComponent(response.title).replace(/&(.+)/i,""), 28 | "sources": [{ 29 | "url": response.url, 30 | "format": "FLV", 31 | "isNative": false 32 | }] 33 | }] 34 | }); 35 | } 36 | } 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /RaiTv.js: -------------------------------------------------------------------------------- 1 | addKiller('RaiTv', { 2 | 3 | 'canKill': function(data) { 4 | if (data.type !== 'application/x-silverlight' && 5 | data.type !== 'application/x-silverlight-2' && 6 | data.type !== 'application/x-shockwave-flash') return false; 7 | return data.src.indexOf('http://www.rai.tv/') !== -1; 8 | }, 9 | 10 | 'process': function(data, callback) { 11 | var chanNames = { 12 | 'Rai Uno': 'RaiUno', 13 | 'Rai Due': 'RaiDue', 14 | 'Rai Tre': 'RaiTre', 15 | 'Rai 5': 'RaiCinque', 16 | 'Rai Premium': 'RaiPremium', 17 | 'Rai YoYo': 'RaiYoyo', 18 | '1': 'RaiUno', 19 | '2': 'RaiDue', 20 | '3': 'RaiTre', 21 | '31': 'RaiCinque', 22 | '32': 'RaiPremium', 23 | '38': 'RaiYoyo' 24 | }; 25 | var url = 'http://www.rai.it/dl/portale/html/palinsesti/replaytv/static/'; 26 | var uest_loc = data.location.indexOf('?') + 1; 27 | var params = data.location.substring(uest_loc, data.location.length); 28 | var hash_loc = data.location.indexOf('#'); 29 | params = params.substring(0, hash_loc != -1 ? 30 | hash_loc : data.location.length); 31 | 32 | // Get parameters off URL string 33 | // from http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript#answer-3855394 34 | var qs = (function(a) { 35 | if (a == '') return {}; 36 | var b = {}; 37 | for (var i = 0; i < a.length; ++i) 38 | { 39 | var p = a[i].split('='); 40 | if (p.length != 2) continue; 41 | b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, ' ')); 42 | } 43 | return b; 44 | })(params.split('&')); 45 | 46 | // Fix for parameters that might be named differently than usual 47 | if (!!!qs['vd'] && !!qs['day']) { 48 | qs['vd'] = qs['day']; 49 | } 50 | if (!!!qs['vc'] && !!qs['ch']) { 51 | qs['vc'] = qs['ch']; 52 | } 53 | 54 | url += chanNames[qs['vc']] + '_' + qs['vd'].replace(/-/g, '_') + '.html'; 55 | 56 | var xhr = new XMLHttpRequest(); 57 | xhr.open('GET', url, false); 58 | xhr.addEventListener('load', function() { 59 | var json = JSON.parse(xhr.responseText); 60 | var selected = {}; 61 | 62 | // Find the entry for the program among a date-indexed json blob 63 | for (key in json[qs['vc']][qs['vd']]) { 64 | if (json[qs['vc']][qs['vd']].hasOwnProperty(key) && 65 | json[qs['vc']][qs['vd']][key]['i'] === qs['v']) { 66 | selected = json[qs['vc']][qs['vd']][key]; 67 | break; 68 | } 69 | } 70 | 71 | // var videourl_mp4 = (!!selected.urlTablet ? 72 | // selected.urlTablet : selected.h264); 73 | var sources = []; 74 | // if (videourl_mp4.indexOf(',') != -1) { 75 | // videourl_mp4 = videourl_mp4.split(','); 76 | // for (var i = 1; i < videourl_mp4.length - 1; i++) { 77 | // console.log(videourl_mp4[i]); 78 | // sources.push({ 'url': videourl_mp4[0] + ',' + videourl_mp4[i] + ',' + videourl_mp4[videourl_mp4.length - 1], 79 | // 'format': videourl_mp4[i], 80 | // 'isNative': true 81 | // }); 82 | // } 83 | // } else { 84 | // sources = [{ 'url': videourl_mp4, 85 | // 'format': 'h264', 86 | // 'isNative': true 87 | // }]; 88 | // } 89 | for (key in selected) { 90 | var h264_loc = key.indexOf('h264_'); 91 | if (h264_loc == 0 && !!selected[key]) { 92 | sources.push({ 'url': selected[key], 93 | 'format': key.substring(5, key.length), 94 | 'isNative': true 95 | }); 96 | } 97 | } 98 | var poster = selected['image']; 99 | 100 | // console.log(selected, sources); 101 | callback({ 102 | 'playlist': [{ 103 | 'poster': poster, 104 | 'title': selected.t, 105 | 'sources': sources 106 | }] 107 | }); 108 | }, false); 109 | xhr.send(); 110 | } 111 | }); 112 | -------------------------------------------------------------------------------- /SKCommsVideo.js: -------------------------------------------------------------------------------- 1 | addKiller("SKCommsVideo", { 2 | "canKill": function(data) { 3 | if (/v.nate.com/.test(data.src)) { data.site="nate"; return true;} 4 | if (/v.egloos.com/.test(data.src)) { data.site="egloos"; return true;} 5 | if (/dbi.video.cyworld.com/.test(data.src)) { data.site="cyworld"; return true; } 6 | return false; 7 | }, 8 | 9 | "process": function(data, callback) { 10 | var flashvars = parseFlashVariables(data.params.flashvars); 11 | // nate (pann, video, ...) 12 | if(data.site=="nate") { 13 | if(flashvars.mov_id) { 14 | this.processNateVideoID(flashvars.mov_id, callback); 15 | } 16 | 17 | // embedded Nate video 18 | var match = data.src.replace(/\|/g, "%7C").match(/v\.nate\.com\/v\.sk\/movie\/0%7C(\d+)\/(\d+)/); 19 | if (match) { 20 | this.processNateVideoID(match[2], callback); 21 | } 22 | return; 23 | } 24 | // Cyworld (merged by Nate) 25 | if(data.site=="cyworld") { 26 | if(flashvars.mov_id) { 27 | this.processNateVideoID(flashvars.mov_id, callback); 28 | } 29 | return; 30 | } 31 | 32 | // egloos (blog) 33 | if(data.site=="egloos") { 34 | if (flashvars.mov_id && flashvars.vs_keys) { 35 | // split vs_keys to blogid & serial 36 | var vs_keys = flashvars.vs_keys.split("|"); 37 | this.processEgloosVideoID(flashvars.mov_id, vs_keys[0], vs_keys[1], callback); 38 | } 39 | 40 | // embedded Egloos Video 41 | var match = data.src.replace(/\|/g, "%7C").match(/v\.egloos\.com\/v\.sk\/egloos\/([a-z]\d+)%7C(\d+)\/(\d+)/); 42 | if (match) { 43 | this.processEgloosVideoID(match[3], match[1], match[2], callback); 44 | } 45 | return; 46 | } 47 | }, 48 | 49 | "processNateVideoID": function(videoid, callback) { 50 | callback({ 51 | "playlist": [{ 52 | "sources": [{ 53 | "url": "http://m.pann.nate.com/video/videoPlayUrlRealTime?video_id="+videoid+"", 54 | "isNative": true 55 | }] 56 | }] 57 | }); 58 | }, 59 | 60 | "processEgloosVideoID": function(videoid, blogid, serial, callback) { 61 | callback({ 62 | "playlist": [{ 63 | "sources": [{ 64 | "url": "http://ebc.egloos.com/exec/mobile/play_movile_video.php?movieid="+videoid+"&blogid="+blogid+"&serial="+serial+"", 65 | "isNative": true 66 | }] 67 | }] 68 | }); 69 | } 70 | }); 71 | -------------------------------------------------------------------------------- /Sevenone.js: -------------------------------------------------------------------------------- 1 | // Sevenone killer (2011-09-16) 2 | 3 | /** 4 | * @link http://www.prosieben.de/ 5 | * @link http://www.kabeleins.de/ 6 | * @link http://www.sat1.de/ 7 | * @link http://www.ran.de/ 8 | */ 9 | addKiller("Sevenone", { 10 | 11 | "canKill": function(data) { 12 | return /^http:\/\/(?:tvtotal\.prosieben\.de|www\.kabeleins\.de|www\.sat1\.de|www\.ran\.de).*(?:player_core|HybridPlayer)\.swf$/.test(data.src); 13 | }, 14 | 15 | "process": function(data, callback) { 16 | var clipId = parseFlashVariables(data.params.flashvars).clip_id; 17 | var handleMIMEType = function(type) { 18 | if(type === 'text/plain') return; 19 | callback({ 20 | playlist: [{ 21 | sources: [{ 22 | url: "http://www.prosieben.de/dynamic/h264/h264map/?ClipID=" + clipId, 23 | format: 'MP4', 24 | isNative: true 25 | }] 26 | }] 27 | }); 28 | }; 29 | getMIMEType("http://www.prosieben.de/dynamic/h264/h264map/?ClipID=" + clipId, handleMIMEType); 30 | } 31 | 32 | }); -------------------------------------------------------------------------------- /Silverlight.js: -------------------------------------------------------------------------------- 1 | addKiller("Silverlight", { 2 | 3 | "canKill": function(data) { 4 | if(data.type !== "application/x-silverlight-2") return false; 5 | var match = /(?:^|,)\s*(m|fileurl|mediaurl|link)=/.exec(data.params.initparams); 6 | if(match) {data.file = match[1]; return true;} 7 | return false; 8 | }, 9 | 10 | "process": function(data, callback) { 11 | var SLvars = parseSLVariables(data.params.initparams); 12 | var mediaURL = decodeURIComponent(SLvars[data.file]); 13 | var info = extInfo(getExt(mediaURL)); 14 | 15 | var audioOnly = false; 16 | var sources = []; 17 | if(info) { 18 | info.url = mediaURL; 19 | sources.push(info); 20 | audioOnly = info.isAudio; 21 | } 22 | 23 | var posterURL; 24 | if(SLvars.thumbnail) posterURL = decodeURIComponent(SLvars.thumbnail); 25 | 26 | callback({ 27 | "playlist": [{"poster": posterURL, "sources": sources}], 28 | "audioOnly": audioOnly 29 | }); 30 | } 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /Spiegel.js: -------------------------------------------------------------------------------- 1 | if (window.safari) { 2 | // SPIEGEL.DE HACKS for ClickToPlugin 3 | safari.extension.addContentStyleSheet("div.jw-controls.jw-reset {display: none !important;}", ["http://*.spiegel.de/*"], []); 4 | 5 | var injectedScript = ` 6 | // This script tries to get the videoID out of the DOM 7 | function respondToMessage(theMessageEvent) { 8 | if(theMessageEvent.name === "getCurrentVideoID") { 9 | var videoID; 10 | var matchingListElement = document.querySelector("#js-video-slider .bx-wrapper .bx-viewport .bxslider .item_active"); 11 | if (matchingListElement) { 12 | var dataVideoNode = matchingListElement.getAttributeNode("data-video"); 13 | videoID = dataVideoNode.value; 14 | } 15 | safari.self.tab.dispatchMessage("pushCurrentVideoID", videoID); 16 | } 17 | } 18 | safari.self.addEventListener("message", respondToMessage, false); 19 | `; 20 | 21 | safari.extension.addContentScript(injectedScript, ["http://*.spiegel.de/*"], [], true); 22 | 23 | } 24 | 25 | 26 | addKiller("Spiegel", { 27 | 28 | 29 | "canKill": function(data) { 30 | return data.baseURL.startsWith("http://www.spiegel.de/"); 31 | }, 32 | 33 | 34 | "process": function(data, callback) { 35 | // Simple check if videoID is probably somewhere 36 | if (data.location.indexOf("-video-") !== -1) { 37 | var videoID = data.location.replace(/.*-video-(\d+).*.html/g, "$1"); 38 | this.processVideoIDAndCreateCallback(videoID, callback); 39 | } 40 | else { 41 | // Only in the following case it makes sense to install the eventListener: 42 | if (data.src === "http://www.spiegel.de/static/flash/flashvideo/jwplayer7.flash.swf") { 43 | var _this = this; 44 | 45 | var myMessageEventListener = function (theMessageEvent) { 46 | if(theMessageEvent.name === "pushCurrentVideoID") { 47 | // remove us: 48 | safari.application.removeEventListener(myMessageEventListener); 49 | var videoID = theMessageEvent.message; 50 | if(isNaN(videoID)) { 51 | return; 52 | } 53 | _this.processVideoIDAndCreateCallback.call(_this, videoID, callback); 54 | } 55 | } 56 | 57 | safari.application.addEventListener("message", myMessageEventListener, false); 58 | safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("getCurrentVideoID", "data"); 59 | } 60 | } 61 | 62 | }, 63 | 64 | 65 | "processVideoIDAndCreateCallback": function(videoID, callback) { 66 | var _this = this; 67 | var xhr = new XMLHttpRequest(); 68 | var jsonInfoUrl = "http://www.spiegel.de/video/video-" + videoID + ".json"; 69 | xhr.open("GET", jsonInfoUrl, true); 70 | xhr.addEventListener("load", function() { 71 | var data = JSON.parse(xhr.responseText); 72 | if(data) { 73 | _this.createCallback(data, callback); 74 | } 75 | }, false); 76 | xhr.send(null); 77 | }, 78 | 79 | 80 | "createCallback": function(data, callback) { 81 | var videoURL = data.cdnhost + data.binaryfilename; 82 | callback({ 83 | "playlist": [{ 84 | "sources": [{ 85 | "url": videoURL, 86 | "isNative": true 87 | }] 88 | }] 89 | }); 90 | } 91 | 92 | 93 | }); -------------------------------------------------------------------------------- /TED.js: -------------------------------------------------------------------------------- 1 | addKiller("TED", { 2 | 3 | "canKill": function(data) { 4 | return data.src.indexOf("ted.com/assets/player") !== -1 && /^https?:\/\/www\.ted\.com\//.test(data.location); 5 | }, 6 | 7 | "process": function(data, callback) { 8 | var xhr = new XMLHttpRequest(); 9 | xhr.open("GET", data.location, true); 10 | xhr.addEventListener("load", function() { 11 | var i = xhr.responseText.lastIndexOf("