Thursday, January 01, 2009

» Automatic YouTube download with IE7 +

So my mom likes to collect silly little clips from YouTube, and she uses IE7 on Windows XP (I've tried to get her to convert to Linux, but she's not very computer saavy and has learned computing with Windows—even Ubuntu is a bit too much for her to take in). She normally just copies the YouTube url, pastes it to KeepVid, followed by a right-click + save-as, pasting in the video title as the file name in the save dialog instead of the default "video.mp4" (or "video.flv"), and finally clicking "OK." That's a lot of work for what should be a simple operation.

I had some free time over the holidays, so I hacked up a little user script and Windows Scripting Host script to allow automatically downloading files from YouTube with IE7. Now you might be thinking something like: "That's lovely, but you could have just downloaded Firefox, installed GreaseMonkey and FlashGot, writen a user script to re-write YouTube urls to add &fmt=18, and used the FlashGot icon in the statusbar to download the video." That's all very true, but as I said, my mother is used to Windows and IE—it was just easier to KISS than to teach her a new technology (not to mention that she watches Netflix movies online, which requires IE—using two browsers for different things would thoroughly confuse her).

Firstly, you need to install the Trixie plugin for IE (get it here), which in turn requires .NET.

Next you need to place the following user script in C:\Program Files\Bhelpuri\Trixie\Scripts:

YouTube.user.js
// ==UserScript==
// @name Download YouTube videos
// @description Creates a link to download YouTube videos directly
// @namespace MonkeeSage@gmail.com
// @include *
// ==/UserScript==

(function()
{
// Trixie's @include directive seems broken using "*youtube.com/watch?*"
// so we manually filter the url here
if (location.href.indexOf("youtube.com/watch?") == -1)
return;

var match;
var node;
var videoId;
var tParam;
var videoTitle;

var videoUrl = "download://www.youtube.com/get_video?";
var videoTitleRe = new RegExp("YouTube - (.+)", "m");
var videoIdRe = new RegExp("video_id=([^&,\"]+)", "m");
var tParamRe = new RegExp("\"t\": \"([^&,\"]+)\"", "m");

try
{
match = document.title.match(videoTitleRe);
if (match) videoTitle = match[1];

match = document.body.innerHTML.match(videoIdRe);
if (match) videoId = match[1];

match = document.getElementsByTagName("head")[0].innerHTML.match(tParamRe);
if (match) tParam = match[1];
}
catch (ex)
{
dump(ex.message);
}

if (videoId && tParam)
{
videoUrl += "video_id=" + videoId + "&t=" + tParam + "&fmt=18#" +
"C:\\Documents and Settings\\mom\\Desktop\\My Music&" +
videoTitle + ".mp4";
a = document.createElement("a");
a.appendChild(document.createTextNode("Download video"));
a.href = videoUrl;
node = document.getElementById("watch-this-vid");
node.appendChild(a);
}

})();

Ps. You obviously need to change the C:\\Documents and Settings\\mom\\Desktop\\My Music to the default location you wish to save to.

Pss.You'll need to enable the script under Tools->Trixie Options (or Trixie Settings, or something similar—I'm going from memory here).

Next, you need to save the following file to C:\Program Files\Common Files\System:

wget.js
(function()
{
function BrowseForFolder(path, file)
{
var objDialog = new ActiveXObject("SAFRCFileDlg.FileSave");
var fso = new ActiveXObject("Scripting.FileSystemObject");

objDialog.FileName = fso.BuildPath(path, file);
objDialog.FileType = "MPEG4 Video";

var rv = objDialog.OpenFileSaveDlg();
if (rv)
{
return objDialog.FileName
}
else
{
return false;
}
}

function DownloadFile(url, file)
{
var data;
var ado;

try
{
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");

// ResolveTimeout, ConnectTimeout, SendTimeout, ReceiveTimeout
WinHttpReq.SetTimeouts(30000, 30000, 30000, 5000);

void(WinHttpReq.Open("GET", url, false));
WinHttpReq.Send();
if (WinHttpReq.Status == 404)
{
return false;
}
data = WinHttpReq.ResponseBody;
}
catch (ex)
{
WScript.Echo("Error downloading file: " + ex.message);
return false;
}

ado = new ActiveXObject("ADODB.Stream");
ado.Type = 1; // binary mode
ado.Open();
ado.Write(data);
ado.SaveToFile(file, 2); // 2 = overwrite existing file
ado.Close();

return true;
}

function SetFileSuffix(filename, suffix)
{
var idx = filename.lastIndexOf(".");
if (idx > -1)
{
filename = filename.slice(0, idx);
}
return filename + suffix;
}

var url;
var file;
var path = "C:\\Documents and Settings\\mom\\Desktop\\My Music";
var filename = "foo";

var objArgs = WScript.Arguments;
if (objArgs.length > 0)
{
url = objArgs(0).split("#");
if (url.length == 2)
{
var tmp = url[1].split("&");
if (tmp.length > 0)
{
path = tmp[0];
}
if (tmp.length > 1)
{
filename = tmp[1];
}
}
url = url[0];
}
else
{
WScript.Echo("A URL argument is required");
return;
}

filename = SetFileSuffix(filename, ".mp4");

// replace the download:// pseudo-protocol with http://
url = "http" + url.slice(8);

file = BrowseForFolder(path, filename);
if (file)
{
var rv = DownloadFile(url, file);
if (!rv)
{
file = SetFileSuffix(file, ".flv");
url = url.replace("&fmt=18", "");
rv = DownloadFile(url, file);
}
if (rv)
{
var objWSH = new ActiveXObject("WScript.Shell");
objWSH.Popup("Finished downloading " + filename, 10, "Download Complete", 64);
}
}

})();

Finally, you need to add a new protocol handler to the registery to handle the download:// pseudo-protocol. Save and run the following regedit file:

YouTubeDL.reg
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\download]
@="URL:Download Protocol"
"URL Protocol"=""

[HKEY_CLASSES_ROOT\download\shell]

[HKEY_CLASSES_ROOT\download\shell\open]

[HKEY_CLASSES_ROOT\download\shell\open\command]
@="C:\\WINDOWS\\system32\\wscript.exe \"C:\\Program Files\\Common Files\\System\\wget.js\" \"%1\""


Now restart IE, and you should be able to download YouTube videos from a link directly under the video (on the left side).

Caveat: There is no progress dialog and no way to cancel downloads. I could probably figure out a COM dialog to display the progress, and run the HTTP GET asychonously (and cancel the Send operation when requested), but my mom didn't need those features, and I'm lazy, so I didn't. ;P

Labels: , , ,

1 Comments:

Anonymous Anonymous said...

Nice Script!

You can also use online tools such as vixy and http://www.getaudiofromvideo.com/ , they work quite well.
January 1, 2009 at 12:45 PM

 

Post a Comment

Links to this post:

Create a Link

<< Home