From 9815bb0a551468e4939cacfffbc2d5cb8dd12431 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Rog=C3=A9rio=20Brito?= <rbrito@ime.usp.br>
Date: Sun, 23 Jun 2013 20:10:29 -0300
Subject: [PATCH] Imported Upstream version 2013.06.26

---
 Makefile                                |    8 +-
 README.md                               |    4 +-
 README.txt                              |    4 +-
 devscripts/release.sh                   |   12 +-
 setup.py                                |    5 +-
 test/test_all_urls.py                   |    2 +-
 test/test_download.py                   |   17 +-
 test/test_write_info_json.py            |    4 +-
 test/test_youtube_lists.py              |    2 +-
 test/test_youtube_subtitles.py          |    2 +-
 test/tests.json                         |   19 +
 youtube-dl                              |  Bin 75144 -> 112794 bytes
 youtube-dl.1                            |    4 +-
 youtube_dl/FileDownloader.py            |    7 +-
 youtube_dl/InfoExtractors.py            | 4617 +----------------------
 youtube_dl/PostProcessor.py             |    5 -
 youtube_dl/__init__.py                  |    9 +-
 youtube_dl/extractor/__init__.py        |  133 +
 youtube_dl/extractor/ard.py             |   45 +
 youtube_dl/extractor/arte.py            |  136 +
 youtube_dl/extractor/bandcamp.py        |   54 +
 youtube_dl/extractor/bliptv.py          |  177 +
 youtube_dl/extractor/breakcom.py        |   25 +
 youtube_dl/extractor/collegehumor.py    |   74 +
 youtube_dl/extractor/comedycentral.py   |  179 +
 youtube_dl/extractor/common.py          |  264 ++
 youtube_dl/extractor/dailymotion.py     |   77 +
 youtube_dl/extractor/depositfiles.py    |   60 +
 youtube_dl/extractor/eighttracks.py     |   51 +
 youtube_dl/extractor/escapist.py        |   68 +
 youtube_dl/extractor/facebook.py        |  111 +
 youtube_dl/extractor/flickr.py          |   57 +
 youtube_dl/extractor/funnyordie.py      |   31 +
 youtube_dl/extractor/gametrailers.py    |   59 +
 youtube_dl/extractor/generic.py         |  151 +
 youtube_dl/extractor/googleplus.py      |   82 +
 youtube_dl/extractor/googlesearch.py    |   39 +
 youtube_dl/extractor/howcast.py         |   37 +
 youtube_dl/extractor/hypem.py           |   63 +
 youtube_dl/extractor/ina.py             |   31 +
 youtube_dl/extractor/infoq.py           |   50 +
 youtube_dl/extractor/justintv.py        |  144 +
 youtube_dl/extractor/keek.py            |   32 +
 youtube_dl/extractor/liveleak.py        |   44 +
 youtube_dl/extractor/metacafe.py        |  110 +
 youtube_dl/extractor/mixcloud.py        |  115 +
 youtube_dl/extractor/mtv.py             |   72 +
 youtube_dl/extractor/myspass.py         |   64 +
 youtube_dl/extractor/myvideo.py         |  164 +
 youtube_dl/extractor/nba.py             |   40 +
 youtube_dl/extractor/photobucket.py     |   66 +
 youtube_dl/extractor/pornotube.py       |   41 +
 youtube_dl/extractor/rbmaradio.py       |   44 +
 youtube_dl/extractor/redtube.py         |   29 +
 youtube_dl/extractor/soundcloud.py      |  129 +
 youtube_dl/extractor/spiegel.py         |   37 +
 youtube_dl/extractor/stanfordoc.py      |  112 +
 youtube_dl/extractor/statigram.py       |   33 +
 youtube_dl/extractor/steam.py           |   63 +
 youtube_dl/extractor/teamcoco.py        |   46 +
 youtube_dl/extractor/ted.py             |   79 +
 youtube_dl/extractor/tumblr.py          |   41 +
 youtube_dl/extractor/ustream.py         |   36 +
 youtube_dl/extractor/vbox7.py           |   46 +
 youtube_dl/extractor/vimeo.py           |  138 +
 youtube_dl/extractor/vine.py            |   37 +
 youtube_dl/extractor/worldstarhiphop.py |   44 +
 youtube_dl/extractor/xhamster.py        |   61 +
 youtube_dl/extractor/xnxx.py            |   45 +
 youtube_dl/extractor/xvideos.py         |   43 +
 youtube_dl/extractor/yahoo.py           |  113 +
 youtube_dl/extractor/youjizz.py         |   45 +
 youtube_dl/extractor/youku.py           |  104 +
 youtube_dl/extractor/youporn.py         |  117 +
 youtube_dl/extractor/youtube.py         |  795 ++++
 youtube_dl/extractor/zdf.py             |   65 +
 youtube_dl/version.py                   |    2 +-
 77 files changed, 5314 insertions(+), 4657 deletions(-)
 create mode 100644 youtube_dl/extractor/__init__.py
 create mode 100644 youtube_dl/extractor/ard.py
 create mode 100644 youtube_dl/extractor/arte.py
 create mode 100644 youtube_dl/extractor/bandcamp.py
 create mode 100644 youtube_dl/extractor/bliptv.py
 create mode 100644 youtube_dl/extractor/breakcom.py
 create mode 100644 youtube_dl/extractor/collegehumor.py
 create mode 100644 youtube_dl/extractor/comedycentral.py
 create mode 100644 youtube_dl/extractor/common.py
 create mode 100644 youtube_dl/extractor/dailymotion.py
 create mode 100644 youtube_dl/extractor/depositfiles.py
 create mode 100644 youtube_dl/extractor/eighttracks.py
 create mode 100644 youtube_dl/extractor/escapist.py
 create mode 100644 youtube_dl/extractor/facebook.py
 create mode 100644 youtube_dl/extractor/flickr.py
 create mode 100644 youtube_dl/extractor/funnyordie.py
 create mode 100644 youtube_dl/extractor/gametrailers.py
 create mode 100644 youtube_dl/extractor/generic.py
 create mode 100644 youtube_dl/extractor/googleplus.py
 create mode 100644 youtube_dl/extractor/googlesearch.py
 create mode 100644 youtube_dl/extractor/howcast.py
 create mode 100644 youtube_dl/extractor/hypem.py
 create mode 100644 youtube_dl/extractor/ina.py
 create mode 100644 youtube_dl/extractor/infoq.py
 create mode 100644 youtube_dl/extractor/justintv.py
 create mode 100644 youtube_dl/extractor/keek.py
 create mode 100644 youtube_dl/extractor/liveleak.py
 create mode 100644 youtube_dl/extractor/metacafe.py
 create mode 100644 youtube_dl/extractor/mixcloud.py
 create mode 100644 youtube_dl/extractor/mtv.py
 create mode 100644 youtube_dl/extractor/myspass.py
 create mode 100644 youtube_dl/extractor/myvideo.py
 create mode 100644 youtube_dl/extractor/nba.py
 create mode 100644 youtube_dl/extractor/photobucket.py
 create mode 100644 youtube_dl/extractor/pornotube.py
 create mode 100644 youtube_dl/extractor/rbmaradio.py
 create mode 100644 youtube_dl/extractor/redtube.py
 create mode 100644 youtube_dl/extractor/soundcloud.py
 create mode 100644 youtube_dl/extractor/spiegel.py
 create mode 100644 youtube_dl/extractor/stanfordoc.py
 create mode 100644 youtube_dl/extractor/statigram.py
 create mode 100644 youtube_dl/extractor/steam.py
 create mode 100644 youtube_dl/extractor/teamcoco.py
 create mode 100644 youtube_dl/extractor/ted.py
 create mode 100644 youtube_dl/extractor/tumblr.py
 create mode 100644 youtube_dl/extractor/ustream.py
 create mode 100644 youtube_dl/extractor/vbox7.py
 create mode 100644 youtube_dl/extractor/vimeo.py
 create mode 100644 youtube_dl/extractor/vine.py
 create mode 100644 youtube_dl/extractor/worldstarhiphop.py
 create mode 100644 youtube_dl/extractor/xhamster.py
 create mode 100644 youtube_dl/extractor/xnxx.py
 create mode 100644 youtube_dl/extractor/xvideos.py
 create mode 100644 youtube_dl/extractor/yahoo.py
 create mode 100644 youtube_dl/extractor/youjizz.py
 create mode 100644 youtube_dl/extractor/youku.py
 create mode 100644 youtube_dl/extractor/youporn.py
 create mode 100644 youtube_dl/extractor/youtube.py
 create mode 100644 youtube_dl/extractor/zdf.py

diff --git a/Makefile b/Makefile
index e00f5e6..85dacfa 100644
--- a/Makefile
+++ b/Makefile
@@ -40,15 +40,15 @@ tar: youtube-dl.tar.gz
 
 pypi-files: youtube-dl.bash-completion README.txt youtube-dl.1
 
-youtube-dl: youtube_dl/*.py
-	zip --quiet youtube-dl youtube_dl/*.py
+youtube-dl: youtube_dl/*.py youtube_dl/*/*.py
+	zip --quiet youtube-dl youtube_dl/*.py youtube_dl/*/*.py
 	zip --quiet --junk-paths youtube-dl youtube_dl/__main__.py
 	echo '#!$(PYTHON)' > youtube-dl
 	cat youtube-dl.zip >> youtube-dl
 	rm youtube-dl.zip
 	chmod a+x youtube-dl
 
-README.md: youtube_dl/*.py
+README.md: youtube_dl/*.py youtube_dl/*/*.py
 	COLUMNS=80 python -m youtube_dl --help | python devscripts/make_readme.py
 
 README.txt: README.md
@@ -57,7 +57,7 @@ README.txt: README.md
 youtube-dl.1: README.md
 	pandoc -s -f markdown -t man README.md -o youtube-dl.1
 
-youtube-dl.bash-completion: youtube_dl/*.py devscripts/bash-completion.in
+youtube-dl.bash-completion: youtube_dl/*.py youtube_dl/*/*.py devscripts/bash-completion.in
 	python devscripts/bash-completion.py
 
 bash-completion: youtube-dl.bash-completion
diff --git a/README.md b/README.md
index 2f3c81a..929f2b5 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 % YOUTUBE-DL(1)
 
 # NAME
-youtube-dl
+youtube-dl - download videos from youtube.com or other video platforms
 
 # SYNOPSIS
 **youtube-dl** [OPTIONS] URL [URL...]
@@ -121,7 +121,7 @@ which means you can modify it, redistribute it or use it however you like.
                                video (currently youtube only)
     --list-subs                lists all available subtitles for the video
                                (currently youtube only)
-    --sub-format LANG          subtitle format [srt/sbv] (default=srt)
+    --sub-format FORMAT        subtitle format [srt/sbv] (default=srt)
                                (currently youtube only)
     --sub-lang LANG            language of the subtitles to download (optional)
                                use IETF language tags like 'en'
diff --git a/README.txt b/README.txt
index c5e2ce3..b58f682 100644
--- a/README.txt
+++ b/README.txt
@@ -1,7 +1,7 @@
 NAME
 ====
 
-youtube-dl
+youtube-dl - download videos from youtube.com or other video platforms
 
 SYNOPSIS
 ========
@@ -136,7 +136,7 @@ Video Format Options:
                                video (currently youtube only)
     --list-subs                lists all available subtitles for the video
                                (currently youtube only)
-    --sub-format LANG          subtitle format [srt/sbv] (default=srt)
+    --sub-format FORMAT        subtitle format [srt/sbv] (default=srt)
                                (currently youtube only)
     --sub-lang LANG            language of the subtitles to download (optional)
                                use IETF language tags like 'en'
diff --git a/devscripts/release.sh b/devscripts/release.sh
index b8efdab..d32ae47 100755
--- a/devscripts/release.sh
+++ b/devscripts/release.sh
@@ -14,6 +14,12 @@
 
 set -e
 
+skip_tests=false
+if [ "$1" = '--skip-test' ]; then
+    skip_tests=true
+    shift
+fi
+
 if [ -z "$1" ]; then echo "ERROR: specify version number like this: $0 1994.09.06"; exit 1; fi
 version="$1"
 if [ ! -z "`git tag | grep "$version"`" ]; then echo 'ERROR: version already present'; exit 1; fi
@@ -22,7 +28,11 @@ if [ ! -f "updates_key.pem" ]; then echo 'ERROR: updates_key.pem missing'; exit
 
 /bin/echo -e "\n### First of all, testing..."
 make cleanall
-nosetests --verbose --with-coverage --cover-package=youtube_dl --cover-html test --stop || exit 1
+if $skip_tests ; then
+    echo 'SKIPPING TESTS'
+else
+    nosetests --verbose --with-coverage --cover-package=youtube_dl --cover-html test --stop || exit 1
+fi
 
 /bin/echo -e "\n### Changing version in version.py..."
 sed -i "s/__version__ = '.*'/__version__ = '$version'/" youtube_dl/version.py
diff --git a/setup.py b/setup.py
index eb7b1a2..61435fc 100644
--- a/setup.py
+++ b/setup.py
@@ -2,6 +2,7 @@
 # -*- coding: utf-8 -*-
 
 from __future__ import print_function
+
 import pkg_resources
 import sys
 
@@ -23,7 +24,7 @@ py2exe_options = {
     "compressed": 1,
     "optimize": 2,
     "dist_dir": '.',
-    "dll_excludes": ['w9xpopen.exe']
+    "dll_excludes": ['w9xpopen.exe'],
 }
 py2exe_console = [{
     "script": "./youtube_dl/__main__.py",
@@ -57,7 +58,7 @@ setup(
     author = 'Ricardo Garcia',
     maintainer = 'Philipp Hagemeister',
     maintainer_email = 'phihag@phihag.de',
-    packages = ['youtube_dl'],
+    packages = ['youtube_dl', 'youtube_dl.extractor'],
 
     # Provokes warning on most systems (why?!)
     #test_suite = 'nose.collector',
diff --git a/test/test_all_urls.py b/test/test_all_urls.py
index dd67286..d3ee296 100644
--- a/test/test_all_urls.py
+++ b/test/test_all_urls.py
@@ -7,7 +7,7 @@ import unittest
 import os
 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
-from youtube_dl.InfoExtractors import YoutubeIE, YoutubePlaylistIE, YoutubeChannelIE, JustinTVIE
+from youtube_dl.extractor import YoutubeIE, YoutubePlaylistIE, YoutubeChannelIE, JustinTVIE
 
 class TestAllURLsMatching(unittest.TestCase):
     def test_youtube_playlist_matching(self):
diff --git a/test/test_download.py b/test/test_download.py
index 577bcdb..8d86984 100644
--- a/test/test_download.py
+++ b/test/test_download.py
@@ -14,7 +14,7 @@ import binascii
 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
 import youtube_dl.FileDownloader
-import youtube_dl.InfoExtractors
+import youtube_dl.extractor
 from youtube_dl.utils import *
 
 DEF_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tests.json')
@@ -72,7 +72,7 @@ class TestDownload(unittest.TestCase):
 def generator(test_case):
 
     def test_template(self):
-        ie = youtube_dl.InfoExtractors.get_info_extractor(test_case['name'])
+        ie = youtube_dl.extractor.get_info_extractor(test_case['name'])
         if not ie._WORKING:
             print('Skipping: IE marked as not _WORKING')
             return
@@ -87,7 +87,7 @@ def generator(test_case):
         params.update(test_case.get('params', {}))
 
         fd = FileDownloader(params)
-        for ie in youtube_dl.InfoExtractors.gen_extractors():
+        for ie in youtube_dl.extractor.gen_extractors():
             fd.add_info_extractor(ie)
         finished_hook_called = set()
         def _hook(status):
@@ -125,11 +125,14 @@ def generator(test_case):
                     self.assertEqual(md5_for_file, tc['md5'])
                 with io.open(tc['file'] + '.info.json', encoding='utf-8') as infof:
                     info_dict = json.load(infof)
-                for (info_field, value) in tc.get('info_dict', {}).items():
-                    if isinstance(value, compat_str) and value.startswith('md5:'):
-                        self.assertEqual(value, 'md5:' + md5(info_dict.get(info_field)))
+                for (info_field, expected) in tc.get('info_dict', {}).items():
+                    if isinstance(expected, compat_str) and expected.startswith('md5:'):
+                        self.assertEqual(expected, 'md5:' + md5(info_dict.get(info_field)))
                     else:
-                        self.assertEqual(value, info_dict.get(info_field))
+                        got = info_dict.get(info_field)
+                        self.assertEqual(
+                            expected, got,
+                            u'invalid value for field %s, expected %r, got %r' % (info_field, expected, got))
 
                 # If checkable fields are missing from the test case, print the info_dict
                 test_info_dict = dict((key, value if not isinstance(value, compat_str) or len(value) < 250 else 'md5:' + md5(value))
diff --git a/test/test_write_info_json.py b/test/test_write_info_json.py
index 8134dda..b5eca76 100644
--- a/test/test_write_info_json.py
+++ b/test/test_write_info_json.py
@@ -10,7 +10,7 @@ import unittest
 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
 import youtube_dl.FileDownloader
-import youtube_dl.InfoExtractors
+import youtube_dl.extractor
 from youtube_dl.utils import *
 
 PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "parameters.json")
@@ -48,7 +48,7 @@ class TestInfoJSON(unittest.TestCase):
         self.tearDown()
 
     def test_info_json(self):
-        ie = youtube_dl.InfoExtractors.YoutubeIE()
+        ie = youtube_dl.extractor.YoutubeIE()
         fd = FileDownloader(params)
         fd.add_info_extractor(ie)
         fd.download([TEST_ID])
diff --git a/test/test_youtube_lists.py b/test/test_youtube_lists.py
index e8b49ff..2c46edf 100644
--- a/test/test_youtube_lists.py
+++ b/test/test_youtube_lists.py
@@ -8,7 +8,7 @@ import json
 import os
 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
-from youtube_dl.InfoExtractors import YoutubeUserIE, YoutubePlaylistIE, YoutubeIE, YoutubeChannelIE
+from youtube_dl.extractor import YoutubeUserIE, YoutubePlaylistIE, YoutubeIE, YoutubeChannelIE
 from youtube_dl.utils import *
 from youtube_dl.FileDownloader import FileDownloader
 
diff --git a/test/test_youtube_subtitles.py b/test/test_youtube_subtitles.py
index c80c90c..129e239 100644
--- a/test/test_youtube_subtitles.py
+++ b/test/test_youtube_subtitles.py
@@ -10,7 +10,7 @@ import hashlib
 import os
 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
-from youtube_dl.InfoExtractors import YoutubeIE
+from youtube_dl.extractor import YoutubeIE
 from youtube_dl.utils import *
 from youtube_dl import FileDownloader
 
diff --git a/test/tests.json b/test/tests.json
index 3e0db29..01367b0 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -630,5 +630,24 @@
         "title": "E3 2013: Debut Trailer"
     },
     "skip": "Requires rtmpdump"
+  },
+  {
+    "name": "Statigram",
+    "url": "http://statigr.am/p/484091715184808010_284179915",
+    "file": "484091715184808010_284179915.mp4",
+    "md5": "deda4ff333abe2e118740321e992605b",
+    "info_dict": {
+        "uploader_id": "videoseconds",
+        "title": "Instagram photo by @videoseconds (Videos)"
+    }
+  },
+  {
+    "name": "Break",
+    "url": "http://www.break.com/video/when-girls-act-like-guys-2468056",
+    "file": "2468056.mp4",
+    "md5": "a3513fb1547fba4fb6cfac1bffc6c46b",
+    "info_dict": {
+        "title": "When Girls Act Like D-Bags"
+    }
   }
 ]
diff --git a/youtube-dl b/youtube-dl
index ea6d889ba2d69a7a9c989380e97ccd92186b8fb2..ffe9a4a46910617eb12fc85c4df4d238a11a397f 100755
GIT binary patch
delta 101234
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%0AZh}w(!i6N?Y_$?)PpKShd~mVU<E<aUm$jDDmMA
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
KPY1SA(EkI{&%Q?h

delta 64558
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
WSqRAgtOoP_@PD(5iAn#1|NjHRU0+`S

diff --git a/youtube-dl.1 b/youtube-dl.1
index 28e8311..8090af4 100644
--- a/youtube-dl.1
+++ b/youtube-dl.1
@@ -1,7 +1,7 @@
 .TH YOUTUBE\-DL 1 "" 
 .SH NAME
 .PP
-youtube\-dl
+youtube\-dl \- download videos from youtube.com or other video platforms
 .SH SYNOPSIS
 .PP
 \f[B]youtube\-dl\f[] OPTIONS (#options) URL [URL...]
@@ -141,7 +141,7 @@ redistribute it or use it however you like.
 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ video\ (currently\ youtube\ only)
 \-\-list\-subs\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lists\ all\ available\ subtitles\ for\ the\ video
 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (currently\ youtube\ only)
-\-\-sub\-format\ LANG\ \ \ \ \ \ \ \ \ \ subtitle\ format\ [srt/sbv]\ (default=srt)
+\-\-sub\-format\ FORMAT\ \ \ \ \ \ \ \ subtitle\ format\ [srt/sbv]\ (default=srt)
 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (currently\ youtube\ only)
 \-\-sub\-lang\ LANG\ \ \ \ \ \ \ \ \ \ \ \ language\ of\ the\ subtitles\ to\ download\ (optional)
 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ use\ IETF\ language\ tags\ like\ \[aq]en\[aq]
diff --git a/youtube_dl/FileDownloader.py b/youtube_dl/FileDownloader.py
index f4ce480..f21c66c 100644
--- a/youtube_dl/FileDownloader.py
+++ b/youtube_dl/FileDownloader.py
@@ -1,8 +1,3 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from __future__ import absolute_import
-
 import math
 import io
 import os
@@ -18,7 +13,7 @@ if os.name == 'nt':
     import ctypes
 
 from .utils import *
-from .InfoExtractors import get_info_extractor
+from .extractor import get_info_extractor
 
 
 class FileDownloader(object):
diff --git a/youtube_dl/InfoExtractors.py b/youtube_dl/InfoExtractors.py
index 17e0f83..672ef9e 100755
--- a/youtube_dl/InfoExtractors.py
+++ b/youtube_dl/InfoExtractors.py
@@ -1,4615 +1,4 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
+# Legacy file for backwards compatibility, use youtube_dl.extractor instead!
 
-from __future__ import absolute_import
-
-import base64
-import datetime
-import itertools
-import netrc
-import os
-import re
-import socket
-import time
-import email.utils
-import xml.etree.ElementTree
-import random
-import math
-import operator
-import hashlib
-import binascii
-import urllib
-
-from .utils import *
-
-
-class InfoExtractor(object):
-    """Information Extractor class.
-
-    Information extractors are the classes that, given a URL, extract
-    information about the video (or videos) the URL refers to. This
-    information includes the real video URL, the video title, author and
-    others. The information is stored in a dictionary which is then
-    passed to the FileDownloader. The FileDownloader processes this
-    information possibly downloading the video to the file system, among
-    other possible outcomes.
-
-    The dictionaries must include the following fields:
-
-    id:             Video identifier.
-    url:            Final video URL.
-    title:          Video title, unescaped.
-    ext:            Video filename extension.
-
-    The following fields are optional:
-
-    format:         The video format, defaults to ext (used for --get-format)
-    thumbnail:      Full URL to a video thumbnail image.
-    description:    One-line video description.
-    uploader:       Full name of the video uploader.
-    upload_date:    Video upload date (YYYYMMDD).
-    uploader_id:    Nickname or id of the video uploader.
-    location:       Physical location of the video.
-    player_url:     SWF Player URL (used for rtmpdump).
-    subtitles:      The subtitle file contents.
-    urlhandle:      [internal] The urlHandle to be used to download the file,
-                    like returned by urllib.request.urlopen
-
-    The fields should all be Unicode strings.
-
-    Subclasses of this one should re-define the _real_initialize() and
-    _real_extract() methods and define a _VALID_URL regexp.
-    Probably, they should also be added to the list of extractors.
-
-    _real_extract() must return a *list* of information dictionaries as
-    described above.
-
-    Finally, the _WORKING attribute should be set to False for broken IEs
-    in order to warn the users and skip the tests.
-    """
-
-    _ready = False
-    _downloader = None
-    _WORKING = True
-
-    def __init__(self, downloader=None):
-        """Constructor. Receives an optional downloader."""
-        self._ready = False
-        self.set_downloader(downloader)
-
-    @classmethod
-    def suitable(cls, url):
-        """Receives a URL and returns True if suitable for this IE."""
-        return re.match(cls._VALID_URL, url) is not None
-
-    @classmethod
-    def working(cls):
-        """Getter method for _WORKING."""
-        return cls._WORKING
-
-    def initialize(self):
-        """Initializes an instance (authentication, etc)."""
-        if not self._ready:
-            self._real_initialize()
-            self._ready = True
-
-    def extract(self, url):
-        """Extracts URL information and returns it in list of dicts."""
-        self.initialize()
-        return self._real_extract(url)
-
-    def set_downloader(self, downloader):
-        """Sets the downloader for this IE."""
-        self._downloader = downloader
-
-    def _real_initialize(self):
-        """Real initialization process. Redefine in subclasses."""
-        pass
-
-    def _real_extract(self, url):
-        """Real extraction process. Redefine in subclasses."""
-        pass
-
-    @property
-    def IE_NAME(self):
-        return type(self).__name__[:-2]
-
-    def _request_webpage(self, url_or_request, video_id, note=None, errnote=None):
-        """ Returns the response handle """
-        if note is None:
-            self.report_download_webpage(video_id)
-        elif note is not False:
-            self.to_screen(u'%s: %s' % (video_id, note))
-        try:
-            return compat_urllib_request.urlopen(url_or_request)
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            if errnote is None:
-                errnote = u'Unable to download webpage'
-            raise ExtractorError(u'%s: %s' % (errnote, compat_str(err)), sys.exc_info()[2])
-
-    def _download_webpage_handle(self, url_or_request, video_id, note=None, errnote=None):
-        """ Returns a tuple (page content as string, URL handle) """
-        urlh = self._request_webpage(url_or_request, video_id, note, errnote)
-        content_type = urlh.headers.get('Content-Type', '')
-        m = re.match(r'[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+\s*;\s*charset=(.+)', content_type)
-        if m:
-            encoding = m.group(1)
-        else:
-            encoding = 'utf-8'
-        webpage_bytes = urlh.read()
-        if self._downloader.params.get('dump_intermediate_pages', False):
-            try:
-                url = url_or_request.get_full_url()
-            except AttributeError:
-                url = url_or_request
-            self.to_screen(u'Dumping request to ' + url)
-            dump = base64.b64encode(webpage_bytes).decode('ascii')
-            self._downloader.to_screen(dump)
-        content = webpage_bytes.decode(encoding, 'replace')
-        return (content, urlh)
-
-    def _download_webpage(self, url_or_request, video_id, note=None, errnote=None):
-        """ Returns the data of the page as a string """
-        return self._download_webpage_handle(url_or_request, video_id, note, errnote)[0]
-
-    def to_screen(self, msg):
-        """Print msg to screen, prefixing it with '[ie_name]'"""
-        self._downloader.to_screen(u'[%s] %s' % (self.IE_NAME, msg))
-
-    def report_extraction(self, id_or_name):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % id_or_name)
-
-    def report_download_webpage(self, video_id):
-        """Report webpage download."""
-        self.to_screen(u'%s: Downloading webpage' % video_id)
-
-    def report_age_confirmation(self):
-        """Report attempt to confirm age."""
-        self.to_screen(u'Confirming age')
-
-    #Methods for following #608
-    #They set the correct value of the '_type' key
-    def video_result(self, video_info):
-        """Returns a video"""
-        video_info['_type'] = 'video'
-        return video_info
-    def url_result(self, url, ie=None):
-        """Returns a url that points to a page that should be processed"""
-        #TODO: ie should be the class used for getting the info
-        video_info = {'_type': 'url',
-                      'url': url,
-                      'ie_key': ie}
-        return video_info
-    def playlist_result(self, entries, playlist_id=None, playlist_title=None):
-        """Returns a playlist"""
-        video_info = {'_type': 'playlist',
-                      'entries': entries}
-        if playlist_id:
-            video_info['id'] = playlist_id
-        if playlist_title:
-            video_info['title'] = playlist_title
-        return video_info
-
-    def _search_regex(self, pattern, string, name, default=None, fatal=True, flags=0):
-        """
-        Perform a regex search on the given string, using a single or a list of
-        patterns returning the first matching group.
-        In case of failure return a default value or raise a WARNING or a
-        ExtractorError, depending on fatal, specifying the field name.
-        """
-        if isinstance(pattern, (str, compat_str, compiled_regex_type)):
-            mobj = re.search(pattern, string, flags)
-        else:
-            for p in pattern:
-                mobj = re.search(p, string, flags)
-                if mobj: break
-
-        if sys.stderr.isatty() and os.name != 'nt':
-            _name = u'\033[0;34m%s\033[0m' % name
-        else:
-            _name = name
-
-        if mobj:
-            # return the first matching group
-            return next(g for g in mobj.groups() if g is not None)
-        elif default is not None:
-            return default
-        elif fatal:
-            raise ExtractorError(u'Unable to extract %s' % _name)
-        else:
-            self._downloader.report_warning(u'unable to extract %s; '
-                u'please report this issue on GitHub.' % _name)
-            return None
-
-    def _html_search_regex(self, pattern, string, name, default=None, fatal=True, flags=0):
-        """
-        Like _search_regex, but strips HTML tags and unescapes entities.
-        """
-        res = self._search_regex(pattern, string, name, default, fatal, flags)
-        if res:
-            return clean_html(res).strip()
-        else:
-            return res
-
-class SearchInfoExtractor(InfoExtractor):
-    """
-    Base class for paged search queries extractors.
-    They accept urls in the format _SEARCH_KEY(|all|[0-9]):{query}
-    Instances should define _SEARCH_KEY and _MAX_RESULTS.
-    """
-
-    @classmethod
-    def _make_valid_url(cls):
-        return r'%s(?P<prefix>|[1-9][0-9]*|all):(?P<query>[\s\S]+)' % cls._SEARCH_KEY
-
-    @classmethod
-    def suitable(cls, url):
-        return re.match(cls._make_valid_url(), url) is not None
-
-    def _real_extract(self, query):
-        mobj = re.match(self._make_valid_url(), query)
-        if mobj is None:
-            raise ExtractorError(u'Invalid search query "%s"' % query)
-
-        prefix = mobj.group('prefix')
-        query = mobj.group('query')
-        if prefix == '':
-            return self._get_n_results(query, 1)
-        elif prefix == 'all':
-            return self._get_n_results(query, self._MAX_RESULTS)
-        else:
-            n = int(prefix)
-            if n <= 0:
-                raise ExtractorError(u'invalid download number %s for query "%s"' % (n, query))
-            elif n > self._MAX_RESULTS:
-                self._downloader.report_warning(u'%s returns max %i results (you requested %i)' % (self._SEARCH_KEY, self._MAX_RESULTS, n))
-                n = self._MAX_RESULTS
-            return self._get_n_results(query, n)
-
-    def _get_n_results(self, query, n):
-        """Get a specified number of results for a query"""
-        raise NotImplementedError("This method must be implemented by sublclasses")
-
-
-class YoutubeIE(InfoExtractor):
-    """Information extractor for youtube.com."""
-
-    _VALID_URL = r"""^
-                     (
-                         (?:https?://)?                                       # http(s):// (optional)
-                         (?:youtu\.be/|(?:\w+\.)?youtube(?:-nocookie)?\.com/|
-                            tube\.majestyc\.net/)                             # the various hostnames, with wildcard subdomains
-                         (?:.*?\#/)?                                          # handle anchor (#/) redirect urls
-                         (?:                                                  # the various things that can precede the ID:
-                             (?:(?:v|embed|e)/)                               # v/ or embed/ or e/
-                             |(?:                                             # or the v= param in all its forms
-                                 (?:watch(?:_popup)?(?:\.php)?)?              # preceding watch(_popup|.php) or nothing (like /?v=xxxx)
-                                 (?:\?|\#!?)                                  # the params delimiter ? or # or #!
-                                 (?:.*?&)?                                    # any other preceding param (like /?s=tuff&v=xxxx)
-                                 v=
-                             )
-                         )?                                                   # optional -> youtube.com/xxxx is OK
-                     )?                                                       # all until now is optional -> you can pass the naked ID
-                     ([0-9A-Za-z_-]+)                                         # here is it! the YouTube video ID
-                     (?(1).+)?                                                # if we found the ID, everything can follow
-                     $"""
-    _LANG_URL = r'https://www.youtube.com/?hl=en&persist_hl=1&gl=US&persist_gl=1&opt_out_ackd=1'
-    _LOGIN_URL = 'https://accounts.google.com/ServiceLogin'
-    _AGE_URL = 'http://www.youtube.com/verify_age?next_url=/&gl=US&hl=en'
-    _NEXT_URL_RE = r'[\?&]next_url=([^&]+)'
-    _NETRC_MACHINE = 'youtube'
-    # Listed in order of quality
-    _available_formats = ['38', '37', '46', '22', '45', '35', '44', '34', '18', '43', '6', '5', '17', '13']
-    _available_formats_prefer_free = ['38', '46', '37', '45', '22', '44', '35', '43', '34', '18', '6', '5', '17', '13']
-    _video_extensions = {
-        '13': '3gp',
-        '17': 'mp4',
-        '18': 'mp4',
-        '22': 'mp4',
-        '37': 'mp4',
-        '38': 'video', # You actually don't know if this will be MOV, AVI or whatever
-        '43': 'webm',
-        '44': 'webm',
-        '45': 'webm',
-        '46': 'webm',
-    }
-    _video_dimensions = {
-        '5': '240x400',
-        '6': '???',
-        '13': '???',
-        '17': '144x176',
-        '18': '360x640',
-        '22': '720x1280',
-        '34': '360x640',
-        '35': '480x854',
-        '37': '1080x1920',
-        '38': '3072x4096',
-        '43': '360x640',
-        '44': '480x854',
-        '45': '720x1280',
-        '46': '1080x1920',
-    }
-    IE_NAME = u'youtube'
-
-    @classmethod
-    def suitable(cls, url):
-        """Receives a URL and returns True if suitable for this IE."""
-        if YoutubePlaylistIE.suitable(url): return False
-        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
-
-    def report_lang(self):
-        """Report attempt to set language."""
-        self.to_screen(u'Setting language')
-
-    def report_login(self):
-        """Report attempt to log in."""
-        self.to_screen(u'Logging in')
-
-    def report_video_webpage_download(self, video_id):
-        """Report attempt to download video webpage."""
-        self.to_screen(u'%s: Downloading video webpage' % video_id)
-
-    def report_video_info_webpage_download(self, video_id):
-        """Report attempt to download video info webpage."""
-        self.to_screen(u'%s: Downloading video info webpage' % video_id)
-
-    def report_video_subtitles_download(self, video_id):
-        """Report attempt to download video info webpage."""
-        self.to_screen(u'%s: Checking available subtitles' % video_id)
-
-    def report_video_subtitles_request(self, video_id, sub_lang, format):
-        """Report attempt to download video info webpage."""
-        self.to_screen(u'%s: Downloading video subtitles for %s.%s' % (video_id, sub_lang, format))
-
-    def report_video_subtitles_available(self, video_id, sub_lang_list):
-        """Report available subtitles."""
-        sub_lang = ",".join(list(sub_lang_list.keys()))
-        self.to_screen(u'%s: Available subtitles for video: %s' % (video_id, sub_lang))
-
-    def report_information_extraction(self, video_id):
-        """Report attempt to extract video information."""
-        self.to_screen(u'%s: Extracting video information' % video_id)
-
-    def report_unavailable_format(self, video_id, format):
-        """Report extracted video URL."""
-        self.to_screen(u'%s: Format %s not available' % (video_id, format))
-
-    def report_rtmp_download(self):
-        """Indicate the download will use the RTMP protocol."""
-        self.to_screen(u'RTMP download detected')
-
-    def _get_available_subtitles(self, video_id):
-        self.report_video_subtitles_download(video_id)
-        request = compat_urllib_request.Request('http://video.google.com/timedtext?hl=en&type=list&v=%s' % video_id)
-        try:
-            sub_list = compat_urllib_request.urlopen(request).read().decode('utf-8')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            return (u'unable to download video subtitles: %s' % compat_str(err), None)
-        sub_lang_list = re.findall(r'name="([^"]*)"[^>]+lang_code="([\w\-]+)"', sub_list)
-        sub_lang_list = dict((l[1], l[0]) for l in sub_lang_list)
-        if not sub_lang_list:
-            return (u'video doesn\'t have subtitles', None)
-        return sub_lang_list
-
-    def _list_available_subtitles(self, video_id):
-        sub_lang_list = self._get_available_subtitles(video_id)
-        self.report_video_subtitles_available(video_id, sub_lang_list)
-
-    def _request_subtitle(self, sub_lang, sub_name, video_id, format):
-        """
-        Return tuple:
-        (error_message, sub_lang, sub)
-        """
-        self.report_video_subtitles_request(video_id, sub_lang, format)
-        params = compat_urllib_parse.urlencode({
-            'lang': sub_lang,
-            'name': sub_name,
-            'v': video_id,
-            'fmt': format,
-        })
-        url = 'http://www.youtube.com/api/timedtext?' + params
-        try:
-            sub = compat_urllib_request.urlopen(url).read().decode('utf-8')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            return (u'unable to download video subtitles: %s' % compat_str(err), None, None)
-        if not sub:
-            return (u'Did not fetch video subtitles', None, None)
-        return (None, sub_lang, sub)
-
-    def _request_automatic_caption(self, video_id, webpage):
-        """We need the webpage for getting the captions url, pass it as an
-           argument to speed up the process."""
-        sub_lang = self._downloader.params.get('subtitleslang')
-        sub_format = self._downloader.params.get('subtitlesformat')
-        self.to_screen(u'%s: Looking for automatic captions' % video_id)
-        mobj = re.search(r';ytplayer.config = ({.*?});', webpage)
-        err_msg = u'Couldn\'t find automatic captions for "%s"' % sub_lang
-        if mobj is None:
-            return [(err_msg, None, None)]
-        player_config = json.loads(mobj.group(1))
-        try:
-            args = player_config[u'args']
-            caption_url = args[u'ttsurl']
-            timestamp = args[u'timestamp']
-            params = compat_urllib_parse.urlencode({
-                'lang': 'en',
-                'tlang': sub_lang,
-                'fmt': sub_format,
-                'ts': timestamp,
-                'kind': 'asr',
-            })
-            subtitles_url = caption_url + '&' + params
-            sub = self._download_webpage(subtitles_url, video_id, u'Downloading automatic captions')
-            return [(None, sub_lang, sub)]
-        except KeyError:
-            return [(err_msg, None, None)]
-
-    def _extract_subtitle(self, video_id):
-        """
-        Return a list with a tuple:
-        [(error_message, sub_lang, sub)]
-        """
-        sub_lang_list = self._get_available_subtitles(video_id)
-        sub_format = self._downloader.params.get('subtitlesformat')
-        if  isinstance(sub_lang_list,tuple): #There was some error, it didn't get the available subtitles
-            return [(sub_lang_list[0], None, None)]
-        if self._downloader.params.get('subtitleslang', False):
-            sub_lang = self._downloader.params.get('subtitleslang')
-        elif 'en' in sub_lang_list:
-            sub_lang = 'en'
-        else:
-            sub_lang = list(sub_lang_list.keys())[0]
-        if not sub_lang in sub_lang_list:
-            return [(u'no closed captions found in the specified language "%s"' % sub_lang, None, None)]
-
-        subtitle = self._request_subtitle(sub_lang, sub_lang_list[sub_lang].encode('utf-8'), video_id, sub_format)
-        return [subtitle]
-
-    def _extract_all_subtitles(self, video_id):
-        sub_lang_list = self._get_available_subtitles(video_id)
-        sub_format = self._downloader.params.get('subtitlesformat')
-        if  isinstance(sub_lang_list,tuple): #There was some error, it didn't get the available subtitles
-            return [(sub_lang_list[0], None, None)]
-        subtitles = []
-        for sub_lang in sub_lang_list:
-            subtitle = self._request_subtitle(sub_lang, sub_lang_list[sub_lang].encode('utf-8'), video_id, sub_format)
-            subtitles.append(subtitle)
-        return subtitles
-
-    def _print_formats(self, formats):
-        print('Available formats:')
-        for x in formats:
-            print('%s\t:\t%s\t[%s]' %(x, self._video_extensions.get(x, 'flv'), self._video_dimensions.get(x, '???')))
-
-    def _real_initialize(self):
-        if self._downloader is None:
-            return
-
-        username = None
-        password = None
-        downloader_params = self._downloader.params
-
-        # Attempt to use provided username and password or .netrc data
-        if downloader_params.get('username', None) is not None:
-            username = downloader_params['username']
-            password = downloader_params['password']
-        elif downloader_params.get('usenetrc', False):
-            try:
-                info = netrc.netrc().authenticators(self._NETRC_MACHINE)
-                if info is not None:
-                    username = info[0]
-                    password = info[2]
-                else:
-                    raise netrc.NetrcParseError('No authenticators for %s' % self._NETRC_MACHINE)
-            except (IOError, netrc.NetrcParseError) as err:
-                self._downloader.report_warning(u'parsing .netrc: %s' % compat_str(err))
-                return
-
-        # Set language
-        request = compat_urllib_request.Request(self._LANG_URL)
-        try:
-            self.report_lang()
-            compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.report_warning(u'unable to set language: %s' % compat_str(err))
-            return
-
-        # No authentication to be performed
-        if username is None:
-            return
-
-        request = compat_urllib_request.Request(self._LOGIN_URL)
-        try:
-            login_page = compat_urllib_request.urlopen(request).read().decode('utf-8')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.report_warning(u'unable to fetch login page: %s' % compat_str(err))
-            return
-
-        galx = None
-        dsh = None
-        match = re.search(re.compile(r'<input.+?name="GALX".+?value="(.+?)"', re.DOTALL), login_page)
-        if match:
-          galx = match.group(1)
-
-        match = re.search(re.compile(r'<input.+?name="dsh".+?value="(.+?)"', re.DOTALL), login_page)
-        if match:
-          dsh = match.group(1)
-
-        # Log in
-        login_form_strs = {
-                u'continue': u'https://www.youtube.com/signin?action_handle_signin=true&feature=sign_in_button&hl=en_US&nomobiletemp=1',
-                u'Email': username,
-                u'GALX': galx,
-                u'Passwd': password,
-                u'PersistentCookie': u'yes',
-                u'_utf8': u'霱',
-                u'bgresponse': u'js_disabled',
-                u'checkConnection': u'',
-                u'checkedDomains': u'youtube',
-                u'dnConn': u'',
-                u'dsh': dsh,
-                u'pstMsg': u'0',
-                u'rmShown': u'1',
-                u'secTok': u'',
-                u'signIn': u'Sign in',
-                u'timeStmp': u'',
-                u'service': u'youtube',
-                u'uilel': u'3',
-                u'hl': u'en_US',
-        }
-        # Convert to UTF-8 *before* urlencode because Python 2.x's urlencode
-        # chokes on unicode
-        login_form = dict((k.encode('utf-8'), v.encode('utf-8')) for k,v in login_form_strs.items())
-        login_data = compat_urllib_parse.urlencode(login_form).encode('ascii')
-        request = compat_urllib_request.Request(self._LOGIN_URL, login_data)
-        try:
-            self.report_login()
-            login_results = compat_urllib_request.urlopen(request).read().decode('utf-8')
-            if re.search(r'(?i)<form[^>]* id="gaia_loginform"', login_results) is not None:
-                self._downloader.report_warning(u'unable to log in: bad username or password')
-                return
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.report_warning(u'unable to log in: %s' % compat_str(err))
-            return
-
-        # Confirm age
-        age_form = {
-                'next_url':     '/',
-                'action_confirm':   'Confirm',
-                }
-        request = compat_urllib_request.Request(self._AGE_URL, compat_urllib_parse.urlencode(age_form))
-        try:
-            self.report_age_confirmation()
-            age_results = compat_urllib_request.urlopen(request).read().decode('utf-8')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to confirm age: %s' % compat_str(err))
-
-    def _extract_id(self, url):
-        mobj = re.match(self._VALID_URL, url, re.VERBOSE)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group(2)
-        return video_id
-
-    def _real_extract(self, url):
-        # Extract original video URL from URL with redirection, like age verification, using next_url parameter
-        mobj = re.search(self._NEXT_URL_RE, url)
-        if mobj:
-            url = 'https://www.youtube.com/' + compat_urllib_parse.unquote(mobj.group(1)).lstrip('/')
-        video_id = self._extract_id(url)
-
-        # Get video webpage
-        self.report_video_webpage_download(video_id)
-        url = 'https://www.youtube.com/watch?v=%s&gl=US&hl=en&has_verified=1' % video_id
-        request = compat_urllib_request.Request(url)
-        try:
-            video_webpage_bytes = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to download video webpage: %s' % compat_str(err))
-
-        video_webpage = video_webpage_bytes.decode('utf-8', 'ignore')
-
-        # Attempt to extract SWF player URL
-        mobj = re.search(r'swfConfig.*?"(http:\\/\\/.*?watch.*?-.*?\.swf)"', video_webpage)
-        if mobj is not None:
-            player_url = re.sub(r'\\(.)', r'\1', mobj.group(1))
-        else:
-            player_url = None
-
-        # Get video info
-        self.report_video_info_webpage_download(video_id)
-        for el_type in ['&el=embedded', '&el=detailpage', '&el=vevo', '']:
-            video_info_url = ('https://www.youtube.com/get_video_info?&video_id=%s%s&ps=default&eurl=&gl=US&hl=en'
-                    % (video_id, el_type))
-            video_info_webpage = self._download_webpage(video_info_url, video_id,
-                                    note=False,
-                                    errnote='unable to download video info webpage')
-            video_info = compat_parse_qs(video_info_webpage)
-            if 'token' in video_info:
-                break
-        if 'token' not in video_info:
-            if 'reason' in video_info:
-                raise ExtractorError(u'YouTube said: %s' % video_info['reason'][0])
-            else:
-                raise ExtractorError(u'"token" parameter not in video info for unknown reason')
-
-        # Check for "rental" videos
-        if 'ypc_video_rental_bar_text' in video_info and 'author' not in video_info:
-            raise ExtractorError(u'"rental" videos not supported')
-
-        # Start extracting information
-        self.report_information_extraction(video_id)
-
-        # uploader
-        if 'author' not in video_info:
-            raise ExtractorError(u'Unable to extract uploader name')
-        video_uploader = compat_urllib_parse.unquote_plus(video_info['author'][0])
-
-        # uploader_id
-        video_uploader_id = None
-        mobj = re.search(r'<link itemprop="url" href="http://www.youtube.com/(?:user|channel)/([^"]+)">', video_webpage)
-        if mobj is not None:
-            video_uploader_id = mobj.group(1)
-        else:
-            self._downloader.report_warning(u'unable to extract uploader nickname')
-
-        # title
-        if 'title' not in video_info:
-            raise ExtractorError(u'Unable to extract video title')
-        video_title = compat_urllib_parse.unquote_plus(video_info['title'][0])
-
-        # thumbnail image
-        if 'thumbnail_url' not in video_info:
-            self._downloader.report_warning(u'unable to extract video thumbnail')
-            video_thumbnail = ''
-        else:   # don't panic if we can't find it
-            video_thumbnail = compat_urllib_parse.unquote_plus(video_info['thumbnail_url'][0])
-
-        # upload date
-        upload_date = None
-        mobj = re.search(r'id="eow-date.*?>(.*?)</span>', video_webpage, re.DOTALL)
-        if mobj is not None:
-            upload_date = ' '.join(re.sub(r'[/,-]', r' ', mobj.group(1)).split())
-            upload_date = unified_strdate(upload_date)
-
-        # description
-        video_description = get_element_by_id("eow-description", video_webpage)
-        if video_description:
-            video_description = clean_html(video_description)
-        else:
-            fd_mobj = re.search(r'<meta name="description" content="([^"]+)"', video_webpage)
-            if fd_mobj:
-                video_description = unescapeHTML(fd_mobj.group(1))
-            else:
-                video_description = u''
-
-        # subtitles
-        video_subtitles = None
-
-        if self._downloader.params.get('writesubtitles', False):
-            video_subtitles = self._extract_subtitle(video_id)
-            if video_subtitles:
-                (sub_error, sub_lang, sub) = video_subtitles[0]
-                if sub_error:
-                    # We try with the automatic captions
-                    video_subtitles = self._request_automatic_caption(video_id, video_webpage)
-                    (sub_error_auto, sub_lang, sub) = video_subtitles[0]
-                    if sub is not None:
-                        pass
-                    else:
-                        # We report the original error
-                        self._downloader.report_error(sub_error)
-
-        if self._downloader.params.get('allsubtitles', False):
-            video_subtitles = self._extract_all_subtitles(video_id)
-            for video_subtitle in video_subtitles:
-                (sub_error, sub_lang, sub) = video_subtitle
-                if sub_error:
-                    self._downloader.report_error(sub_error)
-
-        if self._downloader.params.get('listsubtitles', False):
-            sub_lang_list = self._list_available_subtitles(video_id)
-            return
-
-        if 'length_seconds' not in video_info:
-            self._downloader.report_warning(u'unable to extract video duration')
-            video_duration = ''
-        else:
-            video_duration = compat_urllib_parse.unquote_plus(video_info['length_seconds'][0])
-
-        # token
-        video_token = compat_urllib_parse.unquote_plus(video_info['token'][0])
-
-        # Decide which formats to download
-        req_format = self._downloader.params.get('format', None)
-
-        if 'conn' in video_info and video_info['conn'][0].startswith('rtmp'):
-            self.report_rtmp_download()
-            video_url_list = [(None, video_info['conn'][0])]
-        elif 'url_encoded_fmt_stream_map' in video_info and len(video_info['url_encoded_fmt_stream_map']) >= 1:
-            url_map = {}
-            for url_data_str in video_info['url_encoded_fmt_stream_map'][0].split(','):
-                url_data = compat_parse_qs(url_data_str)
-                if 'itag' in url_data and 'url' in url_data:
-                    url = url_data['url'][0] + '&signature=' + url_data['sig'][0]
-                    if not 'ratebypass' in url: url += '&ratebypass=yes'
-                    url_map[url_data['itag'][0]] = url
-
-            format_limit = self._downloader.params.get('format_limit', None)
-            available_formats = self._available_formats_prefer_free if self._downloader.params.get('prefer_free_formats', False) else self._available_formats
-            if format_limit is not None and format_limit in available_formats:
-                format_list = available_formats[available_formats.index(format_limit):]
-            else:
-                format_list = available_formats
-            existing_formats = [x for x in format_list if x in url_map]
-            if len(existing_formats) == 0:
-                raise ExtractorError(u'no known formats available for video')
-            if self._downloader.params.get('listformats', None):
-                self._print_formats(existing_formats)
-                return
-            if req_format is None or req_format == 'best':
-                video_url_list = [(existing_formats[0], url_map[existing_formats[0]])] # Best quality
-            elif req_format == 'worst':
-                video_url_list = [(existing_formats[len(existing_formats)-1], url_map[existing_formats[len(existing_formats)-1]])] # worst quality
-            elif req_format in ('-1', 'all'):
-                video_url_list = [(f, url_map[f]) for f in existing_formats] # All formats
-            else:
-                # Specific formats. We pick the first in a slash-delimeted sequence.
-                # For example, if '1/2/3/4' is requested and '2' and '4' are available, we pick '2'.
-                req_formats = req_format.split('/')
-                video_url_list = None
-                for rf in req_formats:
-                    if rf in url_map:
-                        video_url_list = [(rf, url_map[rf])]
-                        break
-                if video_url_list is None:
-                    raise ExtractorError(u'requested format not available')
-        else:
-            raise ExtractorError(u'no conn or url_encoded_fmt_stream_map information found in video info')
-
-        results = []
-        for format_param, video_real_url in video_url_list:
-            # Extension
-            video_extension = self._video_extensions.get(format_param, 'flv')
-
-            video_format = '{0} - {1}'.format(format_param if format_param else video_extension,
-                                              self._video_dimensions.get(format_param, '???'))
-
-            results.append({
-                'id':       video_id,
-                'url':      video_real_url,
-                'uploader': video_uploader,
-                'uploader_id': video_uploader_id,
-                'upload_date':  upload_date,
-                'title':    video_title,
-                'ext':      video_extension,
-                'format':   video_format,
-                'thumbnail':    video_thumbnail,
-                'description':  video_description,
-                'player_url':   player_url,
-                'subtitles':    video_subtitles,
-                'duration':     video_duration
-            })
-        return results
-
-
-class MetacafeIE(InfoExtractor):
-    """Information Extractor for metacafe.com."""
-
-    _VALID_URL = r'(?:http://)?(?:www\.)?metacafe\.com/watch/([^/]+)/([^/]+)/.*'
-    _DISCLAIMER = 'http://www.metacafe.com/family_filter/'
-    _FILTER_POST = 'http://www.metacafe.com/f/index.php?inputType=filter&controllerGroup=user'
-    IE_NAME = u'metacafe'
-
-    def report_disclaimer(self):
-        """Report disclaimer retrieval."""
-        self.to_screen(u'Retrieving disclaimer')
-
-    def _real_initialize(self):
-        # Retrieve disclaimer
-        request = compat_urllib_request.Request(self._DISCLAIMER)
-        try:
-            self.report_disclaimer()
-            disclaimer = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to retrieve disclaimer: %s' % compat_str(err))
-
-        # Confirm age
-        disclaimer_form = {
-            'filters': '0',
-            'submit': "Continue - I'm over 18",
-            }
-        request = compat_urllib_request.Request(self._FILTER_POST, compat_urllib_parse.urlencode(disclaimer_form))
-        try:
-            self.report_age_confirmation()
-            disclaimer = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to confirm age: %s' % compat_str(err))
-
-    def _real_extract(self, url):
-        # Extract id and simplified title from URL
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group(1)
-
-        # Check if video comes from YouTube
-        mobj2 = re.match(r'^yt-(.*)$', video_id)
-        if mobj2 is not None:
-            return [self.url_result('http://www.youtube.com/watch?v=%s' % mobj2.group(1), 'Youtube')]
-
-        # Retrieve video webpage to extract further information
-        webpage = self._download_webpage('http://www.metacafe.com/watch/%s/' % video_id, video_id)
-
-        # Extract URL, uploader and title from webpage
-        self.report_extraction(video_id)
-        mobj = re.search(r'(?m)&mediaURL=([^&]+)', webpage)
-        if mobj is not None:
-            mediaURL = compat_urllib_parse.unquote(mobj.group(1))
-            video_extension = mediaURL[-3:]
-
-            # Extract gdaKey if available
-            mobj = re.search(r'(?m)&gdaKey=(.*?)&', webpage)
-            if mobj is None:
-                video_url = mediaURL
-            else:
-                gdaKey = mobj.group(1)
-                video_url = '%s?__gda__=%s' % (mediaURL, gdaKey)
-        else:
-            mobj = re.search(r' name="flashvars" value="(.*?)"', webpage)
-            if mobj is None:
-                raise ExtractorError(u'Unable to extract media URL')
-            vardict = compat_parse_qs(mobj.group(1))
-            if 'mediaData' not in vardict:
-                raise ExtractorError(u'Unable to extract media URL')
-            mobj = re.search(r'"mediaURL":"(?P<mediaURL>http.*?)",(.*?)"key":"(?P<key>.*?)"', vardict['mediaData'][0])
-            if mobj is None:
-                raise ExtractorError(u'Unable to extract media URL')
-            mediaURL = mobj.group('mediaURL').replace('\\/', '/')
-            video_extension = mediaURL[-3:]
-            video_url = '%s?__gda__=%s' % (mediaURL, mobj.group('key'))
-
-        mobj = re.search(r'(?im)<title>(.*) - Video</title>', webpage)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract title')
-        video_title = mobj.group(1).decode('utf-8')
-
-        mobj = re.search(r'submitter=(.*?);', webpage)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract uploader nickname')
-        video_uploader = mobj.group(1)
-
-        return [{
-            'id':       video_id.decode('utf-8'),
-            'url':      video_url.decode('utf-8'),
-            'uploader': video_uploader.decode('utf-8'),
-            'upload_date':  None,
-            'title':    video_title,
-            'ext':      video_extension.decode('utf-8'),
-        }]
-
-class DailymotionIE(InfoExtractor):
-    """Information Extractor for Dailymotion"""
-
-    _VALID_URL = r'(?i)(?:https?://)?(?:www\.)?dailymotion\.[a-z]{2,3}/video/([^/]+)'
-    IE_NAME = u'dailymotion'
-
-    def _real_extract(self, url):
-        # Extract id and simplified title from URL
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group(1).split('_')[0].split('?')[0]
-
-        video_extension = 'mp4'
-
-        # Retrieve video webpage to extract further information
-        request = compat_urllib_request.Request(url)
-        request.add_header('Cookie', 'family_filter=off')
-        webpage = self._download_webpage(request, video_id)
-
-        # Extract URL, uploader and title from webpage
-        self.report_extraction(video_id)
-        mobj = re.search(r'\s*var flashvars = (.*)', webpage)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract media URL')
-        flashvars = compat_urllib_parse.unquote(mobj.group(1))
-
-        for key in ['hd1080URL', 'hd720URL', 'hqURL', 'sdURL', 'ldURL', 'video_url']:
-            if key in flashvars:
-                max_quality = key
-                self.to_screen(u'Using %s' % key)
-                break
-        else:
-            raise ExtractorError(u'Unable to extract video URL')
-
-        mobj = re.search(r'"' + max_quality + r'":"(.+?)"', flashvars)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract video URL')
-
-        video_url = compat_urllib_parse.unquote(mobj.group(1)).replace('\\/', '/')
-
-        # TODO: support choosing qualities
-
-        mobj = re.search(r'<meta property="og:title" content="(?P<title>[^"]*)" />', webpage)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract title')
-        video_title = unescapeHTML(mobj.group('title'))
-
-        video_uploader = None
-        video_uploader = self._search_regex([r'(?im)<span class="owner[^\"]+?">[^<]+?<a [^>]+?>([^<]+?)</a>',
-                                             # Looking for official user
-                                             r'<(?:span|a) .*?rel="author".*?>([^<]+?)</'],
-                                            webpage, 'video uploader')
-
-        video_upload_date = None
-        mobj = re.search(r'<div class="[^"]*uploaded_cont[^"]*" title="[^"]*">([0-9]{2})-([0-9]{2})-([0-9]{4})</div>', webpage)
-        if mobj is not None:
-            video_upload_date = mobj.group(3) + mobj.group(2) + mobj.group(1)
-
-        return [{
-            'id':       video_id,
-            'url':      video_url,
-            'uploader': video_uploader,
-            'upload_date':  video_upload_date,
-            'title':    video_title,
-            'ext':      video_extension,
-        }]
-
-
-class PhotobucketIE(InfoExtractor):
-    """Information extractor for photobucket.com."""
-
-    # TODO: the original _VALID_URL was:
-    # r'(?:http://)?(?:[a-z0-9]+\.)?photobucket\.com/.*[\?\&]current=(.*\.flv)'
-    # Check if it's necessary to keep the old extracion process
-    _VALID_URL = r'(?:http://)?(?:[a-z0-9]+\.)?photobucket\.com/.*(([\?\&]current=)|_)(?P<id>.*)\.(?P<ext>(flv)|(mp4))'
-    IE_NAME = u'photobucket'
-
-    def _real_extract(self, url):
-        # Extract id from URL
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group('id')
-
-        video_extension = mobj.group('ext')
-
-        # Retrieve video webpage to extract further information
-        webpage = self._download_webpage(url, video_id)
-
-        # Extract URL, uploader, and title from webpage
-        self.report_extraction(video_id)
-        # We try first by looking the javascript code:
-        mobj = re.search(r'Pb\.Data\.Shared\.put\(Pb\.Data\.Shared\.MEDIA, (?P<json>.*?)\);', webpage)
-        if mobj is not None:
-            info = json.loads(mobj.group('json'))
-            return [{
-                'id':       video_id,
-                'url':      info[u'downloadUrl'],
-                'uploader': info[u'username'],
-                'upload_date':  datetime.date.fromtimestamp(info[u'creationDate']).strftime('%Y%m%d'),
-                'title':    info[u'title'],
-                'ext':      video_extension,
-                'thumbnail': info[u'thumbUrl'],
-            }]
-
-        # We try looking in other parts of the webpage
-        video_url = self._search_regex(r'<link rel="video_src" href=".*\?file=([^"]+)" />',
-            webpage, u'video URL')
-
-        mobj = re.search(r'<title>(.*) video by (.*) - Photobucket</title>', webpage)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract title')
-        video_title = mobj.group(1).decode('utf-8')
-        video_uploader = mobj.group(2).decode('utf-8')
-
-        return [{
-            'id':       video_id.decode('utf-8'),
-            'url':      video_url.decode('utf-8'),
-            'uploader': video_uploader,
-            'upload_date':  None,
-            'title':    video_title,
-            'ext':      video_extension.decode('utf-8'),
-        }]
-
-
-class YahooIE(InfoExtractor):
-    """Information extractor for screen.yahoo.com."""
-    _VALID_URL = r'http://screen\.yahoo\.com/.*?-(?P<id>\d*?)\.html'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group('id')
-        webpage = self._download_webpage(url, video_id)
-        m_id = re.search(r'YUI\.namespace\("Media"\)\.CONTENT_ID = "(?P<new_id>.+?)";', webpage)
-
-        if m_id is None: 
-            # TODO: Check which url parameters are required
-            info_url = 'http://cosmos.bcst.yahoo.com/rest/v2/pops;lmsoverride=1;outputformat=mrss;cb=974419660;id=%s;rd=news.yahoo.com;datacontext=mdb;lg=KCa2IihxG3qE60vQ7HtyUy' % video_id
-            webpage = self._download_webpage(info_url, video_id, u'Downloading info webpage')
-            info_re = r'''<title><!\[CDATA\[(?P<title>.*?)\]\]></title>.*
-                        <description><!\[CDATA\[(?P<description>.*?)\]\]></description>.*
-                        <media:pubStart><!\[CDATA\[(?P<date>.*?)\ .*\]\]></media:pubStart>.*
-                        <media:content\ medium="image"\ url="(?P<thumb>.*?)"\ name="LARGETHUMB"
-                        '''
-            self.report_extraction(video_id)
-            m_info = re.search(info_re, webpage, re.VERBOSE|re.DOTALL)
-            if m_info is None:
-                raise ExtractorError(u'Unable to extract video info')
-            video_title = m_info.group('title')
-            video_description = m_info.group('description')
-            video_thumb = m_info.group('thumb')
-            video_date = m_info.group('date')
-            video_date = datetime.datetime.strptime(video_date, '%m/%d/%Y').strftime('%Y%m%d')
-    
-            # TODO: Find a way to get mp4 videos
-            rest_url = 'http://cosmos.bcst.yahoo.com/rest/v2/pops;element=stream;outputformat=mrss;id=%s;lmsoverride=1;bw=375;dynamicstream=1;cb=83521105;tech=flv,mp4;rd=news.yahoo.com;datacontext=mdb;lg=KCa2IihxG3qE60vQ7HtyUy' % video_id
-            webpage = self._download_webpage(rest_url, video_id, u'Downloading video url webpage')
-            m_rest = re.search(r'<media:content url="(?P<url>.*?)" path="(?P<path>.*?)"', webpage)
-            video_url = m_rest.group('url')
-            video_path = m_rest.group('path')
-            if m_rest is None:
-                raise ExtractorError(u'Unable to extract video url')
-
-        else: # We have to use a different method if another id is defined
-            long_id = m_id.group('new_id')
-            info_url = 'http://video.query.yahoo.com/v1/public/yql?q=SELECT%20*%20FROM%20yahoo.media.video.streams%20WHERE%20id%3D%22' + long_id + '%22%20AND%20format%3D%22mp4%2Cflv%22%20AND%20protocol%3D%22rtmp%2Chttp%22%20AND%20plrs%3D%2286Gj0vCaSzV_Iuf6hNylf2%22%20AND%20acctid%3D%22389%22%20AND%20plidl%3D%22%22%20AND%20pspid%3D%22792700001%22%20AND%20offnetwork%3D%22false%22%20AND%20site%3D%22ivy%22%20AND%20lang%3D%22en-US%22%20AND%20region%3D%22US%22%20AND%20override%3D%22none%22%3B&env=prod&format=json&callback=YUI.Env.JSONP.yui_3_8_1_1_1368368376830_335'
-            webpage = self._download_webpage(info_url, video_id, u'Downloading info json')
-            json_str = re.search(r'YUI.Env.JSONP.yui.*?\((.*?)\);', webpage).group(1)
-            info = json.loads(json_str)
-            res = info[u'query'][u'results'][u'mediaObj'][0]
-            stream = res[u'streams'][0]
-            video_path = stream[u'path']
-            video_url = stream[u'host']
-            meta = res[u'meta']
-            video_title = meta[u'title']
-            video_description = meta[u'description']
-            video_thumb = meta[u'thumbnail']
-            video_date = None # I can't find it
-
-        info_dict = {
-                     'id': video_id,
-                     'url': video_url,
-                     'play_path': video_path,
-                     'title':video_title,
-                     'description': video_description,
-                     'thumbnail': video_thumb,
-                     'upload_date': video_date,
-                     'ext': 'flv',
-                     }
-        return info_dict
-
-class VimeoIE(InfoExtractor):
-    """Information extractor for vimeo.com."""
-
-    # _VALID_URL matches Vimeo URLs
-    _VALID_URL = r'(?P<proto>https?://)?(?:(?:www|player)\.)?vimeo(?P<pro>pro)?\.com/(?:(?:(?:groups|album)/[^/]+)|(?:.*?)/)?(?P<direct_link>play_redirect_hls\?clip_id=)?(?:videos?/)?(?P<id>[0-9]+)'
-    IE_NAME = u'vimeo'
-
-    def _real_extract(self, url, new_video=True):
-        # Extract ID from URL
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group('id')
-        if not mobj.group('proto'):
-            url = 'https://' + url
-        if mobj.group('direct_link') or mobj.group('pro'):
-            url = 'https://vimeo.com/' + video_id
-
-        # Retrieve video webpage to extract further information
-        request = compat_urllib_request.Request(url, None, std_headers)
-        webpage = self._download_webpage(request, video_id)
-
-        # Now we begin extracting as much information as we can from what we
-        # retrieved. First we extract the information common to all extractors,
-        # and latter we extract those that are Vimeo specific.
-        self.report_extraction(video_id)
-
-        # Extract the config JSON
-        try:
-            config = webpage.split(' = {config:')[1].split(',assets:')[0]
-            config = json.loads(config)
-        except:
-            if re.search('The creator of this video has not given you permission to embed it on this domain.', webpage):
-                raise ExtractorError(u'The author has restricted the access to this video, try with the "--referer" option')
-            else:
-                raise ExtractorError(u'Unable to extract info section')
-
-        # Extract title
-        video_title = config["video"]["title"]
-
-        # Extract uploader and uploader_id
-        video_uploader = config["video"]["owner"]["name"]
-        video_uploader_id = config["video"]["owner"]["url"].split('/')[-1] if config["video"]["owner"]["url"] else None
-
-        # Extract video thumbnail
-        video_thumbnail = config["video"]["thumbnail"]
-
-        # Extract video description
-        video_description = get_element_by_attribute("itemprop", "description", webpage)
-        if video_description: video_description = clean_html(video_description)
-        else: video_description = u''
-
-        # Extract upload date
-        video_upload_date = None
-        mobj = re.search(r'<meta itemprop="dateCreated" content="(\d{4})-(\d{2})-(\d{2})T', webpage)
-        if mobj is not None:
-            video_upload_date = mobj.group(1) + mobj.group(2) + mobj.group(3)
-
-        # Vimeo specific: extract request signature and timestamp
-        sig = config['request']['signature']
-        timestamp = config['request']['timestamp']
-
-        # Vimeo specific: extract video codec and quality information
-        # First consider quality, then codecs, then take everything
-        # TODO bind to format param
-        codecs = [('h264', 'mp4'), ('vp8', 'flv'), ('vp6', 'flv')]
-        files = { 'hd': [], 'sd': [], 'other': []}
-        for codec_name, codec_extension in codecs:
-            if codec_name in config["video"]["files"]:
-                if 'hd' in config["video"]["files"][codec_name]:
-                    files['hd'].append((codec_name, codec_extension, 'hd'))
-                elif 'sd' in config["video"]["files"][codec_name]:
-                    files['sd'].append((codec_name, codec_extension, 'sd'))
-                else:
-                    files['other'].append((codec_name, codec_extension, config["video"]["files"][codec_name][0]))
-
-        for quality in ('hd', 'sd', 'other'):
-            if len(files[quality]) > 0:
-                video_quality = files[quality][0][2]
-                video_codec = files[quality][0][0]
-                video_extension = files[quality][0][1]
-                self.to_screen(u'%s: Downloading %s file at %s quality' % (video_id, video_codec.upper(), video_quality))
-                break
-        else:
-            raise ExtractorError(u'No known codec found')
-
-        video_url = "http://player.vimeo.com/play_redirect?clip_id=%s&sig=%s&time=%s&quality=%s&codecs=%s&type=moogaloop_local&embed_location=" \
-                    %(video_id, sig, timestamp, video_quality, video_codec.upper())
-
-        return [{
-            'id':       video_id,
-            'url':      video_url,
-            'uploader': video_uploader,
-            'uploader_id': video_uploader_id,
-            'upload_date':  video_upload_date,
-            'title':    video_title,
-            'ext':      video_extension,
-            'thumbnail':    video_thumbnail,
-            'description':  video_description,
-        }]
-
-
-class ArteTvIE(InfoExtractor):
-    """arte.tv information extractor."""
-
-    _VALID_URL = r'(?:http://)?videos\.arte\.tv/(?:fr|de)/videos/.*'
-    _LIVE_URL = r'index-[0-9]+\.html$'
-
-    IE_NAME = u'arte.tv'
-
-    def fetch_webpage(self, url):
-        request = compat_urllib_request.Request(url)
-        try:
-            self.report_download_webpage(url)
-            webpage = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to retrieve video webpage: %s' % compat_str(err))
-        except ValueError as err:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        return webpage
-
-    def grep_webpage(self, url, regex, regexFlags, matchTuples):
-        page = self.fetch_webpage(url)
-        mobj = re.search(regex, page, regexFlags)
-        info = {}
-
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        for (i, key, err) in matchTuples:
-            if mobj.group(i) is None:
-                raise ExtractorError(err)
-            else:
-                info[key] = mobj.group(i)
-
-        return info
-
-    def extractLiveStream(self, url):
-        video_lang = url.split('/')[-4]
-        info = self.grep_webpage(
-            url,
-            r'src="(.*?/videothek_js.*?\.js)',
-            0,
-            [
-                (1, 'url', u'Invalid URL: %s' % url)
-            ]
-        )
-        http_host = url.split('/')[2]
-        next_url = 'http://%s%s' % (http_host, compat_urllib_parse.unquote(info.get('url')))
-        info = self.grep_webpage(
-            next_url,
-            r'(s_artestras_scst_geoFRDE_' + video_lang + '.*?)\'.*?' +
-                '(http://.*?\.swf).*?' +
-                '(rtmp://.*?)\'',
-            re.DOTALL,
-            [
-                (1, 'path',   u'could not extract video path: %s' % url),
-                (2, 'player', u'could not extract video player: %s' % url),
-                (3, 'url',    u'could not extract video url: %s' % url)
-            ]
-        )
-        video_url = u'%s/%s' % (info.get('url'), info.get('path'))
-
-    def extractPlus7Stream(self, url):
-        video_lang = url.split('/')[-3]
-        info = self.grep_webpage(
-            url,
-            r'param name="movie".*?videorefFileUrl=(http[^\'"&]*)',
-            0,
-            [
-                (1, 'url', u'Invalid URL: %s' % url)
-            ]
-        )
-        next_url = compat_urllib_parse.unquote(info.get('url'))
-        info = self.grep_webpage(
-            next_url,
-            r'<video lang="%s" ref="(http[^\'"&]*)' % video_lang,
-            0,
-            [
-                (1, 'url', u'Could not find <video> tag: %s' % url)
-            ]
-        )
-        next_url = compat_urllib_parse.unquote(info.get('url'))
-
-        info = self.grep_webpage(
-            next_url,
-            r'<video id="(.*?)".*?>.*?' +
-                '<name>(.*?)</name>.*?' +
-                '<dateVideo>(.*?)</dateVideo>.*?' +
-                '<url quality="hd">(.*?)</url>',
-            re.DOTALL,
-            [
-                (1, 'id',    u'could not extract video id: %s' % url),
-                (2, 'title', u'could not extract video title: %s' % url),
-                (3, 'date',  u'could not extract video date: %s' % url),
-                (4, 'url',   u'could not extract video url: %s' % url)
-            ]
-        )
-
-        return {
-            'id':           info.get('id'),
-            'url':          compat_urllib_parse.unquote(info.get('url')),
-            'uploader':     u'arte.tv',
-            'upload_date':  unified_strdate(info.get('date')),
-            'title':        info.get('title').decode('utf-8'),
-            'ext':          u'mp4',
-            'format':       u'NA',
-            'player_url':   None,
-        }
-
-    def _real_extract(self, url):
-        video_id = url.split('/')[-1]
-        self.report_extraction(video_id)
-
-        if re.search(self._LIVE_URL, video_id) is not None:
-            self.extractLiveStream(url)
-            return
-        else:
-            info = self.extractPlus7Stream(url)
-
-        return [info]
-
-
-class GenericIE(InfoExtractor):
-    """Generic last-resort information extractor."""
-
-    _VALID_URL = r'.*'
-    IE_NAME = u'generic'
-
-    def report_download_webpage(self, video_id):
-        """Report webpage download."""
-        if not self._downloader.params.get('test', False):
-            self._downloader.report_warning(u'Falling back on generic information extractor.')
-        super(GenericIE, self).report_download_webpage(video_id)
-
-    def report_following_redirect(self, new_url):
-        """Report information extraction."""
-        self._downloader.to_screen(u'[redirect] Following redirect to %s' % new_url)
-
-    def _test_redirect(self, url):
-        """Check if it is a redirect, like url shorteners, in case return the new url."""
-        class HeadRequest(compat_urllib_request.Request):
-            def get_method(self):
-                return "HEAD"
-
-        class HEADRedirectHandler(compat_urllib_request.HTTPRedirectHandler):
-            """
-            Subclass the HTTPRedirectHandler to make it use our
-            HeadRequest also on the redirected URL
-            """
-            def redirect_request(self, req, fp, code, msg, headers, newurl):
-                if code in (301, 302, 303, 307):
-                    newurl = newurl.replace(' ', '%20')
-                    newheaders = dict((k,v) for k,v in req.headers.items()
-                                      if k.lower() not in ("content-length", "content-type"))
-                    return HeadRequest(newurl,
-                                       headers=newheaders,
-                                       origin_req_host=req.get_origin_req_host(),
-                                       unverifiable=True)
-                else:
-                    raise compat_urllib_error.HTTPError(req.get_full_url(), code, msg, headers, fp)
-
-        class HTTPMethodFallback(compat_urllib_request.BaseHandler):
-            """
-            Fallback to GET if HEAD is not allowed (405 HTTP error)
-            """
-            def http_error_405(self, req, fp, code, msg, headers):
-                fp.read()
-                fp.close()
-
-                newheaders = dict((k,v) for k,v in req.headers.items()
-                                  if k.lower() not in ("content-length", "content-type"))
-                return self.parent.open(compat_urllib_request.Request(req.get_full_url(),
-                                                 headers=newheaders,
-                                                 origin_req_host=req.get_origin_req_host(),
-                                                 unverifiable=True))
-
-        # Build our opener
-        opener = compat_urllib_request.OpenerDirector()
-        for handler in [compat_urllib_request.HTTPHandler, compat_urllib_request.HTTPDefaultErrorHandler,
-                        HTTPMethodFallback, HEADRedirectHandler,
-                        compat_urllib_request.HTTPErrorProcessor, compat_urllib_request.HTTPSHandler]:
-            opener.add_handler(handler())
-
-        response = opener.open(HeadRequest(url))
-        if response is None:
-            raise ExtractorError(u'Invalid URL protocol')
-        new_url = response.geturl()
-
-        if url == new_url:
-            return False
-
-        self.report_following_redirect(new_url)
-        return new_url
-
-    def _real_extract(self, url):
-        new_url = self._test_redirect(url)
-        if new_url: return [self.url_result(new_url)]
-
-        video_id = url.split('/')[-1]
-        try:
-            webpage = self._download_webpage(url, video_id)
-        except ValueError as err:
-            # since this is the last-resort InfoExtractor, if
-            # this error is thrown, it'll be thrown here
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        self.report_extraction(video_id)
-        # Start with something easy: JW Player in SWFObject
-        mobj = re.search(r'flashvars: [\'"](?:.*&)?file=(http[^\'"&]*)', webpage)
-        if mobj is None:
-            # Broaden the search a little bit
-            mobj = re.search(r'[^A-Za-z0-9]?(?:file|source)=(http[^\'"&]*)', webpage)
-        if mobj is None:
-            # Broaden the search a little bit: JWPlayer JS loader
-            mobj = re.search(r'[^A-Za-z0-9]?file:\s*["\'](http[^\'"&]*)', webpage)
-        if mobj is None:
-            # Try to find twitter cards info
-            mobj = re.search(r'<meta (?:property|name)="twitter:player:stream" (?:content|value)="(.+?)"', webpage)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        # It's possible that one of the regexes
-        # matched, but returned an empty group:
-        if mobj.group(1) is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_url = compat_urllib_parse.unquote(mobj.group(1))
-        video_id = os.path.basename(video_url)
-
-        # here's a fun little line of code for you:
-        video_extension = os.path.splitext(video_id)[1][1:]
-        video_id = os.path.splitext(video_id)[0]
-
-        # it's tempting to parse this further, but you would
-        # have to take into account all the variations like
-        #   Video Title - Site Name
-        #   Site Name | Video Title
-        #   Video Title - Tagline | Site Name
-        # and so on and so forth; it's just not practical
-        video_title = self._html_search_regex(r'<title>(.*)</title>',
-            webpage, u'video title')
-
-        # video uploader is domain name
-        video_uploader = self._search_regex(r'(?:https?://)?([^/]*)/.*',
-            url, u'video uploader')
-
-        return [{
-            'id':       video_id,
-            'url':      video_url,
-            'uploader': video_uploader,
-            'upload_date':  None,
-            'title':    video_title,
-            'ext':      video_extension,
-        }]
-
-
-class YoutubeSearchIE(SearchInfoExtractor):
-    """Information Extractor for YouTube search queries."""
-    _API_URL = 'https://gdata.youtube.com/feeds/api/videos?q=%s&start-index=%i&max-results=50&v=2&alt=jsonc'
-    _MAX_RESULTS = 1000
-    IE_NAME = u'youtube:search'
-    _SEARCH_KEY = 'ytsearch'
-
-    def report_download_page(self, query, pagenum):
-        """Report attempt to download search page with given number."""
-        self._downloader.to_screen(u'[youtube] query "%s": Downloading page %s' % (query, pagenum))
-
-    def _get_n_results(self, query, n):
-        """Get a specified number of results for a query"""
-
-        video_ids = []
-        pagenum = 0
-        limit = n
-
-        while (50 * pagenum) < limit:
-            self.report_download_page(query, pagenum+1)
-            result_url = self._API_URL % (compat_urllib_parse.quote_plus(query), (50*pagenum)+1)
-            request = compat_urllib_request.Request(result_url)
-            try:
-                data = compat_urllib_request.urlopen(request).read().decode('utf-8')
-            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-                raise ExtractorError(u'Unable to download API page: %s' % compat_str(err))
-            api_response = json.loads(data)['data']
-
-            if not 'items' in api_response:
-                raise ExtractorError(u'[youtube] No video results')
-
-            new_ids = list(video['id'] for video in api_response['items'])
-            video_ids += new_ids
-
-            limit = min(n, api_response['totalItems'])
-            pagenum += 1
-
-        if len(video_ids) > n:
-            video_ids = video_ids[:n]
-        videos = [self.url_result('http://www.youtube.com/watch?v=%s' % id, 'Youtube') for id in video_ids]
-        return self.playlist_result(videos, query)
-
-
-class GoogleSearchIE(SearchInfoExtractor):
-    """Information Extractor for Google Video search queries."""
-    _MORE_PAGES_INDICATOR = r'id="pnnext" class="pn"'
-    _MAX_RESULTS = 1000
-    IE_NAME = u'video.google:search'
-    _SEARCH_KEY = 'gvsearch'
-
-    def _get_n_results(self, query, n):
-        """Get a specified number of results for a query"""
-
-        res = {
-            '_type': 'playlist',
-            'id': query,
-            'entries': []
-        }
-
-        for pagenum in itertools.count(1):
-            result_url = u'http://www.google.com/search?tbm=vid&q=%s&start=%s&hl=en' % (compat_urllib_parse.quote_plus(query), pagenum*10)
-            webpage = self._download_webpage(result_url, u'gvsearch:' + query,
-                                             note='Downloading result page ' + str(pagenum))
-
-            for mobj in re.finditer(r'<h3 class="r"><a href="([^"]+)"', webpage):
-                e = {
-                    '_type': 'url',
-                    'url': mobj.group(1)
-                }
-                res['entries'].append(e)
-
-            if (pagenum * 10 > n) or not re.search(self._MORE_PAGES_INDICATOR, webpage):
-                return res
-
-class YahooSearchIE(SearchInfoExtractor):
-    """Information Extractor for Yahoo! Video search queries."""
-
-    _MAX_RESULTS = 1000
-    IE_NAME = u'screen.yahoo:search'
-    _SEARCH_KEY = 'yvsearch'
-
-    def _get_n_results(self, query, n):
-        """Get a specified number of results for a query"""
-
-        res = {
-            '_type': 'playlist',
-            'id': query,
-            'entries': []
-        }
-        for pagenum in itertools.count(0): 
-            result_url = u'http://video.search.yahoo.com/search/?p=%s&fr=screen&o=js&gs=0&b=%d' % (compat_urllib_parse.quote_plus(query), pagenum * 30)
-            webpage = self._download_webpage(result_url, query,
-                                             note='Downloading results page '+str(pagenum+1))
-            info = json.loads(webpage)
-            m = info[u'm']
-            results = info[u'results']
-
-            for (i, r) in enumerate(results):
-                if (pagenum * 30) +i >= n:
-                    break
-                mobj = re.search(r'(?P<url>screen\.yahoo\.com/.*?-\d*?\.html)"', r)
-                e = self.url_result('http://' + mobj.group('url'), 'Yahoo')
-                res['entries'].append(e)
-            if (pagenum * 30 +i >= n) or (m[u'last'] >= (m[u'total'] -1 )):
-                break
-
-        return res
-
-
-class YoutubePlaylistIE(InfoExtractor):
-    """Information Extractor for YouTube playlists."""
-
-    _VALID_URL = r"""(?:
-                        (?:https?://)?
-                        (?:\w+\.)?
-                        youtube\.com/
-                        (?:
-                           (?:course|view_play_list|my_playlists|artist|playlist|watch)
-                           \? (?:.*?&)*? (?:p|a|list)=
-                        |  p/
-                        )
-                        ((?:PL|EC|UU)?[0-9A-Za-z-_]{10,})
-                        .*
-                     |
-                        ((?:PL|EC|UU)[0-9A-Za-z-_]{10,})
-                     )"""
-    _TEMPLATE_URL = 'https://gdata.youtube.com/feeds/api/playlists/%s?max-results=%i&start-index=%i&v=2&alt=json&safeSearch=none'
-    _MAX_RESULTS = 50
-    IE_NAME = u'youtube:playlist'
-
-    @classmethod
-    def suitable(cls, url):
-        """Receives a URL and returns True if suitable for this IE."""
-        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
-
-    def _real_extract(self, url):
-        # Extract playlist id
-        mobj = re.match(self._VALID_URL, url, re.VERBOSE)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        # Download playlist videos from API
-        playlist_id = mobj.group(1) or mobj.group(2)
-        page_num = 1
-        videos = []
-
-        while True:
-            url = self._TEMPLATE_URL % (playlist_id, self._MAX_RESULTS, self._MAX_RESULTS * (page_num - 1) + 1)
-            page = self._download_webpage(url, playlist_id, u'Downloading page #%s' % page_num)
-
-            try:
-                response = json.loads(page)
-            except ValueError as err:
-                raise ExtractorError(u'Invalid JSON in API response: ' + compat_str(err))
-
-            if 'feed' not in response:
-                raise ExtractorError(u'Got a malformed response from YouTube API')
-            playlist_title = response['feed']['title']['$t']
-            if 'entry' not in response['feed']:
-                # Number of videos is a multiple of self._MAX_RESULTS
-                break
-
-            videos += [ (entry['yt$position']['$t'], entry['content']['src'])
-                        for entry in response['feed']['entry']
-                        if 'content' in entry ]
-
-            if len(response['feed']['entry']) < self._MAX_RESULTS:
-                break
-            page_num += 1
-
-        videos = [v[1] for v in sorted(videos)]
-
-        url_results = [self.url_result(url, 'Youtube') for url in videos]
-        return [self.playlist_result(url_results, playlist_id, playlist_title)]
-
-
-class YoutubeChannelIE(InfoExtractor):
-    """Information Extractor for YouTube channels."""
-
-    _VALID_URL = r"^(?:https?://)?(?:youtu\.be|(?:\w+\.)?youtube(?:-nocookie)?\.com)/channel/([0-9A-Za-z_-]+)"
-    _TEMPLATE_URL = 'http://www.youtube.com/channel/%s/videos?sort=da&flow=list&view=0&page=%s&gl=US&hl=en'
-    _MORE_PAGES_INDICATOR = 'yt-uix-load-more'
-    _MORE_PAGES_URL = 'http://www.youtube.com/channel_ajax?action_load_more_videos=1&flow=list&paging=%s&view=0&sort=da&channel_id=%s'
-    IE_NAME = u'youtube:channel'
-
-    def extract_videos_from_page(self, page):
-        ids_in_page = []
-        for mobj in re.finditer(r'href="/watch\?v=([0-9A-Za-z_-]+)&?', page):
-            if mobj.group(1) not in ids_in_page:
-                ids_in_page.append(mobj.group(1))
-        return ids_in_page
-
-    def _real_extract(self, url):
-        # Extract channel id
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        # Download channel page
-        channel_id = mobj.group(1)
-        video_ids = []
-        pagenum = 1
-
-        url = self._TEMPLATE_URL % (channel_id, pagenum)
-        page = self._download_webpage(url, channel_id,
-                                      u'Downloading page #%s' % pagenum)
-
-        # Extract video identifiers
-        ids_in_page = self.extract_videos_from_page(page)
-        video_ids.extend(ids_in_page)
-
-        # Download any subsequent channel pages using the json-based channel_ajax query
-        if self._MORE_PAGES_INDICATOR in page:
-            while True:
-                pagenum = pagenum + 1
-
-                url = self._MORE_PAGES_URL % (pagenum, channel_id)
-                page = self._download_webpage(url, channel_id,
-                                              u'Downloading page #%s' % pagenum)
-
-                page = json.loads(page)
-
-                ids_in_page = self.extract_videos_from_page(page['content_html'])
-                video_ids.extend(ids_in_page)
-
-                if self._MORE_PAGES_INDICATOR  not in page['load_more_widget_html']:
-                    break
-
-        self._downloader.to_screen(u'[youtube] Channel %s: Found %i videos' % (channel_id, len(video_ids)))
-
-        urls = ['http://www.youtube.com/watch?v=%s' % id for id in video_ids]
-        url_entries = [self.url_result(url, 'Youtube') for url in urls]
-        return [self.playlist_result(url_entries, channel_id)]
-
-
-class YoutubeUserIE(InfoExtractor):
-    """Information Extractor for YouTube users."""
-
-    _VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?youtube\.com/user/)|ytuser:)([A-Za-z0-9_-]+)'
-    _TEMPLATE_URL = 'http://gdata.youtube.com/feeds/api/users/%s'
-    _GDATA_PAGE_SIZE = 50
-    _GDATA_URL = 'http://gdata.youtube.com/feeds/api/users/%s/uploads?max-results=%d&start-index=%d'
-    _VIDEO_INDICATOR = r'/watch\?v=(.+?)[\<&]'
-    IE_NAME = u'youtube:user'
-
-    def _real_extract(self, url):
-        # Extract username
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        username = mobj.group(1)
-
-        # Download video ids using YouTube Data API. Result size per
-        # query is limited (currently to 50 videos) so we need to query
-        # page by page until there are no video ids - it means we got
-        # all of them.
-
-        video_ids = []
-        pagenum = 0
-
-        while True:
-            start_index = pagenum * self._GDATA_PAGE_SIZE + 1
-
-            gdata_url = self._GDATA_URL % (username, self._GDATA_PAGE_SIZE, start_index)
-            page = self._download_webpage(gdata_url, username,
-                                          u'Downloading video ids from %d to %d' % (start_index, start_index + self._GDATA_PAGE_SIZE))
-
-            # Extract video identifiers
-            ids_in_page = []
-
-            for mobj in re.finditer(self._VIDEO_INDICATOR, page):
-                if mobj.group(1) not in ids_in_page:
-                    ids_in_page.append(mobj.group(1))
-
-            video_ids.extend(ids_in_page)
-
-            # A little optimization - if current page is not
-            # "full", ie. does not contain PAGE_SIZE video ids then
-            # we can assume that this page is the last one - there
-            # are no more ids on further pages - no need to query
-            # again.
-
-            if len(ids_in_page) < self._GDATA_PAGE_SIZE:
-                break
-
-            pagenum += 1
-
-        urls = ['http://www.youtube.com/watch?v=%s' % video_id for video_id in video_ids]
-        url_results = [self.url_result(url, 'Youtube') for url in urls]
-        return [self.playlist_result(url_results, playlist_title = username)]
-
-
-class BlipTVUserIE(InfoExtractor):
-    """Information Extractor for blip.tv users."""
-
-    _VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?blip\.tv/)|bliptvuser:)([^/]+)/*$'
-    _PAGE_SIZE = 12
-    IE_NAME = u'blip.tv:user'
-
-    def _real_extract(self, url):
-        # Extract username
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        username = mobj.group(1)
-
-        page_base = 'http://m.blip.tv/pr/show_get_full_episode_list?users_id=%s&lite=0&esi=1'
-
-        page = self._download_webpage(url, username, u'Downloading user page')
-        mobj = re.search(r'data-users-id="([^"]+)"', page)
-        page_base = page_base % mobj.group(1)
-
-
-        # Download video ids using BlipTV Ajax calls. Result size per
-        # query is limited (currently to 12 videos) so we need to query
-        # page by page until there are no video ids - it means we got
-        # all of them.
-
-        video_ids = []
-        pagenum = 1
-
-        while True:
-            url = page_base + "&page=" + str(pagenum)
-            page = self._download_webpage(url, username,
-                                          u'Downloading video ids from page %d' % pagenum)
-
-            # Extract video identifiers
-            ids_in_page = []
-
-            for mobj in re.finditer(r'href="/([^"]+)"', page):
-                if mobj.group(1) not in ids_in_page:
-                    ids_in_page.append(unescapeHTML(mobj.group(1)))
-
-            video_ids.extend(ids_in_page)
-
-            # A little optimization - if current page is not
-            # "full", ie. does not contain PAGE_SIZE video ids then
-            # we can assume that this page is the last one - there
-            # are no more ids on further pages - no need to query
-            # again.
-
-            if len(ids_in_page) < self._PAGE_SIZE:
-                break
-
-            pagenum += 1
-
-        urls = [u'http://blip.tv/%s' % video_id for video_id in video_ids]
-        url_entries = [self.url_result(url, 'BlipTV') for url in urls]
-        return [self.playlist_result(url_entries, playlist_title = username)]
-
-
-class DepositFilesIE(InfoExtractor):
-    """Information extractor for depositfiles.com"""
-
-    _VALID_URL = r'(?:http://)?(?:\w+\.)?depositfiles\.com/(?:../(?#locale))?files/(.+)'
-
-    def _real_extract(self, url):
-        file_id = url.split('/')[-1]
-        # Rebuild url in english locale
-        url = 'http://depositfiles.com/en/files/' + file_id
-
-        # Retrieve file webpage with 'Free download' button pressed
-        free_download_indication = { 'gateway_result' : '1' }
-        request = compat_urllib_request.Request(url, compat_urllib_parse.urlencode(free_download_indication))
-        try:
-            self.report_download_webpage(file_id)
-            webpage = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to retrieve file webpage: %s' % compat_str(err))
-
-        # Search for the real file URL
-        mobj = re.search(r'<form action="(http://fileshare.+?)"', webpage)
-        if (mobj is None) or (mobj.group(1) is None):
-            # Try to figure out reason of the error.
-            mobj = re.search(r'<strong>(Attention.*?)</strong>', webpage, re.DOTALL)
-            if (mobj is not None) and (mobj.group(1) is not None):
-                restriction_message = re.sub('\s+', ' ', mobj.group(1)).strip()
-                raise ExtractorError(u'%s' % restriction_message)
-            else:
-                raise ExtractorError(u'Unable to extract download URL from: %s' % url)
-
-        file_url = mobj.group(1)
-        file_extension = os.path.splitext(file_url)[1][1:]
-
-        # Search for file title
-        file_title = self._search_regex(r'<b title="(.*?)">', webpage, u'title')
-
-        return [{
-            'id':       file_id.decode('utf-8'),
-            'url':      file_url.decode('utf-8'),
-            'uploader': None,
-            'upload_date':  None,
-            'title':    file_title,
-            'ext':      file_extension.decode('utf-8'),
-        }]
-
-
-class FacebookIE(InfoExtractor):
-    """Information Extractor for Facebook"""
-
-    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?facebook\.com/(?:video/video|photo)\.php\?(?:.*?)v=(?P<ID>\d+)(?:.*)'
-    _LOGIN_URL = 'https://login.facebook.com/login.php?m&next=http%3A%2F%2Fm.facebook.com%2Fhome.php&'
-    _NETRC_MACHINE = 'facebook'
-    IE_NAME = u'facebook'
-
-    def report_login(self):
-        """Report attempt to log in."""
-        self.to_screen(u'Logging in')
-
-    def _real_initialize(self):
-        if self._downloader is None:
-            return
-
-        useremail = None
-        password = None
-        downloader_params = self._downloader.params
-
-        # Attempt to use provided username and password or .netrc data
-        if downloader_params.get('username', None) is not None:
-            useremail = downloader_params['username']
-            password = downloader_params['password']
-        elif downloader_params.get('usenetrc', False):
-            try:
-                info = netrc.netrc().authenticators(self._NETRC_MACHINE)
-                if info is not None:
-                    useremail = info[0]
-                    password = info[2]
-                else:
-                    raise netrc.NetrcParseError('No authenticators for %s' % self._NETRC_MACHINE)
-            except (IOError, netrc.NetrcParseError) as err:
-                self._downloader.report_warning(u'parsing .netrc: %s' % compat_str(err))
-                return
-
-        if useremail is None:
-            return
-
-        # Log in
-        login_form = {
-            'email': useremail,
-            'pass': password,
-            'login': 'Log+In'
-            }
-        request = compat_urllib_request.Request(self._LOGIN_URL, compat_urllib_parse.urlencode(login_form))
-        try:
-            self.report_login()
-            login_results = compat_urllib_request.urlopen(request).read()
-            if re.search(r'<form(.*)name="login"(.*)</form>', login_results) is not None:
-                self._downloader.report_warning(u'unable to log in: bad username/password, or exceded login rate limit (~3/min). Check credentials or wait.')
-                return
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.report_warning(u'unable to log in: %s' % compat_str(err))
-            return
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group('ID')
-
-        url = 'https://www.facebook.com/video/video.php?v=%s' % video_id
-        webpage = self._download_webpage(url, video_id)
-
-        BEFORE = '{swf.addParam(param[0], param[1]);});\n'
-        AFTER = '.forEach(function(variable) {swf.addVariable(variable[0], variable[1]);});'
-        m = re.search(re.escape(BEFORE) + '(.*?)' + re.escape(AFTER), webpage)
-        if not m:
-            raise ExtractorError(u'Cannot parse data')
-        data = dict(json.loads(m.group(1)))
-        params_raw = compat_urllib_parse.unquote(data['params'])
-        params = json.loads(params_raw)
-        video_data = params['video_data'][0]
-        video_url = video_data.get('hd_src')
-        if not video_url:
-            video_url = video_data['sd_src']
-        if not video_url:
-            raise ExtractorError(u'Cannot find video URL')
-        video_duration = int(video_data['video_duration'])
-        thumbnail = video_data['thumbnail_src']
-
-        video_title = self._html_search_regex('<h2 class="uiHeaderTitle">([^<]+)</h2>',
-            webpage, u'title')
-
-        info = {
-            'id': video_id,
-            'title': video_title,
-            'url': video_url,
-            'ext': 'mp4',
-            'duration': video_duration,
-            'thumbnail': thumbnail,
-        }
-        return [info]
-
-
-class BlipTVIE(InfoExtractor):
-    """Information extractor for blip.tv"""
-
-    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?blip\.tv/((.+/)|(play/)|(api\.swf#))(.+)$'
-    _URL_EXT = r'^.*\.([a-z0-9]+)$'
-    IE_NAME = u'blip.tv'
-
-    def report_direct_download(self, title):
-        """Report information extraction."""
-        self.to_screen(u'%s: Direct download detected' % title)
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        # See https://github.com/rg3/youtube-dl/issues/857
-        api_mobj = re.match(r'http://a\.blip\.tv/api\.swf#(?P<video_id>[\d\w]+)', url)
-        if api_mobj is not None:
-            url = 'http://blip.tv/play/g_%s' % api_mobj.group('video_id')
-        urlp = compat_urllib_parse_urlparse(url)
-        if urlp.path.startswith('/play/'):
-            request = compat_urllib_request.Request(url)
-            response = compat_urllib_request.urlopen(request)
-            redirecturl = response.geturl()
-            rurlp = compat_urllib_parse_urlparse(redirecturl)
-            file_id = compat_parse_qs(rurlp.fragment)['file'][0].rpartition('/')[2]
-            url = 'http://blip.tv/a/a-' + file_id
-            return self._real_extract(url)
-
-
-        if '?' in url:
-            cchar = '&'
-        else:
-            cchar = '?'
-        json_url = url + cchar + 'skin=json&version=2&no_wrap=1'
-        request = compat_urllib_request.Request(json_url)
-        request.add_header('User-Agent', 'iTunes/10.6.1')
-        self.report_extraction(mobj.group(1))
-        info = None
-        try:
-            urlh = compat_urllib_request.urlopen(request)
-            if urlh.headers.get('Content-Type', '').startswith('video/'): # Direct download
-                basename = url.split('/')[-1]
-                title,ext = os.path.splitext(basename)
-                title = title.decode('UTF-8')
-                ext = ext.replace('.', '')
-                self.report_direct_download(title)
-                info = {
-                    'id': title,
-                    'url': url,
-                    'uploader': None,
-                    'upload_date': None,
-                    'title': title,
-                    'ext': ext,
-                    'urlhandle': urlh
-                }
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'ERROR: unable to download video info webpage: %s' % compat_str(err))
-        if info is None: # Regular URL
-            try:
-                json_code_bytes = urlh.read()
-                json_code = json_code_bytes.decode('utf-8')
-            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-                raise ExtractorError(u'Unable to read video info webpage: %s' % compat_str(err))
-
-            try:
-                json_data = json.loads(json_code)
-                if 'Post' in json_data:
-                    data = json_data['Post']
-                else:
-                    data = json_data
-
-                upload_date = datetime.datetime.strptime(data['datestamp'], '%m-%d-%y %H:%M%p').strftime('%Y%m%d')
-                video_url = data['media']['url']
-                umobj = re.match(self._URL_EXT, video_url)
-                if umobj is None:
-                    raise ValueError('Can not determine filename extension')
-                ext = umobj.group(1)
-
-                info = {
-                    'id': data['item_id'],
-                    'url': video_url,
-                    'uploader': data['display_name'],
-                    'upload_date': upload_date,
-                    'title': data['title'],
-                    'ext': ext,
-                    'format': data['media']['mimeType'],
-                    'thumbnail': data['thumbnailUrl'],
-                    'description': data['description'],
-                    'player_url': data['embedUrl'],
-                    'user_agent': 'iTunes/10.6.1',
-                }
-            except (ValueError,KeyError) as err:
-                raise ExtractorError(u'Unable to parse video information: %s' % repr(err))
-
-        return [info]
-
-
-class MyVideoIE(InfoExtractor):
-    """Information Extractor for myvideo.de."""
-
-    _VALID_URL = r'(?:http://)?(?:www\.)?myvideo\.de/watch/([0-9]+)/([^?/]+).*'
-    IE_NAME = u'myvideo'
-
-    # Original Code from: https://github.com/dersphere/plugin.video.myvideo_de.git
-    # Released into the Public Domain by Tristan Fischer on 2013-05-19
-    # https://github.com/rg3/youtube-dl/pull/842
-    def __rc4crypt(self,data, key):
-        x = 0
-        box = list(range(256))
-        for i in list(range(256)):
-            x = (x + box[i] + compat_ord(key[i % len(key)])) % 256
-            box[i], box[x] = box[x], box[i]
-        x = 0
-        y = 0
-        out = ''
-        for char in data:
-            x = (x + 1) % 256
-            y = (y + box[x]) % 256
-            box[x], box[y] = box[y], box[x]
-            out += chr(compat_ord(char) ^ box[(box[x] + box[y]) % 256])
-        return out
-
-    def __md5(self,s):
-        return hashlib.md5(s).hexdigest().encode()
-
-    def _real_extract(self,url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'invalid URL: %s' % url)
-
-        video_id = mobj.group(1)
-
-        GK = (
-          b'WXpnME1EZGhNRGhpTTJNM01XVmhOREU0WldNNVpHTTJOakpt'
-          b'TW1FMU5tVTBNR05pWkRaa05XRXhNVFJoWVRVd1ptSXhaVEV3'
-          b'TnpsbA0KTVRkbU1tSTRNdz09'
-        )
-
-        # Get video webpage
-        webpage_url = 'http://www.myvideo.de/watch/%s' % video_id
-        webpage = self._download_webpage(webpage_url, video_id)
-
-        mobj = re.search('source src=\'(.+?)[.]([^.]+)\'', webpage)
-        if mobj is not None:
-            self.report_extraction(video_id)
-            video_url = mobj.group(1) + '.flv'
-
-            video_title = self._html_search_regex('<title>([^<]+)</title>',
-                webpage, u'title')
-
-            video_ext = self._search_regex('[.](.+?)$', video_url, u'extension')
-
-            return [{
-                'id':       video_id,
-                'url':      video_url,
-                'uploader': None,
-                'upload_date':  None,
-                'title':    video_title,
-                'ext':      u'flv',
-            }]
-
-        # try encxml
-        mobj = re.search('var flashvars={(.+?)}', webpage)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract video')
-
-        params = {}
-        encxml = ''
-        sec = mobj.group(1)
-        for (a, b) in re.findall('(.+?):\'(.+?)\',?', sec):
-            if not a == '_encxml':
-                params[a] = b
-            else:
-                encxml = compat_urllib_parse.unquote(b)
-        if not params.get('domain'):
-            params['domain'] = 'www.myvideo.de'
-        xmldata_url = '%s?%s' % (encxml, compat_urllib_parse.urlencode(params))
-        if 'flash_playertype=MTV' in xmldata_url:
-            self._downloader.report_warning(u'avoiding MTV player')
-            xmldata_url = (
-                'http://www.myvideo.de/dynamic/get_player_video_xml.php'
-                '?flash_playertype=D&ID=%s&_countlimit=4&autorun=yes'
-            ) % video_id
-
-        # get enc data
-        enc_data = self._download_webpage(xmldata_url, video_id).split('=')[1]
-        enc_data_b = binascii.unhexlify(enc_data)
-        sk = self.__md5(
-            base64.b64decode(base64.b64decode(GK)) +
-            self.__md5(
-                str(video_id).encode('utf-8')
-            )
-        )
-        dec_data = self.__rc4crypt(enc_data_b, sk)
-
-        # extracting infos
-        self.report_extraction(video_id)
-
-        video_url = None
-        mobj = re.search('connectionurl=\'(.*?)\'', dec_data)
-        if mobj:
-            video_url = compat_urllib_parse.unquote(mobj.group(1))
-            if 'myvideo2flash' in video_url:
-                self._downloader.report_warning(u'forcing RTMPT ...')
-                video_url = video_url.replace('rtmpe://', 'rtmpt://')
-
-        if not video_url:
-            # extract non rtmp videos
-            mobj = re.search('path=\'(http.*?)\' source=\'(.*?)\'', dec_data)
-            if mobj is None:
-                raise ExtractorError(u'unable to extract url')
-            video_url = compat_urllib_parse.unquote(mobj.group(1)) + compat_urllib_parse.unquote(mobj.group(2))
-
-        video_file = self._search_regex('source=\'(.*?)\'', dec_data, u'video file')
-        video_file = compat_urllib_parse.unquote(video_file)
-
-        if not video_file.endswith('f4m'):
-            ppath, prefix = video_file.split('.')
-            video_playpath = '%s:%s' % (prefix, ppath)
-            video_hls_playlist = ''
-        else:
-            video_playpath = ''
-            video_hls_playlist = (
-                video_filepath + video_file
-            ).replace('.f4m', '.m3u8')
-
-        video_swfobj = self._search_regex('swfobject.embedSWF\(\'(.+?)\'', webpage, u'swfobj')
-        video_swfobj = compat_urllib_parse.unquote(video_swfobj)
-
-        video_title = self._html_search_regex("<h1(?: class='globalHd')?>(.*?)</h1>",
-            webpage, u'title')
-
-        return [{
-            'id':                 video_id,
-            'url':                video_url,
-            'tc_url':             video_url,
-            'uploader':           None,
-            'upload_date':        None,
-            'title':              video_title,
-            'ext':                u'flv',
-            'play_path':          video_playpath,
-            'video_file':         video_file,
-            'video_hls_playlist': video_hls_playlist,
-            'player_url':         video_swfobj,
-        }]
-
-
-class ComedyCentralIE(InfoExtractor):
-    """Information extractor for The Daily Show and Colbert Report """
-
-    # urls can be abbreviations like :thedailyshow or :colbert
-    # urls for episodes like:
-    # or urls for clips like: http://www.thedailyshow.com/watch/mon-december-10-2012/any-given-gun-day
-    #                     or: http://www.colbertnation.com/the-colbert-report-videos/421667/november-29-2012/moon-shattering-news
-    #                     or: http://www.colbertnation.com/the-colbert-report-collections/422008/festival-of-lights/79524
-    _VALID_URL = r"""^(:(?P<shortname>tds|thedailyshow|cr|colbert|colbertnation|colbertreport)
-                      |(https?://)?(www\.)?
-                          (?P<showname>thedailyshow|colbertnation)\.com/
-                         (full-episodes/(?P<episode>.*)|
-                          (?P<clip>
-                              (the-colbert-report-(videos|collections)/(?P<clipID>[0-9]+)/[^/]*/(?P<cntitle>.*?))
-                              |(watch/(?P<date>[^/]*)/(?P<tdstitle>.*)))))
-                     $"""
-
-    _available_formats = ['3500', '2200', '1700', '1200', '750', '400']
-
-    _video_extensions = {
-        '3500': 'mp4',
-        '2200': 'mp4',
-        '1700': 'mp4',
-        '1200': 'mp4',
-        '750': 'mp4',
-        '400': 'mp4',
-    }
-    _video_dimensions = {
-        '3500': '1280x720',
-        '2200': '960x540',
-        '1700': '768x432',
-        '1200': '640x360',
-        '750': '512x288',
-        '400': '384x216',
-    }
-
-    @classmethod
-    def suitable(cls, url):
-        """Receives a URL and returns True if suitable for this IE."""
-        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
-
-    def _print_formats(self, formats):
-        print('Available formats:')
-        for x in formats:
-            print('%s\t:\t%s\t[%s]' %(x, self._video_extensions.get(x, 'mp4'), self._video_dimensions.get(x, '???')))
-
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url, re.VERBOSE)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        if mobj.group('shortname'):
-            if mobj.group('shortname') in ('tds', 'thedailyshow'):
-                url = u'http://www.thedailyshow.com/full-episodes/'
-            else:
-                url = u'http://www.colbertnation.com/full-episodes/'
-            mobj = re.match(self._VALID_URL, url, re.VERBOSE)
-            assert mobj is not None
-
-        if mobj.group('clip'):
-            if mobj.group('showname') == 'thedailyshow':
-                epTitle = mobj.group('tdstitle')
-            else:
-                epTitle = mobj.group('cntitle')
-            dlNewest = False
-        else:
-            dlNewest = not mobj.group('episode')
-            if dlNewest:
-                epTitle = mobj.group('showname')
-            else:
-                epTitle = mobj.group('episode')
-
-        self.report_extraction(epTitle)
-        webpage,htmlHandle = self._download_webpage_handle(url, epTitle)
-        if dlNewest:
-            url = htmlHandle.geturl()
-            mobj = re.match(self._VALID_URL, url, re.VERBOSE)
-            if mobj is None:
-                raise ExtractorError(u'Invalid redirected URL: ' + url)
-            if mobj.group('episode') == '':
-                raise ExtractorError(u'Redirected URL is still not specific: ' + url)
-            epTitle = mobj.group('episode')
-
-        mMovieParams = re.findall('(?:<param name="movie" value="|var url = ")(http://media.mtvnservices.com/([^"]*(?:episode|video).*?:.*?))"', webpage)
-
-        if len(mMovieParams) == 0:
-            # The Colbert Report embeds the information in a without
-            # a URL prefix; so extract the alternate reference
-            # and then add the URL prefix manually.
-
-            altMovieParams = re.findall('data-mgid="([^"]*(?:episode|video).*?:.*?)"', webpage)
-            if len(altMovieParams) == 0:
-                raise ExtractorError(u'unable to find Flash URL in webpage ' + url)
-            else:
-                mMovieParams = [("http://media.mtvnservices.com/" + altMovieParams[0], altMovieParams[0])]
-
-        uri = mMovieParams[0][1]
-        indexUrl = 'http://shadow.comedycentral.com/feeds/video_player/mrss/?' + compat_urllib_parse.urlencode({'uri': uri})
-        indexXml = self._download_webpage(indexUrl, epTitle,
-                                          u'Downloading show index',
-                                          u'unable to download episode index')
-
-        results = []
-
-        idoc = xml.etree.ElementTree.fromstring(indexXml)
-        itemEls = idoc.findall('.//item')
-        for partNum,itemEl in enumerate(itemEls):
-            mediaId = itemEl.findall('./guid')[0].text
-            shortMediaId = mediaId.split(':')[-1]
-            showId = mediaId.split(':')[-2].replace('.com', '')
-            officialTitle = itemEl.findall('./title')[0].text
-            officialDate = unified_strdate(itemEl.findall('./pubDate')[0].text)
-
-            configUrl = ('http://www.comedycentral.com/global/feeds/entertainment/media/mediaGenEntertainment.jhtml?' +
-                        compat_urllib_parse.urlencode({'uri': mediaId}))
-            configXml = self._download_webpage(configUrl, epTitle,
-                                               u'Downloading configuration for %s' % shortMediaId)
-
-            cdoc = xml.etree.ElementTree.fromstring(configXml)
-            turls = []
-            for rendition in cdoc.findall('.//rendition'):
-                finfo = (rendition.attrib['bitrate'], rendition.findall('./src')[0].text)
-                turls.append(finfo)
-
-            if len(turls) == 0:
-                self._downloader.report_error(u'unable to download ' + mediaId + ': No videos found')
-                continue
-
-            if self._downloader.params.get('listformats', None):
-                self._print_formats([i[0] for i in turls])
-                return
-
-            # For now, just pick the highest bitrate
-            format,rtmp_video_url = turls[-1]
-
-            # Get the format arg from the arg stream
-            req_format = self._downloader.params.get('format', None)
-
-            # Select format if we can find one
-            for f,v in turls:
-                if f == req_format:
-                    format, rtmp_video_url = f, v
-                    break
-
-            m = re.match(r'^rtmpe?://.*?/(?P<finalid>gsp.comedystor/.*)$', rtmp_video_url)
-            if not m:
-                raise ExtractorError(u'Cannot transform RTMP url')
-            base = 'http://mtvnmobile.vo.llnwd.net/kip0/_pxn=1+_pxI0=Ripod-h264+_pxL0=undefined+_pxM0=+_pxK=18639+_pxE=mp4/44620/mtvnorigin/'
-            video_url = base + m.group('finalid')
-
-            effTitle = showId + u'-' + epTitle + u' part ' + compat_str(partNum+1)
-            info = {
-                'id': shortMediaId,
-                'url': video_url,
-                'uploader': showId,
-                'upload_date': officialDate,
-                'title': effTitle,
-                'ext': 'mp4',
-                'format': format,
-                'thumbnail': None,
-                'description': officialTitle,
-            }
-            results.append(info)
-
-        return results
-
-
-class EscapistIE(InfoExtractor):
-    """Information extractor for The Escapist """
-
-    _VALID_URL = r'^(https?://)?(www\.)?escapistmagazine\.com/videos/view/(?P<showname>[^/]+)/(?P<episode>[^/?]+)[/?]?.*$'
-    IE_NAME = u'escapist'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        showName = mobj.group('showname')
-        videoId = mobj.group('episode')
-
-        self.report_extraction(videoId)
-        webpage = self._download_webpage(url, videoId)
-
-        videoDesc = self._html_search_regex('<meta name="description" content="([^"]*)"',
-            webpage, u'description', fatal=False)
-
-        imgUrl = self._html_search_regex('<meta property="og:image" content="([^"]*)"',
-            webpage, u'thumbnail', fatal=False)
-
-        playerUrl = self._html_search_regex('<meta property="og:video" content="([^"]*)"',
-            webpage, u'player url')
-
-        title = self._html_search_regex('<meta name="title" content="([^"]*)"',
-            webpage, u'player url').split(' : ')[-1]
-
-        configUrl = self._search_regex('config=(.*)$', playerUrl, u'config url')
-        configUrl = compat_urllib_parse.unquote(configUrl)
-
-        configJSON = self._download_webpage(configUrl, videoId,
-                                            u'Downloading configuration',
-                                            u'unable to download configuration')
-
-        # Technically, it's JavaScript, not JSON
-        configJSON = configJSON.replace("'", '"')
-
-        try:
-            config = json.loads(configJSON)
-        except (ValueError,) as err:
-            raise ExtractorError(u'Invalid JSON in configuration file: ' + compat_str(err))
-
-        playlist = config['playlist']
-        videoUrl = playlist[1]['url']
-
-        info = {
-            'id': videoId,
-            'url': videoUrl,
-            'uploader': showName,
-            'upload_date': None,
-            'title': title,
-            'ext': 'mp4',
-            'thumbnail': imgUrl,
-            'description': videoDesc,
-            'player_url': playerUrl,
-        }
-
-        return [info]
-
-class CollegeHumorIE(InfoExtractor):
-    """Information extractor for collegehumor.com"""
-
-    _WORKING = False
-    _VALID_URL = r'^(?:https?://)?(?:www\.)?collegehumor\.com/video/(?P<videoid>[0-9]+)/(?P<shorttitle>.*)$'
-    IE_NAME = u'collegehumor'
-
-    def report_manifest(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Downloading XML manifest' % video_id)
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group('videoid')
-
-        info = {
-            'id': video_id,
-            'uploader': None,
-            'upload_date': None,
-        }
-
-        self.report_extraction(video_id)
-        xmlUrl = 'http://www.collegehumor.com/moogaloop/video/' + video_id
-        try:
-            metaXml = compat_urllib_request.urlopen(xmlUrl).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to download video info XML: %s' % compat_str(err))
-
-        mdoc = xml.etree.ElementTree.fromstring(metaXml)
-        try:
-            videoNode = mdoc.findall('./video')[0]
-            info['description'] = videoNode.findall('./description')[0].text
-            info['title'] = videoNode.findall('./caption')[0].text
-            info['thumbnail'] = videoNode.findall('./thumbnail')[0].text
-            manifest_url = videoNode.findall('./file')[0].text
-        except IndexError:
-            raise ExtractorError(u'Invalid metadata XML file')
-
-        manifest_url += '?hdcore=2.10.3'
-        self.report_manifest(video_id)
-        try:
-            manifestXml = compat_urllib_request.urlopen(manifest_url).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to download video info XML: %s' % compat_str(err))
-
-        adoc = xml.etree.ElementTree.fromstring(manifestXml)
-        try:
-            media_node = adoc.findall('./{http://ns.adobe.com/f4m/1.0}media')[0]
-            node_id = media_node.attrib['url']
-            video_id = adoc.findall('./{http://ns.adobe.com/f4m/1.0}id')[0].text
-        except IndexError as err:
-            raise ExtractorError(u'Invalid manifest file')
-
-        url_pr = compat_urllib_parse_urlparse(manifest_url)
-        url = url_pr.scheme + '://' + url_pr.netloc + '/z' + video_id[:-2] + '/' + node_id + 'Seg1-Frag1'
-
-        info['url'] = url
-        info['ext'] = 'f4f'
-        return [info]
-
-
-class XVideosIE(InfoExtractor):
-    """Information extractor for xvideos.com"""
-
-    _VALID_URL = r'^(?:https?://)?(?:www\.)?xvideos\.com/video([0-9]+)(?:.*)'
-    IE_NAME = u'xvideos'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group(1)
-
-        webpage = self._download_webpage(url, video_id)
-
-        self.report_extraction(video_id)
-
-        # Extract video URL
-        video_url = compat_urllib_parse.unquote(self._search_regex(r'flv_url=(.+?)&',
-            webpage, u'video URL'))
-
-        # Extract title
-        video_title = self._html_search_regex(r'<title>(.*?)\s+-\s+XVID',
-            webpage, u'title')
-
-        # Extract video thumbnail
-        video_thumbnail = self._search_regex(r'http://(?:img.*?\.)xvideos.com/videos/thumbs/[a-fA-F0-9]+/[a-fA-F0-9]+/[a-fA-F0-9]+/[a-fA-F0-9]+/([a-fA-F0-9.]+jpg)',
-            webpage, u'thumbnail', fatal=False)
-
-        info = {
-            'id': video_id,
-            'url': video_url,
-            'uploader': None,
-            'upload_date': None,
-            'title': video_title,
-            'ext': 'flv',
-            'thumbnail': video_thumbnail,
-            'description': None,
-        }
-
-        return [info]
-
-
-class SoundcloudIE(InfoExtractor):
-    """Information extractor for soundcloud.com
-       To access the media, the uid of the song and a stream token
-       must be extracted from the page source and the script must make
-       a request to media.soundcloud.com/crossdomain.xml. Then
-       the media can be grabbed by requesting from an url composed
-       of the stream token and uid
-     """
-
-    _VALID_URL = r'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/([\w\d-]+)'
-    IE_NAME = u'soundcloud'
-
-    def report_resolve(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Resolving id' % video_id)
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        # extract uploader (which is in the url)
-        uploader = mobj.group(1)
-        # extract simple title (uploader + slug of song title)
-        slug_title =  mobj.group(2)
-        simple_title = uploader + u'-' + slug_title
-        full_title = '%s/%s' % (uploader, slug_title)
-
-        self.report_resolve(full_title)
-
-        url = 'http://soundcloud.com/%s/%s' % (uploader, slug_title)
-        resolv_url = 'http://api.soundcloud.com/resolve.json?url=' + url + '&client_id=b45b1aa10f1ac2941910a7f0d10f8e28'
-        info_json = self._download_webpage(resolv_url, full_title, u'Downloading info JSON')
-
-        info = json.loads(info_json)
-        video_id = info['id']
-        self.report_extraction(full_title)
-
-        streams_url = 'https://api.sndcdn.com/i1/tracks/' + str(video_id) + '/streams?client_id=b45b1aa10f1ac2941910a7f0d10f8e28'
-        stream_json = self._download_webpage(streams_url, full_title,
-                                             u'Downloading stream definitions',
-                                             u'unable to download stream definitions')
-
-        streams = json.loads(stream_json)
-        mediaURL = streams['http_mp3_128_url']
-        upload_date = unified_strdate(info['created_at'])
-
-        return [{
-            'id':       info['id'],
-            'url':      mediaURL,
-            'uploader': info['user']['username'],
-            'upload_date': upload_date,
-            'title':    info['title'],
-            'ext':      u'mp3',
-            'description': info['description'],
-        }]
-
-class SoundcloudSetIE(InfoExtractor):
-    """Information extractor for soundcloud.com sets
-       To access the media, the uid of the song and a stream token
-       must be extracted from the page source and the script must make
-       a request to media.soundcloud.com/crossdomain.xml. Then
-       the media can be grabbed by requesting from an url composed
-       of the stream token and uid
-     """
-
-    _VALID_URL = r'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/sets/([\w\d-]+)'
-    IE_NAME = u'soundcloud:set'
-
-    def report_resolve(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Resolving id' % video_id)
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        # extract uploader (which is in the url)
-        uploader = mobj.group(1)
-        # extract simple title (uploader + slug of song title)
-        slug_title =  mobj.group(2)
-        simple_title = uploader + u'-' + slug_title
-        full_title = '%s/sets/%s' % (uploader, slug_title)
-
-        self.report_resolve(full_title)
-
-        url = 'http://soundcloud.com/%s/sets/%s' % (uploader, slug_title)
-        resolv_url = 'http://api.soundcloud.com/resolve.json?url=' + url + '&client_id=b45b1aa10f1ac2941910a7f0d10f8e28'
-        info_json = self._download_webpage(resolv_url, full_title)
-
-        videos = []
-        info = json.loads(info_json)
-        if 'errors' in info:
-            for err in info['errors']:
-                self._downloader.report_error(u'unable to download video webpage: %s' % compat_str(err['error_message']))
-            return
-
-        self.report_extraction(full_title)
-        for track in info['tracks']:
-            video_id = track['id']
-
-            streams_url = 'https://api.sndcdn.com/i1/tracks/' + str(video_id) + '/streams?client_id=b45b1aa10f1ac2941910a7f0d10f8e28'
-            stream_json = self._download_webpage(streams_url, video_id, u'Downloading track info JSON')
-
-            self.report_extraction(video_id)
-            streams = json.loads(stream_json)
-            mediaURL = streams['http_mp3_128_url']
-
-            videos.append({
-                'id':       video_id,
-                'url':      mediaURL,
-                'uploader': track['user']['username'],
-                'upload_date':  unified_strdate(track['created_at']),
-                'title':    track['title'],
-                'ext':      u'mp3',
-                'description': track['description'],
-            })
-        return videos
-
-
-class InfoQIE(InfoExtractor):
-    """Information extractor for infoq.com"""
-    _VALID_URL = r'^(?:https?://)?(?:www\.)?infoq\.com/[^/]+/[^/]+$'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        webpage = self._download_webpage(url, video_id=url)
-        self.report_extraction(url)
-
-        # Extract video URL
-        mobj = re.search(r"jsclassref ?= ?'([^']*)'", webpage)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract video url')
-        real_id = compat_urllib_parse.unquote(base64.b64decode(mobj.group(1).encode('ascii')).decode('utf-8'))
-        video_url = 'rtmpe://video.infoq.com/cfx/st/' + real_id
-
-        # Extract title
-        video_title = self._search_regex(r'contentTitle = "(.*?)";',
-            webpage, u'title')
-
-        # Extract description
-        video_description = self._html_search_regex(r'<meta name="description" content="(.*)"(?:\s*/)?>',
-            webpage, u'description', fatal=False)
-
-        video_filename = video_url.split('/')[-1]
-        video_id, extension = video_filename.split('.')
-
-        info = {
-            'id': video_id,
-            'url': video_url,
-            'uploader': None,
-            'upload_date': None,
-            'title': video_title,
-            'ext': extension, # Extension is always(?) mp4, but seems to be flv
-            'thumbnail': None,
-            'description': video_description,
-        }
-
-        return [info]
-
-class MixcloudIE(InfoExtractor):
-    """Information extractor for www.mixcloud.com"""
-
-    _WORKING = False # New API, but it seems good http://www.mixcloud.com/developers/documentation/
-    _VALID_URL = r'^(?:https?://)?(?:www\.)?mixcloud\.com/([\w\d-]+)/([\w\d-]+)'
-    IE_NAME = u'mixcloud'
-
-    def report_download_json(self, file_id):
-        """Report JSON download."""
-        self.to_screen(u'Downloading json')
-
-    def get_urls(self, jsonData, fmt, bitrate='best'):
-        """Get urls from 'audio_formats' section in json"""
-        file_url = None
-        try:
-            bitrate_list = jsonData[fmt]
-            if bitrate is None or bitrate == 'best' or bitrate not in bitrate_list:
-                bitrate = max(bitrate_list) # select highest
-
-            url_list = jsonData[fmt][bitrate]
-        except TypeError: # we have no bitrate info.
-            url_list = jsonData[fmt]
-        return url_list
-
-    def check_urls(self, url_list):
-        """Returns 1st active url from list"""
-        for url in url_list:
-            try:
-                compat_urllib_request.urlopen(url)
-                return url
-            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-                url = None
-
-        return None
-
-    def _print_formats(self, formats):
-        print('Available formats:')
-        for fmt in formats.keys():
-            for b in formats[fmt]:
-                try:
-                    ext = formats[fmt][b][0]
-                    print('%s\t%s\t[%s]' % (fmt, b, ext.split('.')[-1]))
-                except TypeError: # we have no bitrate info
-                    ext = formats[fmt][0]
-                    print('%s\t%s\t[%s]' % (fmt, '??', ext.split('.')[-1]))
-                    break
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        # extract uploader & filename from url
-        uploader = mobj.group(1).decode('utf-8')
-        file_id = uploader + "-" + mobj.group(2).decode('utf-8')
-
-        # construct API request
-        file_url = 'http://www.mixcloud.com/api/1/cloudcast/' + '/'.join(url.split('/')[-3:-1]) + '.json'
-        # retrieve .json file with links to files
-        request = compat_urllib_request.Request(file_url)
-        try:
-            self.report_download_json(file_url)
-            jsonData = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to retrieve file: %s' % compat_str(err))
-
-        # parse JSON
-        json_data = json.loads(jsonData)
-        player_url = json_data['player_swf_url']
-        formats = dict(json_data['audio_formats'])
-
-        req_format = self._downloader.params.get('format', None)
-        bitrate = None
-
-        if self._downloader.params.get('listformats', None):
-            self._print_formats(formats)
-            return
-
-        if req_format is None or req_format == 'best':
-            for format_param in formats.keys():
-                url_list = self.get_urls(formats, format_param)
-                # check urls
-                file_url = self.check_urls(url_list)
-                if file_url is not None:
-                    break # got it!
-        else:
-            if req_format not in formats:
-                raise ExtractorError(u'Format is not available')
-
-            url_list = self.get_urls(formats, req_format)
-            file_url = self.check_urls(url_list)
-            format_param = req_format
-
-        return [{
-            'id': file_id.decode('utf-8'),
-            'url': file_url.decode('utf-8'),
-            'uploader': uploader.decode('utf-8'),
-            'upload_date': None,
-            'title': json_data['name'],
-            'ext': file_url.split('.')[-1].decode('utf-8'),
-            'format': (format_param is None and u'NA' or format_param.decode('utf-8')),
-            'thumbnail': json_data['thumbnail_url'],
-            'description': json_data['description'],
-            'player_url': player_url.decode('utf-8'),
-        }]
-
-class StanfordOpenClassroomIE(InfoExtractor):
-    """Information extractor for Stanford's Open ClassRoom"""
-
-    _VALID_URL = r'^(?:https?://)?openclassroom.stanford.edu(?P<path>/?|(/MainFolder/(?:HomePage|CoursePage|VideoPage)\.php([?]course=(?P<course>[^&]+)(&video=(?P<video>[^&]+))?(&.*)?)?))$'
-    IE_NAME = u'stanfordoc'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        if mobj.group('course') and mobj.group('video'): # A specific video
-            course = mobj.group('course')
-            video = mobj.group('video')
-            info = {
-                'id': course + '_' + video,
-                'uploader': None,
-                'upload_date': None,
-            }
-
-            self.report_extraction(info['id'])
-            baseUrl = 'http://openclassroom.stanford.edu/MainFolder/courses/' + course + '/videos/'
-            xmlUrl = baseUrl + video + '.xml'
-            try:
-                metaXml = compat_urllib_request.urlopen(xmlUrl).read()
-            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-                raise ExtractorError(u'Unable to download video info XML: %s' % compat_str(err))
-            mdoc = xml.etree.ElementTree.fromstring(metaXml)
-            try:
-                info['title'] = mdoc.findall('./title')[0].text
-                info['url'] = baseUrl + mdoc.findall('./videoFile')[0].text
-            except IndexError:
-                raise ExtractorError(u'Invalid metadata XML file')
-            info['ext'] = info['url'].rpartition('.')[2]
-            return [info]
-        elif mobj.group('course'): # A course page
-            course = mobj.group('course')
-            info = {
-                'id': course,
-                'type': 'playlist',
-                'uploader': None,
-                'upload_date': None,
-            }
-
-            coursepage = self._download_webpage(url, info['id'],
-                                        note='Downloading course info page',
-                                        errnote='Unable to download course info page')
-
-            info['title'] = self._html_search_regex('<h1>([^<]+)</h1>', coursepage, 'title', default=info['id'])
-
-            info['description'] = self._html_search_regex('<description>([^<]+)</description>',
-                coursepage, u'description', fatal=False)
-
-            links = orderedSet(re.findall('<a href="(VideoPage.php\?[^"]+)">', coursepage))
-            info['list'] = [
-                {
-                    'type': 'reference',
-                    'url': 'http://openclassroom.stanford.edu/MainFolder/' + unescapeHTML(vpage),
-                }
-                    for vpage in links]
-            results = []
-            for entry in info['list']:
-                assert entry['type'] == 'reference'
-                results += self.extract(entry['url'])
-            return results
-        else: # Root page
-            info = {
-                'id': 'Stanford OpenClassroom',
-                'type': 'playlist',
-                'uploader': None,
-                'upload_date': None,
-            }
-
-            self.report_download_webpage(info['id'])
-            rootURL = 'http://openclassroom.stanford.edu/MainFolder/HomePage.php'
-            try:
-                rootpage = compat_urllib_request.urlopen(rootURL).read()
-            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-                raise ExtractorError(u'Unable to download course info page: ' + compat_str(err))
-
-            info['title'] = info['id']
-
-            links = orderedSet(re.findall('<a href="(CoursePage.php\?[^"]+)">', rootpage))
-            info['list'] = [
-                {
-                    'type': 'reference',
-                    'url': 'http://openclassroom.stanford.edu/MainFolder/' + unescapeHTML(cpage),
-                }
-                    for cpage in links]
-
-            results = []
-            for entry in info['list']:
-                assert entry['type'] == 'reference'
-                results += self.extract(entry['url'])
-            return results
-
-class MTVIE(InfoExtractor):
-    """Information extractor for MTV.com"""
-
-    _VALID_URL = r'^(?P<proto>https?://)?(?:www\.)?mtv\.com/videos/[^/]+/(?P<videoid>[0-9]+)/[^/]+$'
-    IE_NAME = u'mtv'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        if not mobj.group('proto'):
-            url = 'http://' + url
-        video_id = mobj.group('videoid')
-
-        webpage = self._download_webpage(url, video_id)
-
-        song_name = self._html_search_regex(r'<meta name="mtv_vt" content="([^"]+)"/>',
-            webpage, u'song name', fatal=False)
-
-        video_title = self._html_search_regex(r'<meta name="mtv_an" content="([^"]+)"/>',
-            webpage, u'title')
-
-        mtvn_uri = self._html_search_regex(r'<meta name="mtvn_uri" content="([^"]+)"/>',
-            webpage, u'mtvn_uri', fatal=False)
-
-        content_id = self._search_regex(r'MTVN.Player.defaultPlaylistId = ([0-9]+);',
-            webpage, u'content id', fatal=False)
-
-        videogen_url = 'http://www.mtv.com/player/includes/mediaGen.jhtml?uri=' + mtvn_uri + '&id=' + content_id + '&vid=' + video_id + '&ref=www.mtvn.com&viewUri=' + mtvn_uri
-        self.report_extraction(video_id)
-        request = compat_urllib_request.Request(videogen_url)
-        try:
-            metadataXml = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            raise ExtractorError(u'Unable to download video metadata: %s' % compat_str(err))
-
-        mdoc = xml.etree.ElementTree.fromstring(metadataXml)
-        renditions = mdoc.findall('.//rendition')
-
-        # For now, always pick the highest quality.
-        rendition = renditions[-1]
-
-        try:
-            _,_,ext = rendition.attrib['type'].partition('/')
-            format = ext + '-' + rendition.attrib['width'] + 'x' + rendition.attrib['height'] + '_' + rendition.attrib['bitrate']
-            video_url = rendition.find('./src').text
-        except KeyError:
-            raise ExtractorError('Invalid rendition field.')
-
-        info = {
-            'id': video_id,
-            'url': video_url,
-            'uploader': performer,
-            'upload_date': None,
-            'title': video_title,
-            'ext': ext,
-            'format': format,
-        }
-
-        return [info]
-
-
-class YoukuIE(InfoExtractor):
-    _VALID_URL =  r'(?:http://)?v\.youku\.com/v_show/id_(?P<ID>[A-Za-z0-9]+)\.html'
-
-    def _gen_sid(self):
-        nowTime = int(time.time() * 1000)
-        random1 = random.randint(1000,1998)
-        random2 = random.randint(1000,9999)
-
-        return "%d%d%d" %(nowTime,random1,random2)
-
-    def _get_file_ID_mix_string(self, seed):
-        mixed = []
-        source = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\:._-1234567890")
-        seed = float(seed)
-        for i in range(len(source)):
-            seed  =  (seed * 211 + 30031 ) % 65536
-            index  =  math.floor(seed / 65536 * len(source) )
-            mixed.append(source[int(index)])
-            source.remove(source[int(index)])
-        #return ''.join(mixed)
-        return mixed
-
-    def _get_file_id(self, fileId, seed):
-        mixed = self._get_file_ID_mix_string(seed)
-        ids = fileId.split('*')
-        realId = []
-        for ch in ids:
-            if ch:
-                realId.append(mixed[int(ch)])
-        return ''.join(realId)
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group('ID')
-
-        info_url = 'http://v.youku.com/player/getPlayList/VideoIDS/' + video_id
-
-        jsondata = self._download_webpage(info_url, video_id)
-
-        self.report_extraction(video_id)
-        try:
-            config = json.loads(jsondata)
-
-            video_title =  config['data'][0]['title']
-            seed = config['data'][0]['seed']
-
-            format = self._downloader.params.get('format', None)
-            supported_format = list(config['data'][0]['streamfileids'].keys())
-
-            if format is None or format == 'best':
-                if 'hd2' in supported_format:
-                    format = 'hd2'
-                else:
-                    format = 'flv'
-                ext = u'flv'
-            elif format == 'worst':
-                format = 'mp4'
-                ext = u'mp4'
-            else:
-                format = 'flv'
-                ext = u'flv'
-
-
-            fileid = config['data'][0]['streamfileids'][format]
-            keys = [s['k'] for s in config['data'][0]['segs'][format]]
-        except (UnicodeDecodeError, ValueError, KeyError):
-            raise ExtractorError(u'Unable to extract info section')
-
-        files_info=[]
-        sid = self._gen_sid()
-        fileid = self._get_file_id(fileid, seed)
-
-        #column 8,9 of fileid represent the segment number
-        #fileid[7:9] should be changed
-        for index, key in enumerate(keys):
-
-            temp_fileid = '%s%02X%s' % (fileid[0:8], index, fileid[10:])
-            download_url = 'http://f.youku.com/player/getFlvPath/sid/%s_%02X/st/flv/fileid/%s?k=%s' % (sid, index, temp_fileid, key)
-
-            info = {
-                'id': '%s_part%02d' % (video_id, index),
-                'url': download_url,
-                'uploader': None,
-                'upload_date': None,
-                'title': video_title,
-                'ext': ext,
-            }
-            files_info.append(info)
-
-        return files_info
-
-
-class XNXXIE(InfoExtractor):
-    """Information extractor for xnxx.com"""
-
-    _VALID_URL = r'^(?:https?://)?video\.xnxx\.com/video([0-9]+)/(.*)'
-    IE_NAME = u'xnxx'
-    VIDEO_URL_RE = r'flv_url=(.*?)&amp;'
-    VIDEO_TITLE_RE = r'<title>(.*?)\s+-\s+XNXX.COM'
-    VIDEO_THUMB_RE = r'url_bigthumb=(.*?)&amp;'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group(1)
-
-        # Get webpage content
-        webpage = self._download_webpage(url, video_id)
-
-        video_url = self._search_regex(self.VIDEO_URL_RE,
-            webpage, u'video URL')
-        video_url = compat_urllib_parse.unquote(video_url)
-
-        video_title = self._html_search_regex(self.VIDEO_TITLE_RE,
-            webpage, u'title')
-
-        video_thumbnail = self._search_regex(self.VIDEO_THUMB_RE,
-            webpage, u'thumbnail', fatal=False)
-
-        return [{
-            'id': video_id,
-            'url': video_url,
-            'uploader': None,
-            'upload_date': None,
-            'title': video_title,
-            'ext': 'flv',
-            'thumbnail': video_thumbnail,
-            'description': None,
-        }]
-
-
-class GooglePlusIE(InfoExtractor):
-    """Information extractor for plus.google.com."""
-
-    _VALID_URL = r'(?:https://)?plus\.google\.com/(?:[^/]+/)*?posts/(\w+)'
-    IE_NAME = u'plus.google'
-
-    def _real_extract(self, url):
-        # Extract id from URL
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        post_url = mobj.group(0)
-        video_id = mobj.group(1)
-
-        video_extension = 'flv'
-
-        # Step 1, Retrieve post webpage to extract further information
-        webpage = self._download_webpage(post_url, video_id, u'Downloading entry webpage')
-
-        self.report_extraction(video_id)
-
-        # Extract update date
-        upload_date = self._html_search_regex('title="Timestamp">(.*?)</a>',
-            webpage, u'upload date', fatal=False)
-        if upload_date:
-            # Convert timestring to a format suitable for filename
-            upload_date = datetime.datetime.strptime(upload_date, "%Y-%m-%d")
-            upload_date = upload_date.strftime('%Y%m%d')
-
-        # Extract uploader
-        uploader = self._html_search_regex(r'rel\="author".*?>(.*?)</a>',
-            webpage, u'uploader', fatal=False)
-
-        # Extract title
-        # Get the first line for title
-        video_title = self._html_search_regex(r'<meta name\=\"Description\" content\=\"(.*?)[\n<"]',
-            webpage, 'title', default=u'NA')
-
-        # Step 2, Stimulate clicking the image box to launch video
-        video_page = self._search_regex('"(https\://plus\.google\.com/photos/.*?)",,"image/jpeg","video"\]',
-            webpage, u'video page URL')
-        webpage = self._download_webpage(video_page, video_id, u'Downloading video page')
-
-        # Extract video links on video page
-        """Extract video links of all sizes"""
-        pattern = '\d+,\d+,(\d+),"(http\://redirector\.googlevideo\.com.*?)"'
-        mobj = re.findall(pattern, webpage)
-        if len(mobj) == 0:
-            raise ExtractorError(u'Unable to extract video links')
-
-        # Sort in resolution
-        links = sorted(mobj)
-
-        # Choose the lowest of the sort, i.e. highest resolution
-        video_url = links[-1]
-        # Only get the url. The resolution part in the tuple has no use anymore
-        video_url = video_url[-1]
-        # Treat escaped \u0026 style hex
-        try:
-            video_url = video_url.decode("unicode_escape")
-        except AttributeError: # Python 3
-            video_url = bytes(video_url, 'ascii').decode('unicode-escape')
-
-
-        return [{
-            'id':       video_id,
-            'url':      video_url,
-            'uploader': uploader,
-            'upload_date':  upload_date,
-            'title':    video_title,
-            'ext':      video_extension,
-        }]
-
-class NBAIE(InfoExtractor):
-    _VALID_URL = r'^(?:https?://)?(?:watch\.|www\.)?nba\.com/(?:nba/)?video(/[^?]*?)(?:/index\.html)?(?:\?.*)?$'
-    IE_NAME = u'nba'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group(1)
-
-        webpage = self._download_webpage(url, video_id)
-
-        video_url = u'http://ht-mobile.cdn.turner.com/nba/big' + video_id + '_nba_1280x720.mp4'
-
-        shortened_video_id = video_id.rpartition('/')[2]
-        title = self._html_search_regex(r'<meta property="og:title" content="(.*?)"',
-            webpage, 'title', default=shortened_video_id).replace('NBA.com: ', '')
-
-        # It isn't there in the HTML it returns to us
-        # uploader_date = self._html_search_regex(r'<b>Date:</b> (.*?)</div>', webpage, 'upload_date', fatal=False)
-
-        description = self._html_search_regex(r'<meta name="description" (?:content|value)="(.*?)" />', webpage, 'description', fatal=False)
-
-        info = {
-            'id': shortened_video_id,
-            'url': video_url,
-            'ext': 'mp4',
-            'title': title,
-            # 'uploader_date': uploader_date,
-            'description': description,
-        }
-        return [info]
-
-class JustinTVIE(InfoExtractor):
-    """Information extractor for justin.tv and twitch.tv"""
-    # TODO: One broadcast may be split into multiple videos. The key
-    # 'broadcast_id' is the same for all parts, and 'broadcast_part'
-    # starts at 1 and increases. Can we treat all parts as one video?
-
-    _VALID_URL = r"""(?x)^(?:http://)?(?:www\.)?(?:twitch|justin)\.tv/
-        (?:
-            (?P<channelid>[^/]+)|
-            (?:(?:[^/]+)/b/(?P<videoid>[^/]+))|
-            (?:(?:[^/]+)/c/(?P<chapterid>[^/]+))
-        )
-        /?(?:\#.*)?$
-        """
-    _JUSTIN_PAGE_LIMIT = 100
-    IE_NAME = u'justin.tv'
-
-    def report_download_page(self, channel, offset):
-        """Report attempt to download a single page of videos."""
-        self.to_screen(u'%s: Downloading video information from %d to %d' %
-                (channel, offset, offset + self._JUSTIN_PAGE_LIMIT))
-
-    # Return count of items, list of *valid* items
-    def _parse_page(self, url, video_id):
-        webpage = self._download_webpage(url, video_id,
-                                         u'Downloading video info JSON',
-                                         u'unable to download video info JSON')
-
-        response = json.loads(webpage)
-        if type(response) != list:
-            error_text = response.get('error', 'unknown error')
-            raise ExtractorError(u'Justin.tv API: %s' % error_text)
-        info = []
-        for clip in response:
-            video_url = clip['video_file_url']
-            if video_url:
-                video_extension = os.path.splitext(video_url)[1][1:]
-                video_date = re.sub('-', '', clip['start_time'][:10])
-                video_uploader_id = clip.get('user_id', clip.get('channel_id'))
-                video_id = clip['id']
-                video_title = clip.get('title', video_id)
-                info.append({
-                    'id': video_id,
-                    'url': video_url,
-                    'title': video_title,
-                    'uploader': clip.get('channel_name', video_uploader_id),
-                    'uploader_id': video_uploader_id,
-                    'upload_date': video_date,
-                    'ext': video_extension,
-                })
-        return (len(response), info)
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'invalid URL: %s' % url)
-
-        api_base = 'http://api.justin.tv'
-        paged = False
-        if mobj.group('channelid'):
-            paged = True
-            video_id = mobj.group('channelid')
-            api = api_base + '/channel/archives/%s.json' % video_id
-        elif mobj.group('chapterid'):
-            chapter_id = mobj.group('chapterid')
-
-            webpage = self._download_webpage(url, chapter_id)
-            m = re.search(r'PP\.archive_id = "([0-9]+)";', webpage)
-            if not m:
-                raise ExtractorError(u'Cannot find archive of a chapter')
-            archive_id = m.group(1)
-
-            api = api_base + '/broadcast/by_chapter/%s.xml' % chapter_id
-            chapter_info_xml = self._download_webpage(api, chapter_id,
-                                             note=u'Downloading chapter information',
-                                             errnote=u'Chapter information download failed')
-            doc = xml.etree.ElementTree.fromstring(chapter_info_xml)
-            for a in doc.findall('.//archive'):
-                if archive_id == a.find('./id').text:
-                    break
-            else:
-                raise ExtractorError(u'Could not find chapter in chapter information')
-
-            video_url = a.find('./video_file_url').text
-            video_ext = video_url.rpartition('.')[2] or u'flv'
-
-            chapter_api_url = u'https://api.twitch.tv/kraken/videos/c' + chapter_id
-            chapter_info_json = self._download_webpage(chapter_api_url, u'c' + chapter_id,
-                                   note='Downloading chapter metadata',
-                                   errnote='Download of chapter metadata failed')
-            chapter_info = json.loads(chapter_info_json)
-
-            bracket_start = int(doc.find('.//bracket_start').text)
-            bracket_end = int(doc.find('.//bracket_end').text)
-
-            # TODO determine start (and probably fix up file)
-            #  youtube-dl -v http://www.twitch.tv/firmbelief/c/1757457
-            #video_url += u'?start=' + TODO:start_timestamp
-            # bracket_start is 13290, but we want 51670615
-            self._downloader.report_warning(u'Chapter detected, but we can just download the whole file. '
-                                            u'Chapter starts at %s and ends at %s' % (formatSeconds(bracket_start), formatSeconds(bracket_end)))
-
-            info = {
-                'id': u'c' + chapter_id,
-                'url': video_url,
-                'ext': video_ext,
-                'title': chapter_info['title'],
-                'thumbnail': chapter_info['preview'],
-                'description': chapter_info['description'],
-                'uploader': chapter_info['channel']['display_name'],
-                'uploader_id': chapter_info['channel']['name'],
-            }
-            return [info]
-        else:
-            video_id = mobj.group('videoid')
-            api = api_base + '/broadcast/by_archive/%s.json' % video_id
-
-        self.report_extraction(video_id)
-
-        info = []
-        offset = 0
-        limit = self._JUSTIN_PAGE_LIMIT
-        while True:
-            if paged:
-                self.report_download_page(video_id, offset)
-            page_url = api + ('?offset=%d&limit=%d' % (offset, limit))
-            page_count, page_info = self._parse_page(page_url, video_id)
-            info.extend(page_info)
-            if not paged or page_count != limit:
-                break
-            offset += limit
-        return info
-
-class FunnyOrDieIE(InfoExtractor):
-    _VALID_URL = r'^(?:https?://)?(?:www\.)?funnyordie\.com/videos/(?P<id>[0-9a-f]+)/.*$'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'invalid URL: %s' % url)
-
-        video_id = mobj.group('id')
-        webpage = self._download_webpage(url, video_id)
-
-        video_url = self._html_search_regex(r'<video[^>]*>\s*<source[^>]*>\s*<source src="(?P<url>[^"]+)"',
-            webpage, u'video URL', flags=re.DOTALL)
-
-        title = self._html_search_regex((r"<h1 class='player_page_h1'.*?>(?P<title>.*?)</h1>",
-            r'<title>(?P<title>[^<]+?)</title>'), webpage, 'title', flags=re.DOTALL)
-
-        video_description = self._html_search_regex(r'<meta property="og:description" content="(?P<desc>.*?)"',
-            webpage, u'description', fatal=False, flags=re.DOTALL)
-
-        info = {
-            'id': video_id,
-            'url': video_url,
-            'ext': 'mp4',
-            'title': title,
-            'description': video_description,
-        }
-        return [info]
-
-class SteamIE(InfoExtractor):
-    _VALID_URL = r"""http://store\.steampowered\.com/
-                (agecheck/)?
-                (?P<urltype>video|app)/ #If the page is only for videos or for a game
-                (?P<gameID>\d+)/?
-                (?P<videoID>\d*)(?P<extra>\??) #For urltype == video we sometimes get the videoID
-                """
-    _VIDEO_PAGE_TEMPLATE = 'http://store.steampowered.com/video/%s/'
-    _AGECHECK_TEMPLATE = 'http://store.steampowered.com/agecheck/video/%s/?snr=1_agecheck_agecheck__age-gate&ageDay=1&ageMonth=January&ageYear=1970'
-
-    @classmethod
-    def suitable(cls, url):
-        """Receives a URL and returns True if suitable for this IE."""
-        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
-
-    def _real_extract(self, url):
-        m = re.match(self._VALID_URL, url, re.VERBOSE)
-        gameID = m.group('gameID')
-
-        videourl = self._VIDEO_PAGE_TEMPLATE % gameID
-        webpage = self._download_webpage(videourl, gameID)
-
-        if re.search('<h2>Please enter your birth date to continue:</h2>', webpage) is not None:
-            videourl = self._AGECHECK_TEMPLATE % gameID
-            self.report_age_confirmation()
-            webpage = self._download_webpage(videourl, gameID)
-
-        self.report_extraction(gameID)
-        game_title = self._html_search_regex(r'<h2 class="pageheader">(.*?)</h2>',
-                                             webpage, 'game title')
-
-        urlRE = r"'movie_(?P<videoID>\d+)': \{\s*FILENAME: \"(?P<videoURL>[\w:/\.\?=]+)\"(,\s*MOVIE_NAME: \"(?P<videoName>[\w:/\.\?=\+-]+)\")?\s*\},"
-        mweb = re.finditer(urlRE, webpage)
-        namesRE = r'<span class="title">(?P<videoName>.+?)</span>'
-        titles = re.finditer(namesRE, webpage)
-        thumbsRE = r'<img class="movie_thumb" src="(?P<thumbnail>.+?)">'
-        thumbs = re.finditer(thumbsRE, webpage)
-        videos = []
-        for vid,vtitle,thumb in zip(mweb,titles,thumbs):
-            video_id = vid.group('videoID')
-            title = vtitle.group('videoName')
-            video_url = vid.group('videoURL')
-            video_thumb = thumb.group('thumbnail')
-            if not video_url:
-                raise ExtractorError(u'Cannot find video url for %s' % video_id)
-            info = {
-                'id':video_id,
-                'url':video_url,
-                'ext': 'flv',
-                'title': unescapeHTML(title),
-                'thumbnail': video_thumb
-                  }
-            videos.append(info)
-        return [self.playlist_result(videos, gameID, game_title)]
-
-class UstreamIE(InfoExtractor):
-    _VALID_URL = r'https?://www\.ustream\.tv/recorded/(?P<videoID>\d+)'
-    IE_NAME = u'ustream'
-
-    def _real_extract(self, url):
-        m = re.match(self._VALID_URL, url)
-        video_id = m.group('videoID')
-
-        video_url = u'http://tcdn.ustream.tv/video/%s' % video_id
-        webpage = self._download_webpage(url, video_id)
-
-        self.report_extraction(video_id)
-
-        video_title = self._html_search_regex(r'data-title="(?P<title>.+)"',
-            webpage, u'title')
-
-        uploader = self._html_search_regex(r'data-content-type="channel".*?>(?P<uploader>.*?)</a>',
-            webpage, u'uploader', fatal=False, flags=re.DOTALL)
-
-        thumbnail = self._html_search_regex(r'<link rel="image_src" href="(?P<thumb>.*?)"',
-            webpage, u'thumbnail', fatal=False)
-
-        info = {
-                'id': video_id,
-                'url': video_url,
-                'ext': 'flv',
-                'title': video_title,
-                'uploader': uploader,
-                'thumbnail': thumbnail,
-               }
-        return info
-
-class WorldStarHipHopIE(InfoExtractor):
-    _VALID_URL = r'https?://(?:www|m)\.worldstar(?:candy|hiphop)\.com/videos/video\.php\?v=(?P<id>.*)'
-    IE_NAME = u'WorldStarHipHop'
-
-    def _real_extract(self, url):
-        m = re.match(self._VALID_URL, url)
-        video_id = m.group('id')
-
-        webpage_src = self._download_webpage(url, video_id)
-
-        video_url = self._search_regex(r'so\.addVariable\("file","(.*?)"\)',
-            webpage_src, u'video URL')
-
-        if 'mp4' in video_url:
-            ext = 'mp4'
-        else:
-            ext = 'flv'
-
-        video_title = self._html_search_regex(r"<title>(.*)</title>",
-            webpage_src, u'title')
-
-        # Getting thumbnail and if not thumbnail sets correct title for WSHH candy video.
-        thumbnail = self._html_search_regex(r'rel="image_src" href="(.*)" />',
-            webpage_src, u'thumbnail', fatal=False)
-
-        if not thumbnail:
-            _title = r"""candytitles.*>(.*)</span>"""
-            mobj = re.search(_title, webpage_src)
-            if mobj is not None:
-                video_title = mobj.group(1)
-
-        results = [{
-                    'id': video_id,
-                    'url' : video_url,
-                    'title' : video_title,
-                    'thumbnail' : thumbnail,
-                    'ext' : ext,
-                    }]
-        return results
-
-class RBMARadioIE(InfoExtractor):
-    _VALID_URL = r'https?://(?:www\.)?rbmaradio\.com/shows/(?P<videoID>[^/]+)$'
-
-    def _real_extract(self, url):
-        m = re.match(self._VALID_URL, url)
-        video_id = m.group('videoID')
-
-        webpage = self._download_webpage(url, video_id)
-
-        json_data = self._search_regex(r'window\.gon.*?gon\.show=(.+?);$',
-            webpage, u'json data', flags=re.MULTILINE)
-
-        try:
-            data = json.loads(json_data)
-        except ValueError as e:
-            raise ExtractorError(u'Invalid JSON: ' + str(e))
-
-        video_url = data['akamai_url'] + '&cbr=256'
-        url_parts = compat_urllib_parse_urlparse(video_url)
-        video_ext = url_parts.path.rpartition('.')[2]
-        info = {
-                'id': video_id,
-                'url': video_url,
-                'ext': video_ext,
-                'title': data['title'],
-                'description': data.get('teaser_text'),
-                'location': data.get('country_of_origin'),
-                'uploader': data.get('host', {}).get('name'),
-                'uploader_id': data.get('host', {}).get('slug'),
-                'thumbnail': data.get('image', {}).get('large_url_2x'),
-                'duration': data.get('duration'),
-        }
-        return [info]
-
-
-class YouPornIE(InfoExtractor):
-    """Information extractor for youporn.com."""
-    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?youporn\.com/watch/(?P<videoid>[0-9]+)/(?P<title>[^/]+)'
-
-    def _print_formats(self, formats):
-        """Print all available formats"""
-        print(u'Available formats:')
-        print(u'ext\t\tformat')
-        print(u'---------------------------------')
-        for format in formats:
-            print(u'%s\t\t%s'  % (format['ext'], format['format']))
-
-    def _specific(self, req_format, formats):
-        for x in formats:
-            if(x["format"]==req_format):
-                return x
-        return None
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group('videoid')
-
-        req = compat_urllib_request.Request(url)
-        req.add_header('Cookie', 'age_verified=1')
-        webpage = self._download_webpage(req, video_id)
-
-        # Get JSON parameters
-        json_params = self._search_regex(r'var currentVideo = new Video\((.*)\);', webpage, u'JSON parameters')
-        try:
-            params = json.loads(json_params)
-        except:
-            raise ExtractorError(u'Invalid JSON')
-
-        self.report_extraction(video_id)
-        try:
-            video_title = params['title']
-            upload_date = unified_strdate(params['release_date_f'])
-            video_description = params['description']
-            video_uploader = params['submitted_by']
-            thumbnail = params['thumbnails'][0]['image']
-        except KeyError:
-            raise ExtractorError('Missing JSON parameter: ' + sys.exc_info()[1])
-
-        # Get all of the formats available
-        DOWNLOAD_LIST_RE = r'(?s)<ul class="downloadList">(?P<download_list>.*?)</ul>'
-        download_list_html = self._search_regex(DOWNLOAD_LIST_RE,
-            webpage, u'download list').strip()
-
-        # Get all of the links from the page
-        LINK_RE = r'(?s)<a href="(?P<url>[^"]+)">'
-        links = re.findall(LINK_RE, download_list_html)
-        if(len(links) == 0):
-            raise ExtractorError(u'ERROR: no known formats available for video')
-
-        self.to_screen(u'Links found: %d' % len(links))
-
-        formats = []
-        for link in links:
-
-            # A link looks like this:
-            # http://cdn1.download.youporn.phncdn.com/201210/31/8004515/480p_370k_8004515/YouPorn%20-%20Nubile%20Films%20The%20Pillow%20Fight.mp4?nvb=20121113051249&nva=20121114051249&ir=1200&sr=1200&hash=014b882080310e95fb6a0
-            # A path looks like this:
-            # /201210/31/8004515/480p_370k_8004515/YouPorn%20-%20Nubile%20Films%20The%20Pillow%20Fight.mp4
-            video_url = unescapeHTML( link )
-            path = compat_urllib_parse_urlparse( video_url ).path
-            extension = os.path.splitext( path )[1][1:]
-            format = path.split('/')[4].split('_')[:2]
-            size = format[0]
-            bitrate = format[1]
-            format = "-".join( format )
-            # title = u'%s-%s-%s' % (video_title, size, bitrate)
-
-            formats.append({
-                'id': video_id,
-                'url': video_url,
-                'uploader': video_uploader,
-                'upload_date': upload_date,
-                'title': video_title,
-                'ext': extension,
-                'format': format,
-                'thumbnail': thumbnail,
-                'description': video_description
-            })
-
-        if self._downloader.params.get('listformats', None):
-            self._print_formats(formats)
-            return
-
-        req_format = self._downloader.params.get('format', None)
-        self.to_screen(u'Format: %s' % req_format)
-
-        if req_format is None or req_format == 'best':
-            return [formats[0]]
-        elif req_format == 'worst':
-            return [formats[-1]]
-        elif req_format in ('-1', 'all'):
-            return formats
-        else:
-            format = self._specific( req_format, formats )
-            if result is None:
-                raise ExtractorError(u'Requested format not available')
-            return [format]
-
-
-
-class PornotubeIE(InfoExtractor):
-    """Information extractor for pornotube.com."""
-    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?pornotube\.com(/c/(?P<channel>[0-9]+))?(/m/(?P<videoid>[0-9]+))(/(?P<title>.+))$'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group('videoid')
-        video_title = mobj.group('title')
-
-        # Get webpage content
-        webpage = self._download_webpage(url, video_id)
-
-        # Get the video URL
-        VIDEO_URL_RE = r'url: "(?P<url>http://video[0-9].pornotube.com/.+\.flv)",'
-        video_url = self._search_regex(VIDEO_URL_RE, webpage, u'video url')
-        video_url = compat_urllib_parse.unquote(video_url)
-
-        #Get the uploaded date
-        VIDEO_UPLOADED_RE = r'<div class="video_added_by">Added (?P<date>[0-9\/]+) by'
-        upload_date = self._html_search_regex(VIDEO_UPLOADED_RE, webpage, u'upload date', fatal=False)
-        if upload_date: upload_date = unified_strdate(upload_date)
-
-        info = {'id': video_id,
-                'url': video_url,
-                'uploader': None,
-                'upload_date': upload_date,
-                'title': video_title,
-                'ext': 'flv',
-                'format': 'flv'}
-
-        return [info]
-
-class YouJizzIE(InfoExtractor):
-    """Information extractor for youjizz.com."""
-    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?youjizz\.com/videos/(?P<videoid>[^.]+).html$'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group('videoid')
-
-        # Get webpage content
-        webpage = self._download_webpage(url, video_id)
-
-        # Get the video title
-        video_title = self._html_search_regex(r'<title>(?P<title>.*)</title>',
-            webpage, u'title').strip()
-
-        # Get the embed page
-        result = re.search(r'https?://www.youjizz.com/videos/embed/(?P<videoid>[0-9]+)', webpage)
-        if result is None:
-            raise ExtractorError(u'ERROR: unable to extract embed page')
-
-        embed_page_url = result.group(0).strip()
-        video_id = result.group('videoid')
-
-        webpage = self._download_webpage(embed_page_url, video_id)
-
-        # Get the video URL
-        video_url = self._search_regex(r'so.addVariable\("file",encodeURIComponent\("(?P<source>[^"]+)"\)\);',
-            webpage, u'video URL')
-
-        info = {'id': video_id,
-                'url': video_url,
-                'title': video_title,
-                'ext': 'flv',
-                'format': 'flv',
-                'player_url': embed_page_url}
-
-        return [info]
-
-class EightTracksIE(InfoExtractor):
-    IE_NAME = '8tracks'
-    _VALID_URL = r'https?://8tracks.com/(?P<user>[^/]+)/(?P<id>[^/#]+)(?:#.*)?$'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        playlist_id = mobj.group('id')
-
-        webpage = self._download_webpage(url, playlist_id)
-
-        json_like = self._search_regex(r"PAGE.mix = (.*?);\n", webpage, u'trax information', flags=re.DOTALL)
-        data = json.loads(json_like)
-
-        session = str(random.randint(0, 1000000000))
-        mix_id = data['id']
-        track_count = data['tracks_count']
-        first_url = 'http://8tracks.com/sets/%s/play?player=sm&mix_id=%s&format=jsonh' % (session, mix_id)
-        next_url = first_url
-        res = []
-        for i in itertools.count():
-            api_json = self._download_webpage(next_url, playlist_id,
-                note=u'Downloading song information %s/%s' % (str(i+1), track_count),
-                errnote=u'Failed to download song information')
-            api_data = json.loads(api_json)
-            track_data = api_data[u'set']['track']
-            info = {
-                'id': track_data['id'],
-                'url': track_data['track_file_stream_url'],
-                'title': track_data['performer'] + u' - ' + track_data['name'],
-                'raw_title': track_data['name'],
-                'uploader_id': data['user']['login'],
-                'ext': 'm4a',
-            }
-            res.append(info)
-            if api_data['set']['at_last_track']:
-                break
-            next_url = 'http://8tracks.com/sets/%s/next?player=sm&mix_id=%s&format=jsonh&track_id=%s' % (session, mix_id, track_data['id'])
-        return res
-
-class KeekIE(InfoExtractor):
-    _VALID_URL = r'http://(?:www\.)?keek\.com/(?:!|\w+/keeks/)(?P<videoID>\w+)'
-    IE_NAME = u'keek'
-
-    def _real_extract(self, url):
-        m = re.match(self._VALID_URL, url)
-        video_id = m.group('videoID')
-
-        video_url = u'http://cdn.keek.com/keek/video/%s' % video_id
-        thumbnail = u'http://cdn.keek.com/keek/thumbnail/%s/w100/h75' % video_id
-        webpage = self._download_webpage(url, video_id)
-
-        video_title = self._html_search_regex(r'<meta property="og:title" content="(?P<title>.*?)"',
-            webpage, u'title')
-
-        uploader = self._html_search_regex(r'<div class="user-name-and-bio">[\S\s]+?<h2>(?P<uploader>.+?)</h2>',
-            webpage, u'uploader', fatal=False)
-
-        info = {
-                'id': video_id,
-                'url': video_url,
-                'ext': 'mp4',
-                'title': video_title,
-                'thumbnail': thumbnail,
-                'uploader': uploader
-        }
-        return [info]
-
-class TEDIE(InfoExtractor):
-    _VALID_URL=r'''http://www\.ted\.com/
-                   (
-                        ((?P<type_playlist>playlists)/(?P<playlist_id>\d+)) # We have a playlist
-                        |
-                        ((?P<type_talk>talks)) # We have a simple talk
-                   )
-                   (/lang/(.*?))? # The url may contain the language
-                   /(?P<name>\w+) # Here goes the name and then ".html"
-                   '''
-
-    @classmethod
-    def suitable(cls, url):
-        """Receives a URL and returns True if suitable for this IE."""
-        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
-
-    def _real_extract(self, url):
-        m=re.match(self._VALID_URL, url, re.VERBOSE)
-        if m.group('type_talk'):
-            return [self._talk_info(url)]
-        else :
-            playlist_id=m.group('playlist_id')
-            name=m.group('name')
-            self.to_screen(u'Getting info of playlist %s: "%s"' % (playlist_id,name))
-            return [self._playlist_videos_info(url,name,playlist_id)]
-
-    def _playlist_videos_info(self,url,name,playlist_id=0):
-        '''Returns the videos of the playlist'''
-        video_RE=r'''
-                     <li\ id="talk_(\d+)"([.\s]*?)data-id="(?P<video_id>\d+)"
-                     ([.\s]*?)data-playlist_item_id="(\d+)"
-                     ([.\s]*?)data-mediaslug="(?P<mediaSlug>.+?)"
-                     '''
-        video_name_RE=r'<p\ class="talk-title"><a href="(?P<talk_url>/talks/(.+).html)">(?P<fullname>.+?)</a></p>'
-        webpage=self._download_webpage(url, playlist_id, 'Downloading playlist webpage')
-        m_videos=re.finditer(video_RE,webpage,re.VERBOSE)
-        m_names=re.finditer(video_name_RE,webpage)
-
-        playlist_title = self._html_search_regex(r'div class="headline">\s*?<h1>\s*?<span>(.*?)</span>',
-                                                 webpage, 'playlist title')
-
-        playlist_entries = []
-        for m_video, m_name in zip(m_videos,m_names):
-            video_id=m_video.group('video_id')
-            talk_url='http://www.ted.com%s' % m_name.group('talk_url')
-            playlist_entries.append(self.url_result(talk_url, 'TED'))
-        return self.playlist_result(playlist_entries, playlist_id = playlist_id, playlist_title = playlist_title)
-
-    def _talk_info(self, url, video_id=0):
-        """Return the video for the talk in the url"""
-        m = re.match(self._VALID_URL, url,re.VERBOSE)
-        video_name = m.group('name')
-        webpage = self._download_webpage(url, video_id, 'Downloading \"%s\" page' % video_name)
-        self.report_extraction(video_name)
-        # If the url includes the language we get the title translated
-        title = self._html_search_regex(r'<span id="altHeadline" >(?P<title>.*)</span>',
-                                        webpage, 'title')
-        json_data = self._search_regex(r'<script.*?>var talkDetails = ({.*?})</script>',
-                                    webpage, 'json data')
-        info = json.loads(json_data)
-        desc = self._html_search_regex(r'<div class="talk-intro">.*?<p.*?>(.*?)</p>',
-                                       webpage, 'description', flags = re.DOTALL)
-        
-        thumbnail = self._search_regex(r'</span>[\s.]*</div>[\s.]*<img src="(.*?)"',
-                                       webpage, 'thumbnail')
-        info = {
-                'id': info['id'],
-                'url': info['htmlStreams'][-1]['file'],
-                'ext': 'mp4',
-                'title': title,
-                'thumbnail': thumbnail,
-                'description': desc,
-                }
-        return info
-
-class MySpassIE(InfoExtractor):
-    _VALID_URL = r'http://www.myspass.de/.*'
-
-    def _real_extract(self, url):
-        META_DATA_URL_TEMPLATE = 'http://www.myspass.de/myspass/includes/apps/video/getvideometadataxml.php?id=%s'
-
-        # video id is the last path element of the URL
-        # usually there is a trailing slash, so also try the second but last
-        url_path = compat_urllib_parse_urlparse(url).path
-        url_parent_path, video_id = os.path.split(url_path)
-        if not video_id:
-            _, video_id = os.path.split(url_parent_path)
-
-        # get metadata
-        metadata_url = META_DATA_URL_TEMPLATE % video_id
-        metadata_text = self._download_webpage(metadata_url, video_id)
-        metadata = xml.etree.ElementTree.fromstring(metadata_text.encode('utf-8'))
-
-        # extract values from metadata
-        url_flv_el = metadata.find('url_flv')
-        if url_flv_el is None:
-            raise ExtractorError(u'Unable to extract download url')
-        video_url = url_flv_el.text
-        extension = os.path.splitext(video_url)[1][1:]
-        title_el = metadata.find('title')
-        if title_el is None:
-            raise ExtractorError(u'Unable to extract title')
-        title = title_el.text
-        format_id_el = metadata.find('format_id')
-        if format_id_el is None:
-            format = ext
-        else:
-            format = format_id_el.text
-        description_el = metadata.find('description')
-        if description_el is not None:
-            description = description_el.text
-        else:
-            description = None
-        imagePreview_el = metadata.find('imagePreview')
-        if imagePreview_el is not None:
-            thumbnail = imagePreview_el.text
-        else:
-            thumbnail = None
-        info = {
-            'id': video_id,
-            'url': video_url,
-            'title': title,
-            'ext': extension,
-            'format': format,
-            'thumbnail': thumbnail,
-            'description': description
-        }
-        return [info]
-
-class SpiegelIE(InfoExtractor):
-    _VALID_URL = r'https?://(?:www\.)?spiegel\.de/video/[^/]*-(?P<videoID>[0-9]+)(?:\.html)?(?:#.*)?$'
-
-    def _real_extract(self, url):
-        m = re.match(self._VALID_URL, url)
-        video_id = m.group('videoID')
-
-        webpage = self._download_webpage(url, video_id)
-
-        video_title = self._html_search_regex(r'<div class="module-title">(.*?)</div>',
-            webpage, u'title')
-
-        xml_url = u'http://video2.spiegel.de/flash/' + video_id + u'.xml'
-        xml_code = self._download_webpage(xml_url, video_id,
-                    note=u'Downloading XML', errnote=u'Failed to download XML')
-
-        idoc = xml.etree.ElementTree.fromstring(xml_code)
-        last_type = idoc[-1]
-        filename = last_type.findall('./filename')[0].text
-        duration = float(last_type.findall('./duration')[0].text)
-
-        video_url = 'http://video2.spiegel.de/flash/' + filename
-        video_ext = filename.rpartition('.')[2]
-        info = {
-            'id': video_id,
-            'url': video_url,
-            'ext': video_ext,
-            'title': video_title,
-            'duration': duration,
-        }
-        return [info]
-
-class LiveLeakIE(InfoExtractor):
-
-    _VALID_URL = r'^(?:http?://)?(?:\w+\.)?liveleak\.com/view\?(?:.*?)i=(?P<video_id>[\w_]+)(?:.*)'
-    IE_NAME = u'liveleak'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group('video_id')
-
-        webpage = self._download_webpage(url, video_id)
-
-        video_url = self._search_regex(r'file: "(.*?)",',
-            webpage, u'video URL')
-
-        video_title = self._html_search_regex(r'<meta property="og:title" content="(?P<title>.*?)"',
-            webpage, u'title').replace('LiveLeak.com -', '').strip()
-
-        video_description = self._html_search_regex(r'<meta property="og:description" content="(?P<desc>.*?)"',
-            webpage, u'description', fatal=False)
-
-        video_uploader = self._html_search_regex(r'By:.*?(\w+)</a>',
-            webpage, u'uploader', fatal=False)
-
-        info = {
-            'id':  video_id,
-            'url': video_url,
-            'ext': 'mp4',
-            'title': video_title,
-            'description': video_description,
-            'uploader': video_uploader
-        }
-
-        return [info]
-
-class ARDIE(InfoExtractor):
-    _VALID_URL = r'^(?:https?://)?(?:(?:www\.)?ardmediathek\.de|mediathek\.daserste\.de)/(?:.*/)(?P<video_id>[^/\?]+)(?:\?.*)?'
-    _TITLE = r'<h1(?: class="boxTopHeadline")?>(?P<title>.*)</h1>'
-    _MEDIA_STREAM = r'mediaCollection\.addMediaStream\((?P<media_type>\d+), (?P<quality>\d+), "(?P<rtmp_url>[^"]*)", "(?P<video_url>[^"]*)", "[^"]*"\)'
-
-    def _real_extract(self, url):
-        # determine video id from url
-        m = re.match(self._VALID_URL, url)
-
-        numid = re.search(r'documentId=([0-9]+)', url)
-        if numid:
-            video_id = numid.group(1)
-        else:
-            video_id = m.group('video_id')
-
-        # determine title and media streams from webpage
-        html = self._download_webpage(url, video_id)
-        title = re.search(self._TITLE, html).group('title')
-        streams = [m.groupdict() for m in re.finditer(self._MEDIA_STREAM, html)]
-        if not streams:
-            assert '"fsk"' in html
-            raise ExtractorError(u'This video is only available after 8:00 pm')
-
-        # choose default media type and highest quality for now
-        stream = max([s for s in streams if int(s["media_type"]) == 0],
-                     key=lambda s: int(s["quality"]))
-
-        # there's two possibilities: RTMP stream or HTTP download
-        info = {'id': video_id, 'title': title, 'ext': 'mp4'}
-        if stream['rtmp_url']:
-            self.to_screen(u'RTMP download detected')
-            assert stream['video_url'].startswith('mp4:')
-            info["url"] = stream["rtmp_url"]
-            info["play_path"] = stream['video_url']
-        else:
-            assert stream["video_url"].endswith('.mp4')
-            info["url"] = stream["video_url"]
-        return [info]
-
-class ZDFIE(InfoExtractor):
-    _VALID_URL = r'^http://www\.zdf\.de\/ZDFmediathek\/(.*beitrag\/video\/)(?P<video_id>[^/\?]+)(?:\?.*)?'
-    _TITLE = r'<h1(?: class="beitragHeadline")?>(?P<title>.*)</h1>'
-    _MEDIA_STREAM = r'<a href="(?P<video_url>.+(?P<media_type>.streaming).+/zdf/(?P<quality>[^\/]+)/[^"]*)".+class="play".+>'
-    _MMS_STREAM = r'href="(?P<video_url>mms://[^"]*)"'
-    _RTSP_STREAM = r'(?P<video_url>rtsp://[^"]*.mp4)'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group('video_id')
-
-        html = self._download_webpage(url, video_id)
-        streams = [m.groupdict() for m in re.finditer(self._MEDIA_STREAM, html)]
-        if streams is None:
-            raise ExtractorError(u'No media url found.')
-
-        # s['media_type'] == 'wstreaming' -> use 'Windows Media Player' and mms url
-        # s['media_type'] == 'hstreaming' -> use 'Quicktime' and rtsp url
-        # choose first/default media type and highest quality for now
-        for s in streams:        #find 300 - dsl1000mbit
-            if s['quality'] == '300' and s['media_type'] == 'wstreaming':
-                stream_=s
-                break
-        for s in streams:        #find veryhigh - dsl2000mbit
-            if s['quality'] == 'veryhigh' and s['media_type'] == 'wstreaming': # 'hstreaming' - rtsp is not working
-                stream_=s
-                break
-        if stream_ is None:
-            raise ExtractorError(u'No stream found.')
-
-        media_link = self._download_webpage(stream_['video_url'], video_id,'Get stream URL')
-
-        self.report_extraction(video_id)
-        mobj = re.search(self._TITLE, html)
-        if mobj is None:
-            raise ExtractorError(u'Cannot extract title')
-        title = unescapeHTML(mobj.group('title'))
-
-        mobj = re.search(self._MMS_STREAM, media_link)
-        if mobj is None:
-            mobj = re.search(self._RTSP_STREAM, media_link)
-            if mobj is None:
-                raise ExtractorError(u'Cannot extract mms:// or rtsp:// URL')
-        mms_url = mobj.group('video_url')
-
-        mobj = re.search('(.*)[.](?P<ext>[^.]+)', mms_url)
-        if mobj is None:
-            raise ExtractorError(u'Cannot extract extention')
-        ext = mobj.group('ext')
-
-        return [{'id': video_id,
-                 'url': mms_url,
-                 'title': title,
-                 'ext': ext
-                 }]
-
-class TumblrIE(InfoExtractor):
-    _VALID_URL = r'http://(?P<blog_name>.*?)\.tumblr\.com/((post)|(video))/(?P<id>\d*)/(.*?)'
-
-    def _real_extract(self, url):
-        m_url = re.match(self._VALID_URL, url)
-        video_id = m_url.group('id')
-        blog = m_url.group('blog_name')
-
-        url = 'http://%s.tumblr.com/post/%s/' % (blog, video_id)
-        webpage = self._download_webpage(url, video_id)
-
-        re_video = r'src=\\x22(?P<video_url>http://%s\.tumblr\.com/video_file/%s/(.*?))\\x22 type=\\x22video/(?P<ext>.*?)\\x22' % (blog, video_id)
-        video = re.search(re_video, webpage)
-        if video is None:
-           raise ExtractorError(u'Unable to extract video')
-        video_url = video.group('video_url')
-        ext = video.group('ext')
-
-        video_thumbnail = self._search_regex(r'posters(.*?)\[\\x22(?P<thumb>.*?)\\x22',
-            webpage, u'thumbnail', fatal=False)  # We pick the first poster
-        if video_thumbnail: video_thumbnail = video_thumbnail.replace('\\', '')
-
-        # The only place where you can get a title, it's not complete,
-        # but searching in other places doesn't work for all videos
-        video_title = self._html_search_regex(r'<title>(?P<title>.*?)</title>',
-            webpage, u'title', flags=re.DOTALL)
-
-        return [{'id': video_id,
-                 'url': video_url,
-                 'title': video_title,
-                 'thumbnail': video_thumbnail,
-                 'ext': ext
-                 }]
-
-class BandcampIE(InfoExtractor):
-    _VALID_URL = r'http://.*?\.bandcamp\.com/track/(?P<title>.*)'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        title = mobj.group('title')
-        webpage = self._download_webpage(url, title)
-        # We get the link to the free download page
-        m_download = re.search(r'freeDownloadPage: "(.*?)"', webpage)
-        if m_download is None:
-            raise ExtractorError(u'No free songs found')
-
-        download_link = m_download.group(1)
-        id = re.search(r'var TralbumData = {(.*?)id: (?P<id>\d*?)$', 
-                       webpage, re.MULTILINE|re.DOTALL).group('id')
-
-        download_webpage = self._download_webpage(download_link, id,
-                                                  'Downloading free downloads page')
-        # We get the dictionary of the track from some javascrip code
-        info = re.search(r'items: (.*?),$',
-                         download_webpage, re.MULTILINE).group(1)
-        info = json.loads(info)[0]
-        # We pick mp3-320 for now, until format selection can be easily implemented.
-        mp3_info = info[u'downloads'][u'mp3-320']
-        # If we try to use this url it says the link has expired
-        initial_url = mp3_info[u'url']
-        re_url = r'(?P<server>http://(.*?)\.bandcamp\.com)/download/track\?enc=mp3-320&fsig=(?P<fsig>.*?)&id=(?P<id>.*?)&ts=(?P<ts>.*)$'
-        m_url = re.match(re_url, initial_url)
-        #We build the url we will use to get the final track url
-        # This url is build in Bandcamp in the script download_bunde_*.js
-        request_url = '%s/statdownload/track?enc=mp3-320&fsig=%s&id=%s&ts=%s&.rand=665028774616&.vrs=1' % (m_url.group('server'), m_url.group('fsig'), id, m_url.group('ts'))
-        final_url_webpage = self._download_webpage(request_url, id, 'Requesting download url')
-        # If we could correctly generate the .rand field the url would be
-        #in the "download_url" key
-        final_url = re.search(r'"retry_url":"(.*?)"', final_url_webpage).group(1)
-
-        track_info = {'id':id,
-                      'title' : info[u'title'],
-                      'ext' :   'mp3',
-                      'url' :   final_url,
-                      'thumbnail' : info[u'thumb_url'],
-                      'uploader' :  info[u'artist']
-                      }
-
-        return [track_info]
-
-class RedTubeIE(InfoExtractor):
-    """Information Extractor for redtube"""
-    _VALID_URL = r'(?:http://)?(?:www\.)?redtube\.com/(?P<id>[0-9]+)'
-
-    def _real_extract(self,url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-
-        video_id = mobj.group('id')
-        video_extension = 'mp4'        
-        webpage = self._download_webpage(url, video_id)
-
-        self.report_extraction(video_id)
-
-        video_url = self._html_search_regex(r'<source src="(.+?)" type="video/mp4">',
-            webpage, u'video URL')
-
-        video_title = self._html_search_regex('<h1 class="videoTitle slidePanelMovable">(.+?)</h1>',
-            webpage, u'title')
-
-        return [{
-            'id':       video_id,
-            'url':      video_url,
-            'ext':      video_extension,
-            'title':    video_title,
-        }]
-        
-class InaIE(InfoExtractor):
-    """Information Extractor for Ina.fr"""
-    _VALID_URL = r'(?:http://)?(?:www\.)?ina\.fr/video/(?P<id>I[0-9]+)/.*'
-
-    def _real_extract(self,url):
-        mobj = re.match(self._VALID_URL, url)
-
-        video_id = mobj.group('id')
-        mrss_url='http://player.ina.fr/notices/%s.mrss' % video_id
-        video_extension = 'mp4'
-        webpage = self._download_webpage(mrss_url, video_id)
-
-        self.report_extraction(video_id)
-
-        video_url = self._html_search_regex(r'<media:player url="(?P<mp4url>http://mp4.ina.fr/[^"]+\.mp4)',
-            webpage, u'video URL')
-
-        video_title = self._search_regex(r'<title><!\[CDATA\[(?P<titre>.*?)]]></title>',
-            webpage, u'title')
-
-        return [{
-            'id':       video_id,
-            'url':      video_url,
-            'ext':      video_extension,
-            'title':    video_title,
-        }]
-
-class HowcastIE(InfoExtractor):
-    """Information Extractor for Howcast.com"""
-    _VALID_URL = r'(?:https?://)?(?:www\.)?howcast\.com/videos/(?P<id>\d+)'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-
-        video_id = mobj.group('id')
-        webpage_url = 'http://www.howcast.com/videos/' + video_id
-        webpage = self._download_webpage(webpage_url, video_id)
-
-        self.report_extraction(video_id)
-
-        video_url = self._search_regex(r'\'?file\'?: "(http://mobile-media\.howcast\.com/[0-9]+\.mp4)',
-            webpage, u'video URL')
-
-        video_title = self._html_search_regex(r'<meta content=(?:"([^"]+)"|\'([^\']+)\') property=\'og:title\'',
-            webpage, u'title')
-
-        video_description = self._html_search_regex(r'<meta content=(?:"([^"]+)"|\'([^\']+)\') name=\'description\'',
-            webpage, u'description', fatal=False)
-
-        thumbnail = self._html_search_regex(r'<meta content=\'(.+?)\' property=\'og:image\'',
-            webpage, u'thumbnail', fatal=False)
-
-        return [{
-            'id':       video_id,
-            'url':      video_url,
-            'ext':      'mp4',
-            'title':    video_title,
-            'description': video_description,
-            'thumbnail': thumbnail,
-        }]
-
-class VineIE(InfoExtractor):
-    """Information Extractor for Vine.co"""
-    _VALID_URL = r'(?:https?://)?(?:www\.)?vine\.co/v/(?P<id>\w+)'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-
-        video_id = mobj.group('id')
-        webpage_url = 'https://vine.co/v/' + video_id
-        webpage = self._download_webpage(webpage_url, video_id)
-
-        self.report_extraction(video_id)
-
-        video_url = self._html_search_regex(r'<meta property="twitter:player:stream" content="(.+?)"',
-            webpage, u'video URL')
-
-        video_title = self._html_search_regex(r'<meta property="og:title" content="(.+?)"',
-            webpage, u'title')
-
-        thumbnail = self._html_search_regex(r'<meta property="og:image" content="(.+?)(\?.*?)?"',
-            webpage, u'thumbnail', fatal=False)
-
-        uploader = self._html_search_regex(r'<div class="user">.*?<h2>(.+?)</h2>',
-            webpage, u'uploader', fatal=False, flags=re.DOTALL)
-
-        return [{
-            'id':        video_id,
-            'url':       video_url,
-            'ext':       'mp4',
-            'title':     video_title,
-            'thumbnail': thumbnail,
-            'uploader':  uploader,
-        }]
-
-class FlickrIE(InfoExtractor):
-    """Information Extractor for Flickr videos"""
-    _VALID_URL = r'(?:https?://)?(?:www\.)?flickr\.com/photos/(?P<uploader_id>[\w\-_@]+)/(?P<id>\d+).*'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-
-        video_id = mobj.group('id')
-        video_uploader_id = mobj.group('uploader_id')
-        webpage_url = 'http://www.flickr.com/photos/' + video_uploader_id + '/' + video_id
-        webpage = self._download_webpage(webpage_url, video_id)
-
-        secret = self._search_regex(r"photo_secret: '(\w+)'", webpage, u'secret')
-
-        first_url = 'https://secure.flickr.com/apps/video/video_mtl_xml.gne?v=x&photo_id=' + video_id + '&secret=' + secret + '&bitrate=700&target=_self'
-        first_xml = self._download_webpage(first_url, video_id, 'Downloading first data webpage')
-
-        node_id = self._html_search_regex(r'<Item id="id">(\d+-\d+)</Item>',
-            first_xml, u'node_id')
-
-        second_url = 'https://secure.flickr.com/video_playlist.gne?node_id=' + node_id + '&tech=flash&mode=playlist&bitrate=700&secret=' + secret + '&rd=video.yahoo.com&noad=1'
-        second_xml = self._download_webpage(second_url, video_id, 'Downloading second data webpage')
-
-        self.report_extraction(video_id)
-
-        mobj = re.search(r'<STREAM APP="(.+?)" FULLPATH="(.+?)"', second_xml)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract video url')
-        video_url = mobj.group(1) + unescapeHTML(mobj.group(2))
-
-        video_title = self._html_search_regex(r'<meta property="og:title" content=(?:"([^"]+)"|\'([^\']+)\')',
-            webpage, u'video title')
-
-        video_description = self._html_search_regex(r'<meta property="og:description" content=(?:"([^"]+)"|\'([^\']+)\')',
-            webpage, u'description', fatal=False)
-
-        thumbnail = self._html_search_regex(r'<meta property="og:image" content=(?:"([^"]+)"|\'([^\']+)\')',
-            webpage, u'thumbnail', fatal=False)
-
-        return [{
-            'id':          video_id,
-            'url':         video_url,
-            'ext':         'mp4',
-            'title':       video_title,
-            'description': video_description,
-            'thumbnail':   thumbnail,
-            'uploader_id': video_uploader_id,
-        }]
-
-class TeamcocoIE(InfoExtractor):
-    _VALID_URL = r'http://teamcoco\.com/video/(?P<url_title>.*)'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        url_title = mobj.group('url_title')
-        webpage = self._download_webpage(url, url_title)
-
-        video_id = self._html_search_regex(r'<article class="video" data-id="(\d+?)"',
-            webpage, u'video id')
-
-        self.report_extraction(video_id)
-
-        video_title = self._html_search_regex(r'<meta property="og:title" content="(.+?)"',
-            webpage, u'title')
-
-        thumbnail = self._html_search_regex(r'<meta property="og:image" content="(.+?)"',
-            webpage, u'thumbnail', fatal=False)
-
-        video_description = self._html_search_regex(r'<meta property="og:description" content="(.*?)"',
-            webpage, u'description', fatal=False)
-
-        data_url = 'http://teamcoco.com/cvp/2.0/%s.xml' % video_id
-        data = self._download_webpage(data_url, video_id, 'Downloading data webpage')
-
-        video_url = self._html_search_regex(r'<file type="high".*?>(.*?)</file>',
-            data, u'video URL')
-
-        return [{
-            'id':          video_id,
-            'url':         video_url,
-            'ext':         'mp4',
-            'title':       video_title,
-            'thumbnail':   thumbnail,
-            'description': video_description,
-        }]
-
-class XHamsterIE(InfoExtractor):
-    """Information Extractor for xHamster"""
-    _VALID_URL = r'(?:http://)?(?:www.)?xhamster\.com/movies/(?P<id>[0-9]+)/.*\.html'
-
-    def _real_extract(self,url):
-        mobj = re.match(self._VALID_URL, url)
-
-        video_id = mobj.group('id')
-        mrss_url = 'http://xhamster.com/movies/%s/.html' % video_id
-        webpage = self._download_webpage(mrss_url, video_id)
-
-        mobj = re.search(r'\'srv\': \'(?P<server>[^\']*)\',\s*\'file\': \'(?P<file>[^\']+)\',', webpage)
-        if mobj is None:
-            raise ExtractorError(u'Unable to extract media URL')
-        if len(mobj.group('server')) == 0:
-            video_url = compat_urllib_parse.unquote(mobj.group('file'))
-        else:
-            video_url = mobj.group('server')+'/key='+mobj.group('file')
-        video_extension = video_url.split('.')[-1]
-
-        video_title = self._html_search_regex(r'<title>(?P<title>.+?) - xHamster\.com</title>',
-            webpage, u'title')
-
-        # Can't see the description anywhere in the UI
-        # video_description = self._html_search_regex(r'<span>Description: </span>(?P<description>[^<]+)',
-        #     webpage, u'description', fatal=False)
-        # if video_description: video_description = unescapeHTML(video_description)
-
-        mobj = re.search(r'hint=\'(?P<upload_date_Y>[0-9]{4})-(?P<upload_date_m>[0-9]{2})-(?P<upload_date_d>[0-9]{2}) [0-9]{2}:[0-9]{2}:[0-9]{2} [A-Z]{3,4}\'', webpage)
-        if mobj:
-            video_upload_date = mobj.group('upload_date_Y')+mobj.group('upload_date_m')+mobj.group('upload_date_d')
-        else:
-            video_upload_date = None
-            self._downloader.report_warning(u'Unable to extract upload date')
-
-        video_uploader_id = self._html_search_regex(r'<a href=\'/user/[^>]+>(?P<uploader_id>[^<]+)',
-            webpage, u'uploader id', default=u'anonymous')
-
-        video_thumbnail = self._search_regex(r'\'image\':\'(?P<thumbnail>[^\']+)\'',
-            webpage, u'thumbnail', fatal=False)
-
-        return [{
-            'id':       video_id,
-            'url':      video_url,
-            'ext':      video_extension,
-            'title':    video_title,
-            # 'description': video_description,
-            'upload_date': video_upload_date,
-            'uploader_id': video_uploader_id,
-            'thumbnail': video_thumbnail
-        }]
-
-class HypemIE(InfoExtractor):
-    """Information Extractor for hypem"""
-    _VALID_URL = r'(?:http://)?(?:www\.)?hypem\.com/track/([^/]+)/([^/]+)'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        track_id = mobj.group(1)
-
-        data = { 'ax': 1, 'ts': time.time() }
-        data_encoded = compat_urllib_parse.urlencode(data)
-        complete_url = url + "?" + data_encoded
-        request = compat_urllib_request.Request(complete_url)
-        response, urlh = self._download_webpage_handle(request, track_id, u'Downloading webpage with the url')
-        cookie = urlh.headers.get('Set-Cookie', '')
-
-        self.report_extraction(track_id)
-
-        html_tracks = self._html_search_regex(r'<script type="application/json" id="displayList-data">(.*?)</script>',
-            response, u'tracks', flags=re.MULTILINE|re.DOTALL).strip()
-        try:
-            track_list = json.loads(html_tracks)
-            track = track_list[u'tracks'][0]
-        except ValueError:
-            raise ExtractorError(u'Hypemachine contained invalid JSON.')
-
-        key = track[u"key"]
-        track_id = track[u"id"]
-        artist = track[u"artist"]
-        title = track[u"song"]
-
-        serve_url = "http://hypem.com/serve/source/%s/%s" % (compat_str(track_id), compat_str(key))
-        request = compat_urllib_request.Request(serve_url, "" , {'Content-Type': 'application/json'})
-        request.add_header('cookie', cookie)
-        song_data_json = self._download_webpage(request, track_id, u'Downloading metadata')
-        try:
-            song_data = json.loads(song_data_json)
-        except ValueError:
-            raise ExtractorError(u'Hypemachine contained invalid JSON.')
-        final_url = song_data[u"url"]
-
-        return [{
-            'id':       track_id,
-            'url':      final_url,
-            'ext':      "mp3",
-            'title':    title,
-            'artist':   artist,
-        }]
-
-class Vbox7IE(InfoExtractor):
-    """Information Extractor for Vbox7"""
-    _VALID_URL = r'(?:http://)?(?:www\.)?vbox7\.com/play:([^/]+)'
-
-    def _real_extract(self,url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group(1)
-
-        redirect_page, urlh = self._download_webpage_handle(url, video_id)
-        new_location = self._search_regex(r'window\.location = \'(.*)\';', redirect_page, u'redirect location')
-        redirect_url = urlh.geturl() + new_location
-        webpage = self._download_webpage(redirect_url, video_id, u'Downloading redirect page')
-
-        title = self._html_search_regex(r'<title>(.*)</title>',
-            webpage, u'title').split('/')[0].strip()
-
-        ext = "flv"
-        info_url = "http://vbox7.com/play/magare.do"
-        data = compat_urllib_parse.urlencode({'as3':'1','vid':video_id})
-        info_request = compat_urllib_request.Request(info_url, data)
-        info_request.add_header('Content-Type', 'application/x-www-form-urlencoded')
-        info_response = self._download_webpage(info_request, video_id, u'Downloading info webpage')
-        if info_response is None:
-            raise ExtractorError(u'Unable to extract the media url')
-        (final_url, thumbnail_url) = map(lambda x: x.split('=')[1], info_response.split('&'))
-
-        return [{
-            'id':        video_id,
-            'url':       final_url,
-            'ext':       ext,
-            'title':     title,
-            'thumbnail': thumbnail_url,
-        }]
-
-class GametrailersIE(InfoExtractor):
-    _VALID_URL = r'http://www.gametrailers.com/(?P<type>videos|reviews|full-episodes)/(?P<id>.*?)/(?P<title>.*)'
-
-    def _real_extract(self, url):
-        mobj = re.match(self._VALID_URL, url)
-        if mobj is None:
-            raise ExtractorError(u'Invalid URL: %s' % url)
-        video_id = mobj.group('id')
-        video_type = mobj.group('type')
-        webpage = self._download_webpage(url, video_id)
-        if video_type == 'full-episodes':
-            mgid_re = r'data-video="(?P<mgid>mgid:.*?)"'
-        else:
-            mgid_re = r'data-contentId=\'(?P<mgid>mgid:.*?)\''
-        mgid = self._search_regex(mgid_re, webpage, u'mgid')
-        data = compat_urllib_parse.urlencode({'uri': mgid, 'acceptMethods': 'fms'})
-
-        info_page = self._download_webpage('http://www.gametrailers.com/feeds/mrss?' + data,
-                                           video_id, u'Downloading video info')
-        links_webpage = self._download_webpage('http://www.gametrailers.com/feeds/mediagen/?' + data,
-                                               video_id, u'Downloading video urls info')
-
-        self.report_extraction(video_id)
-        info_re = r'''<title><!\[CDATA\[(?P<title>.*?)\]\]></title>.*
-                      <description><!\[CDATA\[(?P<description>.*?)\]\]></description>.*
-                      <image>.*
-                        <url>(?P<thumb>.*?)</url>.*
-                      </image>'''
-
-        m_info = re.search(info_re, info_page, re.VERBOSE|re.DOTALL)
-        if m_info is None:
-            raise ExtractorError(u'Unable to extract video info')
-        video_title = m_info.group('title')
-        video_description = m_info.group('description')
-        video_thumb = m_info.group('thumb')
-
-        m_urls = list(re.finditer(r'<src>(?P<url>.*)</src>', links_webpage))
-        if m_urls is None or len(m_urls) == 0:
-            raise ExtractError(u'Unable to extrat video url')
-        # They are sorted from worst to best quality
-        video_url = m_urls[-1].group('url')
-
-        return {'url':         video_url,
-                'id':          video_id,
-                'title':       video_title,
-                # Videos are actually flv not mp4
-                'ext':         'flv',
-                'thumbnail':   video_thumb,
-                'description': video_description,
-                }
-
-def gen_extractors():
-    """ Return a list of an instance of every supported extractor.
-    The order does matter; the first extractor matched is the one handling the URL.
-    """
-    return [
-        YoutubePlaylistIE(),
-        YoutubeChannelIE(),
-        YoutubeUserIE(),
-        YoutubeSearchIE(),
-        YoutubeIE(),
-        MetacafeIE(),
-        DailymotionIE(),
-        GoogleSearchIE(),
-        PhotobucketIE(),
-        YahooIE(),
-        YahooSearchIE(),
-        DepositFilesIE(),
-        FacebookIE(),
-        BlipTVIE(),
-        BlipTVUserIE(),
-        VimeoIE(),
-        MyVideoIE(),
-        ComedyCentralIE(),
-        EscapistIE(),
-        CollegeHumorIE(),
-        XVideosIE(),
-        SoundcloudSetIE(),
-        SoundcloudIE(),
-        InfoQIE(),
-        MixcloudIE(),
-        StanfordOpenClassroomIE(),
-        MTVIE(),
-        YoukuIE(),
-        XNXXIE(),
-        YouJizzIE(),
-        PornotubeIE(),
-        YouPornIE(),
-        GooglePlusIE(),
-        ArteTvIE(),
-        NBAIE(),
-        WorldStarHipHopIE(),
-        JustinTVIE(),
-        FunnyOrDieIE(),
-        SteamIE(),
-        UstreamIE(),
-        RBMARadioIE(),
-        EightTracksIE(),
-        KeekIE(),
-        TEDIE(),
-        MySpassIE(),
-        SpiegelIE(),
-        LiveLeakIE(),
-        ARDIE(),
-        ZDFIE(),
-        TumblrIE(),
-        BandcampIE(),
-        RedTubeIE(),
-        InaIE(),
-        HowcastIE(),
-        VineIE(),
-        FlickrIE(),
-        TeamcocoIE(),
-        XHamsterIE(),
-        HypemIE(),
-        Vbox7IE(),
-        GametrailersIE(),
-        GenericIE()
-    ]
-
-def get_info_extractor(ie_name):
-    """Returns the info extractor class with the given ie_name"""
-    return globals()[ie_name+'IE']
+from .extractor.common import InfoExtractor, SearchInfoExtractor
+from .extractor import gen_extractors, get_info_extractor
diff --git a/youtube_dl/PostProcessor.py b/youtube_dl/PostProcessor.py
index 8868b37..8c5e539 100644
--- a/youtube_dl/PostProcessor.py
+++ b/youtube_dl/PostProcessor.py
@@ -1,8 +1,3 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from __future__ import absolute_import
-
 import os
 import subprocess
 import sys
diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py
index 9279ce7..a8b62a6 100644
--- a/youtube_dl/__init__.py
+++ b/youtube_dl/__init__.py
@@ -1,9 +1,6 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
-from __future__ import with_statement
-from __future__ import absolute_import
-
 __authors__  = (
     'Ricardo Garcia Gonzalez',
     'Danny Colligan',
@@ -48,7 +45,7 @@ from .utils import *
 from .update import update_self
 from .version import __version__
 from .FileDownloader import *
-from .InfoExtractors import gen_extractors
+from .extractor import gen_extractors
 from .PostProcessor import *
 
 def parseOpts(overrideArguments=None):
@@ -200,7 +197,7 @@ def parseOpts(overrideArguments=None):
             action='store_true', dest='listsubtitles',
             help='lists all available subtitles for the video (currently youtube only)', default=False)
     video_format.add_option('--sub-format',
-            action='store', dest='subtitlesformat', metavar='LANG',
+            action='store', dest='subtitlesformat', metavar='FORMAT',
             help='subtitle format [srt/sbv] (default=srt) (currently youtube only)', default='srt')
     video_format.add_option('--sub-lang', '--srt-lang',
             action='store', dest='subtitleslang', metavar='LANG',
@@ -423,7 +420,7 @@ def _real_main(argv=None):
     if opts.usenetrc and (opts.username is not None or opts.password is not None):
         parser.error(u'using .netrc conflicts with giving username/password')
     if opts.password is not None and opts.username is None:
-        parser.error(u'account username missing')
+        print(u'WARNING: account username missing')
     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
         parser.error(u'using output template conflicts with using title, video ID or auto number')
     if opts.usetitle and opts.useid:
diff --git a/youtube_dl/extractor/__init__.py b/youtube_dl/extractor/__init__.py
new file mode 100644
index 0000000..b208f90
--- /dev/null
+++ b/youtube_dl/extractor/__init__.py
@@ -0,0 +1,133 @@
+
+from .ard import ARDIE
+from .arte import ArteTvIE
+from .bandcamp import BandcampIE
+from .bliptv import BlipTVIE, BlipTVUserIE
+from .breakcom import BreakIE
+from .comedycentral import ComedyCentralIE
+from .collegehumor import CollegeHumorIE
+from .dailymotion import DailymotionIE
+from .depositfiles import DepositFilesIE
+from .eighttracks import EightTracksIE
+from .escapist import EscapistIE
+from .facebook import FacebookIE
+from .flickr import FlickrIE
+from .funnyordie import FunnyOrDieIE
+from .gametrailers import GametrailersIE
+from .generic import GenericIE
+from .googleplus import GooglePlusIE
+from .googlesearch import GoogleSearchIE
+from .howcast import HowcastIE
+from .hypem import HypemIE
+from .ina import InaIE
+from .infoq import InfoQIE
+from .justintv import JustinTVIE
+from .keek import KeekIE
+from .liveleak import LiveLeakIE
+from .metacafe import MetacafeIE
+from .mixcloud import MixcloudIE
+from .mtv import MTVIE
+from .myspass import MySpassIE
+from .myvideo import MyVideoIE
+from .nba import NBAIE
+from .statigram import StatigramIE
+from .photobucket import PhotobucketIE
+from .pornotube import PornotubeIE
+from .rbmaradio import RBMARadioIE
+from .redtube import RedTubeIE
+from .soundcloud import SoundcloudIE, SoundcloudSetIE
+from .spiegel import SpiegelIE
+from .stanfordoc import StanfordOpenClassroomIE
+from .steam import SteamIE
+from .teamcoco import TeamcocoIE
+from .ted import TEDIE
+from .tumblr import TumblrIE
+from .ustream import UstreamIE
+from .vbox7 import Vbox7IE
+from .vimeo import VimeoIE
+from .vine import VineIE
+from .worldstarhiphop import WorldStarHipHopIE
+from .xnxx import XNXXIE
+from .xhamster import XHamsterIE
+from .xvideos import XVideosIE
+from .yahoo import YahooIE, YahooSearchIE
+from .youjizz import YouJizzIE
+from .youku import YoukuIE
+from .youporn import YouPornIE
+from .youtube import YoutubeIE, YoutubePlaylistIE, YoutubeSearchIE, YoutubeUserIE, YoutubeChannelIE
+from .zdf import ZDFIE
+
+def gen_extractors():
+    """ Return a list of an instance of every supported extractor.
+    The order does matter; the first extractor matched is the one handling the URL.
+    """
+    return [
+        YoutubePlaylistIE(),
+        YoutubeChannelIE(),
+        YoutubeUserIE(),
+        YoutubeSearchIE(),
+        YoutubeIE(),
+        MetacafeIE(),
+        DailymotionIE(),
+        GoogleSearchIE(),
+        PhotobucketIE(),
+        YahooIE(),
+        YahooSearchIE(),
+        DepositFilesIE(),
+        FacebookIE(),
+        BlipTVIE(),
+        BlipTVUserIE(),
+        VimeoIE(),
+        MyVideoIE(),
+        ComedyCentralIE(),
+        EscapistIE(),
+        CollegeHumorIE(),
+        XVideosIE(),
+        SoundcloudSetIE(),
+        SoundcloudIE(),
+        InfoQIE(),
+        MixcloudIE(),
+        StanfordOpenClassroomIE(),
+        MTVIE(),
+        YoukuIE(),
+        XNXXIE(),
+        YouJizzIE(),
+        PornotubeIE(),
+        YouPornIE(),
+        GooglePlusIE(),
+        ArteTvIE(),
+        NBAIE(),
+        WorldStarHipHopIE(),
+        JustinTVIE(),
+        FunnyOrDieIE(),
+        SteamIE(),
+        UstreamIE(),
+        RBMARadioIE(),
+        EightTracksIE(),
+        KeekIE(),
+        TEDIE(),
+        MySpassIE(),
+        SpiegelIE(),
+        LiveLeakIE(),
+        ARDIE(),
+        ZDFIE(),
+        TumblrIE(),
+        BandcampIE(),
+        RedTubeIE(),
+        InaIE(),
+        HowcastIE(),
+        VineIE(),
+        FlickrIE(),
+        TeamcocoIE(),
+        XHamsterIE(),
+        HypemIE(),
+        Vbox7IE(),
+        GametrailersIE(),
+        StatigramIE(),
+        BreakIE(),
+        GenericIE()
+    ]
+
+def get_info_extractor(ie_name):
+    """Returns the info extractor class with the given ie_name"""
+    return globals()[ie_name+'IE']
diff --git a/youtube_dl/extractor/ard.py b/youtube_dl/extractor/ard.py
new file mode 100644
index 0000000..e1ecdf4
--- /dev/null
+++ b/youtube_dl/extractor/ard.py
@@ -0,0 +1,45 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+class ARDIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?(?:(?:www\.)?ardmediathek\.de|mediathek\.daserste\.de)/(?:.*/)(?P<video_id>[^/\?]+)(?:\?.*)?'
+    _TITLE = r'<h1(?: class="boxTopHeadline")?>(?P<title>.*)</h1>'
+    _MEDIA_STREAM = r'mediaCollection\.addMediaStream\((?P<media_type>\d+), (?P<quality>\d+), "(?P<rtmp_url>[^"]*)", "(?P<video_url>[^"]*)", "[^"]*"\)'
+
+    def _real_extract(self, url):
+        # determine video id from url
+        m = re.match(self._VALID_URL, url)
+
+        numid = re.search(r'documentId=([0-9]+)', url)
+        if numid:
+            video_id = numid.group(1)
+        else:
+            video_id = m.group('video_id')
+
+        # determine title and media streams from webpage
+        html = self._download_webpage(url, video_id)
+        title = re.search(self._TITLE, html).group('title')
+        streams = [m.groupdict() for m in re.finditer(self._MEDIA_STREAM, html)]
+        if not streams:
+            assert '"fsk"' in html
+            raise ExtractorError(u'This video is only available after 8:00 pm')
+
+        # choose default media type and highest quality for now
+        stream = max([s for s in streams if int(s["media_type"]) == 0],
+                     key=lambda s: int(s["quality"]))
+
+        # there's two possibilities: RTMP stream or HTTP download
+        info = {'id': video_id, 'title': title, 'ext': 'mp4'}
+        if stream['rtmp_url']:
+            self.to_screen(u'RTMP download detected')
+            assert stream['video_url'].startswith('mp4:')
+            info["url"] = stream["rtmp_url"]
+            info["play_path"] = stream['video_url']
+        else:
+            assert stream["video_url"].endswith('.mp4')
+            info["url"] = stream["video_url"]
+        return [info]
diff --git a/youtube_dl/extractor/arte.py b/youtube_dl/extractor/arte.py
new file mode 100644
index 0000000..82e3ffe
--- /dev/null
+++ b/youtube_dl/extractor/arte.py
@@ -0,0 +1,136 @@
+import re
+import socket
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_str,
+    compat_urllib_error,
+    compat_urllib_parse,
+    compat_urllib_request,
+
+    ExtractorError,
+    unified_strdate,
+)
+
+class ArteTvIE(InfoExtractor):
+    """arte.tv information extractor."""
+
+    _VALID_URL = r'(?:http://)?videos\.arte\.tv/(?:fr|de)/videos/.*'
+    _LIVE_URL = r'index-[0-9]+\.html$'
+
+    IE_NAME = u'arte.tv'
+
+    def fetch_webpage(self, url):
+        request = compat_urllib_request.Request(url)
+        try:
+            self.report_download_webpage(url)
+            webpage = compat_urllib_request.urlopen(request).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to retrieve video webpage: %s' % compat_str(err))
+        except ValueError as err:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        return webpage
+
+    def grep_webpage(self, url, regex, regexFlags, matchTuples):
+        page = self.fetch_webpage(url)
+        mobj = re.search(regex, page, regexFlags)
+        info = {}
+
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        for (i, key, err) in matchTuples:
+            if mobj.group(i) is None:
+                raise ExtractorError(err)
+            else:
+                info[key] = mobj.group(i)
+
+        return info
+
+    # TODO implement Live Stream
+    # def extractLiveStream(self, url):
+    #     video_lang = url.split('/')[-4]
+    #     info = self.grep_webpage(
+    #         url,
+    #         r'src="(.*?/videothek_js.*?\.js)',
+    #         0,
+    #         [
+    #             (1, 'url', u'Invalid URL: %s' % url)
+    #         ]
+    #     )
+    #     http_host = url.split('/')[2]
+    #     next_url = 'http://%s%s' % (http_host, compat_urllib_parse.unquote(info.get('url')))
+    #     info = self.grep_webpage(
+    #         next_url,
+    #         r'(s_artestras_scst_geoFRDE_' + video_lang + '.*?)\'.*?' +
+    #             '(http://.*?\.swf).*?' +
+    #             '(rtmp://.*?)\'',
+    #         re.DOTALL,
+    #         [
+    #             (1, 'path',   u'could not extract video path: %s' % url),
+    #             (2, 'player', u'could not extract video player: %s' % url),
+    #             (3, 'url',    u'could not extract video url: %s' % url)
+    #         ]
+    #     )
+    #     video_url = u'%s/%s' % (info.get('url'), info.get('path'))
+
+    def extractPlus7Stream(self, url):
+        video_lang = url.split('/')[-3]
+        info = self.grep_webpage(
+            url,
+            r'param name="movie".*?videorefFileUrl=(http[^\'"&]*)',
+            0,
+            [
+                (1, 'url', u'Invalid URL: %s' % url)
+            ]
+        )
+        next_url = compat_urllib_parse.unquote(info.get('url'))
+        info = self.grep_webpage(
+            next_url,
+            r'<video lang="%s" ref="(http[^\'"&]*)' % video_lang,
+            0,
+            [
+                (1, 'url', u'Could not find <video> tag: %s' % url)
+            ]
+        )
+        next_url = compat_urllib_parse.unquote(info.get('url'))
+
+        info = self.grep_webpage(
+            next_url,
+            r'<video id="(.*?)".*?>.*?' +
+                '<name>(.*?)</name>.*?' +
+                '<dateVideo>(.*?)</dateVideo>.*?' +
+                '<url quality="hd">(.*?)</url>',
+            re.DOTALL,
+            [
+                (1, 'id',    u'could not extract video id: %s' % url),
+                (2, 'title', u'could not extract video title: %s' % url),
+                (3, 'date',  u'could not extract video date: %s' % url),
+                (4, 'url',   u'could not extract video url: %s' % url)
+            ]
+        )
+
+        return {
+            'id':           info.get('id'),
+            'url':          compat_urllib_parse.unquote(info.get('url')),
+            'uploader':     u'arte.tv',
+            'upload_date':  unified_strdate(info.get('date')),
+            'title':        info.get('title').decode('utf-8'),
+            'ext':          u'mp4',
+            'format':       u'NA',
+            'player_url':   None,
+        }
+
+    def _real_extract(self, url):
+        video_id = url.split('/')[-1]
+        self.report_extraction(video_id)
+
+        if re.search(self._LIVE_URL, video_id) is not None:
+            raise ExtractorError(u'Arte live streams are not yet supported, sorry')
+            # self.extractLiveStream(url)
+            # return
+        else:
+            info = self.extractPlus7Stream(url)
+
+        return [info]
diff --git a/youtube_dl/extractor/bandcamp.py b/youtube_dl/extractor/bandcamp.py
new file mode 100644
index 0000000..dcf6721
--- /dev/null
+++ b/youtube_dl/extractor/bandcamp.py
@@ -0,0 +1,54 @@
+import json
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class BandcampIE(InfoExtractor):
+    _VALID_URL = r'http://.*?\.bandcamp\.com/track/(?P<title>.*)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        title = mobj.group('title')
+        webpage = self._download_webpage(url, title)
+        # We get the link to the free download page
+        m_download = re.search(r'freeDownloadPage: "(.*?)"', webpage)
+        if m_download is None:
+            raise ExtractorError(u'No free songs found')
+
+        download_link = m_download.group(1)
+        id = re.search(r'var TralbumData = {(.*?)id: (?P<id>\d*?)$', 
+                       webpage, re.MULTILINE|re.DOTALL).group('id')
+
+        download_webpage = self._download_webpage(download_link, id,
+                                                  'Downloading free downloads page')
+        # We get the dictionary of the track from some javascrip code
+        info = re.search(r'items: (.*?),$',
+                         download_webpage, re.MULTILINE).group(1)
+        info = json.loads(info)[0]
+        # We pick mp3-320 for now, until format selection can be easily implemented.
+        mp3_info = info[u'downloads'][u'mp3-320']
+        # If we try to use this url it says the link has expired
+        initial_url = mp3_info[u'url']
+        re_url = r'(?P<server>http://(.*?)\.bandcamp\.com)/download/track\?enc=mp3-320&fsig=(?P<fsig>.*?)&id=(?P<id>.*?)&ts=(?P<ts>.*)$'
+        m_url = re.match(re_url, initial_url)
+        #We build the url we will use to get the final track url
+        # This url is build in Bandcamp in the script download_bunde_*.js
+        request_url = '%s/statdownload/track?enc=mp3-320&fsig=%s&id=%s&ts=%s&.rand=665028774616&.vrs=1' % (m_url.group('server'), m_url.group('fsig'), id, m_url.group('ts'))
+        final_url_webpage = self._download_webpage(request_url, id, 'Requesting download url')
+        # If we could correctly generate the .rand field the url would be
+        #in the "download_url" key
+        final_url = re.search(r'"retry_url":"(.*?)"', final_url_webpage).group(1)
+
+        track_info = {'id':id,
+                      'title' : info[u'title'],
+                      'ext' :   'mp3',
+                      'url' :   final_url,
+                      'thumbnail' : info[u'thumb_url'],
+                      'uploader' :  info[u'artist']
+                      }
+
+        return [track_info]
diff --git a/youtube_dl/extractor/bliptv.py b/youtube_dl/extractor/bliptv.py
new file mode 100644
index 0000000..df2ad4b
--- /dev/null
+++ b/youtube_dl/extractor/bliptv.py
@@ -0,0 +1,177 @@
+import datetime
+import json
+import os
+import re
+import socket
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_parse_qs,
+    compat_str,
+    compat_urllib_error,
+    compat_urllib_parse_urlparse,
+    compat_urllib_request,
+
+    ExtractorError,
+    unescapeHTML,
+)
+
+
+class BlipTVIE(InfoExtractor):
+    """Information extractor for blip.tv"""
+
+    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?blip\.tv/((.+/)|(play/)|(api\.swf#))(.+)$'
+    _URL_EXT = r'^.*\.([a-z0-9]+)$'
+    IE_NAME = u'blip.tv'
+
+    def report_direct_download(self, title):
+        """Report information extraction."""
+        self.to_screen(u'%s: Direct download detected' % title)
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        # See https://github.com/rg3/youtube-dl/issues/857
+        api_mobj = re.match(r'http://a\.blip\.tv/api\.swf#(?P<video_id>[\d\w]+)', url)
+        if api_mobj is not None:
+            url = 'http://blip.tv/play/g_%s' % api_mobj.group('video_id')
+        urlp = compat_urllib_parse_urlparse(url)
+        if urlp.path.startswith('/play/'):
+            request = compat_urllib_request.Request(url)
+            response = compat_urllib_request.urlopen(request)
+            redirecturl = response.geturl()
+            rurlp = compat_urllib_parse_urlparse(redirecturl)
+            file_id = compat_parse_qs(rurlp.fragment)['file'][0].rpartition('/')[2]
+            url = 'http://blip.tv/a/a-' + file_id
+            return self._real_extract(url)
+
+
+        if '?' in url:
+            cchar = '&'
+        else:
+            cchar = '?'
+        json_url = url + cchar + 'skin=json&version=2&no_wrap=1'
+        request = compat_urllib_request.Request(json_url)
+        request.add_header('User-Agent', 'iTunes/10.6.1')
+        self.report_extraction(mobj.group(1))
+        info = None
+        try:
+            urlh = compat_urllib_request.urlopen(request)
+            if urlh.headers.get('Content-Type', '').startswith('video/'): # Direct download
+                basename = url.split('/')[-1]
+                title,ext = os.path.splitext(basename)
+                title = title.decode('UTF-8')
+                ext = ext.replace('.', '')
+                self.report_direct_download(title)
+                info = {
+                    'id': title,
+                    'url': url,
+                    'uploader': None,
+                    'upload_date': None,
+                    'title': title,
+                    'ext': ext,
+                    'urlhandle': urlh
+                }
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'ERROR: unable to download video info webpage: %s' % compat_str(err))
+        if info is None: # Regular URL
+            try:
+                json_code_bytes = urlh.read()
+                json_code = json_code_bytes.decode('utf-8')
+            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+                raise ExtractorError(u'Unable to read video info webpage: %s' % compat_str(err))
+
+            try:
+                json_data = json.loads(json_code)
+                if 'Post' in json_data:
+                    data = json_data['Post']
+                else:
+                    data = json_data
+
+                upload_date = datetime.datetime.strptime(data['datestamp'], '%m-%d-%y %H:%M%p').strftime('%Y%m%d')
+                video_url = data['media']['url']
+                umobj = re.match(self._URL_EXT, video_url)
+                if umobj is None:
+                    raise ValueError('Can not determine filename extension')
+                ext = umobj.group(1)
+
+                info = {
+                    'id': data['item_id'],
+                    'url': video_url,
+                    'uploader': data['display_name'],
+                    'upload_date': upload_date,
+                    'title': data['title'],
+                    'ext': ext,
+                    'format': data['media']['mimeType'],
+                    'thumbnail': data['thumbnailUrl'],
+                    'description': data['description'],
+                    'player_url': data['embedUrl'],
+                    'user_agent': 'iTunes/10.6.1',
+                }
+            except (ValueError,KeyError) as err:
+                raise ExtractorError(u'Unable to parse video information: %s' % repr(err))
+
+        return [info]
+
+
+class BlipTVUserIE(InfoExtractor):
+    """Information Extractor for blip.tv users."""
+
+    _VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?blip\.tv/)|bliptvuser:)([^/]+)/*$'
+    _PAGE_SIZE = 12
+    IE_NAME = u'blip.tv:user'
+
+    def _real_extract(self, url):
+        # Extract username
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        username = mobj.group(1)
+
+        page_base = 'http://m.blip.tv/pr/show_get_full_episode_list?users_id=%s&lite=0&esi=1'
+
+        page = self._download_webpage(url, username, u'Downloading user page')
+        mobj = re.search(r'data-users-id="([^"]+)"', page)
+        page_base = page_base % mobj.group(1)
+
+
+        # Download video ids using BlipTV Ajax calls. Result size per
+        # query is limited (currently to 12 videos) so we need to query
+        # page by page until there are no video ids - it means we got
+        # all of them.
+
+        video_ids = []
+        pagenum = 1
+
+        while True:
+            url = page_base + "&page=" + str(pagenum)
+            page = self._download_webpage(url, username,
+                                          u'Downloading video ids from page %d' % pagenum)
+
+            # Extract video identifiers
+            ids_in_page = []
+
+            for mobj in re.finditer(r'href="/([^"]+)"', page):
+                if mobj.group(1) not in ids_in_page:
+                    ids_in_page.append(unescapeHTML(mobj.group(1)))
+
+            video_ids.extend(ids_in_page)
+
+            # A little optimization - if current page is not
+            # "full", ie. does not contain PAGE_SIZE video ids then
+            # we can assume that this page is the last one - there
+            # are no more ids on further pages - no need to query
+            # again.
+
+            if len(ids_in_page) < self._PAGE_SIZE:
+                break
+
+            pagenum += 1
+
+        urls = [u'http://blip.tv/%s' % video_id for video_id in video_ids]
+        url_entries = [self.url_result(url, 'BlipTV') for url in urls]
+        return [self.playlist_result(url_entries, playlist_title = username)]
diff --git a/youtube_dl/extractor/breakcom.py b/youtube_dl/extractor/breakcom.py
new file mode 100644
index 0000000..1f6620d
--- /dev/null
+++ b/youtube_dl/extractor/breakcom.py
@@ -0,0 +1,25 @@
+import re
+
+from .common import InfoExtractor
+
+
+class BreakIE(InfoExtractor):
+    _VALID_URL = r'(?:http://)?(?:www\.)?break\.com/video/([^/]+)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        video_id = mobj.group(1).split("-")[-1]
+        webpage = self._download_webpage(url, video_id)
+        video_url = re.search(r"videoPath: '(.+?)',",webpage).group(1)
+        key = re.search(r"icon: '(.+?)',",webpage).group(1)
+        final_url = str(video_url)+"?"+str(key)
+        thumbnail_url = re.search(r"thumbnailURL: '(.+?)'",webpage).group(1)
+        title = re.search(r"sVidTitle: '(.+)',",webpage).group(1)
+        ext = video_url.split('.')[-1]
+        return [{
+            'id':        video_id,
+            'url':       final_url,
+            'ext':       ext,
+            'title':     title,
+            'thumbnail': thumbnail_url,
+        }]
diff --git a/youtube_dl/extractor/collegehumor.py b/youtube_dl/extractor/collegehumor.py
new file mode 100644
index 0000000..7ae0972
--- /dev/null
+++ b/youtube_dl/extractor/collegehumor.py
@@ -0,0 +1,74 @@
+import re
+import socket
+import xml.etree.ElementTree
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_str,
+    compat_urllib_error,
+    compat_urllib_parse_urlparse,
+    compat_urllib_request,
+
+    ExtractorError,
+)
+
+
+class CollegeHumorIE(InfoExtractor):
+    _WORKING = False
+    _VALID_URL = r'^(?:https?://)?(?:www\.)?collegehumor\.com/video/(?P<videoid>[0-9]+)/(?P<shorttitle>.*)$'
+
+    def report_manifest(self, video_id):
+        """Report information extraction."""
+        self.to_screen(u'%s: Downloading XML manifest' % video_id)
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group('videoid')
+
+        info = {
+            'id': video_id,
+            'uploader': None,
+            'upload_date': None,
+        }
+
+        self.report_extraction(video_id)
+        xmlUrl = 'http://www.collegehumor.com/moogaloop/video/' + video_id
+        try:
+            metaXml = compat_urllib_request.urlopen(xmlUrl).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to download video info XML: %s' % compat_str(err))
+
+        mdoc = xml.etree.ElementTree.fromstring(metaXml)
+        try:
+            videoNode = mdoc.findall('./video')[0]
+            info['description'] = videoNode.findall('./description')[0].text
+            info['title'] = videoNode.findall('./caption')[0].text
+            info['thumbnail'] = videoNode.findall('./thumbnail')[0].text
+            manifest_url = videoNode.findall('./file')[0].text
+        except IndexError:
+            raise ExtractorError(u'Invalid metadata XML file')
+
+        manifest_url += '?hdcore=2.10.3'
+        self.report_manifest(video_id)
+        try:
+            manifestXml = compat_urllib_request.urlopen(manifest_url).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to download video info XML: %s' % compat_str(err))
+
+        adoc = xml.etree.ElementTree.fromstring(manifestXml)
+        try:
+            media_node = adoc.findall('./{http://ns.adobe.com/f4m/1.0}media')[0]
+            node_id = media_node.attrib['url']
+            video_id = adoc.findall('./{http://ns.adobe.com/f4m/1.0}id')[0].text
+        except IndexError as err:
+            raise ExtractorError(u'Invalid manifest file')
+
+        url_pr = compat_urllib_parse_urlparse(manifest_url)
+        url = url_pr.scheme + '://' + url_pr.netloc + '/z' + video_id[:-2] + '/' + node_id + 'Seg1-Frag1'
+
+        info['url'] = url
+        info['ext'] = 'f4f'
+        return [info]
diff --git a/youtube_dl/extractor/comedycentral.py b/youtube_dl/extractor/comedycentral.py
new file mode 100644
index 0000000..1bb3590
--- /dev/null
+++ b/youtube_dl/extractor/comedycentral.py
@@ -0,0 +1,179 @@
+import re
+import xml.etree.ElementTree
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_str,
+    compat_urllib_parse,
+
+    ExtractorError,
+    unified_strdate,
+)
+
+
+class ComedyCentralIE(InfoExtractor):
+    """Information extractor for The Daily Show and Colbert Report """
+
+    # urls can be abbreviations like :thedailyshow or :colbert
+    # urls for episodes like:
+    # or urls for clips like: http://www.thedailyshow.com/watch/mon-december-10-2012/any-given-gun-day
+    #                     or: http://www.colbertnation.com/the-colbert-report-videos/421667/november-29-2012/moon-shattering-news
+    #                     or: http://www.colbertnation.com/the-colbert-report-collections/422008/festival-of-lights/79524
+    _VALID_URL = r"""^(:(?P<shortname>tds|thedailyshow|cr|colbert|colbertnation|colbertreport)
+                      |(https?://)?(www\.)?
+                          (?P<showname>thedailyshow|colbertnation)\.com/
+                         (full-episodes/(?P<episode>.*)|
+                          (?P<clip>
+                              (the-colbert-report-(videos|collections)/(?P<clipID>[0-9]+)/[^/]*/(?P<cntitle>.*?))
+                              |(watch/(?P<date>[^/]*)/(?P<tdstitle>.*)))))
+                     $"""
+
+    _available_formats = ['3500', '2200', '1700', '1200', '750', '400']
+
+    _video_extensions = {
+        '3500': 'mp4',
+        '2200': 'mp4',
+        '1700': 'mp4',
+        '1200': 'mp4',
+        '750': 'mp4',
+        '400': 'mp4',
+    }
+    _video_dimensions = {
+        '3500': '1280x720',
+        '2200': '960x540',
+        '1700': '768x432',
+        '1200': '640x360',
+        '750': '512x288',
+        '400': '384x216',
+    }
+
+    @classmethod
+    def suitable(cls, url):
+        """Receives a URL and returns True if suitable for this IE."""
+        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
+
+    def _print_formats(self, formats):
+        print('Available formats:')
+        for x in formats:
+            print('%s\t:\t%s\t[%s]' %(x, self._video_extensions.get(x, 'mp4'), self._video_dimensions.get(x, '???')))
+
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url, re.VERBOSE)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        if mobj.group('shortname'):
+            if mobj.group('shortname') in ('tds', 'thedailyshow'):
+                url = u'http://www.thedailyshow.com/full-episodes/'
+            else:
+                url = u'http://www.colbertnation.com/full-episodes/'
+            mobj = re.match(self._VALID_URL, url, re.VERBOSE)
+            assert mobj is not None
+
+        if mobj.group('clip'):
+            if mobj.group('showname') == 'thedailyshow':
+                epTitle = mobj.group('tdstitle')
+            else:
+                epTitle = mobj.group('cntitle')
+            dlNewest = False
+        else:
+            dlNewest = not mobj.group('episode')
+            if dlNewest:
+                epTitle = mobj.group('showname')
+            else:
+                epTitle = mobj.group('episode')
+
+        self.report_extraction(epTitle)
+        webpage,htmlHandle = self._download_webpage_handle(url, epTitle)
+        if dlNewest:
+            url = htmlHandle.geturl()
+            mobj = re.match(self._VALID_URL, url, re.VERBOSE)
+            if mobj is None:
+                raise ExtractorError(u'Invalid redirected URL: ' + url)
+            if mobj.group('episode') == '':
+                raise ExtractorError(u'Redirected URL is still not specific: ' + url)
+            epTitle = mobj.group('episode')
+
+        mMovieParams = re.findall('(?:<param name="movie" value="|var url = ")(http://media.mtvnservices.com/([^"]*(?:episode|video).*?:.*?))"', webpage)
+
+        if len(mMovieParams) == 0:
+            # The Colbert Report embeds the information in a without
+            # a URL prefix; so extract the alternate reference
+            # and then add the URL prefix manually.
+
+            altMovieParams = re.findall('data-mgid="([^"]*(?:episode|video).*?:.*?)"', webpage)
+            if len(altMovieParams) == 0:
+                raise ExtractorError(u'unable to find Flash URL in webpage ' + url)
+            else:
+                mMovieParams = [("http://media.mtvnservices.com/" + altMovieParams[0], altMovieParams[0])]
+
+        uri = mMovieParams[0][1]
+        indexUrl = 'http://shadow.comedycentral.com/feeds/video_player/mrss/?' + compat_urllib_parse.urlencode({'uri': uri})
+        indexXml = self._download_webpage(indexUrl, epTitle,
+                                          u'Downloading show index',
+                                          u'unable to download episode index')
+
+        results = []
+
+        idoc = xml.etree.ElementTree.fromstring(indexXml)
+        itemEls = idoc.findall('.//item')
+        for partNum,itemEl in enumerate(itemEls):
+            mediaId = itemEl.findall('./guid')[0].text
+            shortMediaId = mediaId.split(':')[-1]
+            showId = mediaId.split(':')[-2].replace('.com', '')
+            officialTitle = itemEl.findall('./title')[0].text
+            officialDate = unified_strdate(itemEl.findall('./pubDate')[0].text)
+
+            configUrl = ('http://www.comedycentral.com/global/feeds/entertainment/media/mediaGenEntertainment.jhtml?' +
+                        compat_urllib_parse.urlencode({'uri': mediaId}))
+            configXml = self._download_webpage(configUrl, epTitle,
+                                               u'Downloading configuration for %s' % shortMediaId)
+
+            cdoc = xml.etree.ElementTree.fromstring(configXml)
+            turls = []
+            for rendition in cdoc.findall('.//rendition'):
+                finfo = (rendition.attrib['bitrate'], rendition.findall('./src')[0].text)
+                turls.append(finfo)
+
+            if len(turls) == 0:
+                self._downloader.report_error(u'unable to download ' + mediaId + ': No videos found')
+                continue
+
+            if self._downloader.params.get('listformats', None):
+                self._print_formats([i[0] for i in turls])
+                return
+
+            # For now, just pick the highest bitrate
+            format,rtmp_video_url = turls[-1]
+
+            # Get the format arg from the arg stream
+            req_format = self._downloader.params.get('format', None)
+
+            # Select format if we can find one
+            for f,v in turls:
+                if f == req_format:
+                    format, rtmp_video_url = f, v
+                    break
+
+            m = re.match(r'^rtmpe?://.*?/(?P<finalid>gsp.comedystor/.*)$', rtmp_video_url)
+            if not m:
+                raise ExtractorError(u'Cannot transform RTMP url')
+            base = 'http://mtvnmobile.vo.llnwd.net/kip0/_pxn=1+_pxI0=Ripod-h264+_pxL0=undefined+_pxM0=+_pxK=18639+_pxE=mp4/44620/mtvnorigin/'
+            video_url = base + m.group('finalid')
+
+            effTitle = showId + u'-' + epTitle + u' part ' + compat_str(partNum+1)
+            info = {
+                'id': shortMediaId,
+                'url': video_url,
+                'uploader': showId,
+                'upload_date': officialDate,
+                'title': effTitle,
+                'ext': 'mp4',
+                'format': format,
+                'thumbnail': None,
+                'description': officialTitle,
+            }
+            results.append(info)
+
+        return results
diff --git a/youtube_dl/extractor/common.py b/youtube_dl/extractor/common.py
new file mode 100644
index 0000000..062f4cf
--- /dev/null
+++ b/youtube_dl/extractor/common.py
@@ -0,0 +1,264 @@
+import base64
+import os
+import re
+import socket
+import sys
+
+from ..utils import (
+    compat_http_client,
+    compat_urllib_error,
+    compat_urllib_request,
+    compat_str,
+
+    clean_html,
+    compiled_regex_type,
+    ExtractorError,
+)
+
+class InfoExtractor(object):
+    """Information Extractor class.
+
+    Information extractors are the classes that, given a URL, extract
+    information about the video (or videos) the URL refers to. This
+    information includes the real video URL, the video title, author and
+    others. The information is stored in a dictionary which is then
+    passed to the FileDownloader. The FileDownloader processes this
+    information possibly downloading the video to the file system, among
+    other possible outcomes.
+
+    The dictionaries must include the following fields:
+
+    id:             Video identifier.
+    url:            Final video URL.
+    title:          Video title, unescaped.
+    ext:            Video filename extension.
+
+    The following fields are optional:
+
+    format:         The video format, defaults to ext (used for --get-format)
+    thumbnail:      Full URL to a video thumbnail image.
+    description:    One-line video description.
+    uploader:       Full name of the video uploader.
+    upload_date:    Video upload date (YYYYMMDD).
+    uploader_id:    Nickname or id of the video uploader.
+    location:       Physical location of the video.
+    player_url:     SWF Player URL (used for rtmpdump).
+    subtitles:      The subtitle file contents.
+    urlhandle:      [internal] The urlHandle to be used to download the file,
+                    like returned by urllib.request.urlopen
+
+    The fields should all be Unicode strings.
+
+    Subclasses of this one should re-define the _real_initialize() and
+    _real_extract() methods and define a _VALID_URL regexp.
+    Probably, they should also be added to the list of extractors.
+
+    _real_extract() must return a *list* of information dictionaries as
+    described above.
+
+    Finally, the _WORKING attribute should be set to False for broken IEs
+    in order to warn the users and skip the tests.
+    """
+
+    _ready = False
+    _downloader = None
+    _WORKING = True
+
+    def __init__(self, downloader=None):
+        """Constructor. Receives an optional downloader."""
+        self._ready = False
+        self.set_downloader(downloader)
+
+    @classmethod
+    def suitable(cls, url):
+        """Receives a URL and returns True if suitable for this IE."""
+        return re.match(cls._VALID_URL, url) is not None
+
+    @classmethod
+    def working(cls):
+        """Getter method for _WORKING."""
+        return cls._WORKING
+
+    def initialize(self):
+        """Initializes an instance (authentication, etc)."""
+        if not self._ready:
+            self._real_initialize()
+            self._ready = True
+
+    def extract(self, url):
+        """Extracts URL information and returns it in list of dicts."""
+        self.initialize()
+        return self._real_extract(url)
+
+    def set_downloader(self, downloader):
+        """Sets the downloader for this IE."""
+        self._downloader = downloader
+
+    def _real_initialize(self):
+        """Real initialization process. Redefine in subclasses."""
+        pass
+
+    def _real_extract(self, url):
+        """Real extraction process. Redefine in subclasses."""
+        pass
+
+    @property
+    def IE_NAME(self):
+        return type(self).__name__[:-2]
+
+    def _request_webpage(self, url_or_request, video_id, note=None, errnote=None):
+        """ Returns the response handle """
+        if note is None:
+            self.report_download_webpage(video_id)
+        elif note is not False:
+            self.to_screen(u'%s: %s' % (video_id, note))
+        try:
+            return compat_urllib_request.urlopen(url_or_request)
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            if errnote is None:
+                errnote = u'Unable to download webpage'
+            raise ExtractorError(u'%s: %s' % (errnote, compat_str(err)), sys.exc_info()[2])
+
+    def _download_webpage_handle(self, url_or_request, video_id, note=None, errnote=None):
+        """ Returns a tuple (page content as string, URL handle) """
+        urlh = self._request_webpage(url_or_request, video_id, note, errnote)
+        content_type = urlh.headers.get('Content-Type', '')
+        m = re.match(r'[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+\s*;\s*charset=(.+)', content_type)
+        if m:
+            encoding = m.group(1)
+        else:
+            encoding = 'utf-8'
+        webpage_bytes = urlh.read()
+        if self._downloader.params.get('dump_intermediate_pages', False):
+            try:
+                url = url_or_request.get_full_url()
+            except AttributeError:
+                url = url_or_request
+            self.to_screen(u'Dumping request to ' + url)
+            dump = base64.b64encode(webpage_bytes).decode('ascii')
+            self._downloader.to_screen(dump)
+        content = webpage_bytes.decode(encoding, 'replace')
+        return (content, urlh)
+
+    def _download_webpage(self, url_or_request, video_id, note=None, errnote=None):
+        """ Returns the data of the page as a string """
+        return self._download_webpage_handle(url_or_request, video_id, note, errnote)[0]
+
+    def to_screen(self, msg):
+        """Print msg to screen, prefixing it with '[ie_name]'"""
+        self._downloader.to_screen(u'[%s] %s' % (self.IE_NAME, msg))
+
+    def report_extraction(self, id_or_name):
+        """Report information extraction."""
+        self.to_screen(u'%s: Extracting information' % id_or_name)
+
+    def report_download_webpage(self, video_id):
+        """Report webpage download."""
+        self.to_screen(u'%s: Downloading webpage' % video_id)
+
+    def report_age_confirmation(self):
+        """Report attempt to confirm age."""
+        self.to_screen(u'Confirming age')
+
+    #Methods for following #608
+    #They set the correct value of the '_type' key
+    def video_result(self, video_info):
+        """Returns a video"""
+        video_info['_type'] = 'video'
+        return video_info
+    def url_result(self, url, ie=None):
+        """Returns a url that points to a page that should be processed"""
+        #TODO: ie should be the class used for getting the info
+        video_info = {'_type': 'url',
+                      'url': url,
+                      'ie_key': ie}
+        return video_info
+    def playlist_result(self, entries, playlist_id=None, playlist_title=None):
+        """Returns a playlist"""
+        video_info = {'_type': 'playlist',
+                      'entries': entries}
+        if playlist_id:
+            video_info['id'] = playlist_id
+        if playlist_title:
+            video_info['title'] = playlist_title
+        return video_info
+
+    def _search_regex(self, pattern, string, name, default=None, fatal=True, flags=0):
+        """
+        Perform a regex search on the given string, using a single or a list of
+        patterns returning the first matching group.
+        In case of failure return a default value or raise a WARNING or a
+        ExtractorError, depending on fatal, specifying the field name.
+        """
+        if isinstance(pattern, (str, compat_str, compiled_regex_type)):
+            mobj = re.search(pattern, string, flags)
+        else:
+            for p in pattern:
+                mobj = re.search(p, string, flags)
+                if mobj: break
+
+        if sys.stderr.isatty() and os.name != 'nt':
+            _name = u'\033[0;34m%s\033[0m' % name
+        else:
+            _name = name
+
+        if mobj:
+            # return the first matching group
+            return next(g for g in mobj.groups() if g is not None)
+        elif default is not None:
+            return default
+        elif fatal:
+            raise ExtractorError(u'Unable to extract %s' % _name)
+        else:
+            self._downloader.report_warning(u'unable to extract %s; '
+                u'please report this issue on GitHub.' % _name)
+            return None
+
+    def _html_search_regex(self, pattern, string, name, default=None, fatal=True, flags=0):
+        """
+        Like _search_regex, but strips HTML tags and unescapes entities.
+        """
+        res = self._search_regex(pattern, string, name, default, fatal, flags)
+        if res:
+            return clean_html(res).strip()
+        else:
+            return res
+
+class SearchInfoExtractor(InfoExtractor):
+    """
+    Base class for paged search queries extractors.
+    They accept urls in the format _SEARCH_KEY(|all|[0-9]):{query}
+    Instances should define _SEARCH_KEY and _MAX_RESULTS.
+    """
+
+    @classmethod
+    def _make_valid_url(cls):
+        return r'%s(?P<prefix>|[1-9][0-9]*|all):(?P<query>[\s\S]+)' % cls._SEARCH_KEY
+
+    @classmethod
+    def suitable(cls, url):
+        return re.match(cls._make_valid_url(), url) is not None
+
+    def _real_extract(self, query):
+        mobj = re.match(self._make_valid_url(), query)
+        if mobj is None:
+            raise ExtractorError(u'Invalid search query "%s"' % query)
+
+        prefix = mobj.group('prefix')
+        query = mobj.group('query')
+        if prefix == '':
+            return self._get_n_results(query, 1)
+        elif prefix == 'all':
+            return self._get_n_results(query, self._MAX_RESULTS)
+        else:
+            n = int(prefix)
+            if n <= 0:
+                raise ExtractorError(u'invalid download number %s for query "%s"' % (n, query))
+            elif n > self._MAX_RESULTS:
+                self._downloader.report_warning(u'%s returns max %i results (you requested %i)' % (self._SEARCH_KEY, self._MAX_RESULTS, n))
+                n = self._MAX_RESULTS
+            return self._get_n_results(query, n)
+
+    def _get_n_results(self, query, n):
+        """Get a specified number of results for a query"""
+        raise NotImplementedError("This method must be implemented by sublclasses")
diff --git a/youtube_dl/extractor/dailymotion.py b/youtube_dl/extractor/dailymotion.py
new file mode 100644
index 0000000..34306b0
--- /dev/null
+++ b/youtube_dl/extractor/dailymotion.py
@@ -0,0 +1,77 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_request,
+    compat_urllib_parse,
+
+    ExtractorError,
+    unescapeHTML,
+)
+
+class DailymotionIE(InfoExtractor):
+    """Information Extractor for Dailymotion"""
+
+    _VALID_URL = r'(?i)(?:https?://)?(?:www\.)?dailymotion\.[a-z]{2,3}/video/([^/]+)'
+    IE_NAME = u'dailymotion'
+
+    def _real_extract(self, url):
+        # Extract id and simplified title from URL
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group(1).split('_')[0].split('?')[0]
+
+        video_extension = 'mp4'
+
+        # Retrieve video webpage to extract further information
+        request = compat_urllib_request.Request(url)
+        request.add_header('Cookie', 'family_filter=off')
+        webpage = self._download_webpage(request, video_id)
+
+        # Extract URL, uploader and title from webpage
+        self.report_extraction(video_id)
+        mobj = re.search(r'\s*var flashvars = (.*)', webpage)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract media URL')
+        flashvars = compat_urllib_parse.unquote(mobj.group(1))
+
+        for key in ['hd1080URL', 'hd720URL', 'hqURL', 'sdURL', 'ldURL', 'video_url']:
+            if key in flashvars:
+                max_quality = key
+                self.to_screen(u'Using %s' % key)
+                break
+        else:
+            raise ExtractorError(u'Unable to extract video URL')
+
+        mobj = re.search(r'"' + max_quality + r'":"(.+?)"', flashvars)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract video URL')
+
+        video_url = compat_urllib_parse.unquote(mobj.group(1)).replace('\\/', '/')
+
+        # TODO: support choosing qualities
+
+        mobj = re.search(r'<meta property="og:title" content="(?P<title>[^"]*)" />', webpage)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract title')
+        video_title = unescapeHTML(mobj.group('title'))
+
+        video_uploader = None
+        video_uploader = self._search_regex([r'(?im)<span class="owner[^\"]+?">[^<]+?<a [^>]+?>([^<]+?)</a>',
+                                             # Looking for official user
+                                             r'<(?:span|a) .*?rel="author".*?>([^<]+?)</'],
+                                            webpage, 'video uploader')
+
+        video_upload_date = None
+        mobj = re.search(r'<div class="[^"]*uploaded_cont[^"]*" title="[^"]*">([0-9]{2})-([0-9]{2})-([0-9]{4})</div>', webpage)
+        if mobj is not None:
+            video_upload_date = mobj.group(3) + mobj.group(2) + mobj.group(1)
+
+        return [{
+            'id':       video_id,
+            'url':      video_url,
+            'uploader': video_uploader,
+            'upload_date':  video_upload_date,
+            'title':    video_title,
+            'ext':      video_extension,
+        }]
diff --git a/youtube_dl/extractor/depositfiles.py b/youtube_dl/extractor/depositfiles.py
new file mode 100644
index 0000000..d433489
--- /dev/null
+++ b/youtube_dl/extractor/depositfiles.py
@@ -0,0 +1,60 @@
+import re
+import os
+import socket
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_str,
+    compat_urllib_error,
+    compat_urllib_parse,
+    compat_urllib_request,
+
+    ExtractorError,
+)
+
+
+class DepositFilesIE(InfoExtractor):
+    """Information extractor for depositfiles.com"""
+
+    _VALID_URL = r'(?:http://)?(?:\w+\.)?depositfiles\.com/(?:../(?#locale))?files/(.+)'
+
+    def _real_extract(self, url):
+        file_id = url.split('/')[-1]
+        # Rebuild url in english locale
+        url = 'http://depositfiles.com/en/files/' + file_id
+
+        # Retrieve file webpage with 'Free download' button pressed
+        free_download_indication = { 'gateway_result' : '1' }
+        request = compat_urllib_request.Request(url, compat_urllib_parse.urlencode(free_download_indication))
+        try:
+            self.report_download_webpage(file_id)
+            webpage = compat_urllib_request.urlopen(request).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to retrieve file webpage: %s' % compat_str(err))
+
+        # Search for the real file URL
+        mobj = re.search(r'<form action="(http://fileshare.+?)"', webpage)
+        if (mobj is None) or (mobj.group(1) is None):
+            # Try to figure out reason of the error.
+            mobj = re.search(r'<strong>(Attention.*?)</strong>', webpage, re.DOTALL)
+            if (mobj is not None) and (mobj.group(1) is not None):
+                restriction_message = re.sub('\s+', ' ', mobj.group(1)).strip()
+                raise ExtractorError(u'%s' % restriction_message)
+            else:
+                raise ExtractorError(u'Unable to extract download URL from: %s' % url)
+
+        file_url = mobj.group(1)
+        file_extension = os.path.splitext(file_url)[1][1:]
+
+        # Search for file title
+        file_title = self._search_regex(r'<b title="(.*?)">', webpage, u'title')
+
+        return [{
+            'id':       file_id.decode('utf-8'),
+            'url':      file_url.decode('utf-8'),
+            'uploader': None,
+            'upload_date':  None,
+            'title':    file_title,
+            'ext':      file_extension.decode('utf-8'),
+        }]
diff --git a/youtube_dl/extractor/eighttracks.py b/youtube_dl/extractor/eighttracks.py
new file mode 100644
index 0000000..c3d4343
--- /dev/null
+++ b/youtube_dl/extractor/eighttracks.py
@@ -0,0 +1,51 @@
+import itertools
+import json
+import random
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class EightTracksIE(InfoExtractor):
+    IE_NAME = '8tracks'
+    _VALID_URL = r'https?://8tracks.com/(?P<user>[^/]+)/(?P<id>[^/#]+)(?:#.*)?$'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        playlist_id = mobj.group('id')
+
+        webpage = self._download_webpage(url, playlist_id)
+
+        json_like = self._search_regex(r"PAGE.mix = (.*?);\n", webpage, u'trax information', flags=re.DOTALL)
+        data = json.loads(json_like)
+
+        session = str(random.randint(0, 1000000000))
+        mix_id = data['id']
+        track_count = data['tracks_count']
+        first_url = 'http://8tracks.com/sets/%s/play?player=sm&mix_id=%s&format=jsonh' % (session, mix_id)
+        next_url = first_url
+        res = []
+        for i in itertools.count():
+            api_json = self._download_webpage(next_url, playlist_id,
+                note=u'Downloading song information %s/%s' % (str(i+1), track_count),
+                errnote=u'Failed to download song information')
+            api_data = json.loads(api_json)
+            track_data = api_data[u'set']['track']
+            info = {
+                'id': track_data['id'],
+                'url': track_data['track_file_stream_url'],
+                'title': track_data['performer'] + u' - ' + track_data['name'],
+                'raw_title': track_data['name'],
+                'uploader_id': data['user']['login'],
+                'ext': 'm4a',
+            }
+            res.append(info)
+            if api_data['set']['at_last_track']:
+                break
+            next_url = 'http://8tracks.com/sets/%s/next?player=sm&mix_id=%s&format=jsonh&track_id=%s' % (session, mix_id, track_data['id'])
+        return res
diff --git a/youtube_dl/extractor/escapist.py b/youtube_dl/extractor/escapist.py
new file mode 100644
index 0000000..86b145b
--- /dev/null
+++ b/youtube_dl/extractor/escapist.py
@@ -0,0 +1,68 @@
+import json
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_str,
+    compat_urllib_parse,
+
+    ExtractorError,
+)
+
+
+class EscapistIE(InfoExtractor):
+    _VALID_URL = r'^(https?://)?(www\.)?escapistmagazine\.com/videos/view/(?P<showname>[^/]+)/(?P<episode>[^/?]+)[/?]?.*$'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        showName = mobj.group('showname')
+        videoId = mobj.group('episode')
+
+        self.report_extraction(videoId)
+        webpage = self._download_webpage(url, videoId)
+
+        videoDesc = self._html_search_regex('<meta name="description" content="([^"]*)"',
+            webpage, u'description', fatal=False)
+
+        imgUrl = self._html_search_regex('<meta property="og:image" content="([^"]*)"',
+            webpage, u'thumbnail', fatal=False)
+
+        playerUrl = self._html_search_regex('<meta property="og:video" content="([^"]*)"',
+            webpage, u'player url')
+
+        title = self._html_search_regex('<meta name="title" content="([^"]*)"',
+            webpage, u'player url').split(' : ')[-1]
+
+        configUrl = self._search_regex('config=(.*)$', playerUrl, u'config url')
+        configUrl = compat_urllib_parse.unquote(configUrl)
+
+        configJSON = self._download_webpage(configUrl, videoId,
+                                            u'Downloading configuration',
+                                            u'unable to download configuration')
+
+        # Technically, it's JavaScript, not JSON
+        configJSON = configJSON.replace("'", '"')
+
+        try:
+            config = json.loads(configJSON)
+        except (ValueError,) as err:
+            raise ExtractorError(u'Invalid JSON in configuration file: ' + compat_str(err))
+
+        playlist = config['playlist']
+        videoUrl = playlist[1]['url']
+
+        info = {
+            'id': videoId,
+            'url': videoUrl,
+            'uploader': showName,
+            'upload_date': None,
+            'title': title,
+            'ext': 'mp4',
+            'thumbnail': imgUrl,
+            'description': videoDesc,
+            'player_url': playerUrl,
+        }
+
+        return [info]
diff --git a/youtube_dl/extractor/facebook.py b/youtube_dl/extractor/facebook.py
new file mode 100644
index 0000000..c694f9a
--- /dev/null
+++ b/youtube_dl/extractor/facebook.py
@@ -0,0 +1,111 @@
+import json
+import netrc
+import re
+import socket
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_str,
+    compat_urllib_error,
+    compat_urllib_parse,
+    compat_urllib_request,
+
+    ExtractorError,
+)
+
+
+class FacebookIE(InfoExtractor):
+    """Information Extractor for Facebook"""
+
+    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?facebook\.com/(?:video/video|photo)\.php\?(?:.*?)v=(?P<ID>\d+)(?:.*)'
+    _LOGIN_URL = 'https://login.facebook.com/login.php?m&next=http%3A%2F%2Fm.facebook.com%2Fhome.php&'
+    _NETRC_MACHINE = 'facebook'
+    IE_NAME = u'facebook'
+
+    def report_login(self):
+        """Report attempt to log in."""
+        self.to_screen(u'Logging in')
+
+    def _real_initialize(self):
+        if self._downloader is None:
+            return
+
+        useremail = None
+        password = None
+        downloader_params = self._downloader.params
+
+        # Attempt to use provided username and password or .netrc data
+        if downloader_params.get('username', None) is not None:
+            useremail = downloader_params['username']
+            password = downloader_params['password']
+        elif downloader_params.get('usenetrc', False):
+            try:
+                info = netrc.netrc().authenticators(self._NETRC_MACHINE)
+                if info is not None:
+                    useremail = info[0]
+                    password = info[2]
+                else:
+                    raise netrc.NetrcParseError('No authenticators for %s' % self._NETRC_MACHINE)
+            except (IOError, netrc.NetrcParseError) as err:
+                self._downloader.report_warning(u'parsing .netrc: %s' % compat_str(err))
+                return
+
+        if useremail is None:
+            return
+
+        # Log in
+        login_form = {
+            'email': useremail,
+            'pass': password,
+            'login': 'Log+In'
+            }
+        request = compat_urllib_request.Request(self._LOGIN_URL, compat_urllib_parse.urlencode(login_form))
+        try:
+            self.report_login()
+            login_results = compat_urllib_request.urlopen(request).read()
+            if re.search(r'<form(.*)name="login"(.*)</form>', login_results) is not None:
+                self._downloader.report_warning(u'unable to log in: bad username/password, or exceded login rate limit (~3/min). Check credentials or wait.')
+                return
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            self._downloader.report_warning(u'unable to log in: %s' % compat_str(err))
+            return
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group('ID')
+
+        url = 'https://www.facebook.com/video/video.php?v=%s' % video_id
+        webpage = self._download_webpage(url, video_id)
+
+        BEFORE = '{swf.addParam(param[0], param[1]);});\n'
+        AFTER = '.forEach(function(variable) {swf.addVariable(variable[0], variable[1]);});'
+        m = re.search(re.escape(BEFORE) + '(.*?)' + re.escape(AFTER), webpage)
+        if not m:
+            raise ExtractorError(u'Cannot parse data')
+        data = dict(json.loads(m.group(1)))
+        params_raw = compat_urllib_parse.unquote(data['params'])
+        params = json.loads(params_raw)
+        video_data = params['video_data'][0]
+        video_url = video_data.get('hd_src')
+        if not video_url:
+            video_url = video_data['sd_src']
+        if not video_url:
+            raise ExtractorError(u'Cannot find video URL')
+        video_duration = int(video_data['video_duration'])
+        thumbnail = video_data['thumbnail_src']
+
+        video_title = self._html_search_regex('<h2 class="uiHeaderTitle">([^<]+)</h2>',
+            webpage, u'title')
+
+        info = {
+            'id': video_id,
+            'title': video_title,
+            'url': video_url,
+            'ext': 'mp4',
+            'duration': video_duration,
+            'thumbnail': thumbnail,
+        }
+        return [info]
diff --git a/youtube_dl/extractor/flickr.py b/youtube_dl/extractor/flickr.py
new file mode 100644
index 0000000..791d5b6
--- /dev/null
+++ b/youtube_dl/extractor/flickr.py
@@ -0,0 +1,57 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+    unescapeHTML,
+)
+
+
+class FlickrIE(InfoExtractor):
+    """Information Extractor for Flickr videos"""
+    _VALID_URL = r'(?:https?://)?(?:www\.)?flickr\.com/photos/(?P<uploader_id>[\w\-_@]+)/(?P<id>\d+).*'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('id')
+        video_uploader_id = mobj.group('uploader_id')
+        webpage_url = 'http://www.flickr.com/photos/' + video_uploader_id + '/' + video_id
+        webpage = self._download_webpage(webpage_url, video_id)
+
+        secret = self._search_regex(r"photo_secret: '(\w+)'", webpage, u'secret')
+
+        first_url = 'https://secure.flickr.com/apps/video/video_mtl_xml.gne?v=x&photo_id=' + video_id + '&secret=' + secret + '&bitrate=700&target=_self'
+        first_xml = self._download_webpage(first_url, video_id, 'Downloading first data webpage')
+
+        node_id = self._html_search_regex(r'<Item id="id">(\d+-\d+)</Item>',
+            first_xml, u'node_id')
+
+        second_url = 'https://secure.flickr.com/video_playlist.gne?node_id=' + node_id + '&tech=flash&mode=playlist&bitrate=700&secret=' + secret + '&rd=video.yahoo.com&noad=1'
+        second_xml = self._download_webpage(second_url, video_id, 'Downloading second data webpage')
+
+        self.report_extraction(video_id)
+
+        mobj = re.search(r'<STREAM APP="(.+?)" FULLPATH="(.+?)"', second_xml)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract video url')
+        video_url = mobj.group(1) + unescapeHTML(mobj.group(2))
+
+        video_title = self._html_search_regex(r'<meta property="og:title" content=(?:"([^"]+)"|\'([^\']+)\')',
+            webpage, u'video title')
+
+        video_description = self._html_search_regex(r'<meta property="og:description" content=(?:"([^"]+)"|\'([^\']+)\')',
+            webpage, u'description', fatal=False)
+
+        thumbnail = self._html_search_regex(r'<meta property="og:image" content=(?:"([^"]+)"|\'([^\']+)\')',
+            webpage, u'thumbnail', fatal=False)
+
+        return [{
+            'id':          video_id,
+            'url':         video_url,
+            'ext':         'mp4',
+            'title':       video_title,
+            'description': video_description,
+            'thumbnail':   thumbnail,
+            'uploader_id': video_uploader_id,
+        }]
diff --git a/youtube_dl/extractor/funnyordie.py b/youtube_dl/extractor/funnyordie.py
new file mode 100644
index 0000000..3045978
--- /dev/null
+++ b/youtube_dl/extractor/funnyordie.py
@@ -0,0 +1,31 @@
+import re
+
+from .common import InfoExtractor
+
+
+class FunnyOrDieIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?(?:www\.)?funnyordie\.com/videos/(?P<id>[0-9a-f]+)/.*$'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('id')
+        webpage = self._download_webpage(url, video_id)
+
+        video_url = self._html_search_regex(r'<video[^>]*>\s*<source[^>]*>\s*<source src="(?P<url>[^"]+)"',
+            webpage, u'video URL', flags=re.DOTALL)
+
+        title = self._html_search_regex((r"<h1 class='player_page_h1'.*?>(?P<title>.*?)</h1>",
+            r'<title>(?P<title>[^<]+?)</title>'), webpage, 'title', flags=re.DOTALL)
+
+        video_description = self._html_search_regex(r'<meta property="og:description" content="(?P<desc>.*?)"',
+            webpage, u'description', fatal=False, flags=re.DOTALL)
+
+        info = {
+            'id': video_id,
+            'url': video_url,
+            'ext': 'mp4',
+            'title': title,
+            'description': video_description,
+        }
+        return [info]
diff --git a/youtube_dl/extractor/gametrailers.py b/youtube_dl/extractor/gametrailers.py
new file mode 100644
index 0000000..33e59e8
--- /dev/null
+++ b/youtube_dl/extractor/gametrailers.py
@@ -0,0 +1,59 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+
+    ExtractorError,
+)
+
+class GametrailersIE(InfoExtractor):
+    _VALID_URL = r'http://www.gametrailers.com/(?P<type>videos|reviews|full-episodes)/(?P<id>.*?)/(?P<title>.*)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group('id')
+        video_type = mobj.group('type')
+        webpage = self._download_webpage(url, video_id)
+        if video_type == 'full-episodes':
+            mgid_re = r'data-video="(?P<mgid>mgid:.*?)"'
+        else:
+            mgid_re = r'data-contentId=\'(?P<mgid>mgid:.*?)\''
+        mgid = self._search_regex(mgid_re, webpage, u'mgid')
+        data = compat_urllib_parse.urlencode({'uri': mgid, 'acceptMethods': 'fms'})
+
+        info_page = self._download_webpage('http://www.gametrailers.com/feeds/mrss?' + data,
+                                           video_id, u'Downloading video info')
+        links_webpage = self._download_webpage('http://www.gametrailers.com/feeds/mediagen/?' + data,
+                                               video_id, u'Downloading video urls info')
+
+        self.report_extraction(video_id)
+        info_re = r'''<title><!\[CDATA\[(?P<title>.*?)\]\]></title>.*
+                      <description><!\[CDATA\[(?P<description>.*?)\]\]></description>.*
+                      <image>.*
+                        <url>(?P<thumb>.*?)</url>.*
+                      </image>'''
+
+        m_info = re.search(info_re, info_page, re.VERBOSE|re.DOTALL)
+        if m_info is None:
+            raise ExtractorError(u'Unable to extract video info')
+        video_title = m_info.group('title')
+        video_description = m_info.group('description')
+        video_thumb = m_info.group('thumb')
+
+        m_urls = list(re.finditer(r'<src>(?P<url>.*)</src>', links_webpage))
+        if m_urls is None or len(m_urls) == 0:
+            raise ExtractorError(u'Unable to extract video url')
+        # They are sorted from worst to best quality
+        video_url = m_urls[-1].group('url')
+
+        return {'url':         video_url,
+                'id':          video_id,
+                'title':       video_title,
+                # Videos are actually flv not mp4
+                'ext':         'flv',
+                'thumbnail':   video_thumb,
+                'description': video_description,
+                }
diff --git a/youtube_dl/extractor/generic.py b/youtube_dl/extractor/generic.py
new file mode 100644
index 0000000..7a877b3
--- /dev/null
+++ b/youtube_dl/extractor/generic.py
@@ -0,0 +1,151 @@
+import os
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_error,
+    compat_urllib_parse,
+    compat_urllib_request,
+
+    ExtractorError,
+)
+
+class GenericIE(InfoExtractor):
+    """Generic last-resort information extractor."""
+
+    _VALID_URL = r'.*'
+    IE_NAME = u'generic'
+
+    def report_download_webpage(self, video_id):
+        """Report webpage download."""
+        if not self._downloader.params.get('test', False):
+            self._downloader.report_warning(u'Falling back on generic information extractor.')
+        super(GenericIE, self).report_download_webpage(video_id)
+
+    def report_following_redirect(self, new_url):
+        """Report information extraction."""
+        self._downloader.to_screen(u'[redirect] Following redirect to %s' % new_url)
+
+    def _test_redirect(self, url):
+        """Check if it is a redirect, like url shorteners, in case return the new url."""
+        class HeadRequest(compat_urllib_request.Request):
+            def get_method(self):
+                return "HEAD"
+
+        class HEADRedirectHandler(compat_urllib_request.HTTPRedirectHandler):
+            """
+            Subclass the HTTPRedirectHandler to make it use our
+            HeadRequest also on the redirected URL
+            """
+            def redirect_request(self, req, fp, code, msg, headers, newurl):
+                if code in (301, 302, 303, 307):
+                    newurl = newurl.replace(' ', '%20')
+                    newheaders = dict((k,v) for k,v in req.headers.items()
+                                      if k.lower() not in ("content-length", "content-type"))
+                    return HeadRequest(newurl,
+                                       headers=newheaders,
+                                       origin_req_host=req.get_origin_req_host(),
+                                       unverifiable=True)
+                else:
+                    raise compat_urllib_error.HTTPError(req.get_full_url(), code, msg, headers, fp)
+
+        class HTTPMethodFallback(compat_urllib_request.BaseHandler):
+            """
+            Fallback to GET if HEAD is not allowed (405 HTTP error)
+            """
+            def http_error_405(self, req, fp, code, msg, headers):
+                fp.read()
+                fp.close()
+
+                newheaders = dict((k,v) for k,v in req.headers.items()
+                                  if k.lower() not in ("content-length", "content-type"))
+                return self.parent.open(compat_urllib_request.Request(req.get_full_url(),
+                                                 headers=newheaders,
+                                                 origin_req_host=req.get_origin_req_host(),
+                                                 unverifiable=True))
+
+        # Build our opener
+        opener = compat_urllib_request.OpenerDirector()
+        for handler in [compat_urllib_request.HTTPHandler, compat_urllib_request.HTTPDefaultErrorHandler,
+                        HTTPMethodFallback, HEADRedirectHandler,
+                        compat_urllib_request.HTTPErrorProcessor, compat_urllib_request.HTTPSHandler]:
+            opener.add_handler(handler())
+
+        response = opener.open(HeadRequest(url))
+        if response is None:
+            raise ExtractorError(u'Invalid URL protocol')
+        new_url = response.geturl()
+
+        if url == new_url:
+            return False
+
+        self.report_following_redirect(new_url)
+        return new_url
+
+    def _real_extract(self, url):
+        new_url = self._test_redirect(url)
+        if new_url: return [self.url_result(new_url)]
+
+        video_id = url.split('/')[-1]
+        try:
+            webpage = self._download_webpage(url, video_id)
+        except ValueError:
+            # since this is the last-resort InfoExtractor, if
+            # this error is thrown, it'll be thrown here
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        self.report_extraction(video_id)
+        # Start with something easy: JW Player in SWFObject
+        mobj = re.search(r'flashvars: [\'"](?:.*&)?file=(http[^\'"&]*)', webpage)
+        if mobj is None:
+            # Broaden the search a little bit
+            mobj = re.search(r'[^A-Za-z0-9]?(?:file|source)=(http[^\'"&]*)', webpage)
+        if mobj is None:
+            # Broaden the search a little bit: JWPlayer JS loader
+            mobj = re.search(r'[^A-Za-z0-9]?file:\s*["\'](http[^\'"&]*)', webpage)
+        if mobj is None:
+            # Try to find twitter cards info
+            mobj = re.search(r'<meta (?:property|name)="twitter:player:stream" (?:content|value)="(.+?)"', webpage)
+        if mobj is None:
+            # We look for Open Graph info:
+            # We have to match any number spaces between elements, some sites try to align them (eg.: statigr.am)
+            m_video_type = re.search(r'<meta.*?property="og:video:type".*?content="video/(.*?)"', webpage)
+            # We only look in og:video if the MIME type is a video, don't try if it's a Flash player:
+            if m_video_type is not None:
+                mobj = re.search(r'<meta.*?property="og:video".*?content="(.*?)"', webpage)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        # It's possible that one of the regexes
+        # matched, but returned an empty group:
+        if mobj.group(1) is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        video_url = compat_urllib_parse.unquote(mobj.group(1))
+        video_id = os.path.basename(video_url)
+
+        # here's a fun little line of code for you:
+        video_extension = os.path.splitext(video_id)[1][1:]
+        video_id = os.path.splitext(video_id)[0]
+
+        # it's tempting to parse this further, but you would
+        # have to take into account all the variations like
+        #   Video Title - Site Name
+        #   Site Name | Video Title
+        #   Video Title - Tagline | Site Name
+        # and so on and so forth; it's just not practical
+        video_title = self._html_search_regex(r'<title>(.*)</title>',
+            webpage, u'video title')
+
+        # video uploader is domain name
+        video_uploader = self._search_regex(r'(?:https?://)?([^/]*)/.*',
+            url, u'video uploader')
+
+        return [{
+            'id':       video_id,
+            'url':      video_url,
+            'uploader': video_uploader,
+            'upload_date':  None,
+            'title':    video_title,
+            'ext':      video_extension,
+        }]
diff --git a/youtube_dl/extractor/googleplus.py b/youtube_dl/extractor/googleplus.py
new file mode 100644
index 0000000..e922bd1
--- /dev/null
+++ b/youtube_dl/extractor/googleplus.py
@@ -0,0 +1,82 @@
+import datetime
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class GooglePlusIE(InfoExtractor):
+    """Information extractor for plus.google.com."""
+
+    _VALID_URL = r'(?:https://)?plus\.google\.com/(?:[^/]+/)*?posts/(\w+)'
+    IE_NAME = u'plus.google'
+
+    def _real_extract(self, url):
+        # Extract id from URL
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        post_url = mobj.group(0)
+        video_id = mobj.group(1)
+
+        video_extension = 'flv'
+
+        # Step 1, Retrieve post webpage to extract further information
+        webpage = self._download_webpage(post_url, video_id, u'Downloading entry webpage')
+
+        self.report_extraction(video_id)
+
+        # Extract update date
+        upload_date = self._html_search_regex('title="Timestamp">(.*?)</a>',
+            webpage, u'upload date', fatal=False)
+        if upload_date:
+            # Convert timestring to a format suitable for filename
+            upload_date = datetime.datetime.strptime(upload_date, "%Y-%m-%d")
+            upload_date = upload_date.strftime('%Y%m%d')
+
+        # Extract uploader
+        uploader = self._html_search_regex(r'rel\="author".*?>(.*?)</a>',
+            webpage, u'uploader', fatal=False)
+
+        # Extract title
+        # Get the first line for title
+        video_title = self._html_search_regex(r'<meta name\=\"Description\" content\=\"(.*?)[\n<"]',
+            webpage, 'title', default=u'NA')
+
+        # Step 2, Stimulate clicking the image box to launch video
+        video_page = self._search_regex('"(https\://plus\.google\.com/photos/.*?)",,"image/jpeg","video"\]',
+            webpage, u'video page URL')
+        webpage = self._download_webpage(video_page, video_id, u'Downloading video page')
+
+        # Extract video links on video page
+        """Extract video links of all sizes"""
+        pattern = '\d+,\d+,(\d+),"(http\://redirector\.googlevideo\.com.*?)"'
+        mobj = re.findall(pattern, webpage)
+        if len(mobj) == 0:
+            raise ExtractorError(u'Unable to extract video links')
+
+        # Sort in resolution
+        links = sorted(mobj)
+
+        # Choose the lowest of the sort, i.e. highest resolution
+        video_url = links[-1]
+        # Only get the url. The resolution part in the tuple has no use anymore
+        video_url = video_url[-1]
+        # Treat escaped \u0026 style hex
+        try:
+            video_url = video_url.decode("unicode_escape")
+        except AttributeError: # Python 3
+            video_url = bytes(video_url, 'ascii').decode('unicode-escape')
+
+
+        return [{
+            'id':       video_id,
+            'url':      video_url,
+            'uploader': uploader,
+            'upload_date':  upload_date,
+            'title':    video_title,
+            'ext':      video_extension,
+        }]
diff --git a/youtube_dl/extractor/googlesearch.py b/youtube_dl/extractor/googlesearch.py
new file mode 100644
index 0000000..21c240e
--- /dev/null
+++ b/youtube_dl/extractor/googlesearch.py
@@ -0,0 +1,39 @@
+import itertools
+import re
+
+from .common import SearchInfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+)
+
+
+class GoogleSearchIE(SearchInfoExtractor):
+    """Information Extractor for Google Video search queries."""
+    _MORE_PAGES_INDICATOR = r'id="pnnext" class="pn"'
+    _MAX_RESULTS = 1000
+    IE_NAME = u'video.google:search'
+    _SEARCH_KEY = 'gvsearch'
+
+    def _get_n_results(self, query, n):
+        """Get a specified number of results for a query"""
+
+        res = {
+            '_type': 'playlist',
+            'id': query,
+            'entries': []
+        }
+
+        for pagenum in itertools.count(1):
+            result_url = u'http://www.google.com/search?tbm=vid&q=%s&start=%s&hl=en' % (compat_urllib_parse.quote_plus(query), pagenum*10)
+            webpage = self._download_webpage(result_url, u'gvsearch:' + query,
+                                             note='Downloading result page ' + str(pagenum))
+
+            for mobj in re.finditer(r'<h3 class="r"><a href="([^"]+)"', webpage):
+                e = {
+                    '_type': 'url',
+                    'url': mobj.group(1)
+                }
+                res['entries'].append(e)
+
+            if (pagenum * 10 > n) or not re.search(self._MORE_PAGES_INDICATOR, webpage):
+                return res
diff --git a/youtube_dl/extractor/howcast.py b/youtube_dl/extractor/howcast.py
new file mode 100644
index 0000000..7b94f85
--- /dev/null
+++ b/youtube_dl/extractor/howcast.py
@@ -0,0 +1,37 @@
+import re
+
+from .common import InfoExtractor
+
+
+class HowcastIE(InfoExtractor):
+    _VALID_URL = r'(?:https?://)?(?:www\.)?howcast\.com/videos/(?P<id>\d+)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('id')
+        webpage_url = 'http://www.howcast.com/videos/' + video_id
+        webpage = self._download_webpage(webpage_url, video_id)
+
+        self.report_extraction(video_id)
+
+        video_url = self._search_regex(r'\'?file\'?: "(http://mobile-media\.howcast\.com/[0-9]+\.mp4)',
+            webpage, u'video URL')
+
+        video_title = self._html_search_regex(r'<meta content=(?:"([^"]+)"|\'([^\']+)\') property=\'og:title\'',
+            webpage, u'title')
+
+        video_description = self._html_search_regex(r'<meta content=(?:"([^"]+)"|\'([^\']+)\') name=\'description\'',
+            webpage, u'description', fatal=False)
+
+        thumbnail = self._html_search_regex(r'<meta content=\'(.+?)\' property=\'og:image\'',
+            webpage, u'thumbnail', fatal=False)
+
+        return [{
+            'id':       video_id,
+            'url':      video_url,
+            'ext':      'mp4',
+            'title':    video_title,
+            'description': video_description,
+            'thumbnail': thumbnail,
+        }]
diff --git a/youtube_dl/extractor/hypem.py b/youtube_dl/extractor/hypem.py
new file mode 100644
index 0000000..ceec4f6
--- /dev/null
+++ b/youtube_dl/extractor/hypem.py
@@ -0,0 +1,63 @@
+import json
+import re
+import time
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_str,
+    compat_urllib_parse,
+    compat_urllib_request,
+
+    ExtractorError,
+)
+
+
+class HypemIE(InfoExtractor):
+    """Information Extractor for hypem"""
+    _VALID_URL = r'(?:http://)?(?:www\.)?hypem\.com/track/([^/]+)/([^/]+)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        track_id = mobj.group(1)
+
+        data = { 'ax': 1, 'ts': time.time() }
+        data_encoded = compat_urllib_parse.urlencode(data)
+        complete_url = url + "?" + data_encoded
+        request = compat_urllib_request.Request(complete_url)
+        response, urlh = self._download_webpage_handle(request, track_id, u'Downloading webpage with the url')
+        cookie = urlh.headers.get('Set-Cookie', '')
+
+        self.report_extraction(track_id)
+
+        html_tracks = self._html_search_regex(r'<script type="application/json" id="displayList-data">(.*?)</script>',
+            response, u'tracks', flags=re.MULTILINE|re.DOTALL).strip()
+        try:
+            track_list = json.loads(html_tracks)
+            track = track_list[u'tracks'][0]
+        except ValueError:
+            raise ExtractorError(u'Hypemachine contained invalid JSON.')
+
+        key = track[u"key"]
+        track_id = track[u"id"]
+        artist = track[u"artist"]
+        title = track[u"song"]
+
+        serve_url = "http://hypem.com/serve/source/%s/%s" % (compat_str(track_id), compat_str(key))
+        request = compat_urllib_request.Request(serve_url, "" , {'Content-Type': 'application/json'})
+        request.add_header('cookie', cookie)
+        song_data_json = self._download_webpage(request, track_id, u'Downloading metadata')
+        try:
+            song_data = json.loads(song_data_json)
+        except ValueError:
+            raise ExtractorError(u'Hypemachine contained invalid JSON.')
+        final_url = song_data[u"url"]
+
+        return [{
+            'id':       track_id,
+            'url':      final_url,
+            'ext':      "mp3",
+            'title':    title,
+            'artist':   artist,
+        }]
\ No newline at end of file
diff --git a/youtube_dl/extractor/ina.py b/youtube_dl/extractor/ina.py
new file mode 100644
index 0000000..c19b956
--- /dev/null
+++ b/youtube_dl/extractor/ina.py
@@ -0,0 +1,31 @@
+import re
+
+from .common import InfoExtractor
+
+
+class InaIE(InfoExtractor):
+    """Information Extractor for Ina.fr"""
+    _VALID_URL = r'(?:http://)?(?:www\.)?ina\.fr/video/(?P<id>I[0-9]+)/.*'
+
+    def _real_extract(self,url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('id')
+        mrss_url='http://player.ina.fr/notices/%s.mrss' % video_id
+        video_extension = 'mp4'
+        webpage = self._download_webpage(mrss_url, video_id)
+
+        self.report_extraction(video_id)
+
+        video_url = self._html_search_regex(r'<media:player url="(?P<mp4url>http://mp4.ina.fr/[^"]+\.mp4)',
+            webpage, u'video URL')
+
+        video_title = self._search_regex(r'<title><!\[CDATA\[(?P<titre>.*?)]]></title>',
+            webpage, u'title')
+
+        return [{
+            'id':       video_id,
+            'url':      video_url,
+            'ext':      video_extension,
+            'title':    video_title,
+        }]
diff --git a/youtube_dl/extractor/infoq.py b/youtube_dl/extractor/infoq.py
new file mode 100644
index 0000000..9056742
--- /dev/null
+++ b/youtube_dl/extractor/infoq.py
@@ -0,0 +1,50 @@
+import base64
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+
+    ExtractorError,
+)
+
+
+class InfoQIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?(?:www\.)?infoq\.com/[^/]+/[^/]+$'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+
+        webpage = self._download_webpage(url, video_id=url)
+        self.report_extraction(url)
+
+        # Extract video URL
+        mobj = re.search(r"jsclassref ?= ?'([^']*)'", webpage)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract video url')
+        real_id = compat_urllib_parse.unquote(base64.b64decode(mobj.group(1).encode('ascii')).decode('utf-8'))
+        video_url = 'rtmpe://video.infoq.com/cfx/st/' + real_id
+
+        # Extract title
+        video_title = self._search_regex(r'contentTitle = "(.*?)";',
+            webpage, u'title')
+
+        # Extract description
+        video_description = self._html_search_regex(r'<meta name="description" content="(.*)"(?:\s*/)?>',
+            webpage, u'description', fatal=False)
+
+        video_filename = video_url.split('/')[-1]
+        video_id, extension = video_filename.split('.')
+
+        info = {
+            'id': video_id,
+            'url': video_url,
+            'uploader': None,
+            'upload_date': None,
+            'title': video_title,
+            'ext': extension, # Extension is always(?) mp4, but seems to be flv
+            'thumbnail': None,
+            'description': video_description,
+        }
+
+        return [info]
\ No newline at end of file
diff --git a/youtube_dl/extractor/justintv.py b/youtube_dl/extractor/justintv.py
new file mode 100644
index 0000000..b2006e3
--- /dev/null
+++ b/youtube_dl/extractor/justintv.py
@@ -0,0 +1,144 @@
+import json
+import os
+import re
+import xml.etree.ElementTree
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+    formatSeconds,
+)
+
+
+class JustinTVIE(InfoExtractor):
+    """Information extractor for justin.tv and twitch.tv"""
+    # TODO: One broadcast may be split into multiple videos. The key
+    # 'broadcast_id' is the same for all parts, and 'broadcast_part'
+    # starts at 1 and increases. Can we treat all parts as one video?
+
+    _VALID_URL = r"""(?x)^(?:http://)?(?:www\.)?(?:twitch|justin)\.tv/
+        (?:
+            (?P<channelid>[^/]+)|
+            (?:(?:[^/]+)/b/(?P<videoid>[^/]+))|
+            (?:(?:[^/]+)/c/(?P<chapterid>[^/]+))
+        )
+        /?(?:\#.*)?$
+        """
+    _JUSTIN_PAGE_LIMIT = 100
+    IE_NAME = u'justin.tv'
+
+    def report_download_page(self, channel, offset):
+        """Report attempt to download a single page of videos."""
+        self.to_screen(u'%s: Downloading video information from %d to %d' %
+                (channel, offset, offset + self._JUSTIN_PAGE_LIMIT))
+
+    # Return count of items, list of *valid* items
+    def _parse_page(self, url, video_id):
+        info_json = self._download_webpage(url, video_id,
+                                           u'Downloading video info JSON',
+                                           u'unable to download video info JSON')
+
+        response = json.loads(info_json)
+        if type(response) != list:
+            error_text = response.get('error', 'unknown error')
+            raise ExtractorError(u'Justin.tv API: %s' % error_text)
+        info = []
+        for clip in response:
+            video_url = clip['video_file_url']
+            if video_url:
+                video_extension = os.path.splitext(video_url)[1][1:]
+                video_date = re.sub('-', '', clip['start_time'][:10])
+                video_uploader_id = clip.get('user_id', clip.get('channel_id'))
+                video_id = clip['id']
+                video_title = clip.get('title', video_id)
+                info.append({
+                    'id': video_id,
+                    'url': video_url,
+                    'title': video_title,
+                    'uploader': clip.get('channel_name', video_uploader_id),
+                    'uploader_id': video_uploader_id,
+                    'upload_date': video_date,
+                    'ext': video_extension,
+                })
+        return (len(response), info)
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'invalid URL: %s' % url)
+
+        api_base = 'http://api.justin.tv'
+        paged = False
+        if mobj.group('channelid'):
+            paged = True
+            video_id = mobj.group('channelid')
+            api = api_base + '/channel/archives/%s.json' % video_id
+        elif mobj.group('chapterid'):
+            chapter_id = mobj.group('chapterid')
+
+            webpage = self._download_webpage(url, chapter_id)
+            m = re.search(r'PP\.archive_id = "([0-9]+)";', webpage)
+            if not m:
+                raise ExtractorError(u'Cannot find archive of a chapter')
+            archive_id = m.group(1)
+
+            api = api_base + '/broadcast/by_chapter/%s.xml' % chapter_id
+            chapter_info_xml = self._download_webpage(api, chapter_id,
+                                             note=u'Downloading chapter information',
+                                             errnote=u'Chapter information download failed')
+            doc = xml.etree.ElementTree.fromstring(chapter_info_xml)
+            for a in doc.findall('.//archive'):
+                if archive_id == a.find('./id').text:
+                    break
+            else:
+                raise ExtractorError(u'Could not find chapter in chapter information')
+
+            video_url = a.find('./video_file_url').text
+            video_ext = video_url.rpartition('.')[2] or u'flv'
+
+            chapter_api_url = u'https://api.twitch.tv/kraken/videos/c' + chapter_id
+            chapter_info_json = self._download_webpage(chapter_api_url, u'c' + chapter_id,
+                                   note='Downloading chapter metadata',
+                                   errnote='Download of chapter metadata failed')
+            chapter_info = json.loads(chapter_info_json)
+
+            bracket_start = int(doc.find('.//bracket_start').text)
+            bracket_end = int(doc.find('.//bracket_end').text)
+
+            # TODO determine start (and probably fix up file)
+            #  youtube-dl -v http://www.twitch.tv/firmbelief/c/1757457
+            #video_url += u'?start=' + TODO:start_timestamp
+            # bracket_start is 13290, but we want 51670615
+            self._downloader.report_warning(u'Chapter detected, but we can just download the whole file. '
+                                            u'Chapter starts at %s and ends at %s' % (formatSeconds(bracket_start), formatSeconds(bracket_end)))
+
+            info = {
+                'id': u'c' + chapter_id,
+                'url': video_url,
+                'ext': video_ext,
+                'title': chapter_info['title'],
+                'thumbnail': chapter_info['preview'],
+                'description': chapter_info['description'],
+                'uploader': chapter_info['channel']['display_name'],
+                'uploader_id': chapter_info['channel']['name'],
+            }
+            return [info]
+        else:
+            video_id = mobj.group('videoid')
+            api = api_base + '/broadcast/by_archive/%s.json' % video_id
+
+        self.report_extraction(video_id)
+
+        info = []
+        offset = 0
+        limit = self._JUSTIN_PAGE_LIMIT
+        while True:
+            if paged:
+                self.report_download_page(video_id, offset)
+            page_url = api + ('?offset=%d&limit=%d' % (offset, limit))
+            page_count, page_info = self._parse_page(page_url, video_id)
+            info.extend(page_info)
+            if not paged or page_count != limit:
+                break
+            offset += limit
+        return info
diff --git a/youtube_dl/extractor/keek.py b/youtube_dl/extractor/keek.py
new file mode 100644
index 0000000..e2093a0
--- /dev/null
+++ b/youtube_dl/extractor/keek.py
@@ -0,0 +1,32 @@
+import re
+
+from .common import InfoExtractor
+
+
+class KeekIE(InfoExtractor):
+    _VALID_URL = r'http://(?:www\.)?keek\.com/(?:!|\w+/keeks/)(?P<videoID>\w+)'
+    IE_NAME = u'keek'
+
+    def _real_extract(self, url):
+        m = re.match(self._VALID_URL, url)
+        video_id = m.group('videoID')
+
+        video_url = u'http://cdn.keek.com/keek/video/%s' % video_id
+        thumbnail = u'http://cdn.keek.com/keek/thumbnail/%s/w100/h75' % video_id
+        webpage = self._download_webpage(url, video_id)
+
+        video_title = self._html_search_regex(r'<meta property="og:title" content="(?P<title>.*?)"',
+            webpage, u'title')
+
+        uploader = self._html_search_regex(r'<div class="user-name-and-bio">[\S\s]+?<h2>(?P<uploader>.+?)</h2>',
+            webpage, u'uploader', fatal=False)
+
+        info = {
+                'id': video_id,
+                'url': video_url,
+                'ext': 'mp4',
+                'title': video_title,
+                'thumbnail': thumbnail,
+                'uploader': uploader
+        }
+        return [info]
diff --git a/youtube_dl/extractor/liveleak.py b/youtube_dl/extractor/liveleak.py
new file mode 100644
index 0000000..d4b142e
--- /dev/null
+++ b/youtube_dl/extractor/liveleak.py
@@ -0,0 +1,44 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class LiveLeakIE(InfoExtractor):
+
+    _VALID_URL = r'^(?:http?://)?(?:\w+\.)?liveleak\.com/view\?(?:.*?)i=(?P<video_id>[\w_]+)(?:.*)'
+    IE_NAME = u'liveleak'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        video_id = mobj.group('video_id')
+
+        webpage = self._download_webpage(url, video_id)
+
+        video_url = self._search_regex(r'file: "(.*?)",',
+            webpage, u'video URL')
+
+        video_title = self._html_search_regex(r'<meta property="og:title" content="(?P<title>.*?)"',
+            webpage, u'title').replace('LiveLeak.com -', '').strip()
+
+        video_description = self._html_search_regex(r'<meta property="og:description" content="(?P<desc>.*?)"',
+            webpage, u'description', fatal=False)
+
+        video_uploader = self._html_search_regex(r'By:.*?(\w+)</a>',
+            webpage, u'uploader', fatal=False)
+
+        info = {
+            'id':  video_id,
+            'url': video_url,
+            'ext': 'mp4',
+            'title': video_title,
+            'description': video_description,
+            'uploader': video_uploader
+        }
+
+        return [info]
diff --git a/youtube_dl/extractor/metacafe.py b/youtube_dl/extractor/metacafe.py
new file mode 100644
index 0000000..66d6554
--- /dev/null
+++ b/youtube_dl/extractor/metacafe.py
@@ -0,0 +1,110 @@
+import re
+import socket
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_parse_qs,
+    compat_urllib_error,
+    compat_urllib_parse,
+    compat_urllib_request,
+    compat_str,
+
+    ExtractorError,
+)
+
+class MetacafeIE(InfoExtractor):
+    """Information Extractor for metacafe.com."""
+
+    _VALID_URL = r'(?:http://)?(?:www\.)?metacafe\.com/watch/([^/]+)/([^/]+)/.*'
+    _DISCLAIMER = 'http://www.metacafe.com/family_filter/'
+    _FILTER_POST = 'http://www.metacafe.com/f/index.php?inputType=filter&controllerGroup=user'
+    IE_NAME = u'metacafe'
+
+    def report_disclaimer(self):
+        """Report disclaimer retrieval."""
+        self.to_screen(u'Retrieving disclaimer')
+
+    def _real_initialize(self):
+        # Retrieve disclaimer
+        request = compat_urllib_request.Request(self._DISCLAIMER)
+        try:
+            self.report_disclaimer()
+            compat_urllib_request.urlopen(request).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to retrieve disclaimer: %s' % compat_str(err))
+
+        # Confirm age
+        disclaimer_form = {
+            'filters': '0',
+            'submit': "Continue - I'm over 18",
+            }
+        request = compat_urllib_request.Request(self._FILTER_POST, compat_urllib_parse.urlencode(disclaimer_form))
+        try:
+            self.report_age_confirmation()
+            compat_urllib_request.urlopen(request).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to confirm age: %s' % compat_str(err))
+
+    def _real_extract(self, url):
+        # Extract id and simplified title from URL
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        video_id = mobj.group(1)
+
+        # Check if video comes from YouTube
+        mobj2 = re.match(r'^yt-(.*)$', video_id)
+        if mobj2 is not None:
+            return [self.url_result('http://www.youtube.com/watch?v=%s' % mobj2.group(1), 'Youtube')]
+
+        # Retrieve video webpage to extract further information
+        webpage = self._download_webpage('http://www.metacafe.com/watch/%s/' % video_id, video_id)
+
+        # Extract URL, uploader and title from webpage
+        self.report_extraction(video_id)
+        mobj = re.search(r'(?m)&mediaURL=([^&]+)', webpage)
+        if mobj is not None:
+            mediaURL = compat_urllib_parse.unquote(mobj.group(1))
+            video_extension = mediaURL[-3:]
+
+            # Extract gdaKey if available
+            mobj = re.search(r'(?m)&gdaKey=(.*?)&', webpage)
+            if mobj is None:
+                video_url = mediaURL
+            else:
+                gdaKey = mobj.group(1)
+                video_url = '%s?__gda__=%s' % (mediaURL, gdaKey)
+        else:
+            mobj = re.search(r' name="flashvars" value="(.*?)"', webpage)
+            if mobj is None:
+                raise ExtractorError(u'Unable to extract media URL')
+            vardict = compat_parse_qs(mobj.group(1))
+            if 'mediaData' not in vardict:
+                raise ExtractorError(u'Unable to extract media URL')
+            mobj = re.search(r'"mediaURL":"(?P<mediaURL>http.*?)",(.*?)"key":"(?P<key>.*?)"', vardict['mediaData'][0])
+            if mobj is None:
+                raise ExtractorError(u'Unable to extract media URL')
+            mediaURL = mobj.group('mediaURL').replace('\\/', '/')
+            video_extension = mediaURL[-3:]
+            video_url = '%s?__gda__=%s' % (mediaURL, mobj.group('key'))
+
+        mobj = re.search(r'(?im)<title>(.*) - Video</title>', webpage)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract title')
+        video_title = mobj.group(1).decode('utf-8')
+
+        mobj = re.search(r'submitter=(.*?);', webpage)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract uploader nickname')
+        video_uploader = mobj.group(1)
+
+        return [{
+            'id':       video_id.decode('utf-8'),
+            'url':      video_url.decode('utf-8'),
+            'uploader': video_uploader.decode('utf-8'),
+            'upload_date':  None,
+            'title':    video_title,
+            'ext':      video_extension.decode('utf-8'),
+        }]
diff --git a/youtube_dl/extractor/mixcloud.py b/youtube_dl/extractor/mixcloud.py
new file mode 100644
index 0000000..8245b55
--- /dev/null
+++ b/youtube_dl/extractor/mixcloud.py
@@ -0,0 +1,115 @@
+import json
+import re
+import socket
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_str,
+    compat_urllib_error,
+    compat_urllib_request,
+
+    ExtractorError,
+)
+
+
+class MixcloudIE(InfoExtractor):
+    _WORKING = False # New API, but it seems good http://www.mixcloud.com/developers/documentation/
+    _VALID_URL = r'^(?:https?://)?(?:www\.)?mixcloud\.com/([\w\d-]+)/([\w\d-]+)'
+    IE_NAME = u'mixcloud'
+
+    def report_download_json(self, file_id):
+        """Report JSON download."""
+        self.to_screen(u'Downloading json')
+
+    def get_urls(self, jsonData, fmt, bitrate='best'):
+        """Get urls from 'audio_formats' section in json"""
+        try:
+            bitrate_list = jsonData[fmt]
+            if bitrate is None or bitrate == 'best' or bitrate not in bitrate_list:
+                bitrate = max(bitrate_list) # select highest
+
+            url_list = jsonData[fmt][bitrate]
+        except TypeError: # we have no bitrate info.
+            url_list = jsonData[fmt]
+        return url_list
+
+    def check_urls(self, url_list):
+        """Returns 1st active url from list"""
+        for url in url_list:
+            try:
+                compat_urllib_request.urlopen(url)
+                return url
+            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error):
+                url = None
+
+        return None
+
+    def _print_formats(self, formats):
+        print('Available formats:')
+        for fmt in formats.keys():
+            for b in formats[fmt]:
+                try:
+                    ext = formats[fmt][b][0]
+                    print('%s\t%s\t[%s]' % (fmt, b, ext.split('.')[-1]))
+                except TypeError: # we have no bitrate info
+                    ext = formats[fmt][0]
+                    print('%s\t%s\t[%s]' % (fmt, '??', ext.split('.')[-1]))
+                    break
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        # extract uploader & filename from url
+        uploader = mobj.group(1).decode('utf-8')
+        file_id = uploader + "-" + mobj.group(2).decode('utf-8')
+
+        # construct API request
+        file_url = 'http://www.mixcloud.com/api/1/cloudcast/' + '/'.join(url.split('/')[-3:-1]) + '.json'
+        # retrieve .json file with links to files
+        request = compat_urllib_request.Request(file_url)
+        try:
+            self.report_download_json(file_url)
+            jsonData = compat_urllib_request.urlopen(request).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to retrieve file: %s' % compat_str(err))
+
+        # parse JSON
+        json_data = json.loads(jsonData)
+        player_url = json_data['player_swf_url']
+        formats = dict(json_data['audio_formats'])
+
+        req_format = self._downloader.params.get('format', None)
+
+        if self._downloader.params.get('listformats', None):
+            self._print_formats(formats)
+            return
+
+        if req_format is None or req_format == 'best':
+            for format_param in formats.keys():
+                url_list = self.get_urls(formats, format_param)
+                # check urls
+                file_url = self.check_urls(url_list)
+                if file_url is not None:
+                    break # got it!
+        else:
+            if req_format not in formats:
+                raise ExtractorError(u'Format is not available')
+
+            url_list = self.get_urls(formats, req_format)
+            file_url = self.check_urls(url_list)
+            format_param = req_format
+
+        return [{
+            'id': file_id.decode('utf-8'),
+            'url': file_url.decode('utf-8'),
+            'uploader': uploader.decode('utf-8'),
+            'upload_date': None,
+            'title': json_data['name'],
+            'ext': file_url.split('.')[-1].decode('utf-8'),
+            'format': (format_param is None and u'NA' or format_param.decode('utf-8')),
+            'thumbnail': json_data['thumbnail_url'],
+            'description': json_data['description'],
+            'player_url': player_url.decode('utf-8'),
+        }]
diff --git a/youtube_dl/extractor/mtv.py b/youtube_dl/extractor/mtv.py
new file mode 100644
index 0000000..a801c81
--- /dev/null
+++ b/youtube_dl/extractor/mtv.py
@@ -0,0 +1,72 @@
+import re
+import socket
+import xml.etree.ElementTree
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_str,
+    compat_urllib_error,
+    compat_urllib_request,
+
+    ExtractorError,
+)
+
+
+class MTVIE(InfoExtractor):
+    _VALID_URL = r'^(?P<proto>https?://)?(?:www\.)?mtv\.com/videos/[^/]+/(?P<videoid>[0-9]+)/[^/]+$'
+    _WORKING = False
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        if not mobj.group('proto'):
+            url = 'http://' + url
+        video_id = mobj.group('videoid')
+
+        webpage = self._download_webpage(url, video_id)
+
+        #song_name = self._html_search_regex(r'<meta name="mtv_vt" content="([^"]+)"/>',
+        #    webpage, u'song name', fatal=False)
+
+        video_title = self._html_search_regex(r'<meta name="mtv_an" content="([^"]+)"/>',
+            webpage, u'title')
+
+        mtvn_uri = self._html_search_regex(r'<meta name="mtvn_uri" content="([^"]+)"/>',
+            webpage, u'mtvn_uri', fatal=False)
+
+        content_id = self._search_regex(r'MTVN.Player.defaultPlaylistId = ([0-9]+);',
+            webpage, u'content id', fatal=False)
+
+        videogen_url = 'http://www.mtv.com/player/includes/mediaGen.jhtml?uri=' + mtvn_uri + '&id=' + content_id + '&vid=' + video_id + '&ref=www.mtvn.com&viewUri=' + mtvn_uri
+        self.report_extraction(video_id)
+        request = compat_urllib_request.Request(videogen_url)
+        try:
+            metadataXml = compat_urllib_request.urlopen(request).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to download video metadata: %s' % compat_str(err))
+
+        mdoc = xml.etree.ElementTree.fromstring(metadataXml)
+        renditions = mdoc.findall('.//rendition')
+
+        # For now, always pick the highest quality.
+        rendition = renditions[-1]
+
+        try:
+            _,_,ext = rendition.attrib['type'].partition('/')
+            format = ext + '-' + rendition.attrib['width'] + 'x' + rendition.attrib['height'] + '_' + rendition.attrib['bitrate']
+            video_url = rendition.find('./src').text
+        except KeyError:
+            raise ExtractorError('Invalid rendition field.')
+
+        info = {
+            'id': video_id,
+            'url': video_url,
+            'upload_date': None,
+            'title': video_title,
+            'ext': ext,
+            'format': format,
+        }
+
+        return [info]
diff --git a/youtube_dl/extractor/myspass.py b/youtube_dl/extractor/myspass.py
new file mode 100644
index 0000000..7b016bb
--- /dev/null
+++ b/youtube_dl/extractor/myspass.py
@@ -0,0 +1,64 @@
+import os.path
+import xml.etree.ElementTree
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse_urlparse,
+
+    ExtractorError,
+)
+
+
+class MySpassIE(InfoExtractor):
+    _VALID_URL = r'http://www.myspass.de/.*'
+
+    def _real_extract(self, url):
+        META_DATA_URL_TEMPLATE = 'http://www.myspass.de/myspass/includes/apps/video/getvideometadataxml.php?id=%s'
+
+        # video id is the last path element of the URL
+        # usually there is a trailing slash, so also try the second but last
+        url_path = compat_urllib_parse_urlparse(url).path
+        url_parent_path, video_id = os.path.split(url_path)
+        if not video_id:
+            _, video_id = os.path.split(url_parent_path)
+
+        # get metadata
+        metadata_url = META_DATA_URL_TEMPLATE % video_id
+        metadata_text = self._download_webpage(metadata_url, video_id)
+        metadata = xml.etree.ElementTree.fromstring(metadata_text.encode('utf-8'))
+
+        # extract values from metadata
+        url_flv_el = metadata.find('url_flv')
+        if url_flv_el is None:
+            raise ExtractorError(u'Unable to extract download url')
+        video_url = url_flv_el.text
+        extension = os.path.splitext(video_url)[1][1:]
+        title_el = metadata.find('title')
+        if title_el is None:
+            raise ExtractorError(u'Unable to extract title')
+        title = title_el.text
+        format_id_el = metadata.find('format_id')
+        if format_id_el is None:
+            format = 'mp4'
+        else:
+            format = format_id_el.text
+        description_el = metadata.find('description')
+        if description_el is not None:
+            description = description_el.text
+        else:
+            description = None
+        imagePreview_el = metadata.find('imagePreview')
+        if imagePreview_el is not None:
+            thumbnail = imagePreview_el.text
+        else:
+            thumbnail = None
+        info = {
+            'id': video_id,
+            'url': video_url,
+            'title': title,
+            'ext': extension,
+            'format': format,
+            'thumbnail': thumbnail,
+            'description': description
+        }
+        return [info]
diff --git a/youtube_dl/extractor/myvideo.py b/youtube_dl/extractor/myvideo.py
new file mode 100644
index 0000000..47a44e3
--- /dev/null
+++ b/youtube_dl/extractor/myvideo.py
@@ -0,0 +1,164 @@
+import binascii
+import base64
+import hashlib
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_ord,
+    compat_urllib_parse,
+
+    ExtractorError,
+)
+
+
+
+class MyVideoIE(InfoExtractor):
+    """Information Extractor for myvideo.de."""
+
+    _VALID_URL = r'(?:http://)?(?:www\.)?myvideo\.de/watch/([0-9]+)/([^?/]+).*'
+    IE_NAME = u'myvideo'
+
+    # Original Code from: https://github.com/dersphere/plugin.video.myvideo_de.git
+    # Released into the Public Domain by Tristan Fischer on 2013-05-19
+    # https://github.com/rg3/youtube-dl/pull/842
+    def __rc4crypt(self,data, key):
+        x = 0
+        box = list(range(256))
+        for i in list(range(256)):
+            x = (x + box[i] + compat_ord(key[i % len(key)])) % 256
+            box[i], box[x] = box[x], box[i]
+        x = 0
+        y = 0
+        out = ''
+        for char in data:
+            x = (x + 1) % 256
+            y = (y + box[x]) % 256
+            box[x], box[y] = box[y], box[x]
+            out += chr(compat_ord(char) ^ box[(box[x] + box[y]) % 256])
+        return out
+
+    def __md5(self,s):
+        return hashlib.md5(s).hexdigest().encode()
+
+    def _real_extract(self,url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'invalid URL: %s' % url)
+
+        video_id = mobj.group(1)
+
+        GK = (
+          b'WXpnME1EZGhNRGhpTTJNM01XVmhOREU0WldNNVpHTTJOakpt'
+          b'TW1FMU5tVTBNR05pWkRaa05XRXhNVFJoWVRVd1ptSXhaVEV3'
+          b'TnpsbA0KTVRkbU1tSTRNdz09'
+        )
+
+        # Get video webpage
+        webpage_url = 'http://www.myvideo.de/watch/%s' % video_id
+        webpage = self._download_webpage(webpage_url, video_id)
+
+        mobj = re.search('source src=\'(.+?)[.]([^.]+)\'', webpage)
+        if mobj is not None:
+            self.report_extraction(video_id)
+            video_url = mobj.group(1) + '.flv'
+
+            video_title = self._html_search_regex('<title>([^<]+)</title>',
+                webpage, u'title')
+
+            video_ext = self._search_regex('[.](.+?)$', video_url, u'extension')
+
+            return [{
+                'id':       video_id,
+                'url':      video_url,
+                'uploader': None,
+                'upload_date':  None,
+                'title':    video_title,
+                'ext':      video_ext,
+            }]
+
+        # try encxml
+        mobj = re.search('var flashvars={(.+?)}', webpage)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract video')
+
+        params = {}
+        encxml = ''
+        sec = mobj.group(1)
+        for (a, b) in re.findall('(.+?):\'(.+?)\',?', sec):
+            if not a == '_encxml':
+                params[a] = b
+            else:
+                encxml = compat_urllib_parse.unquote(b)
+        if not params.get('domain'):
+            params['domain'] = 'www.myvideo.de'
+        xmldata_url = '%s?%s' % (encxml, compat_urllib_parse.urlencode(params))
+        if 'flash_playertype=MTV' in xmldata_url:
+            self._downloader.report_warning(u'avoiding MTV player')
+            xmldata_url = (
+                'http://www.myvideo.de/dynamic/get_player_video_xml.php'
+                '?flash_playertype=D&ID=%s&_countlimit=4&autorun=yes'
+            ) % video_id
+
+        # get enc data
+        enc_data = self._download_webpage(xmldata_url, video_id).split('=')[1]
+        enc_data_b = binascii.unhexlify(enc_data)
+        sk = self.__md5(
+            base64.b64decode(base64.b64decode(GK)) +
+            self.__md5(
+                str(video_id).encode('utf-8')
+            )
+        )
+        dec_data = self.__rc4crypt(enc_data_b, sk)
+
+        # extracting infos
+        self.report_extraction(video_id)
+
+        video_url = None
+        mobj = re.search('connectionurl=\'(.*?)\'', dec_data)
+        if mobj:
+            video_url = compat_urllib_parse.unquote(mobj.group(1))
+            if 'myvideo2flash' in video_url:
+                self._downloader.report_warning(u'forcing RTMPT ...')
+                video_url = video_url.replace('rtmpe://', 'rtmpt://')
+
+        if not video_url:
+            # extract non rtmp videos
+            mobj = re.search('path=\'(http.*?)\' source=\'(.*?)\'', dec_data)
+            if mobj is None:
+                raise ExtractorError(u'unable to extract url')
+            video_url = compat_urllib_parse.unquote(mobj.group(1)) + compat_urllib_parse.unquote(mobj.group(2))
+
+        video_file = self._search_regex('source=\'(.*?)\'', dec_data, u'video file')
+        video_file = compat_urllib_parse.unquote(video_file)
+
+        if not video_file.endswith('f4m'):
+            ppath, prefix = video_file.split('.')
+            video_playpath = '%s:%s' % (prefix, ppath)
+            video_hls_playlist = ''
+        else:
+            video_playpath = ''
+            video_hls_playlist = (
+                video_file
+            ).replace('.f4m', '.m3u8')
+
+        video_swfobj = self._search_regex('swfobject.embedSWF\(\'(.+?)\'', webpage, u'swfobj')
+        video_swfobj = compat_urllib_parse.unquote(video_swfobj)
+
+        video_title = self._html_search_regex("<h1(?: class='globalHd')?>(.*?)</h1>",
+            webpage, u'title')
+
+        return [{
+            'id':                 video_id,
+            'url':                video_url,
+            'tc_url':             video_url,
+            'uploader':           None,
+            'upload_date':        None,
+            'title':              video_title,
+            'ext':                u'flv',
+            'play_path':          video_playpath,
+            'video_file':         video_file,
+            'video_hls_playlist': video_hls_playlist,
+            'player_url':         video_swfobj,
+        }]
+
diff --git a/youtube_dl/extractor/nba.py b/youtube_dl/extractor/nba.py
new file mode 100644
index 0000000..296d4cd
--- /dev/null
+++ b/youtube_dl/extractor/nba.py
@@ -0,0 +1,40 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class NBAIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?(?:watch\.|www\.)?nba\.com/(?:nba/)?video(/[^?]*?)(?:/index\.html)?(?:\?.*)?$'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        video_id = mobj.group(1)
+
+        webpage = self._download_webpage(url, video_id)
+
+        video_url = u'http://ht-mobile.cdn.turner.com/nba/big' + video_id + '_nba_1280x720.mp4'
+
+        shortened_video_id = video_id.rpartition('/')[2]
+        title = self._html_search_regex(r'<meta property="og:title" content="(.*?)"',
+            webpage, 'title', default=shortened_video_id).replace('NBA.com: ', '')
+
+        # It isn't there in the HTML it returns to us
+        # uploader_date = self._html_search_regex(r'<b>Date:</b> (.*?)</div>', webpage, 'upload_date', fatal=False)
+
+        description = self._html_search_regex(r'<meta name="description" (?:content|value)="(.*?)" />', webpage, 'description', fatal=False)
+
+        info = {
+            'id': shortened_video_id,
+            'url': video_url,
+            'ext': 'mp4',
+            'title': title,
+            # 'uploader_date': uploader_date,
+            'description': description,
+        }
+        return [info]
diff --git a/youtube_dl/extractor/photobucket.py b/youtube_dl/extractor/photobucket.py
new file mode 100644
index 0000000..cd7fe6f
--- /dev/null
+++ b/youtube_dl/extractor/photobucket.py
@@ -0,0 +1,66 @@
+import datetime
+import json
+import re
+
+from .common import InfoExtractor
+
+from ..utils import (
+    ExtractorError,
+)
+
+class PhotobucketIE(InfoExtractor):
+    """Information extractor for photobucket.com."""
+
+    # TODO: the original _VALID_URL was:
+    # r'(?:http://)?(?:[a-z0-9]+\.)?photobucket\.com/.*[\?\&]current=(.*\.flv)'
+    # Check if it's necessary to keep the old extracion process
+    _VALID_URL = r'(?:http://)?(?:[a-z0-9]+\.)?photobucket\.com/.*(([\?\&]current=)|_)(?P<id>.*)\.(?P<ext>(flv)|(mp4))'
+    IE_NAME = u'photobucket'
+
+    def _real_extract(self, url):
+        # Extract id from URL
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        video_id = mobj.group('id')
+
+        video_extension = mobj.group('ext')
+
+        # Retrieve video webpage to extract further information
+        webpage = self._download_webpage(url, video_id)
+
+        # Extract URL, uploader, and title from webpage
+        self.report_extraction(video_id)
+        # We try first by looking the javascript code:
+        mobj = re.search(r'Pb\.Data\.Shared\.put\(Pb\.Data\.Shared\.MEDIA, (?P<json>.*?)\);', webpage)
+        if mobj is not None:
+            info = json.loads(mobj.group('json'))
+            return [{
+                'id':       video_id,
+                'url':      info[u'downloadUrl'],
+                'uploader': info[u'username'],
+                'upload_date':  datetime.date.fromtimestamp(info[u'creationDate']).strftime('%Y%m%d'),
+                'title':    info[u'title'],
+                'ext':      video_extension,
+                'thumbnail': info[u'thumbUrl'],
+            }]
+
+        # We try looking in other parts of the webpage
+        video_url = self._search_regex(r'<link rel="video_src" href=".*\?file=([^"]+)" />',
+            webpage, u'video URL')
+
+        mobj = re.search(r'<title>(.*) video by (.*) - Photobucket</title>', webpage)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract title')
+        video_title = mobj.group(1).decode('utf-8')
+        video_uploader = mobj.group(2).decode('utf-8')
+
+        return [{
+            'id':       video_id.decode('utf-8'),
+            'url':      video_url.decode('utf-8'),
+            'uploader': video_uploader,
+            'upload_date':  None,
+            'title':    video_title,
+            'ext':      video_extension.decode('utf-8'),
+        }]
diff --git a/youtube_dl/extractor/pornotube.py b/youtube_dl/extractor/pornotube.py
new file mode 100644
index 0000000..0adb40d
--- /dev/null
+++ b/youtube_dl/extractor/pornotube.py
@@ -0,0 +1,41 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+
+    unified_strdate,
+)
+
+
+class PornotubeIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?pornotube\.com(/c/(?P<channel>[0-9]+))?(/m/(?P<videoid>[0-9]+))(/(?P<title>.+))$'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('videoid')
+        video_title = mobj.group('title')
+
+        # Get webpage content
+        webpage = self._download_webpage(url, video_id)
+
+        # Get the video URL
+        VIDEO_URL_RE = r'url: "(?P<url>http://video[0-9].pornotube.com/.+\.flv)",'
+        video_url = self._search_regex(VIDEO_URL_RE, webpage, u'video url')
+        video_url = compat_urllib_parse.unquote(video_url)
+
+        #Get the uploaded date
+        VIDEO_UPLOADED_RE = r'<div class="video_added_by">Added (?P<date>[0-9\/]+) by'
+        upload_date = self._html_search_regex(VIDEO_UPLOADED_RE, webpage, u'upload date', fatal=False)
+        if upload_date: upload_date = unified_strdate(upload_date)
+
+        info = {'id': video_id,
+                'url': video_url,
+                'uploader': None,
+                'upload_date': upload_date,
+                'title': video_title,
+                'ext': 'flv',
+                'format': 'flv'}
+
+        return [info]
diff --git a/youtube_dl/extractor/rbmaradio.py b/youtube_dl/extractor/rbmaradio.py
new file mode 100644
index 0000000..0c75eee
--- /dev/null
+++ b/youtube_dl/extractor/rbmaradio.py
@@ -0,0 +1,44 @@
+import json
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse_urlparse,
+
+    ExtractorError,
+)
+
+
+class RBMARadioIE(InfoExtractor):
+    _VALID_URL = r'https?://(?:www\.)?rbmaradio\.com/shows/(?P<videoID>[^/]+)$'
+
+    def _real_extract(self, url):
+        m = re.match(self._VALID_URL, url)
+        video_id = m.group('videoID')
+
+        webpage = self._download_webpage(url, video_id)
+
+        json_data = self._search_regex(r'window\.gon.*?gon\.show=(.+?);$',
+            webpage, u'json data', flags=re.MULTILINE)
+
+        try:
+            data = json.loads(json_data)
+        except ValueError as e:
+            raise ExtractorError(u'Invalid JSON: ' + str(e))
+
+        video_url = data['akamai_url'] + '&cbr=256'
+        url_parts = compat_urllib_parse_urlparse(video_url)
+        video_ext = url_parts.path.rpartition('.')[2]
+        info = {
+                'id': video_id,
+                'url': video_url,
+                'ext': video_ext,
+                'title': data['title'],
+                'description': data.get('teaser_text'),
+                'location': data.get('country_of_origin'),
+                'uploader': data.get('host', {}).get('name'),
+                'uploader_id': data.get('host', {}).get('slug'),
+                'thumbnail': data.get('image', {}).get('large_url_2x'),
+                'duration': data.get('duration'),
+        }
+        return [info]
diff --git a/youtube_dl/extractor/redtube.py b/youtube_dl/extractor/redtube.py
new file mode 100644
index 0000000..ebc4e23
--- /dev/null
+++ b/youtube_dl/extractor/redtube.py
@@ -0,0 +1,29 @@
+import re
+
+from .common import InfoExtractor
+
+
+class RedTubeIE(InfoExtractor):
+    _VALID_URL = r'(?:http://)?(?:www\.)?redtube\.com/(?P<id>[0-9]+)'
+
+    def _real_extract(self,url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('id')
+        video_extension = 'mp4'        
+        webpage = self._download_webpage(url, video_id)
+
+        self.report_extraction(video_id)
+
+        video_url = self._html_search_regex(r'<source src="(.+?)" type="video/mp4">',
+            webpage, u'video URL')
+
+        video_title = self._html_search_regex('<h1 class="videoTitle slidePanelMovable">(.+?)</h1>',
+            webpage, u'title')
+
+        return [{
+            'id':       video_id,
+            'url':      video_url,
+            'ext':      video_extension,
+            'title':    video_title,
+        }]
diff --git a/youtube_dl/extractor/soundcloud.py b/youtube_dl/extractor/soundcloud.py
new file mode 100644
index 0000000..80d7e1b
--- /dev/null
+++ b/youtube_dl/extractor/soundcloud.py
@@ -0,0 +1,129 @@
+import json
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_str,
+
+    ExtractorError,
+    unified_strdate,
+)
+
+
+class SoundcloudIE(InfoExtractor):
+    """Information extractor for soundcloud.com
+       To access the media, the uid of the song and a stream token
+       must be extracted from the page source and the script must make
+       a request to media.soundcloud.com/crossdomain.xml. Then
+       the media can be grabbed by requesting from an url composed
+       of the stream token and uid
+     """
+
+    _VALID_URL = r'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/([\w\d-]+)'
+    IE_NAME = u'soundcloud'
+
+    def report_resolve(self, video_id):
+        """Report information extraction."""
+        self.to_screen(u'%s: Resolving id' % video_id)
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        # extract uploader (which is in the url)
+        uploader = mobj.group(1)
+        # extract simple title (uploader + slug of song title)
+        slug_title =  mobj.group(2)
+        full_title = '%s/%s' % (uploader, slug_title)
+
+        self.report_resolve(full_title)
+
+        url = 'http://soundcloud.com/%s/%s' % (uploader, slug_title)
+        resolv_url = 'http://api.soundcloud.com/resolve.json?url=' + url + '&client_id=b45b1aa10f1ac2941910a7f0d10f8e28'
+        info_json = self._download_webpage(resolv_url, full_title, u'Downloading info JSON')
+
+        info = json.loads(info_json)
+        video_id = info['id']
+        self.report_extraction(full_title)
+
+        streams_url = 'https://api.sndcdn.com/i1/tracks/' + str(video_id) + '/streams?client_id=b45b1aa10f1ac2941910a7f0d10f8e28'
+        stream_json = self._download_webpage(streams_url, full_title,
+                                             u'Downloading stream definitions',
+                                             u'unable to download stream definitions')
+
+        streams = json.loads(stream_json)
+        mediaURL = streams['http_mp3_128_url']
+        upload_date = unified_strdate(info['created_at'])
+
+        return [{
+            'id':       info['id'],
+            'url':      mediaURL,
+            'uploader': info['user']['username'],
+            'upload_date': upload_date,
+            'title':    info['title'],
+            'ext':      u'mp3',
+            'description': info['description'],
+        }]
+
+class SoundcloudSetIE(InfoExtractor):
+    """Information extractor for soundcloud.com sets
+       To access the media, the uid of the song and a stream token
+       must be extracted from the page source and the script must make
+       a request to media.soundcloud.com/crossdomain.xml. Then
+       the media can be grabbed by requesting from an url composed
+       of the stream token and uid
+     """
+
+    _VALID_URL = r'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/sets/([\w\d-]+)'
+    IE_NAME = u'soundcloud:set'
+
+    def report_resolve(self, video_id):
+        """Report information extraction."""
+        self.to_screen(u'%s: Resolving id' % video_id)
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        # extract uploader (which is in the url)
+        uploader = mobj.group(1)
+        # extract simple title (uploader + slug of song title)
+        slug_title =  mobj.group(2)
+        full_title = '%s/sets/%s' % (uploader, slug_title)
+
+        self.report_resolve(full_title)
+
+        url = 'http://soundcloud.com/%s/sets/%s' % (uploader, slug_title)
+        resolv_url = 'http://api.soundcloud.com/resolve.json?url=' + url + '&client_id=b45b1aa10f1ac2941910a7f0d10f8e28'
+        info_json = self._download_webpage(resolv_url, full_title)
+
+        videos = []
+        info = json.loads(info_json)
+        if 'errors' in info:
+            for err in info['errors']:
+                self._downloader.report_error(u'unable to download video webpage: %s' % compat_str(err['error_message']))
+            return
+
+        self.report_extraction(full_title)
+        for track in info['tracks']:
+            video_id = track['id']
+
+            streams_url = 'https://api.sndcdn.com/i1/tracks/' + str(video_id) + '/streams?client_id=b45b1aa10f1ac2941910a7f0d10f8e28'
+            stream_json = self._download_webpage(streams_url, video_id, u'Downloading track info JSON')
+
+            self.report_extraction(video_id)
+            streams = json.loads(stream_json)
+            mediaURL = streams['http_mp3_128_url']
+
+            videos.append({
+                'id':       video_id,
+                'url':      mediaURL,
+                'uploader': track['user']['username'],
+                'upload_date':  unified_strdate(track['created_at']),
+                'title':    track['title'],
+                'ext':      u'mp3',
+                'description': track['description'],
+            })
+        return videos
diff --git a/youtube_dl/extractor/spiegel.py b/youtube_dl/extractor/spiegel.py
new file mode 100644
index 0000000..98a65b7
--- /dev/null
+++ b/youtube_dl/extractor/spiegel.py
@@ -0,0 +1,37 @@
+import re
+import xml.etree.ElementTree
+
+from .common import InfoExtractor
+
+
+class SpiegelIE(InfoExtractor):
+    _VALID_URL = r'https?://(?:www\.)?spiegel\.de/video/[^/]*-(?P<videoID>[0-9]+)(?:\.html)?(?:#.*)?$'
+
+    def _real_extract(self, url):
+        m = re.match(self._VALID_URL, url)
+        video_id = m.group('videoID')
+
+        webpage = self._download_webpage(url, video_id)
+
+        video_title = self._html_search_regex(r'<div class="module-title">(.*?)</div>',
+            webpage, u'title')
+
+        xml_url = u'http://video2.spiegel.de/flash/' + video_id + u'.xml'
+        xml_code = self._download_webpage(xml_url, video_id,
+                    note=u'Downloading XML', errnote=u'Failed to download XML')
+
+        idoc = xml.etree.ElementTree.fromstring(xml_code)
+        last_type = idoc[-1]
+        filename = last_type.findall('./filename')[0].text
+        duration = float(last_type.findall('./duration')[0].text)
+
+        video_url = 'http://video2.spiegel.de/flash/' + filename
+        video_ext = filename.rpartition('.')[2]
+        info = {
+            'id': video_id,
+            'url': video_url,
+            'ext': video_ext,
+            'title': video_title,
+            'duration': duration,
+        }
+        return [info]
diff --git a/youtube_dl/extractor/stanfordoc.py b/youtube_dl/extractor/stanfordoc.py
new file mode 100644
index 0000000..8d3e32a
--- /dev/null
+++ b/youtube_dl/extractor/stanfordoc.py
@@ -0,0 +1,112 @@
+import re
+import socket
+import xml.etree.ElementTree
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_str,
+    compat_urllib_error,
+    compat_urllib_request,
+
+    ExtractorError,
+    orderedSet,
+    unescapeHTML,
+)
+
+
+class StanfordOpenClassroomIE(InfoExtractor):
+    """Information extractor for Stanford's Open ClassRoom"""
+
+    _VALID_URL = r'^(?:https?://)?openclassroom.stanford.edu(?P<path>/?|(/MainFolder/(?:HomePage|CoursePage|VideoPage)\.php([?]course=(?P<course>[^&]+)(&video=(?P<video>[^&]+))?(&.*)?)?))$'
+    IE_NAME = u'stanfordoc'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        if mobj.group('course') and mobj.group('video'): # A specific video
+            course = mobj.group('course')
+            video = mobj.group('video')
+            info = {
+                'id': course + '_' + video,
+                'uploader': None,
+                'upload_date': None,
+            }
+
+            self.report_extraction(info['id'])
+            baseUrl = 'http://openclassroom.stanford.edu/MainFolder/courses/' + course + '/videos/'
+            xmlUrl = baseUrl + video + '.xml'
+            try:
+                metaXml = compat_urllib_request.urlopen(xmlUrl).read()
+            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+                raise ExtractorError(u'Unable to download video info XML: %s' % compat_str(err))
+            mdoc = xml.etree.ElementTree.fromstring(metaXml)
+            try:
+                info['title'] = mdoc.findall('./title')[0].text
+                info['url'] = baseUrl + mdoc.findall('./videoFile')[0].text
+            except IndexError:
+                raise ExtractorError(u'Invalid metadata XML file')
+            info['ext'] = info['url'].rpartition('.')[2]
+            return [info]
+        elif mobj.group('course'): # A course page
+            course = mobj.group('course')
+            info = {
+                'id': course,
+                'type': 'playlist',
+                'uploader': None,
+                'upload_date': None,
+            }
+
+            coursepage = self._download_webpage(url, info['id'],
+                                        note='Downloading course info page',
+                                        errnote='Unable to download course info page')
+
+            info['title'] = self._html_search_regex('<h1>([^<]+)</h1>', coursepage, 'title', default=info['id'])
+
+            info['description'] = self._html_search_regex('<description>([^<]+)</description>',
+                coursepage, u'description', fatal=False)
+
+            links = orderedSet(re.findall('<a href="(VideoPage.php\?[^"]+)">', coursepage))
+            info['list'] = [
+                {
+                    'type': 'reference',
+                    'url': 'http://openclassroom.stanford.edu/MainFolder/' + unescapeHTML(vpage),
+                }
+                    for vpage in links]
+            results = []
+            for entry in info['list']:
+                assert entry['type'] == 'reference'
+                results += self.extract(entry['url'])
+            return results
+        else: # Root page
+            info = {
+                'id': 'Stanford OpenClassroom',
+                'type': 'playlist',
+                'uploader': None,
+                'upload_date': None,
+            }
+
+            self.report_download_webpage(info['id'])
+            rootURL = 'http://openclassroom.stanford.edu/MainFolder/HomePage.php'
+            try:
+                rootpage = compat_urllib_request.urlopen(rootURL).read()
+            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+                raise ExtractorError(u'Unable to download course info page: ' + compat_str(err))
+
+            info['title'] = info['id']
+
+            links = orderedSet(re.findall('<a href="(CoursePage.php\?[^"]+)">', rootpage))
+            info['list'] = [
+                {
+                    'type': 'reference',
+                    'url': 'http://openclassroom.stanford.edu/MainFolder/' + unescapeHTML(cpage),
+                }
+                    for cpage in links]
+
+            results = []
+            for entry in info['list']:
+                assert entry['type'] == 'reference'
+                results += self.extract(entry['url'])
+            return results
diff --git a/youtube_dl/extractor/statigram.py b/youtube_dl/extractor/statigram.py
new file mode 100644
index 0000000..95d2ee3
--- /dev/null
+++ b/youtube_dl/extractor/statigram.py
@@ -0,0 +1,33 @@
+import re
+
+from .common import InfoExtractor
+
+class StatigramIE(InfoExtractor):
+    _VALID_URL = r'(?:http://)?(?:www\.)?statigr\.am/p/([^/]+)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        video_id = mobj.group(1)
+        webpage = self._download_webpage(url, video_id)
+        video_url = self._html_search_regex(
+            r'<meta property="og:video:secure_url" content="(.+?)">',
+            webpage, u'video URL')
+        thumbnail_url = self._html_search_regex(
+            r'<meta property="og:image" content="(.+?)" />',
+            webpage, u'thumbnail URL', fatal=False)
+        html_title = self._html_search_regex(
+            r'<title>(.+?)</title>',
+            webpage, u'title')
+        title = html_title.rpartition(u' | Statigram')[0]
+        uploader_id = self._html_search_regex(
+            r'@([^ ]+)', title, u'uploader name', fatal=False)
+        ext = 'mp4'
+
+        return [{
+            'id':        video_id,
+            'url':       video_url,
+            'ext':       ext,
+            'title':     title,
+            'thumbnail': thumbnail_url,
+            'uploader_id' : uploader_id
+        }]
diff --git a/youtube_dl/extractor/steam.py b/youtube_dl/extractor/steam.py
new file mode 100644
index 0000000..30cb832
--- /dev/null
+++ b/youtube_dl/extractor/steam.py
@@ -0,0 +1,63 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+    unescapeHTML,
+)
+
+
+class SteamIE(InfoExtractor):
+    _VALID_URL = r"""http://store\.steampowered\.com/
+                (agecheck/)?
+                (?P<urltype>video|app)/ #If the page is only for videos or for a game
+                (?P<gameID>\d+)/?
+                (?P<videoID>\d*)(?P<extra>\??) #For urltype == video we sometimes get the videoID
+                """
+    _VIDEO_PAGE_TEMPLATE = 'http://store.steampowered.com/video/%s/'
+    _AGECHECK_TEMPLATE = 'http://store.steampowered.com/agecheck/video/%s/?snr=1_agecheck_agecheck__age-gate&ageDay=1&ageMonth=January&ageYear=1970'
+
+    @classmethod
+    def suitable(cls, url):
+        """Receives a URL and returns True if suitable for this IE."""
+        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
+
+    def _real_extract(self, url):
+        m = re.match(self._VALID_URL, url, re.VERBOSE)
+        gameID = m.group('gameID')
+
+        videourl = self._VIDEO_PAGE_TEMPLATE % gameID
+        webpage = self._download_webpage(videourl, gameID)
+
+        if re.search('<h2>Please enter your birth date to continue:</h2>', webpage) is not None:
+            videourl = self._AGECHECK_TEMPLATE % gameID
+            self.report_age_confirmation()
+            webpage = self._download_webpage(videourl, gameID)
+
+        self.report_extraction(gameID)
+        game_title = self._html_search_regex(r'<h2 class="pageheader">(.*?)</h2>',
+                                             webpage, 'game title')
+
+        urlRE = r"'movie_(?P<videoID>\d+)': \{\s*FILENAME: \"(?P<videoURL>[\w:/\.\?=]+)\"(,\s*MOVIE_NAME: \"(?P<videoName>[\w:/\.\?=\+-]+)\")?\s*\},"
+        mweb = re.finditer(urlRE, webpage)
+        namesRE = r'<span class="title">(?P<videoName>.+?)</span>'
+        titles = re.finditer(namesRE, webpage)
+        thumbsRE = r'<img class="movie_thumb" src="(?P<thumbnail>.+?)">'
+        thumbs = re.finditer(thumbsRE, webpage)
+        videos = []
+        for vid,vtitle,thumb in zip(mweb,titles,thumbs):
+            video_id = vid.group('videoID')
+            title = vtitle.group('videoName')
+            video_url = vid.group('videoURL')
+            video_thumb = thumb.group('thumbnail')
+            if not video_url:
+                raise ExtractorError(u'Cannot find video url for %s' % video_id)
+            info = {
+                'id':video_id,
+                'url':video_url,
+                'ext': 'flv',
+                'title': unescapeHTML(title),
+                'thumbnail': video_thumb
+                  }
+            videos.append(info)
+        return [self.playlist_result(videos, gameID, game_title)]
diff --git a/youtube_dl/extractor/teamcoco.py b/youtube_dl/extractor/teamcoco.py
new file mode 100644
index 0000000..092ac74
--- /dev/null
+++ b/youtube_dl/extractor/teamcoco.py
@@ -0,0 +1,46 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class TeamcocoIE(InfoExtractor):
+    _VALID_URL = r'http://teamcoco\.com/video/(?P<url_title>.*)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        url_title = mobj.group('url_title')
+        webpage = self._download_webpage(url, url_title)
+
+        video_id = self._html_search_regex(r'<article class="video" data-id="(\d+?)"',
+            webpage, u'video id')
+
+        self.report_extraction(video_id)
+
+        video_title = self._html_search_regex(r'<meta property="og:title" content="(.+?)"',
+            webpage, u'title')
+
+        thumbnail = self._html_search_regex(r'<meta property="og:image" content="(.+?)"',
+            webpage, u'thumbnail', fatal=False)
+
+        video_description = self._html_search_regex(r'<meta property="og:description" content="(.*?)"',
+            webpage, u'description', fatal=False)
+
+        data_url = 'http://teamcoco.com/cvp/2.0/%s.xml' % video_id
+        data = self._download_webpage(data_url, video_id, 'Downloading data webpage')
+
+        video_url = self._html_search_regex(r'<file type="high".*?>(.*?)</file>',
+            data, u'video URL')
+
+        return [{
+            'id':          video_id,
+            'url':         video_url,
+            'ext':         'mp4',
+            'title':       video_title,
+            'thumbnail':   thumbnail,
+            'description': video_description,
+        }]
diff --git a/youtube_dl/extractor/ted.py b/youtube_dl/extractor/ted.py
new file mode 100644
index 0000000..ccad1c7
--- /dev/null
+++ b/youtube_dl/extractor/ted.py
@@ -0,0 +1,79 @@
+import json
+import re
+
+from .common import InfoExtractor
+
+
+class TEDIE(InfoExtractor):
+    _VALID_URL=r'''http://www\.ted\.com/
+                   (
+                        ((?P<type_playlist>playlists)/(?P<playlist_id>\d+)) # We have a playlist
+                        |
+                        ((?P<type_talk>talks)) # We have a simple talk
+                   )
+                   (/lang/(.*?))? # The url may contain the language
+                   /(?P<name>\w+) # Here goes the name and then ".html"
+                   '''
+
+    @classmethod
+    def suitable(cls, url):
+        """Receives a URL and returns True if suitable for this IE."""
+        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
+
+    def _real_extract(self, url):
+        m=re.match(self._VALID_URL, url, re.VERBOSE)
+        if m.group('type_talk'):
+            return [self._talk_info(url)]
+        else :
+            playlist_id=m.group('playlist_id')
+            name=m.group('name')
+            self.to_screen(u'Getting info of playlist %s: "%s"' % (playlist_id,name))
+            return [self._playlist_videos_info(url,name,playlist_id)]
+
+    def _playlist_videos_info(self,url,name,playlist_id=0):
+        '''Returns the videos of the playlist'''
+        video_RE=r'''
+                     <li\ id="talk_(\d+)"([.\s]*?)data-id="(?P<video_id>\d+)"
+                     ([.\s]*?)data-playlist_item_id="(\d+)"
+                     ([.\s]*?)data-mediaslug="(?P<mediaSlug>.+?)"
+                     '''
+        video_name_RE=r'<p\ class="talk-title"><a href="(?P<talk_url>/talks/(.+).html)">(?P<fullname>.+?)</a></p>'
+        webpage=self._download_webpage(url, playlist_id, 'Downloading playlist webpage')
+        m_videos=re.finditer(video_RE,webpage,re.VERBOSE)
+        m_names=re.finditer(video_name_RE,webpage)
+
+        playlist_title = self._html_search_regex(r'div class="headline">\s*?<h1>\s*?<span>(.*?)</span>',
+                                                 webpage, 'playlist title')
+
+        playlist_entries = []
+        for m_video, m_name in zip(m_videos,m_names):
+            talk_url='http://www.ted.com%s' % m_name.group('talk_url')
+            playlist_entries.append(self.url_result(talk_url, 'TED'))
+        return self.playlist_result(playlist_entries, playlist_id = playlist_id, playlist_title = playlist_title)
+
+    def _talk_info(self, url, video_id=0):
+        """Return the video for the talk in the url"""
+        m = re.match(self._VALID_URL, url,re.VERBOSE)
+        video_name = m.group('name')
+        webpage = self._download_webpage(url, video_id, 'Downloading \"%s\" page' % video_name)
+        self.report_extraction(video_name)
+        # If the url includes the language we get the title translated
+        title = self._html_search_regex(r'<span id="altHeadline" >(?P<title>.*)</span>',
+                                        webpage, 'title')
+        json_data = self._search_regex(r'<script.*?>var talkDetails = ({.*?})</script>',
+                                    webpage, 'json data')
+        info = json.loads(json_data)
+        desc = self._html_search_regex(r'<div class="talk-intro">.*?<p.*?>(.*?)</p>',
+                                       webpage, 'description', flags = re.DOTALL)
+        
+        thumbnail = self._search_regex(r'</span>[\s.]*</div>[\s.]*<img src="(.*?)"',
+                                       webpage, 'thumbnail')
+        info = {
+                'id': info['id'],
+                'url': info['htmlStreams'][-1]['file'],
+                'ext': 'mp4',
+                'title': title,
+                'thumbnail': thumbnail,
+                'description': desc,
+                }
+        return info
diff --git a/youtube_dl/extractor/tumblr.py b/youtube_dl/extractor/tumblr.py
new file mode 100644
index 0000000..b0851b4
--- /dev/null
+++ b/youtube_dl/extractor/tumblr.py
@@ -0,0 +1,41 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class TumblrIE(InfoExtractor):
+    _VALID_URL = r'http://(?P<blog_name>.*?)\.tumblr\.com/((post)|(video))/(?P<id>\d*)/(.*?)'
+
+    def _real_extract(self, url):
+        m_url = re.match(self._VALID_URL, url)
+        video_id = m_url.group('id')
+        blog = m_url.group('blog_name')
+
+        url = 'http://%s.tumblr.com/post/%s/' % (blog, video_id)
+        webpage = self._download_webpage(url, video_id)
+
+        re_video = r'src=\\x22(?P<video_url>http://%s\.tumblr\.com/video_file/%s/(.*?))\\x22 type=\\x22video/(?P<ext>.*?)\\x22' % (blog, video_id)
+        video = re.search(re_video, webpage)
+        if video is None:
+           raise ExtractorError(u'Unable to extract video')
+        video_url = video.group('video_url')
+        ext = video.group('ext')
+
+        video_thumbnail = self._search_regex(r'posters(.*?)\[\\x22(?P<thumb>.*?)\\x22',
+            webpage, u'thumbnail', fatal=False)  # We pick the first poster
+        if video_thumbnail: video_thumbnail = video_thumbnail.replace('\\', '')
+
+        # The only place where you can get a title, it's not complete,
+        # but searching in other places doesn't work for all videos
+        video_title = self._html_search_regex(r'<title>(?P<title>.*?)</title>',
+            webpage, u'title', flags=re.DOTALL)
+
+        return [{'id': video_id,
+                 'url': video_url,
+                 'title': video_title,
+                 'thumbnail': video_thumbnail,
+                 'ext': ext
+                 }]
diff --git a/youtube_dl/extractor/ustream.py b/youtube_dl/extractor/ustream.py
new file mode 100644
index 0000000..cfe3a68
--- /dev/null
+++ b/youtube_dl/extractor/ustream.py
@@ -0,0 +1,36 @@
+import re
+
+from .common import InfoExtractor
+
+
+class UstreamIE(InfoExtractor):
+    _VALID_URL = r'https?://www\.ustream\.tv/recorded/(?P<videoID>\d+)'
+    IE_NAME = u'ustream'
+
+    def _real_extract(self, url):
+        m = re.match(self._VALID_URL, url)
+        video_id = m.group('videoID')
+
+        video_url = u'http://tcdn.ustream.tv/video/%s' % video_id
+        webpage = self._download_webpage(url, video_id)
+
+        self.report_extraction(video_id)
+
+        video_title = self._html_search_regex(r'data-title="(?P<title>.+)"',
+            webpage, u'title')
+
+        uploader = self._html_search_regex(r'data-content-type="channel".*?>(?P<uploader>.*?)</a>',
+            webpage, u'uploader', fatal=False, flags=re.DOTALL)
+
+        thumbnail = self._html_search_regex(r'<link rel="image_src" href="(?P<thumb>.*?)"',
+            webpage, u'thumbnail', fatal=False)
+
+        info = {
+                'id': video_id,
+                'url': video_url,
+                'ext': 'flv',
+                'title': video_title,
+                'uploader': uploader,
+                'thumbnail': thumbnail,
+               }
+        return info
diff --git a/youtube_dl/extractor/vbox7.py b/youtube_dl/extractor/vbox7.py
new file mode 100644
index 0000000..2f3ce46
--- /dev/null
+++ b/youtube_dl/extractor/vbox7.py
@@ -0,0 +1,46 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+    compat_urllib_request,
+
+    ExtractorError,
+)
+
+
+class Vbox7IE(InfoExtractor):
+    """Information Extractor for Vbox7"""
+    _VALID_URL = r'(?:http://)?(?:www\.)?vbox7\.com/play:([^/]+)'
+
+    def _real_extract(self,url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group(1)
+
+        redirect_page, urlh = self._download_webpage_handle(url, video_id)
+        new_location = self._search_regex(r'window\.location = \'(.*)\';', redirect_page, u'redirect location')
+        redirect_url = urlh.geturl() + new_location
+        webpage = self._download_webpage(redirect_url, video_id, u'Downloading redirect page')
+
+        title = self._html_search_regex(r'<title>(.*)</title>',
+            webpage, u'title').split('/')[0].strip()
+
+        ext = "flv"
+        info_url = "http://vbox7.com/play/magare.do"
+        data = compat_urllib_parse.urlencode({'as3':'1','vid':video_id})
+        info_request = compat_urllib_request.Request(info_url, data)
+        info_request.add_header('Content-Type', 'application/x-www-form-urlencoded')
+        info_response = self._download_webpage(info_request, video_id, u'Downloading info webpage')
+        if info_response is None:
+            raise ExtractorError(u'Unable to extract the media url')
+        (final_url, thumbnail_url) = map(lambda x: x.split('=')[1], info_response.split('&'))
+
+        return [{
+            'id':        video_id,
+            'url':       final_url,
+            'ext':       ext,
+            'title':     title,
+            'thumbnail': thumbnail_url,
+        }]
diff --git a/youtube_dl/extractor/vimeo.py b/youtube_dl/extractor/vimeo.py
new file mode 100644
index 0000000..677cf4e
--- /dev/null
+++ b/youtube_dl/extractor/vimeo.py
@@ -0,0 +1,138 @@
+import json
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+    compat_urllib_request,
+
+    clean_html,
+    get_element_by_attribute,
+    ExtractorError,
+    std_headers,
+)
+
+class VimeoIE(InfoExtractor):
+    """Information extractor for vimeo.com."""
+
+    # _VALID_URL matches Vimeo URLs
+    _VALID_URL = r'(?P<proto>https?://)?(?:(?:www|player)\.)?vimeo(?P<pro>pro)?\.com/(?:(?:(?:groups|album)/[^/]+)|(?:.*?)/)?(?P<direct_link>play_redirect_hls\?clip_id=)?(?:videos?/)?(?P<id>[0-9]+)'
+    IE_NAME = u'vimeo'
+
+    def _verify_video_password(self, url, video_id, webpage):
+        password = self._downloader.params.get('password', None)
+        if password is None:
+            raise ExtractorError(u'This video is protected by a password, use the --password option')
+        token = re.search(r'xsrft: \'(.*?)\'', webpage).group(1)
+        data = compat_urllib_parse.urlencode({'password': password,
+                                              'token': token})
+        # I didn't manage to use the password with https
+        if url.startswith('https'):
+            pass_url = url.replace('https','http')
+        else:
+            pass_url = url
+        password_request = compat_urllib_request.Request(pass_url+'/password', data)
+        password_request.add_header('Content-Type', 'application/x-www-form-urlencoded')
+        password_request.add_header('Cookie', 'xsrft=%s' % token)
+        self._download_webpage(password_request, video_id,
+                               u'Verifying the password',
+                               u'Wrong password')
+
+    def _real_extract(self, url, new_video=True):
+        # Extract ID from URL
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        video_id = mobj.group('id')
+        if not mobj.group('proto'):
+            url = 'https://' + url
+        if mobj.group('direct_link') or mobj.group('pro'):
+            url = 'https://vimeo.com/' + video_id
+
+        # Retrieve video webpage to extract further information
+        request = compat_urllib_request.Request(url, None, std_headers)
+        webpage = self._download_webpage(request, video_id)
+
+        # Now we begin extracting as much information as we can from what we
+        # retrieved. First we extract the information common to all extractors,
+        # and latter we extract those that are Vimeo specific.
+        self.report_extraction(video_id)
+
+        # Extract the config JSON
+        try:
+            config = webpage.split(' = {config:')[1].split(',assets:')[0]
+            config = json.loads(config)
+        except:
+            if re.search('The creator of this video has not given you permission to embed it on this domain.', webpage):
+                raise ExtractorError(u'The author has restricted the access to this video, try with the "--referer" option')
+
+            if re.search('If so please provide the correct password.', webpage):
+                self._verify_video_password(url, video_id, webpage)
+                return self._real_extract(url)
+            else:
+                raise ExtractorError(u'Unable to extract info section')
+
+        # Extract title
+        video_title = config["video"]["title"]
+
+        # Extract uploader and uploader_id
+        video_uploader = config["video"]["owner"]["name"]
+        video_uploader_id = config["video"]["owner"]["url"].split('/')[-1] if config["video"]["owner"]["url"] else None
+
+        # Extract video thumbnail
+        video_thumbnail = config["video"]["thumbnail"]
+
+        # Extract video description
+        video_description = get_element_by_attribute("itemprop", "description", webpage)
+        if video_description: video_description = clean_html(video_description)
+        else: video_description = u''
+
+        # Extract upload date
+        video_upload_date = None
+        mobj = re.search(r'<meta itemprop="dateCreated" content="(\d{4})-(\d{2})-(\d{2})T', webpage)
+        if mobj is not None:
+            video_upload_date = mobj.group(1) + mobj.group(2) + mobj.group(3)
+
+        # Vimeo specific: extract request signature and timestamp
+        sig = config['request']['signature']
+        timestamp = config['request']['timestamp']
+
+        # Vimeo specific: extract video codec and quality information
+        # First consider quality, then codecs, then take everything
+        # TODO bind to format param
+        codecs = [('h264', 'mp4'), ('vp8', 'flv'), ('vp6', 'flv')]
+        files = { 'hd': [], 'sd': [], 'other': []}
+        for codec_name, codec_extension in codecs:
+            if codec_name in config["video"]["files"]:
+                if 'hd' in config["video"]["files"][codec_name]:
+                    files['hd'].append((codec_name, codec_extension, 'hd'))
+                elif 'sd' in config["video"]["files"][codec_name]:
+                    files['sd'].append((codec_name, codec_extension, 'sd'))
+                else:
+                    files['other'].append((codec_name, codec_extension, config["video"]["files"][codec_name][0]))
+
+        for quality in ('hd', 'sd', 'other'):
+            if len(files[quality]) > 0:
+                video_quality = files[quality][0][2]
+                video_codec = files[quality][0][0]
+                video_extension = files[quality][0][1]
+                self.to_screen(u'%s: Downloading %s file at %s quality' % (video_id, video_codec.upper(), video_quality))
+                break
+        else:
+            raise ExtractorError(u'No known codec found')
+
+        video_url = "http://player.vimeo.com/play_redirect?clip_id=%s&sig=%s&time=%s&quality=%s&codecs=%s&type=moogaloop_local&embed_location=" \
+                    %(video_id, sig, timestamp, video_quality, video_codec.upper())
+
+        return [{
+            'id':       video_id,
+            'url':      video_url,
+            'uploader': video_uploader,
+            'uploader_id': video_uploader_id,
+            'upload_date':  video_upload_date,
+            'title':    video_title,
+            'ext':      video_extension,
+            'thumbnail':    video_thumbnail,
+            'description':  video_description,
+        }]
diff --git a/youtube_dl/extractor/vine.py b/youtube_dl/extractor/vine.py
new file mode 100644
index 0000000..b44b1cb
--- /dev/null
+++ b/youtube_dl/extractor/vine.py
@@ -0,0 +1,37 @@
+import re
+
+from .common import InfoExtractor
+
+
+class VineIE(InfoExtractor):
+    _VALID_URL = r'(?:https?://)?(?:www\.)?vine\.co/v/(?P<id>\w+)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('id')
+        webpage_url = 'https://vine.co/v/' + video_id
+        webpage = self._download_webpage(webpage_url, video_id)
+
+        self.report_extraction(video_id)
+
+        video_url = self._html_search_regex(r'<meta property="twitter:player:stream" content="(.+?)"',
+            webpage, u'video URL')
+
+        video_title = self._html_search_regex(r'<meta property="og:title" content="(.+?)"',
+            webpage, u'title')
+
+        thumbnail = self._html_search_regex(r'<meta property="og:image" content="(.+?)(\?.*?)?"',
+            webpage, u'thumbnail', fatal=False)
+
+        uploader = self._html_search_regex(r'<div class="user">.*?<h2>(.+?)</h2>',
+            webpage, u'uploader', fatal=False, flags=re.DOTALL)
+
+        return [{
+            'id':        video_id,
+            'url':       video_url,
+            'ext':       'mp4',
+            'title':     video_title,
+            'thumbnail': thumbnail,
+            'uploader':  uploader,
+        }]
diff --git a/youtube_dl/extractor/worldstarhiphop.py b/youtube_dl/extractor/worldstarhiphop.py
new file mode 100644
index 0000000..54a77b6
--- /dev/null
+++ b/youtube_dl/extractor/worldstarhiphop.py
@@ -0,0 +1,44 @@
+import re
+
+from .common import InfoExtractor
+
+
+class WorldStarHipHopIE(InfoExtractor):
+    _VALID_URL = r'https?://(?:www|m)\.worldstar(?:candy|hiphop)\.com/videos/video\.php\?v=(?P<id>.*)'
+    IE_NAME = u'WorldStarHipHop'
+
+    def _real_extract(self, url):
+        m = re.match(self._VALID_URL, url)
+        video_id = m.group('id')
+
+        webpage_src = self._download_webpage(url, video_id)
+
+        video_url = self._search_regex(r'so\.addVariable\("file","(.*?)"\)',
+            webpage_src, u'video URL')
+
+        if 'mp4' in video_url:
+            ext = 'mp4'
+        else:
+            ext = 'flv'
+
+        video_title = self._html_search_regex(r"<title>(.*)</title>",
+            webpage_src, u'title')
+
+        # Getting thumbnail and if not thumbnail sets correct title for WSHH candy video.
+        thumbnail = self._html_search_regex(r'rel="image_src" href="(.*)" />',
+            webpage_src, u'thumbnail', fatal=False)
+
+        if not thumbnail:
+            _title = r"""candytitles.*>(.*)</span>"""
+            mobj = re.search(_title, webpage_src)
+            if mobj is not None:
+                video_title = mobj.group(1)
+
+        results = [{
+                    'id': video_id,
+                    'url' : video_url,
+                    'title' : video_title,
+                    'thumbnail' : thumbnail,
+                    'ext' : ext,
+                    }]
+        return results
diff --git a/youtube_dl/extractor/xhamster.py b/youtube_dl/extractor/xhamster.py
new file mode 100644
index 0000000..0013509
--- /dev/null
+++ b/youtube_dl/extractor/xhamster.py
@@ -0,0 +1,61 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+
+    ExtractorError,
+)
+
+
+class XHamsterIE(InfoExtractor):
+    """Information Extractor for xHamster"""
+    _VALID_URL = r'(?:http://)?(?:www.)?xhamster\.com/movies/(?P<id>[0-9]+)/.*\.html'
+
+    def _real_extract(self,url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('id')
+        mrss_url = 'http://xhamster.com/movies/%s/.html' % video_id
+        webpage = self._download_webpage(mrss_url, video_id)
+
+        mobj = re.search(r'\'srv\': \'(?P<server>[^\']*)\',\s*\'file\': \'(?P<file>[^\']+)\',', webpage)
+        if mobj is None:
+            raise ExtractorError(u'Unable to extract media URL')
+        if len(mobj.group('server')) == 0:
+            video_url = compat_urllib_parse.unquote(mobj.group('file'))
+        else:
+            video_url = mobj.group('server')+'/key='+mobj.group('file')
+        video_extension = video_url.split('.')[-1]
+
+        video_title = self._html_search_regex(r'<title>(?P<title>.+?) - xHamster\.com</title>',
+            webpage, u'title')
+
+        # Can't see the description anywhere in the UI
+        # video_description = self._html_search_regex(r'<span>Description: </span>(?P<description>[^<]+)',
+        #     webpage, u'description', fatal=False)
+        # if video_description: video_description = unescapeHTML(video_description)
+
+        mobj = re.search(r'hint=\'(?P<upload_date_Y>[0-9]{4})-(?P<upload_date_m>[0-9]{2})-(?P<upload_date_d>[0-9]{2}) [0-9]{2}:[0-9]{2}:[0-9]{2} [A-Z]{3,4}\'', webpage)
+        if mobj:
+            video_upload_date = mobj.group('upload_date_Y')+mobj.group('upload_date_m')+mobj.group('upload_date_d')
+        else:
+            video_upload_date = None
+            self._downloader.report_warning(u'Unable to extract upload date')
+
+        video_uploader_id = self._html_search_regex(r'<a href=\'/user/[^>]+>(?P<uploader_id>[^<]+)',
+            webpage, u'uploader id', default=u'anonymous')
+
+        video_thumbnail = self._search_regex(r'\'image\':\'(?P<thumbnail>[^\']+)\'',
+            webpage, u'thumbnail', fatal=False)
+
+        return [{
+            'id':       video_id,
+            'url':      video_url,
+            'ext':      video_extension,
+            'title':    video_title,
+            # 'description': video_description,
+            'upload_date': video_upload_date,
+            'uploader_id': video_uploader_id,
+            'thumbnail': video_thumbnail
+        }]
diff --git a/youtube_dl/extractor/xnxx.py b/youtube_dl/extractor/xnxx.py
new file mode 100644
index 0000000..68acb84
--- /dev/null
+++ b/youtube_dl/extractor/xnxx.py
@@ -0,0 +1,45 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+
+    ExtractorError,
+)
+
+
+class XNXXIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?video\.xnxx\.com/video([0-9]+)/(.*)'
+    VIDEO_URL_RE = r'flv_url=(.*?)&amp;'
+    VIDEO_TITLE_RE = r'<title>(.*?)\s+-\s+XNXX.COM'
+    VIDEO_THUMB_RE = r'url_bigthumb=(.*?)&amp;'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group(1)
+
+        # Get webpage content
+        webpage = self._download_webpage(url, video_id)
+
+        video_url = self._search_regex(self.VIDEO_URL_RE,
+            webpage, u'video URL')
+        video_url = compat_urllib_parse.unquote(video_url)
+
+        video_title = self._html_search_regex(self.VIDEO_TITLE_RE,
+            webpage, u'title')
+
+        video_thumbnail = self._search_regex(self.VIDEO_THUMB_RE,
+            webpage, u'thumbnail', fatal=False)
+
+        return [{
+            'id': video_id,
+            'url': video_url,
+            'uploader': None,
+            'upload_date': None,
+            'title': video_title,
+            'ext': 'flv',
+            'thumbnail': video_thumbnail,
+            'description': None,
+        }]
diff --git a/youtube_dl/extractor/xvideos.py b/youtube_dl/extractor/xvideos.py
new file mode 100644
index 0000000..8b3cb39
--- /dev/null
+++ b/youtube_dl/extractor/xvideos.py
@@ -0,0 +1,43 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+)
+
+
+class XVideosIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?(?:www\.)?xvideos\.com/video([0-9]+)(?:.*)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        video_id = mobj.group(1)
+
+        webpage = self._download_webpage(url, video_id)
+
+        self.report_extraction(video_id)
+
+        # Extract video URL
+        video_url = compat_urllib_parse.unquote(self._search_regex(r'flv_url=(.+?)&',
+            webpage, u'video URL'))
+
+        # Extract title
+        video_title = self._html_search_regex(r'<title>(.*?)\s+-\s+XVID',
+            webpage, u'title')
+
+        # Extract video thumbnail
+        video_thumbnail = self._search_regex(r'http://(?:img.*?\.)xvideos.com/videos/thumbs/[a-fA-F0-9]+/[a-fA-F0-9]+/[a-fA-F0-9]+/[a-fA-F0-9]+/([a-fA-F0-9.]+jpg)',
+            webpage, u'thumbnail', fatal=False)
+
+        info = {
+            'id': video_id,
+            'url': video_url,
+            'uploader': None,
+            'upload_date': None,
+            'title': video_title,
+            'ext': 'flv',
+            'thumbnail': video_thumbnail,
+            'description': None,
+        }
+
+        return [info]
diff --git a/youtube_dl/extractor/yahoo.py b/youtube_dl/extractor/yahoo.py
new file mode 100644
index 0000000..4b3aec9
--- /dev/null
+++ b/youtube_dl/extractor/yahoo.py
@@ -0,0 +1,113 @@
+import datetime
+import itertools
+import json
+import re
+
+from .common import InfoExtractor, SearchInfoExtractor
+from ..utils import (
+    compat_urllib_parse,
+
+    ExtractorError,
+)
+
+class YahooIE(InfoExtractor):
+    """Information extractor for screen.yahoo.com."""
+    _VALID_URL = r'http://screen\.yahoo\.com/.*?-(?P<id>\d*?)\.html'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group('id')
+        webpage = self._download_webpage(url, video_id)
+        m_id = re.search(r'YUI\.namespace\("Media"\)\.CONTENT_ID = "(?P<new_id>.+?)";', webpage)
+
+        if m_id is None: 
+            # TODO: Check which url parameters are required
+            info_url = 'http://cosmos.bcst.yahoo.com/rest/v2/pops;lmsoverride=1;outputformat=mrss;cb=974419660;id=%s;rd=news.yahoo.com;datacontext=mdb;lg=KCa2IihxG3qE60vQ7HtyUy' % video_id
+            webpage = self._download_webpage(info_url, video_id, u'Downloading info webpage')
+            info_re = r'''<title><!\[CDATA\[(?P<title>.*?)\]\]></title>.*
+                        <description><!\[CDATA\[(?P<description>.*?)\]\]></description>.*
+                        <media:pubStart><!\[CDATA\[(?P<date>.*?)\ .*\]\]></media:pubStart>.*
+                        <media:content\ medium="image"\ url="(?P<thumb>.*?)"\ name="LARGETHUMB"
+                        '''
+            self.report_extraction(video_id)
+            m_info = re.search(info_re, webpage, re.VERBOSE|re.DOTALL)
+            if m_info is None:
+                raise ExtractorError(u'Unable to extract video info')
+            video_title = m_info.group('title')
+            video_description = m_info.group('description')
+            video_thumb = m_info.group('thumb')
+            video_date = m_info.group('date')
+            video_date = datetime.datetime.strptime(video_date, '%m/%d/%Y').strftime('%Y%m%d')
+    
+            # TODO: Find a way to get mp4 videos
+            rest_url = 'http://cosmos.bcst.yahoo.com/rest/v2/pops;element=stream;outputformat=mrss;id=%s;lmsoverride=1;bw=375;dynamicstream=1;cb=83521105;tech=flv,mp4;rd=news.yahoo.com;datacontext=mdb;lg=KCa2IihxG3qE60vQ7HtyUy' % video_id
+            webpage = self._download_webpage(rest_url, video_id, u'Downloading video url webpage')
+            m_rest = re.search(r'<media:content url="(?P<url>.*?)" path="(?P<path>.*?)"', webpage)
+            video_url = m_rest.group('url')
+            video_path = m_rest.group('path')
+            if m_rest is None:
+                raise ExtractorError(u'Unable to extract video url')
+
+        else: # We have to use a different method if another id is defined
+            long_id = m_id.group('new_id')
+            info_url = 'http://video.query.yahoo.com/v1/public/yql?q=SELECT%20*%20FROM%20yahoo.media.video.streams%20WHERE%20id%3D%22' + long_id + '%22%20AND%20format%3D%22mp4%2Cflv%22%20AND%20protocol%3D%22rtmp%2Chttp%22%20AND%20plrs%3D%2286Gj0vCaSzV_Iuf6hNylf2%22%20AND%20acctid%3D%22389%22%20AND%20plidl%3D%22%22%20AND%20pspid%3D%22792700001%22%20AND%20offnetwork%3D%22false%22%20AND%20site%3D%22ivy%22%20AND%20lang%3D%22en-US%22%20AND%20region%3D%22US%22%20AND%20override%3D%22none%22%3B&env=prod&format=json&callback=YUI.Env.JSONP.yui_3_8_1_1_1368368376830_335'
+            webpage = self._download_webpage(info_url, video_id, u'Downloading info json')
+            json_str = re.search(r'YUI.Env.JSONP.yui.*?\((.*?)\);', webpage).group(1)
+            info = json.loads(json_str)
+            res = info[u'query'][u'results'][u'mediaObj'][0]
+            stream = res[u'streams'][0]
+            video_path = stream[u'path']
+            video_url = stream[u'host']
+            meta = res[u'meta']
+            video_title = meta[u'title']
+            video_description = meta[u'description']
+            video_thumb = meta[u'thumbnail']
+            video_date = None # I can't find it
+
+        info_dict = {
+                     'id': video_id,
+                     'url': video_url,
+                     'play_path': video_path,
+                     'title':video_title,
+                     'description': video_description,
+                     'thumbnail': video_thumb,
+                     'upload_date': video_date,
+                     'ext': 'flv',
+                     }
+        return info_dict
+
+class YahooSearchIE(SearchInfoExtractor):
+    """Information Extractor for Yahoo! Video search queries."""
+
+    _MAX_RESULTS = 1000
+    IE_NAME = u'screen.yahoo:search'
+    _SEARCH_KEY = 'yvsearch'
+
+    def _get_n_results(self, query, n):
+        """Get a specified number of results for a query"""
+
+        res = {
+            '_type': 'playlist',
+            'id': query,
+            'entries': []
+        }
+        for pagenum in itertools.count(0): 
+            result_url = u'http://video.search.yahoo.com/search/?p=%s&fr=screen&o=js&gs=0&b=%d' % (compat_urllib_parse.quote_plus(query), pagenum * 30)
+            webpage = self._download_webpage(result_url, query,
+                                             note='Downloading results page '+str(pagenum+1))
+            info = json.loads(webpage)
+            m = info[u'm']
+            results = info[u'results']
+
+            for (i, r) in enumerate(results):
+                if (pagenum * 30) +i >= n:
+                    break
+                mobj = re.search(r'(?P<url>screen\.yahoo\.com/.*?-\d*?\.html)"', r)
+                e = self.url_result('http://' + mobj.group('url'), 'Yahoo')
+                res['entries'].append(e)
+            if (pagenum * 30 +i >= n) or (m[u'last'] >= (m[u'total'] -1 )):
+                break
+
+        return res
diff --git a/youtube_dl/extractor/youjizz.py b/youtube_dl/extractor/youjizz.py
new file mode 100644
index 0000000..d9efac7
--- /dev/null
+++ b/youtube_dl/extractor/youjizz.py
@@ -0,0 +1,45 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class YouJizzIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?youjizz\.com/videos/(?P<videoid>[^.]+).html$'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+
+        video_id = mobj.group('videoid')
+
+        # Get webpage content
+        webpage = self._download_webpage(url, video_id)
+
+        # Get the video title
+        video_title = self._html_search_regex(r'<title>(?P<title>.*)</title>',
+            webpage, u'title').strip()
+
+        # Get the embed page
+        result = re.search(r'https?://www.youjizz.com/videos/embed/(?P<videoid>[0-9]+)', webpage)
+        if result is None:
+            raise ExtractorError(u'ERROR: unable to extract embed page')
+
+        embed_page_url = result.group(0).strip()
+        video_id = result.group('videoid')
+
+        webpage = self._download_webpage(embed_page_url, video_id)
+
+        # Get the video URL
+        video_url = self._search_regex(r'so.addVariable\("file",encodeURIComponent\("(?P<source>[^"]+)"\)\);',
+            webpage, u'video URL')
+
+        info = {'id': video_id,
+                'url': video_url,
+                'title': video_title,
+                'ext': 'flv',
+                'format': 'flv',
+                'player_url': embed_page_url}
+
+        return [info]
diff --git a/youtube_dl/extractor/youku.py b/youtube_dl/extractor/youku.py
new file mode 100644
index 0000000..ed43f42
--- /dev/null
+++ b/youtube_dl/extractor/youku.py
@@ -0,0 +1,104 @@
+import json
+import math
+import random
+import re
+import time
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+)
+
+
+class YoukuIE(InfoExtractor):
+    _VALID_URL =  r'(?:http://)?v\.youku\.com/v_show/id_(?P<ID>[A-Za-z0-9]+)\.html'
+
+    def _gen_sid(self):
+        nowTime = int(time.time() * 1000)
+        random1 = random.randint(1000,1998)
+        random2 = random.randint(1000,9999)
+
+        return "%d%d%d" %(nowTime,random1,random2)
+
+    def _get_file_ID_mix_string(self, seed):
+        mixed = []
+        source = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/\:._-1234567890")
+        seed = float(seed)
+        for i in range(len(source)):
+            seed  =  (seed * 211 + 30031 ) % 65536
+            index  =  math.floor(seed / 65536 * len(source) )
+            mixed.append(source[int(index)])
+            source.remove(source[int(index)])
+        #return ''.join(mixed)
+        return mixed
+
+    def _get_file_id(self, fileId, seed):
+        mixed = self._get_file_ID_mix_string(seed)
+        ids = fileId.split('*')
+        realId = []
+        for ch in ids:
+            if ch:
+                realId.append(mixed[int(ch)])
+        return ''.join(realId)
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group('ID')
+
+        info_url = 'http://v.youku.com/player/getPlayList/VideoIDS/' + video_id
+
+        jsondata = self._download_webpage(info_url, video_id)
+
+        self.report_extraction(video_id)
+        try:
+            config = json.loads(jsondata)
+
+            video_title =  config['data'][0]['title']
+            seed = config['data'][0]['seed']
+
+            format = self._downloader.params.get('format', None)
+            supported_format = list(config['data'][0]['streamfileids'].keys())
+
+            if format is None or format == 'best':
+                if 'hd2' in supported_format:
+                    format = 'hd2'
+                else:
+                    format = 'flv'
+                ext = u'flv'
+            elif format == 'worst':
+                format = 'mp4'
+                ext = u'mp4'
+            else:
+                format = 'flv'
+                ext = u'flv'
+
+
+            fileid = config['data'][0]['streamfileids'][format]
+            keys = [s['k'] for s in config['data'][0]['segs'][format]]
+        except (UnicodeDecodeError, ValueError, KeyError):
+            raise ExtractorError(u'Unable to extract info section')
+
+        files_info=[]
+        sid = self._gen_sid()
+        fileid = self._get_file_id(fileid, seed)
+
+        #column 8,9 of fileid represent the segment number
+        #fileid[7:9] should be changed
+        for index, key in enumerate(keys):
+
+            temp_fileid = '%s%02X%s' % (fileid[0:8], index, fileid[10:])
+            download_url = 'http://f.youku.com/player/getFlvPath/sid/%s_%02X/st/flv/fileid/%s?k=%s' % (sid, index, temp_fileid, key)
+
+            info = {
+                'id': '%s_part%02d' % (video_id, index),
+                'url': download_url,
+                'uploader': None,
+                'upload_date': None,
+                'title': video_title,
+                'ext': ext,
+            }
+            files_info.append(info)
+
+        return files_info
diff --git a/youtube_dl/extractor/youporn.py b/youtube_dl/extractor/youporn.py
new file mode 100644
index 0000000..5d8b7db
--- /dev/null
+++ b/youtube_dl/extractor/youporn.py
@@ -0,0 +1,117 @@
+import json
+import os
+import re
+import sys
+
+from .common import InfoExtractor
+from ..utils import (
+    compat_urllib_parse_urlparse,
+    compat_urllib_request,
+
+    ExtractorError,
+    unescapeHTML,
+    unified_strdate,
+)
+
+
+class YouPornIE(InfoExtractor):
+    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?youporn\.com/watch/(?P<videoid>[0-9]+)/(?P<title>[^/]+)'
+
+    def _print_formats(self, formats):
+        """Print all available formats"""
+        print(u'Available formats:')
+        print(u'ext\t\tformat')
+        print(u'---------------------------------')
+        for format in formats:
+            print(u'%s\t\t%s'  % (format['ext'], format['format']))
+
+    def _specific(self, req_format, formats):
+        for x in formats:
+            if x["format"] == req_format:
+                return x
+        return None
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        video_id = mobj.group('videoid')
+
+        req = compat_urllib_request.Request(url)
+        req.add_header('Cookie', 'age_verified=1')
+        webpage = self._download_webpage(req, video_id)
+
+        # Get JSON parameters
+        json_params = self._search_regex(r'var currentVideo = new Video\((.*)\);', webpage, u'JSON parameters')
+        try:
+            params = json.loads(json_params)
+        except:
+            raise ExtractorError(u'Invalid JSON')
+
+        self.report_extraction(video_id)
+        try:
+            video_title = params['title']
+            upload_date = unified_strdate(params['release_date_f'])
+            video_description = params['description']
+            video_uploader = params['submitted_by']
+            thumbnail = params['thumbnails'][0]['image']
+        except KeyError:
+            raise ExtractorError('Missing JSON parameter: ' + sys.exc_info()[1])
+
+        # Get all of the formats available
+        DOWNLOAD_LIST_RE = r'(?s)<ul class="downloadList">(?P<download_list>.*?)</ul>'
+        download_list_html = self._search_regex(DOWNLOAD_LIST_RE,
+            webpage, u'download list').strip()
+
+        # Get all of the links from the page
+        LINK_RE = r'(?s)<a href="(?P<url>[^"]+)">'
+        links = re.findall(LINK_RE, download_list_html)
+        if(len(links) == 0):
+            raise ExtractorError(u'ERROR: no known formats available for video')
+
+        self.to_screen(u'Links found: %d' % len(links))
+
+        formats = []
+        for link in links:
+
+            # A link looks like this:
+            # http://cdn1.download.youporn.phncdn.com/201210/31/8004515/480p_370k_8004515/YouPorn%20-%20Nubile%20Films%20The%20Pillow%20Fight.mp4?nvb=20121113051249&nva=20121114051249&ir=1200&sr=1200&hash=014b882080310e95fb6a0
+            # A path looks like this:
+            # /201210/31/8004515/480p_370k_8004515/YouPorn%20-%20Nubile%20Films%20The%20Pillow%20Fight.mp4
+            video_url = unescapeHTML( link )
+            path = compat_urllib_parse_urlparse( video_url ).path
+            extension = os.path.splitext( path )[1][1:]
+            format = path.split('/')[4].split('_')[:2]
+            # size = format[0]
+            # bitrate = format[1]
+            format = "-".join( format )
+            # title = u'%s-%s-%s' % (video_title, size, bitrate)
+
+            formats.append({
+                'id': video_id,
+                'url': video_url,
+                'uploader': video_uploader,
+                'upload_date': upload_date,
+                'title': video_title,
+                'ext': extension,
+                'format': format,
+                'thumbnail': thumbnail,
+                'description': video_description
+            })
+
+        if self._downloader.params.get('listformats', None):
+            self._print_formats(formats)
+            return
+
+        req_format = self._downloader.params.get('format', None)
+        self.to_screen(u'Format: %s' % req_format)
+
+        if req_format is None or req_format == 'best':
+            return [formats[0]]
+        elif req_format == 'worst':
+            return [formats[-1]]
+        elif req_format in ('-1', 'all'):
+            return formats
+        else:
+            format = self._specific( req_format, formats )
+            if format is None:
+                raise ExtractorError(u'Requested format not available')
+            return [format]
diff --git a/youtube_dl/extractor/youtube.py b/youtube_dl/extractor/youtube.py
new file mode 100644
index 0000000..fbe8d63
--- /dev/null
+++ b/youtube_dl/extractor/youtube.py
@@ -0,0 +1,795 @@
+# coding: utf-8
+
+import json
+import netrc
+import re
+import socket
+
+from .common import InfoExtractor, SearchInfoExtractor
+from ..utils import (
+    compat_http_client,
+    compat_parse_qs,
+    compat_urllib_error,
+    compat_urllib_parse,
+    compat_urllib_request,
+    compat_str,
+
+    clean_html,
+    get_element_by_id,
+    ExtractorError,
+    unescapeHTML,
+    unified_strdate,
+)
+
+
+class YoutubeIE(InfoExtractor):
+    """Information extractor for youtube.com."""
+
+    _VALID_URL = r"""^
+                     (
+                         (?:https?://)?                                       # http(s):// (optional)
+                         (?:youtu\.be/|(?:\w+\.)?youtube(?:-nocookie)?\.com/|
+                            tube\.majestyc\.net/)                             # the various hostnames, with wildcard subdomains
+                         (?:.*?\#/)?                                          # handle anchor (#/) redirect urls
+                         (?:                                                  # the various things that can precede the ID:
+                             (?:(?:v|embed|e)/)                               # v/ or embed/ or e/
+                             |(?:                                             # or the v= param in all its forms
+                                 (?:watch(?:_popup)?(?:\.php)?)?              # preceding watch(_popup|.php) or nothing (like /?v=xxxx)
+                                 (?:\?|\#!?)                                  # the params delimiter ? or # or #!
+                                 (?:.*?&)?                                    # any other preceding param (like /?s=tuff&v=xxxx)
+                                 v=
+                             )
+                         )?                                                   # optional -> youtube.com/xxxx is OK
+                     )?                                                       # all until now is optional -> you can pass the naked ID
+                     ([0-9A-Za-z_-]+)                                         # here is it! the YouTube video ID
+                     (?(1).+)?                                                # if we found the ID, everything can follow
+                     $"""
+    _LANG_URL = r'https://www.youtube.com/?hl=en&persist_hl=1&gl=US&persist_gl=1&opt_out_ackd=1'
+    _LOGIN_URL = 'https://accounts.google.com/ServiceLogin'
+    _AGE_URL = 'http://www.youtube.com/verify_age?next_url=/&gl=US&hl=en'
+    _NEXT_URL_RE = r'[\?&]next_url=([^&]+)'
+    _NETRC_MACHINE = 'youtube'
+    # Listed in order of quality
+    _available_formats = ['38', '37', '46', '22', '45', '35', '44', '34', '18', '43', '6', '5', '17', '13']
+    _available_formats_prefer_free = ['38', '46', '37', '45', '22', '44', '35', '43', '34', '18', '6', '5', '17', '13']
+    _video_extensions = {
+        '13': '3gp',
+        '17': 'mp4',
+        '18': 'mp4',
+        '22': 'mp4',
+        '37': 'mp4',
+        '38': 'video', # You actually don't know if this will be MOV, AVI or whatever
+        '43': 'webm',
+        '44': 'webm',
+        '45': 'webm',
+        '46': 'webm',
+    }
+    _video_dimensions = {
+        '5': '240x400',
+        '6': '???',
+        '13': '???',
+        '17': '144x176',
+        '18': '360x640',
+        '22': '720x1280',
+        '34': '360x640',
+        '35': '480x854',
+        '37': '1080x1920',
+        '38': '3072x4096',
+        '43': '360x640',
+        '44': '480x854',
+        '45': '720x1280',
+        '46': '1080x1920',
+    }
+    IE_NAME = u'youtube'
+
+    @classmethod
+    def suitable(cls, url):
+        """Receives a URL and returns True if suitable for this IE."""
+        if YoutubePlaylistIE.suitable(url): return False
+        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
+
+    def report_lang(self):
+        """Report attempt to set language."""
+        self.to_screen(u'Setting language')
+
+    def report_login(self):
+        """Report attempt to log in."""
+        self.to_screen(u'Logging in')
+
+    def report_video_webpage_download(self, video_id):
+        """Report attempt to download video webpage."""
+        self.to_screen(u'%s: Downloading video webpage' % video_id)
+
+    def report_video_info_webpage_download(self, video_id):
+        """Report attempt to download video info webpage."""
+        self.to_screen(u'%s: Downloading video info webpage' % video_id)
+
+    def report_video_subtitles_download(self, video_id):
+        """Report attempt to download video info webpage."""
+        self.to_screen(u'%s: Checking available subtitles' % video_id)
+
+    def report_video_subtitles_request(self, video_id, sub_lang, format):
+        """Report attempt to download video info webpage."""
+        self.to_screen(u'%s: Downloading video subtitles for %s.%s' % (video_id, sub_lang, format))
+
+    def report_video_subtitles_available(self, video_id, sub_lang_list):
+        """Report available subtitles."""
+        sub_lang = ",".join(list(sub_lang_list.keys()))
+        self.to_screen(u'%s: Available subtitles for video: %s' % (video_id, sub_lang))
+
+    def report_information_extraction(self, video_id):
+        """Report attempt to extract video information."""
+        self.to_screen(u'%s: Extracting video information' % video_id)
+
+    def report_unavailable_format(self, video_id, format):
+        """Report extracted video URL."""
+        self.to_screen(u'%s: Format %s not available' % (video_id, format))
+
+    def report_rtmp_download(self):
+        """Indicate the download will use the RTMP protocol."""
+        self.to_screen(u'RTMP download detected')
+
+    @staticmethod
+    def _decrypt_signature(s):
+        """Decrypt the key the two subkeys must have a length of 43"""
+        (a,b) = s.split('.')
+        if len(a) != 43 or len(b) != 43:
+            raise ExtractorError(u'Unable to decrypt signature, subkeys lengths not valid')
+        b = ''.join([b[:8],a[0],b[9:18],b[-4],b[19:39], b[18]])[0:40]
+        a = a[-40:]
+        s_dec = '.'.join((a,b))[::-1]
+        return s_dec
+
+    def _get_available_subtitles(self, video_id):
+        self.report_video_subtitles_download(video_id)
+        request = compat_urllib_request.Request('http://video.google.com/timedtext?hl=en&type=list&v=%s' % video_id)
+        try:
+            sub_list = compat_urllib_request.urlopen(request).read().decode('utf-8')
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            return (u'unable to download video subtitles: %s' % compat_str(err), None)
+        sub_lang_list = re.findall(r'name="([^"]*)"[^>]+lang_code="([\w\-]+)"', sub_list)
+        sub_lang_list = dict((l[1], l[0]) for l in sub_lang_list)
+        if not sub_lang_list:
+            return (u'video doesn\'t have subtitles', None)
+        return sub_lang_list
+
+    def _list_available_subtitles(self, video_id):
+        sub_lang_list = self._get_available_subtitles(video_id)
+        self.report_video_subtitles_available(video_id, sub_lang_list)
+
+    def _request_subtitle(self, sub_lang, sub_name, video_id, format):
+        """
+        Return tuple:
+        (error_message, sub_lang, sub)
+        """
+        self.report_video_subtitles_request(video_id, sub_lang, format)
+        params = compat_urllib_parse.urlencode({
+            'lang': sub_lang,
+            'name': sub_name,
+            'v': video_id,
+            'fmt': format,
+        })
+        url = 'http://www.youtube.com/api/timedtext?' + params
+        try:
+            sub = compat_urllib_request.urlopen(url).read().decode('utf-8')
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            return (u'unable to download video subtitles: %s' % compat_str(err), None, None)
+        if not sub:
+            return (u'Did not fetch video subtitles', None, None)
+        return (None, sub_lang, sub)
+
+    def _request_automatic_caption(self, video_id, webpage):
+        """We need the webpage for getting the captions url, pass it as an
+           argument to speed up the process."""
+        sub_lang = self._downloader.params.get('subtitleslang') or 'en'
+        sub_format = self._downloader.params.get('subtitlesformat')
+        self.to_screen(u'%s: Looking for automatic captions' % video_id)
+        mobj = re.search(r';ytplayer.config = ({.*?});', webpage)
+        err_msg = u'Couldn\'t find automatic captions for "%s"' % sub_lang
+        if mobj is None:
+            return [(err_msg, None, None)]
+        player_config = json.loads(mobj.group(1))
+        try:
+            args = player_config[u'args']
+            caption_url = args[u'ttsurl']
+            timestamp = args[u'timestamp']
+            params = compat_urllib_parse.urlencode({
+                'lang': 'en',
+                'tlang': sub_lang,
+                'fmt': sub_format,
+                'ts': timestamp,
+                'kind': 'asr',
+            })
+            subtitles_url = caption_url + '&' + params
+            sub = self._download_webpage(subtitles_url, video_id, u'Downloading automatic captions')
+            return [(None, sub_lang, sub)]
+        except KeyError:
+            return [(err_msg, None, None)]
+
+    def _extract_subtitle(self, video_id):
+        """
+        Return a list with a tuple:
+        [(error_message, sub_lang, sub)]
+        """
+        sub_lang_list = self._get_available_subtitles(video_id)
+        sub_format = self._downloader.params.get('subtitlesformat')
+        if  isinstance(sub_lang_list,tuple): #There was some error, it didn't get the available subtitles
+            return [(sub_lang_list[0], None, None)]
+        if self._downloader.params.get('subtitleslang', False):
+            sub_lang = self._downloader.params.get('subtitleslang')
+        elif 'en' in sub_lang_list:
+            sub_lang = 'en'
+        else:
+            sub_lang = list(sub_lang_list.keys())[0]
+        if not sub_lang in sub_lang_list:
+            return [(u'no closed captions found in the specified language "%s"' % sub_lang, None, None)]
+
+        subtitle = self._request_subtitle(sub_lang, sub_lang_list[sub_lang].encode('utf-8'), video_id, sub_format)
+        return [subtitle]
+
+    def _extract_all_subtitles(self, video_id):
+        sub_lang_list = self._get_available_subtitles(video_id)
+        sub_format = self._downloader.params.get('subtitlesformat')
+        if  isinstance(sub_lang_list,tuple): #There was some error, it didn't get the available subtitles
+            return [(sub_lang_list[0], None, None)]
+        subtitles = []
+        for sub_lang in sub_lang_list:
+            subtitle = self._request_subtitle(sub_lang, sub_lang_list[sub_lang].encode('utf-8'), video_id, sub_format)
+            subtitles.append(subtitle)
+        return subtitles
+
+    def _print_formats(self, formats):
+        print('Available formats:')
+        for x in formats:
+            print('%s\t:\t%s\t[%s]' %(x, self._video_extensions.get(x, 'flv'), self._video_dimensions.get(x, '???')))
+
+    def _real_initialize(self):
+        if self._downloader is None:
+            return
+
+        username = None
+        password = None
+        downloader_params = self._downloader.params
+
+        # Attempt to use provided username and password or .netrc data
+        if downloader_params.get('username', None) is not None:
+            username = downloader_params['username']
+            password = downloader_params['password']
+        elif downloader_params.get('usenetrc', False):
+            try:
+                info = netrc.netrc().authenticators(self._NETRC_MACHINE)
+                if info is not None:
+                    username = info[0]
+                    password = info[2]
+                else:
+                    raise netrc.NetrcParseError('No authenticators for %s' % self._NETRC_MACHINE)
+            except (IOError, netrc.NetrcParseError) as err:
+                self._downloader.report_warning(u'parsing .netrc: %s' % compat_str(err))
+                return
+
+        # Set language
+        request = compat_urllib_request.Request(self._LANG_URL)
+        try:
+            self.report_lang()
+            compat_urllib_request.urlopen(request).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            self._downloader.report_warning(u'unable to set language: %s' % compat_str(err))
+            return
+
+        # No authentication to be performed
+        if username is None:
+            return
+
+        request = compat_urllib_request.Request(self._LOGIN_URL)
+        try:
+            login_page = compat_urllib_request.urlopen(request).read().decode('utf-8')
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            self._downloader.report_warning(u'unable to fetch login page: %s' % compat_str(err))
+            return
+
+        galx = None
+        dsh = None
+        match = re.search(re.compile(r'<input.+?name="GALX".+?value="(.+?)"', re.DOTALL), login_page)
+        if match:
+          galx = match.group(1)
+
+        match = re.search(re.compile(r'<input.+?name="dsh".+?value="(.+?)"', re.DOTALL), login_page)
+        if match:
+          dsh = match.group(1)
+
+        # Log in
+        login_form_strs = {
+                u'continue': u'https://www.youtube.com/signin?action_handle_signin=true&feature=sign_in_button&hl=en_US&nomobiletemp=1',
+                u'Email': username,
+                u'GALX': galx,
+                u'Passwd': password,
+                u'PersistentCookie': u'yes',
+                u'_utf8': u'霱',
+                u'bgresponse': u'js_disabled',
+                u'checkConnection': u'',
+                u'checkedDomains': u'youtube',
+                u'dnConn': u'',
+                u'dsh': dsh,
+                u'pstMsg': u'0',
+                u'rmShown': u'1',
+                u'secTok': u'',
+                u'signIn': u'Sign in',
+                u'timeStmp': u'',
+                u'service': u'youtube',
+                u'uilel': u'3',
+                u'hl': u'en_US',
+        }
+        # Convert to UTF-8 *before* urlencode because Python 2.x's urlencode
+        # chokes on unicode
+        login_form = dict((k.encode('utf-8'), v.encode('utf-8')) for k,v in login_form_strs.items())
+        login_data = compat_urllib_parse.urlencode(login_form).encode('ascii')
+        request = compat_urllib_request.Request(self._LOGIN_URL, login_data)
+        try:
+            self.report_login()
+            login_results = compat_urllib_request.urlopen(request).read().decode('utf-8')
+            if re.search(r'(?i)<form[^>]* id="gaia_loginform"', login_results) is not None:
+                self._downloader.report_warning(u'unable to log in: bad username or password')
+                return
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            self._downloader.report_warning(u'unable to log in: %s' % compat_str(err))
+            return
+
+        # Confirm age
+        age_form = {
+                'next_url':     '/',
+                'action_confirm':   'Confirm',
+                }
+        request = compat_urllib_request.Request(self._AGE_URL, compat_urllib_parse.urlencode(age_form))
+        try:
+            self.report_age_confirmation()
+            compat_urllib_request.urlopen(request).read().decode('utf-8')
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to confirm age: %s' % compat_str(err))
+
+    def _extract_id(self, url):
+        mobj = re.match(self._VALID_URL, url, re.VERBOSE)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group(2)
+        return video_id
+
+    def _real_extract(self, url):
+        # Extract original video URL from URL with redirection, like age verification, using next_url parameter
+        mobj = re.search(self._NEXT_URL_RE, url)
+        if mobj:
+            url = 'https://www.youtube.com/' + compat_urllib_parse.unquote(mobj.group(1)).lstrip('/')
+        video_id = self._extract_id(url)
+
+        # Get video webpage
+        self.report_video_webpage_download(video_id)
+        url = 'https://www.youtube.com/watch?v=%s&gl=US&hl=en&has_verified=1' % video_id
+        request = compat_urllib_request.Request(url)
+        try:
+            video_webpage_bytes = compat_urllib_request.urlopen(request).read()
+        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+            raise ExtractorError(u'Unable to download video webpage: %s' % compat_str(err))
+
+        video_webpage = video_webpage_bytes.decode('utf-8', 'ignore')
+
+        # Attempt to extract SWF player URL
+        mobj = re.search(r'swfConfig.*?"(http:\\/\\/.*?watch.*?-.*?\.swf)"', video_webpage)
+        if mobj is not None:
+            player_url = re.sub(r'\\(.)', r'\1', mobj.group(1))
+        else:
+            player_url = None
+
+        # Get video info
+        self.report_video_info_webpage_download(video_id)
+        for el_type in ['&el=embedded', '&el=detailpage', '&el=vevo', '']:
+            video_info_url = ('https://www.youtube.com/get_video_info?&video_id=%s%s&ps=default&eurl=&gl=US&hl=en'
+                    % (video_id, el_type))
+            video_info_webpage = self._download_webpage(video_info_url, video_id,
+                                    note=False,
+                                    errnote='unable to download video info webpage')
+            video_info = compat_parse_qs(video_info_webpage)
+            if 'token' in video_info:
+                break
+        if 'token' not in video_info:
+            if 'reason' in video_info:
+                raise ExtractorError(u'YouTube said: %s' % video_info['reason'][0])
+            else:
+                raise ExtractorError(u'"token" parameter not in video info for unknown reason')
+
+        # Check for "rental" videos
+        if 'ypc_video_rental_bar_text' in video_info and 'author' not in video_info:
+            raise ExtractorError(u'"rental" videos not supported')
+
+        # Start extracting information
+        self.report_information_extraction(video_id)
+
+        # uploader
+        if 'author' not in video_info:
+            raise ExtractorError(u'Unable to extract uploader name')
+        video_uploader = compat_urllib_parse.unquote_plus(video_info['author'][0])
+
+        # uploader_id
+        video_uploader_id = None
+        mobj = re.search(r'<link itemprop="url" href="http://www.youtube.com/(?:user|channel)/([^"]+)">', video_webpage)
+        if mobj is not None:
+            video_uploader_id = mobj.group(1)
+        else:
+            self._downloader.report_warning(u'unable to extract uploader nickname')
+
+        # title
+        if 'title' not in video_info:
+            raise ExtractorError(u'Unable to extract video title')
+        video_title = compat_urllib_parse.unquote_plus(video_info['title'][0])
+
+        # thumbnail image
+        if 'thumbnail_url' not in video_info:
+            self._downloader.report_warning(u'unable to extract video thumbnail')
+            video_thumbnail = ''
+        else:   # don't panic if we can't find it
+            video_thumbnail = compat_urllib_parse.unquote_plus(video_info['thumbnail_url'][0])
+
+        # upload date
+        upload_date = None
+        mobj = re.search(r'id="eow-date.*?>(.*?)</span>', video_webpage, re.DOTALL)
+        if mobj is not None:
+            upload_date = ' '.join(re.sub(r'[/,-]', r' ', mobj.group(1)).split())
+            upload_date = unified_strdate(upload_date)
+
+        # description
+        video_description = get_element_by_id("eow-description", video_webpage)
+        if video_description:
+            video_description = clean_html(video_description)
+        else:
+            fd_mobj = re.search(r'<meta name="description" content="([^"]+)"', video_webpage)
+            if fd_mobj:
+                video_description = unescapeHTML(fd_mobj.group(1))
+            else:
+                video_description = u''
+
+        # subtitles
+        video_subtitles = None
+
+        if self._downloader.params.get('writesubtitles', False):
+            video_subtitles = self._extract_subtitle(video_id)
+            if video_subtitles:
+                (sub_error, sub_lang, sub) = video_subtitles[0]
+                if sub_error:
+                    # We try with the automatic captions
+                    video_subtitles = self._request_automatic_caption(video_id, video_webpage)
+                    (sub_error_auto, sub_lang, sub) = video_subtitles[0]
+                    if sub is not None:
+                        pass
+                    else:
+                        # We report the original error
+                        self._downloader.report_warning(sub_error)
+
+        if self._downloader.params.get('allsubtitles', False):
+            video_subtitles = self._extract_all_subtitles(video_id)
+            for video_subtitle in video_subtitles:
+                (sub_error, sub_lang, sub) = video_subtitle
+                if sub_error:
+                    self._downloader.report_warning(sub_error)
+
+        if self._downloader.params.get('listsubtitles', False):
+            self._list_available_subtitles(video_id)
+            return
+
+        if 'length_seconds' not in video_info:
+            self._downloader.report_warning(u'unable to extract video duration')
+            video_duration = ''
+        else:
+            video_duration = compat_urllib_parse.unquote_plus(video_info['length_seconds'][0])
+
+        # Decide which formats to download
+        req_format = self._downloader.params.get('format', None)
+
+        try:
+            mobj = re.search(r';ytplayer.config = ({.*?});', video_webpage)
+            info = json.loads(mobj.group(1))
+            args = info['args']
+            if args.get('ptk','') == 'vevo' or 'dashmpd':
+                # Vevo videos with encrypted signatures
+                self.to_screen(u'%s: Vevo video detected.' % video_id)
+                video_info['url_encoded_fmt_stream_map'] = [args['url_encoded_fmt_stream_map']]
+        except ValueError:
+            pass
+
+        if 'conn' in video_info and video_info['conn'][0].startswith('rtmp'):
+            self.report_rtmp_download()
+            video_url_list = [(None, video_info['conn'][0])]
+        elif 'url_encoded_fmt_stream_map' in video_info and len(video_info['url_encoded_fmt_stream_map']) >= 1:
+            url_map = {}
+            for url_data_str in video_info['url_encoded_fmt_stream_map'][0].split(','):
+                url_data = compat_parse_qs(url_data_str)
+                if 'itag' in url_data and 'url' in url_data:
+                    url = url_data['url'][0]
+                    if 'sig' in url_data:
+                        url += '&signature=' + url_data['sig'][0]
+                    elif 's' in url_data:
+                        signature = self._decrypt_signature(url_data['s'][0])
+                        url += '&signature=' + signature
+                    if 'ratebypass' not in url:
+                        url += '&ratebypass=yes'
+                    url_map[url_data['itag'][0]] = url
+
+            format_limit = self._downloader.params.get('format_limit', None)
+            available_formats = self._available_formats_prefer_free if self._downloader.params.get('prefer_free_formats', False) else self._available_formats
+            if format_limit is not None and format_limit in available_formats:
+                format_list = available_formats[available_formats.index(format_limit):]
+            else:
+                format_list = available_formats
+            existing_formats = [x for x in format_list if x in url_map]
+            if len(existing_formats) == 0:
+                raise ExtractorError(u'no known formats available for video')
+            if self._downloader.params.get('listformats', None):
+                self._print_formats(existing_formats)
+                return
+            if req_format is None or req_format == 'best':
+                video_url_list = [(existing_formats[0], url_map[existing_formats[0]])] # Best quality
+            elif req_format == 'worst':
+                video_url_list = [(existing_formats[len(existing_formats)-1], url_map[existing_formats[len(existing_formats)-1]])] # worst quality
+            elif req_format in ('-1', 'all'):
+                video_url_list = [(f, url_map[f]) for f in existing_formats] # All formats
+            else:
+                # Specific formats. We pick the first in a slash-delimeted sequence.
+                # For example, if '1/2/3/4' is requested and '2' and '4' are available, we pick '2'.
+                req_formats = req_format.split('/')
+                video_url_list = None
+                for rf in req_formats:
+                    if rf in url_map:
+                        video_url_list = [(rf, url_map[rf])]
+                        break
+                if video_url_list is None:
+                    raise ExtractorError(u'requested format not available')
+        else:
+            raise ExtractorError(u'no conn or url_encoded_fmt_stream_map information found in video info')
+
+        results = []
+        for format_param, video_real_url in video_url_list:
+            # Extension
+            video_extension = self._video_extensions.get(format_param, 'flv')
+
+            video_format = '{0} - {1}'.format(format_param if format_param else video_extension,
+                                              self._video_dimensions.get(format_param, '???'))
+
+            results.append({
+                'id':       video_id,
+                'url':      video_real_url,
+                'uploader': video_uploader,
+                'uploader_id': video_uploader_id,
+                'upload_date':  upload_date,
+                'title':    video_title,
+                'ext':      video_extension,
+                'format':   video_format,
+                'thumbnail':    video_thumbnail,
+                'description':  video_description,
+                'player_url':   player_url,
+                'subtitles':    video_subtitles,
+                'duration':     video_duration
+            })
+        return results
+
+class YoutubePlaylistIE(InfoExtractor):
+    """Information Extractor for YouTube playlists."""
+
+    _VALID_URL = r"""(?:
+                        (?:https?://)?
+                        (?:\w+\.)?
+                        youtube\.com/
+                        (?:
+                           (?:course|view_play_list|my_playlists|artist|playlist|watch)
+                           \? (?:.*?&)*? (?:p|a|list)=
+                        |  p/
+                        )
+                        ((?:PL|EC|UU)?[0-9A-Za-z-_]{10,})
+                        .*
+                     |
+                        ((?:PL|EC|UU)[0-9A-Za-z-_]{10,})
+                     )"""
+    _TEMPLATE_URL = 'https://gdata.youtube.com/feeds/api/playlists/%s?max-results=%i&start-index=%i&v=2&alt=json&safeSearch=none'
+    _MAX_RESULTS = 50
+    IE_NAME = u'youtube:playlist'
+
+    @classmethod
+    def suitable(cls, url):
+        """Receives a URL and returns True if suitable for this IE."""
+        return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
+
+    def _real_extract(self, url):
+        # Extract playlist id
+        mobj = re.match(self._VALID_URL, url, re.VERBOSE)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        # Download playlist videos from API
+        playlist_id = mobj.group(1) or mobj.group(2)
+        page_num = 1
+        videos = []
+
+        while True:
+            url = self._TEMPLATE_URL % (playlist_id, self._MAX_RESULTS, self._MAX_RESULTS * (page_num - 1) + 1)
+            page = self._download_webpage(url, playlist_id, u'Downloading page #%s' % page_num)
+
+            try:
+                response = json.loads(page)
+            except ValueError as err:
+                raise ExtractorError(u'Invalid JSON in API response: ' + compat_str(err))
+
+            if 'feed' not in response:
+                raise ExtractorError(u'Got a malformed response from YouTube API')
+            playlist_title = response['feed']['title']['$t']
+            if 'entry' not in response['feed']:
+                # Number of videos is a multiple of self._MAX_RESULTS
+                break
+
+            for entry in response['feed']['entry']:
+                index = entry['yt$position']['$t']
+                if 'media$group' in entry and 'media$player' in entry['media$group']:
+                    videos.append((index, entry['media$group']['media$player']['url']))
+
+            if len(response['feed']['entry']) < self._MAX_RESULTS:
+                break
+            page_num += 1
+
+        videos = [v[1] for v in sorted(videos)]
+
+        url_results = [self.url_result(url, 'Youtube') for url in videos]
+        return [self.playlist_result(url_results, playlist_id, playlist_title)]
+
+
+class YoutubeChannelIE(InfoExtractor):
+    """Information Extractor for YouTube channels."""
+
+    _VALID_URL = r"^(?:https?://)?(?:youtu\.be|(?:\w+\.)?youtube(?:-nocookie)?\.com)/channel/([0-9A-Za-z_-]+)"
+    _TEMPLATE_URL = 'http://www.youtube.com/channel/%s/videos?sort=da&flow=list&view=0&page=%s&gl=US&hl=en'
+    _MORE_PAGES_INDICATOR = 'yt-uix-load-more'
+    _MORE_PAGES_URL = 'http://www.youtube.com/channel_ajax?action_load_more_videos=1&flow=list&paging=%s&view=0&sort=da&channel_id=%s'
+    IE_NAME = u'youtube:channel'
+
+    def extract_videos_from_page(self, page):
+        ids_in_page = []
+        for mobj in re.finditer(r'href="/watch\?v=([0-9A-Za-z_-]+)&?', page):
+            if mobj.group(1) not in ids_in_page:
+                ids_in_page.append(mobj.group(1))
+        return ids_in_page
+
+    def _real_extract(self, url):
+        # Extract channel id
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        # Download channel page
+        channel_id = mobj.group(1)
+        video_ids = []
+        pagenum = 1
+
+        url = self._TEMPLATE_URL % (channel_id, pagenum)
+        page = self._download_webpage(url, channel_id,
+                                      u'Downloading page #%s' % pagenum)
+
+        # Extract video identifiers
+        ids_in_page = self.extract_videos_from_page(page)
+        video_ids.extend(ids_in_page)
+
+        # Download any subsequent channel pages using the json-based channel_ajax query
+        if self._MORE_PAGES_INDICATOR in page:
+            while True:
+                pagenum = pagenum + 1
+
+                url = self._MORE_PAGES_URL % (pagenum, channel_id)
+                page = self._download_webpage(url, channel_id,
+                                              u'Downloading page #%s' % pagenum)
+
+                page = json.loads(page)
+
+                ids_in_page = self.extract_videos_from_page(page['content_html'])
+                video_ids.extend(ids_in_page)
+
+                if self._MORE_PAGES_INDICATOR  not in page['load_more_widget_html']:
+                    break
+
+        self._downloader.to_screen(u'[youtube] Channel %s: Found %i videos' % (channel_id, len(video_ids)))
+
+        urls = ['http://www.youtube.com/watch?v=%s' % id for id in video_ids]
+        url_entries = [self.url_result(url, 'Youtube') for url in urls]
+        return [self.playlist_result(url_entries, channel_id)]
+
+
+class YoutubeUserIE(InfoExtractor):
+    """Information Extractor for YouTube users."""
+
+    _VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?youtube\.com/user/)|ytuser:)([A-Za-z0-9_-]+)'
+    _TEMPLATE_URL = 'http://gdata.youtube.com/feeds/api/users/%s'
+    _GDATA_PAGE_SIZE = 50
+    _GDATA_URL = 'http://gdata.youtube.com/feeds/api/users/%s/uploads?max-results=%d&start-index=%d'
+    _VIDEO_INDICATOR = r'/watch\?v=(.+?)[\<&]'
+    IE_NAME = u'youtube:user'
+
+    def _real_extract(self, url):
+        # Extract username
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+
+        username = mobj.group(1)
+
+        # Download video ids using YouTube Data API. Result size per
+        # query is limited (currently to 50 videos) so we need to query
+        # page by page until there are no video ids - it means we got
+        # all of them.
+
+        video_ids = []
+        pagenum = 0
+
+        while True:
+            start_index = pagenum * self._GDATA_PAGE_SIZE + 1
+
+            gdata_url = self._GDATA_URL % (username, self._GDATA_PAGE_SIZE, start_index)
+            page = self._download_webpage(gdata_url, username,
+                                          u'Downloading video ids from %d to %d' % (start_index, start_index + self._GDATA_PAGE_SIZE))
+
+            # Extract video identifiers
+            ids_in_page = []
+
+            for mobj in re.finditer(self._VIDEO_INDICATOR, page):
+                if mobj.group(1) not in ids_in_page:
+                    ids_in_page.append(mobj.group(1))
+
+            video_ids.extend(ids_in_page)
+
+            # A little optimization - if current page is not
+            # "full", ie. does not contain PAGE_SIZE video ids then
+            # we can assume that this page is the last one - there
+            # are no more ids on further pages - no need to query
+            # again.
+
+            if len(ids_in_page) < self._GDATA_PAGE_SIZE:
+                break
+
+            pagenum += 1
+
+        urls = ['http://www.youtube.com/watch?v=%s' % video_id for video_id in video_ids]
+        url_results = [self.url_result(url, 'Youtube') for url in urls]
+        return [self.playlist_result(url_results, playlist_title = username)]
+
+class YoutubeSearchIE(SearchInfoExtractor):
+    """Information Extractor for YouTube search queries."""
+    _API_URL = 'https://gdata.youtube.com/feeds/api/videos?q=%s&start-index=%i&max-results=50&v=2&alt=jsonc'
+    _MAX_RESULTS = 1000
+    IE_NAME = u'youtube:search'
+    _SEARCH_KEY = 'ytsearch'
+
+    def report_download_page(self, query, pagenum):
+        """Report attempt to download search page with given number."""
+        self._downloader.to_screen(u'[youtube] query "%s": Downloading page %s' % (query, pagenum))
+
+    def _get_n_results(self, query, n):
+        """Get a specified number of results for a query"""
+
+        video_ids = []
+        pagenum = 0
+        limit = n
+
+        while (50 * pagenum) < limit:
+            self.report_download_page(query, pagenum+1)
+            result_url = self._API_URL % (compat_urllib_parse.quote_plus(query), (50*pagenum)+1)
+            request = compat_urllib_request.Request(result_url)
+            try:
+                data = compat_urllib_request.urlopen(request).read().decode('utf-8')
+            except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
+                raise ExtractorError(u'Unable to download API page: %s' % compat_str(err))
+            api_response = json.loads(data)['data']
+
+            if not 'items' in api_response:
+                raise ExtractorError(u'[youtube] No video results')
+
+            new_ids = list(video['id'] for video in api_response['items'])
+            video_ids += new_ids
+
+            limit = min(n, api_response['totalItems'])
+            pagenum += 1
+
+        if len(video_ids) > n:
+            video_ids = video_ids[:n]
+        videos = [self.url_result('http://www.youtube.com/watch?v=%s' % id, 'Youtube') for id in video_ids]
+        return self.playlist_result(videos, query)
diff --git a/youtube_dl/extractor/zdf.py b/youtube_dl/extractor/zdf.py
new file mode 100644
index 0000000..418509c
--- /dev/null
+++ b/youtube_dl/extractor/zdf.py
@@ -0,0 +1,65 @@
+import re
+
+from .common import InfoExtractor
+from ..utils import (
+    ExtractorError,
+    unescapeHTML,
+)
+
+class ZDFIE(InfoExtractor):
+    _VALID_URL = r'^http://www\.zdf\.de\/ZDFmediathek\/(.*beitrag\/video\/)(?P<video_id>[^/\?]+)(?:\?.*)?'
+    _TITLE = r'<h1(?: class="beitragHeadline")?>(?P<title>.*)</h1>'
+    _MEDIA_STREAM = r'<a href="(?P<video_url>.+(?P<media_type>.streaming).+/zdf/(?P<quality>[^\/]+)/[^"]*)".+class="play".+>'
+    _MMS_STREAM = r'href="(?P<video_url>mms://[^"]*)"'
+    _RTSP_STREAM = r'(?P<video_url>rtsp://[^"]*.mp4)'
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            raise ExtractorError(u'Invalid URL: %s' % url)
+        video_id = mobj.group('video_id')
+
+        html = self._download_webpage(url, video_id)
+        streams = [m.groupdict() for m in re.finditer(self._MEDIA_STREAM, html)]
+        if streams is None:
+            raise ExtractorError(u'No media url found.')
+
+        # s['media_type'] == 'wstreaming' -> use 'Windows Media Player' and mms url
+        # s['media_type'] == 'hstreaming' -> use 'Quicktime' and rtsp url
+        # choose first/default media type and highest quality for now
+        for s in streams:        #find 300 - dsl1000mbit
+            if s['quality'] == '300' and s['media_type'] == 'wstreaming':
+                stream_=s
+                break
+        for s in streams:        #find veryhigh - dsl2000mbit
+            if s['quality'] == 'veryhigh' and s['media_type'] == 'wstreaming': # 'hstreaming' - rtsp is not working
+                stream_=s
+                break
+        if stream_ is None:
+            raise ExtractorError(u'No stream found.')
+
+        media_link = self._download_webpage(stream_['video_url'], video_id,'Get stream URL')
+
+        self.report_extraction(video_id)
+        mobj = re.search(self._TITLE, html)
+        if mobj is None:
+            raise ExtractorError(u'Cannot extract title')
+        title = unescapeHTML(mobj.group('title'))
+
+        mobj = re.search(self._MMS_STREAM, media_link)
+        if mobj is None:
+            mobj = re.search(self._RTSP_STREAM, media_link)
+            if mobj is None:
+                raise ExtractorError(u'Cannot extract mms:// or rtsp:// URL')
+        mms_url = mobj.group('video_url')
+
+        mobj = re.search('(.*)[.](?P<ext>[^.]+)', mms_url)
+        if mobj is None:
+            raise ExtractorError(u'Cannot extract extention')
+        ext = mobj.group('ext')
+
+        return [{'id': video_id,
+                 'url': mms_url,
+                 'title': title,
+                 'ext': ext
+                 }]
diff --git a/youtube_dl/version.py b/youtube_dl/version.py
index 7c6757e..c037c74 100644
--- a/youtube_dl/version.py
+++ b/youtube_dl/version.py
@@ -1,2 +1,2 @@
 
-__version__ = '2013.06.21'
+__version__ = '2013.06.26'
-- 
2.41.3