Added extractors for 3 porn sites
[youtube-dl] / youtube_dl / InfoExtractors.py
index d7295ae3fe0bafb87dd3a1ea88e431ffd31cd32f..72ad25ad316967a3e85e554fd650e6a76cd3a092 100755 (executable)
@@ -3,6 +3,7 @@
 
 from __future__ import absolute_import
 
+import base64
 import datetime
 import netrc
 import os
@@ -13,6 +14,10 @@ import email.utils
 import xml.etree.ElementTree
 import random
 import math
+import urllib
+import urllib2
+import httplib
+from urlparse import parse_qs, urlparse
 
 from .utils import *
 
@@ -105,6 +110,20 @@ class InfoExtractor(object):
     def IE_NAME(self):
         return type(self).__name__[:-2]
 
+    def _download_webpage(self, url_or_request, video_id, note=None, errnote=None):
+        if note is None:
+            note = u'Downloading video webpage'
+        self._downloader.to_screen(u'[%s] %s: %s' % (self.IE_NAME, video_id, note))
+        try:
+            urlh = compat_urllib_request.urlopen(url_or_request)
+            webpage_bytes = urlh.read()
+            return webpage_bytes.decode('utf-8', 'replace')
+        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])
+
+
 class YoutubeIE(InfoExtractor):
     """Information extractor for youtube.com."""
 
@@ -397,7 +416,7 @@ class YoutubeIE(InfoExtractor):
 
         # uploader_id
         video_uploader_id = None
-        mobj = re.search(r'<link itemprop="url" href="http://www.youtube.com/user/([^"]+)">', video_webpage)
+        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:
@@ -660,10 +679,6 @@ class DailymotionIE(InfoExtractor):
     def __init__(self, downloader=None):
         InfoExtractor.__init__(self, downloader)
 
-    def report_download_webpage(self, video_id):
-        """Report webpage download."""
-        self._downloader.to_screen(u'[dailymotion] %s: Downloading webpage' % video_id)
-
     def report_extraction(self, video_id):
         """Report information extraction."""
         self._downloader.to_screen(u'[dailymotion] %s: Extracting information' % video_id)
@@ -682,13 +697,7 @@ class DailymotionIE(InfoExtractor):
         # Retrieve video webpage to extract further information
         request = compat_urllib_request.Request(url)
         request.add_header('Cookie', 'family_filter=off')
-        try:
-            self.report_download_webpage(video_id)
-            webpage_bytes = compat_urllib_request.urlopen(request).read()
-            webpage = webpage_bytes.decode('utf-8')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable retrieve video webpage: %s' % compat_str(err))
-            return
+        webpage = self._download_webpage(request, video_id)
 
         # Extract URL, uploader and title from webpage
         self.report_extraction(video_id)
@@ -1910,10 +1919,6 @@ class DepositFilesIE(InfoExtractor):
     """Information extractor for depositfiles.com"""
 
     _VALID_URL = r'(?:http://)?(?:\w+\.)?depositfiles\.com/(?:../(?#locale))?files/(.+)'
-    IE_NAME = u'DepositFiles'
-
-    def __init__(self, downloader=None):
-        InfoExtractor.__init__(self, downloader)
 
     def report_download_webpage(self, file_id):
         """Report webpage download."""
@@ -2276,10 +2281,6 @@ class MyVideoIE(InfoExtractor):
     def __init__(self, downloader=None):
         InfoExtractor.__init__(self, downloader)
 
-    def report_download_webpage(self, video_id):
-        """Report webpage download."""
-        self._downloader.to_screen(u'[myvideo] %s: Downloading webpage' % video_id)
-
     def report_extraction(self, video_id):
         """Report information extraction."""
         self._downloader.to_screen(u'[myvideo] %s: Extracting information' % video_id)
@@ -2293,13 +2294,8 @@ class MyVideoIE(InfoExtractor):
         video_id = mobj.group(1)
 
         # Get video webpage
-        request = compat_urllib_request.Request('http://www.myvideo.de/watch/%s' % video_id)
-        try:
-            self.report_download_webpage(video_id)
-            webpage = compat_urllib_request.urlopen(request).read().decode('utf-8')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: Unable to retrieve video webpage: %s' % compat_str(err))
-            return
+        webpage_url = 'http://www.myvideo.de/watch/%s' % video_id
+        webpage = self._download_webpage(webpage_url, video_id)
 
         self.report_extraction(video_id)
         mobj = re.search(r'<link rel=\'image_src\' href=\'(http://is[0-9].myvideo\.de/de/movie[0-9]+/[a-f0-9]+)/thumbs/[^.]+\.jpg\' />',
@@ -2690,10 +2686,6 @@ class XVideosIE(InfoExtractor):
     _VALID_URL = r'^(?:https?://)?(?:www\.)?xvideos\.com/video([0-9]+)(?:.*)'
     IE_NAME = u'xvideos'
 
-    def report_webpage(self, video_id):
-        """Report information extraction."""
-        self._downloader.to_screen(u'[%s] %s: Downloading webpage' % (self.IE_NAME, video_id))
-
     def report_extraction(self, video_id):
         """Report information extraction."""
         self._downloader.to_screen(u'[%s] %s: Extracting information' % (self.IE_NAME, video_id))
@@ -2705,15 +2697,7 @@ class XVideosIE(InfoExtractor):
             return
         video_id = mobj.group(1)
 
-        self.report_webpage(video_id)
-
-        request = compat_urllib_request.Request(r'http://www.xvideos.com/video' + video_id)
-        try:
-            webpage_bytes = compat_urllib_request.urlopen(request).read()
-            webpage = webpage_bytes.decode('utf-8', 'replace')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable to download video webpage: %s' % compat_str(err))
-            return
+        webpage = self._download_webpage(url, video_id)
 
         self.report_extraction(video_id)
 
@@ -2812,7 +2796,7 @@ class SoundcloudIE(InfoExtractor):
             stream_json_bytes = compat_urllib_request.urlopen(request).read()
             stream_json = stream_json_bytes.decode('utf-8')
         except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable to download video webpage: %s' % compat_str(err))
+            self._downloader.trouble(u'ERROR: unable to download stream definitions: %s' % compat_str(err))
             return
 
         streams = json.loads(stream_json)
@@ -2831,13 +2815,7 @@ class SoundcloudIE(InfoExtractor):
 
 class InfoQIE(InfoExtractor):
     """Information extractor for infoq.com"""
-
     _VALID_URL = r'^(?:https?://)?(?:www\.)?infoq\.com/[^/]+/[^/]+$'
-    IE_NAME = u'infoq'
-
-    def report_webpage(self, video_id):
-        """Report information extraction."""
-        self._downloader.to_screen(u'[%s] %s: Downloading webpage' % (self.IE_NAME, video_id))
 
     def report_extraction(self, video_id):
         """Report information extraction."""
@@ -2849,38 +2827,29 @@ class InfoQIE(InfoExtractor):
             self._downloader.trouble(u'ERROR: invalid URL: %s' % url)
             return
 
-        self.report_webpage(url)
-
-        request = compat_urllib_request.Request(url)
-        try:
-            webpage = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable to download video webpage: %s' % compat_str(err))
-            return
-
+        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:
             self._downloader.trouble(u'ERROR: unable to extract video url')
             return
-        video_url = 'rtmpe://video.infoq.com/cfx/st/' + compat_urllib_parse.unquote(mobj.group(1).decode('base64'))
-
+        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
         mobj = re.search(r'contentTitle = "(.*?)";', webpage)
         if mobj is None:
             self._downloader.trouble(u'ERROR: unable to extract video title')
             return
-        video_title = mobj.group(1).decode('utf-8')
+        video_title = mobj.group(1)
 
         # Extract description
         video_description = u'No description available.'
         mobj = re.search(r'<meta name="description" content="(.*)"(?:\s*/)?>', webpage)
         if mobj is not None:
-            video_description = mobj.group(1).decode('utf-8')
+            video_description = mobj.group(1)
 
         video_filename = video_url.split('/')[-1]
         video_id, extension = video_filename.split('.')
@@ -3136,10 +3105,6 @@ class MTVIE(InfoExtractor):
     _VALID_URL = r'^(?P<proto>https?://)?(?:www\.)?mtv\.com/videos/[^/]+/(?P<videoid>[0-9]+)/[^/]+$'
     IE_NAME = u'mtv'
 
-    def report_webpage(self, video_id):
-        """Report information extraction."""
-        self._downloader.to_screen(u'[%s] %s: Downloading webpage' % (self.IE_NAME, video_id))
-
     def report_extraction(self, video_id):
         """Report information extraction."""
         self._downloader.to_screen(u'[%s] %s: Extracting information' % (self.IE_NAME, video_id))
@@ -3152,14 +3117,8 @@ class MTVIE(InfoExtractor):
         if not mobj.group('proto'):
             url = 'http://' + url
         video_id = mobj.group('videoid')
-        self.report_webpage(video_id)
 
-        request = compat_urllib_request.Request(url)
-        try:
-            webpage = compat_urllib_request.urlopen(request).read()
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable to download video webpage: %s' % compat_str(err))
-            return
+        webpage = self._download_webpage(url, video_id)
 
         mobj = re.search(r'<meta name="mtv_vt" content="([^"]+)"/>', webpage)
         if mobj is None:
@@ -3222,20 +3181,15 @@ class MTVIE(InfoExtractor):
 
 
 class YoukuIE(InfoExtractor):
-
     _VALID_URL =  r'(?:http://)?v\.youku\.com/v_show/id_(?P<ID>[A-Za-z0-9]+)\.html'
-    IE_NAME = u'Youku'
-
-    def __init__(self, downloader=None):
-        InfoExtractor.__init__(self, downloader)
 
     def report_download_webpage(self, file_id):
         """Report webpage download."""
-        self._downloader.to_screen(u'[Youku] %s: Downloading webpage' % file_id)
+        self._downloader.to_screen(u'[%s] %s: Downloading webpage' % (self.IE_NAME, file_id))
 
     def report_extraction(self, file_id):
         """Report information extraction."""
-        self._downloader.to_screen(u'[Youku] %s: Extracting information' % file_id)
+        self._downloader.to_screen(u'[%s] %s: Extracting information' % (self.IE_NAME, file_id))
 
     def _gen_sid(self):
         nowTime = int(time.time() * 1000)
@@ -3529,9 +3483,6 @@ class NBAIE(InfoExtractor):
     _VALID_URL = r'^(?:https?://)?(?:watch\.|www\.)?nba\.com/(?:nba/)?video(/[^?]*)(\?.*)?$'
     IE_NAME = u'nba'
 
-    def report_extraction(self, video_id):
-        self._downloader.to_screen(u'[%s] %s: Extracting information' % (self.IE_NAME, video_id))
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -3542,14 +3493,7 @@ class NBAIE(InfoExtractor):
         if video_id.endswith('/index.html'):
             video_id = video_id[:-len('/index.html')]
 
-        self.report_extraction(video_id)
-        try:
-            urlh = compat_urllib_request.urlopen(url)
-            webpage_bytes = urlh.read()
-            webpage = webpage_bytes.decode('utf-8', 'ignore')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable to download video info XML: %s' % compat_str(err))
-            return
+        webpage = self._download_webpage(url, video_id)
 
         video_url = u'http://ht-mobile.cdn.turner.com/nba/big' + video_id + '_nba_1280x720.mp4'
         def _findProp(rexp, default=None):
@@ -3652,10 +3596,6 @@ class JustinTVIE(InfoExtractor):
 
 class FunnyOrDieIE(InfoExtractor):
     _VALID_URL = r'^(?:https?://)?(?:www\.)?funnyordie\.com/videos/(?P<id>[0-9a-f]+)/.*$'
-    IE_NAME = u'FunnyOrDie'
-
-    def report_extraction(self, video_id):
-        self._downloader.to_screen(u'[%s] %s: Extracting information' % (self.IE_NAME, video_id))
 
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
@@ -3664,14 +3604,7 @@ class FunnyOrDieIE(InfoExtractor):
             return
 
         video_id = mobj.group('id')
-        self.report_extraction(video_id)
-        try:
-            urlh = compat_urllib_request.urlopen(url)
-            webpage_bytes = urlh.read()
-            webpage = webpage_bytes.decode('utf-8', 'ignore')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable to download webpage: %s' % compat_str(err))
-            return
+        webpage = self._download_webpage(url, video_id)
 
         m = re.search(r'<video[^>]*>\s*<source[^>]*>\s*<source src="(?P<url>[^"]+)"', webpage, re.DOTALL)
         if not m:
@@ -3701,9 +3634,6 @@ class FunnyOrDieIE(InfoExtractor):
 class TweetReelIE(InfoExtractor):
     _VALID_URL = r'^(?:https?://)?(?:www\.)?tweetreel\.com/[?](?P<id>[0-9a-z]+)$'
 
-    def report_extraction(self, video_id):
-        self._downloader.to_screen(u'[%s] %s: Extracting information' % (self.IE_NAME, video_id))
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -3711,14 +3641,7 @@ class TweetReelIE(InfoExtractor):
             return
 
         video_id = mobj.group('id')
-        self.report_extraction(video_id)
-        try:
-            urlh = compat_urllib_request.urlopen(url)
-            webpage_bytes = urlh.read()
-            webpage = webpage_bytes.decode('utf-8', 'ignore')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable to download webpage: %s' % compat_str(err))
-            return
+        webpage = self._download_webpage(url, video_id)
 
         m = re.search(r'<div id="left" status_id="([0-9]+)">', webpage)
         if not m:
@@ -3763,45 +3686,425 @@ class SteamIE(InfoExtractor):
                 (?P<gameID>\d+)/?
                 (?P<videoID>\d*)(?P<extra>\??) #For urltype == video we sometimes get the videoID
                 """
-    IE_NAME = u'Steam'
-    
+
     def suitable(self, url):
         """Receives a URL and returns True if suitable for this IE."""
         return re.match(self._VALID_URL, url, re.VERBOSE) is not None
-        
-    def report_download_video_page(self, game_id):
-        self._downloader.to_screen(u'[%s] %s: Downloading video page' % (self.IE_NAME, game_id))
-        
+
     def _real_extract(self, url):
         m = re.match(self._VALID_URL, url, re.VERBOSE)
         urlRE = r"'movie_(?P<videoID>\d+)': \{\s*FILENAME: \"(?P<videoURL>[\w:/\.\?=]+)\"(,\s*MOVIE_NAME: \"(?P<videoName>[\w:/\.\?=\+-]+)\")?\s*\},"
         gameID = m.group('gameID')
         videourl = 'http://store.steampowered.com/video/%s/' % gameID
-        try:
-            self.report_download_video_page(gameID)
-            urlh = compat_urllib_request.urlopen(videourl)
-            webpage_bytes = urlh.read()
-            webpage = webpage_bytes.decode('utf-8', 'ignore')
-        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
-            self._downloader.trouble(u'ERROR: unable to download webpage: %s' % compat_str(err))
-            return
+        webpage = self._download_webpage(videourl, gameID)
         mweb = re.finditer(urlRE, webpage)
-        namesRE = r'<span class=\"title\">(?P<videoName>[\w:/\.\?=\+\s-]+)</span>'
-        titles = list(re.finditer(namesRE, webpage))
+        namesRE = r'<span class="title">(?P<videoName>.+?)</span>'
+        titles = re.finditer(namesRE, webpage)
         videos = []
-        i = 0
-        for vid in mweb:
+        for vid,vtitle in zip(mweb,titles):
             video_id = vid.group('videoID')
-            title = titles[i].group('videoName')
-            video_url=vid.group('videoURL')
+            title = vtitle.group('videoName')
+            video_url = vid.group('videoURL')
             if not video_url:
                 self._downloader.trouble(u'ERROR: Cannot find video url for %s' % video_id)
-            i += 1
             info = {
                 'id':video_id,
                 'url':video_url,
                 'ext': 'flv',
-                'title': title
+                'title': unescapeHTML(title)
                   }
             videos.append(info)
         return videos
+        
+class UstreamIE(InfoExtractor):
+    _VALID_URL = r'http://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)
+        m = re.search(r'data-title="(?P<title>.+)"',webpage)
+        title = m.group('title')
+        m = re.search(r'<a class="state" data-content-type="channel" data-content-id="(?P<uploader>\d+)"',webpage)
+        uploader = m.group('uploader')
+        info = {
+                'id':video_id,
+                'url':video_url,
+                'ext': 'flv',
+                'title': title,
+                'uploader': uploader
+                  }
+        return [info]
+
+
+
+class YouPornIE(InfoExtractor):
+    """Information extractor for youporn.com."""
+
+    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?youporn\.com/watch/(?P<videoid>[0-9]+)/(?P<title>[^/]+)'
+    IE_NAME = u'youporn'
+    VIDEO_TITLE_RE = r'videoTitleArea">(?P<title>.*)</h1>'
+    VIDEO_DATE_RE = r'Date:</b>(?P<date>.*)</li>'
+    VIDEO_UPLOADER_RE = r'Submitted:</b>(?P<uploader>.*)</li>'
+    DOWNLOAD_LIST_RE = r'(?s)<ul class="downloadList">(?P<download_list>.*?)</ul>'
+    LINK_RE = r'(?s)<a href="(?P<url>[^"]+)">'
+
+    def __init__(self, downloader=None):
+        InfoExtractor.__init__(self, downloader)
+
+    def report_id(self, video_id):
+        """Report finding video ID"""
+        self._downloader.to_screen(u'[youporn] Video ID: %s' % video_id)
+
+    def report_webpage(self, url):
+        """Report downloading page"""
+        self._downloader.to_screen(u'[youporn] Downloaded page: %s' % url)
+
+    def report_title(self, video_title):
+        """Report dfinding title"""
+        self._downloader.to_screen(u'[youporn] Title: %s' % video_title)
+    
+    def report_uploader(self, uploader):
+        """Report dfinding title"""
+        self._downloader.to_screen(u'[youporn] Uploader: %s' % uploader)
+
+    def report_upload_date(self, video_date):
+        """Report finding date"""
+        self._downloader.to_screen(u'[youporn] Date: %s' % video_date)
+
+    def _print_formats(self, formats):
+        """Print all available formats"""
+        print '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:
+            self._downloader.trouble(u'ERROR: invalid URL: %s' % url)
+            return
+
+        video_id = mobj.group('videoid').decode('utf-8')
+        self.report_id(video_id)
+
+        # Get webpage content
+        try:
+            webpage = urllib2.urlopen(url).read()
+        except (urllib2.URLError, httplib.HTTPException, socket.error), err:
+            self._downloader.trouble(u'ERROR: unable to download video webpage: %s' % err)
+            return
+        self.report_webpage(url)
+
+        # Get the video title
+        result = re.search(self.VIDEO_TITLE_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract video title')
+            return
+        video_title = result.group('title').decode('utf-8').strip()
+        self.report_title(video_title)
+
+        # Get the video date
+        result = re.search(self.VIDEO_DATE_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract video date')
+            return
+        upload_date = result.group('date').decode('utf-8').strip()
+        self.report_upload_date(upload_date)
+
+        # Get the video uploader
+        result = re.search(self.VIDEO_UPLOADER_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract uploader')
+            return
+        video_uploader = result.group('uploader').decode('utf-8').strip()
+        video_uploader = clean_html( video_uploader )
+        self.report_uploader(video_uploader)
+
+        # Get all of the formats available
+        result = re.search(self.DOWNLOAD_LIST_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract download list')
+            return
+        download_list_html = result.group('download_list').decode('utf-8').strip()
+
+        # Get all of the links from the page
+        links = re.findall(self.LINK_RE, download_list_html)
+        if(len(links) == 0):
+            self._downloader.trouble(u'ERROR: no known formats available for video')
+            return
+        
+        self._downloader.to_screen(u'[youporn] 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.decode('utf-8') )
+            path = 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': title,
+                'ext': extension,
+                'format': format,
+                'thumbnail': None,
+                'description': None,
+                'player_url': None
+            })
+
+        if self._downloader.params.get('listformats', None):
+            self._print_formats(formats)
+            return
+
+        req_format = self._downloader.params.get('format', None)
+        #format_limit = self._downloader.params.get('format_limit', None)
+        self._downloader.to_screen(u'[youporn] 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:
+                self._downloader.trouble(u'ERROR: requested format not available')
+                return
+            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>.+))$'
+    IE_NAME = u'pornotube'
+    VIDEO_URL_RE = r'url: "(?P<url>http://video[0-9].pornotube.com/.+\.flv)",'
+    VIDEO_UPLOADED_RE = r'<div class="video_added_by">Added (?P<date>[0-9\/]+) by'
+
+
+    def __init__(self, downloader=None):
+        InfoExtractor.__init__(self, downloader)
+
+    def report_extract_entry(self, url):
+        """Report downloading extry"""
+        self._downloader.to_screen(u'[pornotube] Downloading entry: %s' % url.decode('utf-8'))
+
+    def report_date(self, upload_date):
+        """Report finding uploaded date"""
+        self._downloader.to_screen(u'[pornotube] Entry date: %s' % upload_date)
+
+    def report_webpage(self, url):
+        """Report downloading page"""
+        self._downloader.to_screen(u'[pornotube] Downloaded page: %s' % url)
+
+    def report_title(self, video_title):
+        """Report downloading extry"""
+        self._downloader.to_screen(u'[pornotube] Title: %s' % video_title.decode('utf-8'))
+
+    def _real_extract(self, url):
+        mobj = re.match(self._VALID_URL, url)
+        if mobj is None:
+            self._downloader.trouble(u'ERROR: invalid URL: %s' % url)
+            return
+
+        video_id = mobj.group('videoid').decode('utf-8')
+        video_title = mobj.group('title').decode('utf-8')
+        self.report_title(video_title);
+
+        # Get webpage content
+        try:
+            webpage = urllib2.urlopen(url).read()
+        except (urllib2.URLError, httplib.HTTPException, socket.error), err:
+            self._downloader.trouble(u'ERROR: unable to download video webpage: %s' % err)
+            return
+        self.report_webpage(url)
+
+        # Get the video URL
+        result = re.search(self.VIDEO_URL_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract video url')
+            return
+        video_url = urllib.unquote(result.group('url').decode('utf-8'))
+        self.report_extract_entry(video_url)
+
+        #Get the uploaded date
+        result = re.search(self.VIDEO_UPLOADED_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract video title')
+            return
+        upload_date = result.group('date').decode('utf-8')
+        self.report_date(upload_date);
+
+
+        info = {'id': video_id,
+                'url': video_url,
+                'uploader': None,
+                'upload_date': upload_date,
+                'title': video_title,
+                'ext': 'flv',
+                'format': 'flv',
+                'thumbnail': None,
+                'description': None,
+                'player_url': None}
+
+        return [info]
+
+
+
+class YouJizzIE(InfoExtractor):
+    """Information extractor for youjizz.com."""
+
+    _VALID_URL = r'^(?:https?://)?(?:\w+\.)?youjizz\.com/videos/([^.]+).html$'
+    IE_NAME = u'youjizz'
+    VIDEO_TITLE_RE = r'<title>(?P<title>.*)</title>'
+    EMBED_PAGE_RE = r'http://www.youjizz.com/videos/embed/(?P<videoid>[0-9]+)'
+    SOURCE_RE = r'so.addVariable\("file",encodeURIComponent\("(?P<source>[^"]+)"\)\);'
+
+    def __init__(self, downloader=None):
+        InfoExtractor.__init__(self, downloader)
+
+    def report_extract_entry(self, url):
+        """Report downloading extry"""
+        self._downloader.to_screen(u'[youjizz] Downloading entry: %s' % url.decode('utf-8'))
+
+    def report_webpage(self, url):
+        """Report downloading page"""
+        self._downloader.to_screen(u'[youjizz] Downloaded page: %s' % url)
+
+    def report_title(self, video_title):
+        """Report downloading extry"""
+        self._downloader.to_screen(u'[youjizz] Title: %s' % video_title.decode('utf-8'))
+
+    def report_embed_page(self, embed_page):
+        """Report downloading extry"""
+        self._downloader.to_screen(u'[youjizz] Embed Page: %s' % embed_page.decode('utf-8'))
+
+    def _real_extract(self, url):
+        # Get webpage content
+        try:
+            webpage = urllib2.urlopen(url).read()
+        except (urllib2.URLError, httplib.HTTPException, socket.error), err:
+            self._downloader.trouble(u'ERROR: unable to download video webpage: %s' % err)
+            return
+        self.report_webpage(url)
+
+        # Get the video title
+        result = re.search(self.VIDEO_TITLE_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract video title')
+            return
+        video_title = result.group('title').decode('utf-8').strip()
+        self.report_title(video_title)
+
+        # Get the embed page
+        result = re.search(self.EMBED_PAGE_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract embed page')
+            return
+
+        embed_page_url = result.group(0).decode('utf-8').strip()
+        video_id = result.group('videoid').decode('utf-8')
+        self.report_embed_page(embed_page_url)
+    
+        try:
+            webpage = urllib2.urlopen(embed_page_url).read()
+        except (urllib2.URLError, httplib.HTTPException, socket.error), err:
+            self._downloader.trouble(u'ERROR: unable to download video embed page: %s' % err)
+            return
+        
+        # Get the video URL
+        result = re.search(self.SOURCE_RE, webpage)
+        if result is None:
+            self._downloader.trouble(u'ERROR: unable to extract video url')
+            return
+        video_url = result.group('source').decode('utf-8')
+        self.report_extract_entry(video_url)
+
+        info = {'id': video_id,
+                'url': video_url,
+                'uploader': None,
+                'upload_date': None,
+                'title': video_title,
+                'ext': 'flv',
+                'format': 'flv',
+                'thumbnail': None,
+                'description': None,
+                'player_url': embed_page_url}
+
+        return [info]
+
+
+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(),
+        BlipTVUserIE(),
+        BlipTVIE(),
+        VimeoIE(),
+        MyVideoIE(),
+        ComedyCentralIE(),
+        EscapistIE(),
+        CollegeHumorIE(),
+        XVideosIE(),
+        SoundcloudIE(),
+        InfoQIE(),
+        MixcloudIE(),
+        StanfordOpenClassroomIE(),
+        MTVIE(),
+        YoukuIE(),
+        XNXXIE(),
+        YouJizzIE(),
+        PornotubeIE(),
+        YouPornIE(),
+        GooglePlusIE(),
+        ArteTvIE(),
+        NBAIE(),
+        JustinTVIE(),
+        FunnyOrDieIE(),
+        TweetReelIE(),
+        SteamIE(),
+        UstreamIE(),
+        GenericIE()
+    ]
+
+