Scramblings
... has been trying to make sense for half a year

Downloading YouTube: Black holes and revelations

Introduction

Have you ever looked at a video on YouTube and wondered: "Man, this vid is awesome. I'd like to have it on my iPod/iPhone/iWhatever". Of course, if you had done some digging you would eventually stumble upon sites like Clipnabber. But these only give you the flv file. For conversions to mp4 for your iPod you'll have to resort to a not-so-awesome graphical frontend of the very-awesome ffmpeg (also known as the swiss army knife of video conversion). Well, lucky for you, I've spent the last two weeks coding an application to download video's from youtube and convert them to mp4/avi/wmv or even extract their mp3 on the fly, and then deleting those .flv files. In this article I will elaborate on some difficulties and discoveries I have made writing this program.

The set-up

At first, I downloaded video's from YouTube using this shell script:

#!/bin/sh
youtube-dl $1 -o $2.flv
ffmpeg -i $2.flv $2.mp4
rm $2.flv

That seems easy, doesn't it? Well, it was too easy for me. I personally despise going to the terminal for something I need to do on a regular basis. So I decided to do it the hard way: I was going to write a GUI for this script. With fancy progressbars, colored textboxes and beautiful Tango icons. Oh joy!

The crash

Sounds easy, doesn't it? So in all my youthful enthusiasm, I started putting out code like a madman. I was making quite a sprint in progress, when suddenly, SHEBANG! After updating the progressbar once, my GTK user-interface crashed like my ISP's dns on a sunday evening. Taking the PHP-GTK approach of running a Gtk.Main.IterationDo after every update didn't help. I tried all-sorts of functions that are supposed to unstick the stickyness of a crashed GTK app, I even tried to time the updates so that the bar would only get updated every 10 seconds. I got no response in the #gtk and #mono channels on FreeNode. But eventually salvation came: an article on the Mono website told me how to do this. Now this is going to look wierd, but:

// This will crash your GTK thread ...
DownloadProgress.Fraction = 0.1337;
// But this wont!
Gtk.Application.Invoke(delegate { DownloadProgress.Fraction = 0.1337; });

The article actually made sense. In order to change something heavily related to that thread, you will have to be in that threads domain. And lo and behold: the code actually worked beautifully!

The userfriendly factor

Something I also don't like about applications are messageboxes for litterally every single thing: telling me that the operation has succeeded/failed, that progress xyz has gone bananas or that the dog needs a walk. In my humble opinion, many errors can be caught and reported the moment the user makes them, and you still have their attention. For example, numerous websites still have a registration page that requires you to fill in the whole form again if your nickname was taken, your zip code cannot exist or your email-address is invalid (tu quoque, phpBB). When I have filled in something wrong, I want to know it immidiately, and not through an extra window as soon as I click the submit button. That's why I sat down and took the time to validate the two major things the application asks for: the filename and the YouTube URL. If either is filled in wrong, three things happen:

  1. You can't click the button to add the URL and filename to the list
  2. The field that has faulty or incorrect data is highlighted in a not-too-bright red color
  3. The error message is viewed on a normally hidden label.

This way, you can correct the data while you are still typing and there is no need for you to grab your mouse to go back to the field.

image here
Invalid URL enteredFile already existsCorrent input given (huzzah!)The empty form

The usability

I found myself downloading mp3's via the aforementioned bash script more often than I used my filesharing client. When my girlfriend asked for a way for her to download video's from YouTube to her iPod, I spotted two uses for the program. One is to download the video's to like in a format you like, so you don't have to bother with applications written for either specifically downloading or specifically converting. The other is to get the mp3's you like from a trustable source: It is fast, you can kind-of pre-listen them before downloads and often the record labels themselves upload the material. Also, there is a vast database of video's on YouTube for you to grab. And while I was at it, I created a possibility for the user to specify multiple URLs, tell the program to download and convert, and in the meantime you can go fetch some tea. I just slammed them in a treeview and used the provided foreach function to walk through them and call the function that downloads and encodes them. So lastly, a few screenshots of the downloads list in action:

image here
Downloading first fileEncoding first fileDownloading second fileSpot the pattern?

Downloads

I've exported these files with MonoDevelop. At the moment, I am not working on a windows version yet, but feel free to do so. The files are licenced under the CC-BY license found in the LICENSE file in each archive. They depend on ffmpeg compiled with mp4 support, and youtube-dl and thus python for downloading the videos. Perhaps I'll translate youtube-dl into C# so we can forget about the python and youtube-dl. This will also make it easier to port the program to Windows/Mac. I do however fear that it will always keep depending on ffmpeg. Rewriting that in C# would be ludacris. I have included the deb packages for the custom ffmpeg. These are compiled against an i386 architecture on an ubuntu system.

Comments

[Reply]Volker says:
Just used this software running on Ubuntu Hardy. Worked very well. Thank you.

[Reply]GencizKeync says:
I'm new here, just wanted to say hello and introduce myself.


(optional)


Valid XHTML 1.0 Strict Valid CSS 2.1