TumblrIE
[youtube-dl] / youtube_dl / InfoExtractors.py
index d444e21d9c9acf32706b11c5be773ce6f6a60180..6a6545c9b578fba948962542d602bc5352b86840 100755 (executable)
@@ -148,6 +148,14 @@ class InfoExtractor(object):
         """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_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):
@@ -246,10 +254,6 @@ class YoutubeIE(InfoExtractor):
         """Report attempt to log in."""
         self.to_screen(u'Logging in')
 
-    def report_age_confirmation(self):
-        """Report attempt to confirm age."""
-        self.to_screen(u'Confirming age')
-
     def report_video_webpage_download(self, video_id):
         """Report attempt to download video webpage."""
         self.to_screen(u'%s: Downloading video webpage' % video_id)
@@ -618,8 +622,7 @@ class YoutubeIE(InfoExtractor):
                 format_list = available_formats
             existing_formats = [x for x in format_list if x in url_map]
             if len(existing_formats) == 0:
-                self._downloader.report_error(u'no known formats available for video')
-                return
+                raise ExtractorError(u'no known formats available for video')
             if self._downloader.params.get('listformats', None):
                 self._print_formats(existing_formats)
                 return
@@ -639,11 +642,9 @@ class YoutubeIE(InfoExtractor):
                         video_url_list = [(rf, url_map[rf])]
                         break
                 if video_url_list is None:
-                    self._downloader.report_error(u'requested format not available')
-                    return
+                    raise ExtractorError(u'requested format not available')
         else:
-            self._downloader.report_error(u'no conn or url_encoded_fmt_stream_map information found in video info')
-            return
+            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:
@@ -686,18 +687,10 @@ class MetacafeIE(InfoExtractor):
         """Report disclaimer retrieval."""
         self.to_screen(u'Retrieving disclaimer')
 
-    def report_age_confirmation(self):
-        """Report attempt to confirm age."""
-        self.to_screen(u'Confirming age')
-
     def report_download_webpage(self, video_id):
         """Report webpage download."""
         self.to_screen(u'%s: Downloading webpage' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_initialize(self):
         # Retrieve disclaimer
         request = compat_urllib_request.Request(self._DISCLAIMER)
@@ -801,10 +794,6 @@ class DailymotionIE(InfoExtractor):
     def __init__(self, downloader=None):
         InfoExtractor.__init__(self, downloader)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url):
         # Extract id and simplified title from URL
         mobj = re.match(self._VALID_URL, url)
@@ -893,10 +882,6 @@ class PhotobucketIE(InfoExtractor):
         """Report webpage download."""
         self.to_screen(u'%s: Downloading webpage' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url):
         # Extract id from URL
         mobj = re.match(self._VALID_URL, url)
@@ -962,10 +947,6 @@ class YahooIE(InfoExtractor):
         """Report webpage download."""
         self.to_screen(u'%s: Downloading webpage' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url, new_video=True):
         # Extract ID from URL
         mobj = re.match(self._VALID_URL, url)
@@ -1102,10 +1083,6 @@ class VimeoIE(InfoExtractor):
         """Report webpage download."""
         self.to_screen(u'%s: Downloading webpage' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url, new_video=True):
         # Extract ID from URL
         mobj = re.match(self._VALID_URL, url)
@@ -1223,10 +1200,6 @@ class ArteTvIE(InfoExtractor):
         """Report webpage download."""
         self.to_screen(u'%s: Downloading webpage' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def fetch_webpage(self, url):
         request = compat_urllib_request.Request(url)
         try:
@@ -1359,10 +1332,6 @@ class GenericIE(InfoExtractor):
             self._downloader.report_warning(u'Falling back on generic information extractor.')
         self.to_screen(u'%s: Downloading webpage' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def report_following_redirect(self, new_url):
         """Report information extraction."""
         self._downloader.to_screen(u'[redirect] Following redirect to %s' % new_url)
@@ -2051,10 +2020,6 @@ class DepositFilesIE(InfoExtractor):
         """Report webpage download."""
         self.to_screen(u'%s: Downloading webpage' % file_id)
 
-    def report_extraction(self, file_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % file_id)
-
     def _real_extract(self, url):
         file_id = url.split('/')[-1]
         # Rebuild url in english locale
@@ -2208,10 +2173,6 @@ class BlipTVIE(InfoExtractor):
     _URL_EXT = r'^.*\.([a-z0-9]+)$'
     IE_NAME = u'blip.tv'
 
-    def report_extraction(self, file_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % file_id)
-
     def report_direct_download(self, title):
         """Report information extraction."""
         self.to_screen(u'%s: Direct download detected' % title)
@@ -2312,10 +2273,6 @@ class MyVideoIE(InfoExtractor):
     def __init__(self, downloader=None):
         InfoExtractor.__init__(self, downloader)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self,url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -2393,9 +2350,6 @@ class ComedyCentralIE(InfoExtractor):
         """Receives a URL and returns True if suitable for this IE."""
         return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
 
-    def report_extraction(self, episode_id):
-        self.to_screen(u'%s: Extracting information' % episode_id)
-
     def report_config_download(self, episode_id, media_id):
         self.to_screen(u'%s: Downloading configuration for %s' % (episode_id, media_id))
 
@@ -2554,9 +2508,6 @@ class EscapistIE(InfoExtractor):
     _VALID_URL = r'^(https?://)?(www\.)?escapistmagazine\.com/videos/view/(?P<showname>[^/]+)/(?P<episode>[^/?]+)[/?]?.*$'
     IE_NAME = u'escapist'
 
-    def report_extraction(self, showName):
-        self.to_screen(u'%s: Extracting information' % showName)
-
     def report_config_download(self, showName):
         self.to_screen(u'%s: Downloading configuration' % showName)
 
@@ -2633,10 +2584,6 @@ class CollegeHumorIE(InfoExtractor):
         """Report information extraction."""
         self.to_screen(u'%s: Downloading XML manifest' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -2700,10 +2647,6 @@ class XVideosIE(InfoExtractor):
     _VALID_URL = r'^(?:https?://)?(?:www\.)?xvideos\.com/video([0-9]+)(?:.*)'
     IE_NAME = u'xvideos'
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -2772,10 +2715,6 @@ class SoundcloudIE(InfoExtractor):
         """Report information extraction."""
         self.to_screen(u'%s: Resolving id' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Retrieving stream' % video_id)
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -2845,10 +2784,6 @@ class SoundcloudSetIE(InfoExtractor):
         """Report information extraction."""
         self.to_screen(u'%s: Resolving id' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Retrieving stream' % video_id)
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -2912,10 +2847,6 @@ class InfoQIE(InfoExtractor):
     """Information extractor for infoq.com"""
     _VALID_URL = r'^(?:https?://)?(?:www\.)?infoq\.com/[^/]+/[^/]+$'
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -2976,10 +2907,6 @@ class MixcloudIE(InfoExtractor):
         """Report JSON download."""
         self.to_screen(u'Downloading json')
 
-    def report_extraction(self, file_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % file_id)
-
     def get_urls(self, jsonData, fmt, bitrate='best'):
         """Get urls from 'audio_formats' section in json"""
         file_url = None
@@ -3087,10 +3014,6 @@ class StanfordOpenClassroomIE(InfoExtractor):
         """Report information extraction."""
         self.to_screen(u'%s: Downloading webpage' % objid)
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -3195,10 +3118,6 @@ class MTVIE(InfoExtractor):
     _VALID_URL = r'^(?P<proto>https?://)?(?:www\.)?mtv\.com/videos/[^/]+/(?P<videoid>[0-9]+)/[^/]+$'
     IE_NAME = u'mtv'
 
-    def report_extraction(self, video_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -3277,10 +3196,6 @@ class YoukuIE(InfoExtractor):
         """Report webpage download."""
         self.to_screen(u'%s: Downloading webpage' % file_id)
 
-    def report_extraction(self, file_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % file_id)
-
     def _gen_sid(self):
         nowTime = int(time.time() * 1000)
         random1 = random.randint(1000,1998)
@@ -3394,10 +3309,6 @@ class XNXXIE(InfoExtractor):
         """Report information extraction"""
         self.to_screen(u'%s: Downloading webpage' % video_id)
 
-    def report_extraction(self, video_id):
-        """Report information extraction"""
-        self.to_screen(u'%s: Extracting information' % video_id)
-
     def _real_extract(self, url):
         mobj = re.match(self._VALID_URL, url)
         if mobj is None:
@@ -3616,10 +3527,6 @@ class JustinTVIE(InfoExtractor):
     _JUSTIN_PAGE_LIMIT = 100
     IE_NAME = u'justin.tv'
 
-    def report_extraction(self, file_id):
-        """Report information extraction."""
-        self.to_screen(u'%s: Extracting information' % file_id)
-
     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' %
@@ -3745,10 +3652,13 @@ class SteamIE(InfoExtractor):
 
     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
+        videourl = 'http://store.steampowered.com/agecheck/video/%s/?snr=1_agecheck_agecheck__age-gate&ageDay=1&ageMonth=January&ageYear=1970' % gameID
+        self.report_age_confirmation()
         webpage = self._download_webpage(videourl, gameID)
+        game_title = re.search(r'<h2 class="pageheader">(?P<game_title>.*?)</h2>', webpage).group('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)
@@ -3770,7 +3680,7 @@ class SteamIE(InfoExtractor):
                 'thumbnail': video_thumb
                   }
             videos.append(info)
-        return videos
+        return [self.playlist_result(videos, gameID, game_title)]
 
 class UstreamIE(InfoExtractor):
     _VALID_URL = r'https?://www\.ustream\.tv/recorded/(?P<videoID>\d+)'
@@ -4417,6 +4327,40 @@ class ARDIE(InfoExtractor):
             info["url"] = stream["video_url"]
         return [info]
 
+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:
+            self.to_screen("No video founded")
+            return []
+        video_url = video.group('video_url')
+        ext = video.group('ext')
+
+        re_thumb = r'posters(.*?)\[\\x22(?P<thumb>.*?)\\x22'  # We pick the first poster
+        thumb = re.search(re_thumb, webpage).group('thumb').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
+        re_title = r'<title>(.*?) - (?P<title>.*?)</title>'
+        title = unescapeHTML(re.search(re_title, webpage).group('title'))
+
+        return [{'id': video_id,
+                 'url': video_url,
+                 'title': title,
+                 'thumbnail': thumb,
+                 'ext': ext
+                 }]
+
 
 def gen_extractors():
     """ Return a list of an instance of every supported extractor.
@@ -4471,6 +4415,7 @@ def gen_extractors():
         SpiegelIE(),
         LiveLeakIE(),
         ARDIE(),
+        TumblrIE(),
         GenericIE()
     ]