By Manuel Seeger
Has 10 other scripts.
// ==UserScript==
// @name Apple Trailer Download
// @namespace http://www.manuelseeger.de
// @description Download the movie trailers from apple.com
// @include http://*apple.com/trailers/*
// @version 2.1.5
// ==/UserScript==
(function() {
// the box holding the links to the full movies:
atdcontainer = document.createElement("div");
atdcontainer.mh = 35; // height of containerbox
// reset styles we may have inherited from <body>
var style = "display: none; background-color: #999; "+
"position: fixed; width: 100px; height: 35px; " +
"right: 10px; bottom: 10px; z-index: 900;padding:5px;"+
"text-align:left;-moz-opacity: 0.8;border:2px solid #333;" +
"font-family:Arial;color:#333;";
atdcontainer.setAttribute("style", style);
atdcontainer.innerHTML =
'<p style="font-weight:bold;font-size:8pt;'+
'margin:0 0 5px 0;padding:0;">'+
'Apple Trailer Download:</p>';
linkcontainer = document.createElement("ul");
linkcontainer.setAttribute("style",
"list-style-image:url(http://www.apple.com/favicon.ico);" +
"margin:0;padding-left:25px;vertical-align:middle;");
atdcontainer.appendChild(linkcontainer);
document.body.insertBefore(atdcontainer,document.body.firstChild);
/**
* Insert an absolute positioned div-box at
* the upper left corner of the embed element found
* in getDownloadLink()
*/
function insertDownloadLink(movie_url, res) {
var title = "Download Trailer (" + res + ")";
res = parseInt(res);
// actually, the resolution is not always 4/3, but hey...
var smilie = ""+res + "x"+(res*0.75);
inner_html = ''+
'<a title="'+title+'" href="'+movie_url+'" ' +
'style="color:#333;font-weight:900;font-size:8pt;'+
'text-decoration:none;">' +
smilie + '</a>';
var li = document.createElement("li");
li.innerHTML = inner_html;
linkcontainer.appendChild(li);
atdcontainer.style.display = "block";
atdcontainer.mh = atdcontainer.mh + 25;
atdcontainer.style.height = atdcontainer.mh + 'px';
}
/**
* Scans the page for quicktime movies.
*
* The method first tries to locate <embed> objects holding the links
* to quicktime movies via XPath.
* If that does not work, the method searches for URLs to quicktime
* movies within all <script> areas. Apple sometimes injects the
* <embed> object after the page has loaded using scripting.
*
* All movie URLs found will then be downloaded and processed
*/
function getDownloadLink() {
var sources = new Array();
var src_url = "";
var j = 0;
// TODO: find a better way to determine if the found
// movies are real trailers or just hyperlink replacements
// pass 1:
var nobjects = xpath(document, "//object/embed[@height > 100]");
if (nobjects.length == 0) {
// pass 2: search in (embedded) script areas
var scripts = xpath(document, "//script[not(@src)]/text()");
for (j=0; j < scripts.length; j++) {
regex = /.*(http:\/\/(movies|images).apple.com\/movies\/[\w-._]+\/[\w-._]+\/.+\.mov).*/i;
if (regex.test(scripts[j].nodeValue)) {
var result = regex.exec(scripts[j].nodeValue);
src_url = result[1];
sources.push(src_url);
}
}
} else {
for (j=0; j<nobjects.length; j++) {
if (nobjects[j] != null) {
// some trailer reference the quicktime file via href
src_url = nobjects[j].getAttribute("href");
if (src_url == null) {
src_url = nobjects[j].getAttribute("src");
}
sources.push(src_url);
}
}
}
for (j=0; j<sources.length; j++) {
/**
* Anynchronously fetches the quicktime streaming file
* via an xmlhttpRequest.
* That one is only a dummy Quicktime movie, pointing to the
* full movie. The path to the full movie seems to
* begin at position 44 in the streaming file (open one
* with a hex editor).
* The onload() callback reads this path and
* passes the URL to the full movie to insertDownloadLink()
*/
GM_xmlhttpRequest({ // start of xmlHTTPRequest()
method: 'GET',
url: sources[j],
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': '*/*'
},
onload: function(responseDetails) {
var path_default = readQtDummyFile(responseDetails.responseText, 44);
if (path_default.indexOf(".mov") != (path_default.length-4)) {
// no URL found!
insertDownloadLink("", 0);
} else {
var pos = this.url.lastIndexOf("/")+1;
var url_default = this.url.substring(0,pos)+path_default;
if (this.url.indexOf("-h.ref.mov") == -1) {
// custom or HD trailer page, we are done:
var res = path_default.replace(/.*([0-9]{4}).?\.mov/, "$1");
if (res == path_default) {
var res = path_default.replace(/.*([0-9]{3}).*/, "$1");
}
insertDownloadLink(url_default, res);
} else {
// default trailer page, get the other resolutions:
// Many thanks to Hans Schmidt for this code
//
// 12/21/2007: update: this is deprecated now, as trailer URLs
// seem to always end the same way now
//
//var url_480 = readQtDummyFile(responseDetails.responseText,
// (44+path_default.length+99));
//url_480 = this.url.substring(0,pos)+url_480;
pos = url_default.lastIndexOf(".")-3;
var url_480 = url_default.substring(0,pos)+"480.mov";
var url_640 = url_default.substring(0,pos)+"640w.mov";
insertDownloadLink(url_default, 320);
insertDownloadLink(url_480, 480);
insertDownloadLink(url_640, 640);
}
}
},
onerror: function(responseDetails) {
alert(responseDetails.status);
}
}); // end of xmlHTTPRequest()
}
}
function xpath(node, expr) {
var resultSet = document.evaluate(expr, node, null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var found = [];
var res;
for (var i = 0; i < resultSet.snapshotLength; i++) {
found.push(resultSet.snapshotItem(i));
}
return found;
}
/**
* Reads the filename of the full quicktime movie
*/
function readQtDummyFile(res, start_pos) {
var p = start_pos;
var p1 = 0;
var p2 = 0;
var p3 = 0
var p4 = 0;
var path = "";
while (false ==
// the movie's path should
// end with this code sequence:
(p4 == 46 &&
p3 == 109 &&
p2 == 111 &&
p1 == 118 &&
res.charCodeAt(p) == 0) &&
p < (start_pos+150)) {
path += res.charAt(p);
p4 = p3;
p3 = p2;
p2 = p1;
p1 = res.charCodeAt(p);
p = p + 1;
}
return path;
}
window.addEventListener("load", function() { getDownloadLink(); }, false);
})();