Merge remote-tracking branch 'jefftimesten/master'
authorPhilipp Hagemeister <phihag@phihag.de>
Sat, 12 Jan 2013 14:12:50 +0000 (15:12 +0100)
committerPhilipp Hagemeister <phihag@phihag.de>
Sat, 12 Jan 2013 14:12:50 +0000 (15:12 +0100)
1  2 
test/tests.json
youtube_dl/InfoExtractors.py

diff --combined test/tests.json
index cbb1a4d58d183ab4023580014bc9cf459823dee5,f4d7b2b691385d9683bb69c7a7d1af82c6c98ba2..540c5d1834a0535c0619a667630e0a23aeebdd23
      "url":  "http://www.xvideos.com/video939581/funny_porns_by_s_-1",
      "file":  "939581.flv"
    },
+   {
+     "name": "YouPorn",
+     "md5": "c37ddbaaa39058c76a7e86c6813423c1",
+     "url": "http://www.youporn.com/watch/505835/sex-ed-is-it-safe-to-masturbate-daily/",
+     "file": "505835.mp4"
+   },
+   {
+     "name": "Pornotube",
+     "md5": "374dd6dcedd24234453b295209aa69b6",
+     "url": "http://pornotube.com/c/173/m/1689755/Marilyn-Monroe-Bathing",
+     "file": "1689755.flv"
+   },
+   {
+     "name": "YouJizz",
+     "md5": "07e15fa469ba384c7693fd246905547c",
+     "url": "http://www.youjizz.com/videos/zeichentrick-1-2189178.html",
+     "file": "2189178.flv"
+   },
    {
      "name": "Vimeo",
      "md5":  "8879b6cc097e987f02484baf890129e5",
      "params": {
        "skip_download": true
      }
 +  },
 +  {
 +    "name": "ComedyCentral",
 +    "url": "http://www.thedailyshow.com/full-episodes/thu-december-13-2012-kristen-stewart",
 +    "playlist": [
 +      {
 +        "file": "422204.mp4",
 +        "md5": "7a7abe068b31ff03e7b8a37596e72380",
 +        "info_dict": {
 +            "title": "thedailyshow-thu-december-13-2012-kristen-stewart part 1"
 +        }
 +      },
 +      {
 +        "file": "422205.mp4",
 +        "md5": "30552b7274c94dbb933f64600eadddd2",
 +        "info_dict": {
 +            "title": "thedailyshow-thu-december-13-2012-kristen-stewart part 2"
 +        }
 +      },
 +      {
 +        "file": "422206.mp4",
 +        "md5": "1f4c0664b352cb8e8fe85d5da4fbee91",
 +        "info_dict": {
 +            "title": "thedailyshow-thu-december-13-2012-kristen-stewart part 3"
 +        }
 +      },
 +      {
 +        "file": "422207.mp4",
 +        "md5": "f61ee8a4e6bd1308438e03badad78554",
 +        "info_dict": {
 +            "title": "thedailyshow-thu-december-13-2012-kristen-stewart part 4"
 +        }
 +      }
 +    ]
    }
  ]
index a992ccc1b9832e25333dbe6681061cccea51bcb9,83be8313f1d3591dd936491ac0e1087791f92ab5..092bfef22ba7cdf7e4847ebc562bae0814037141
@@@ -2333,6 -2333,7 +2333,6 @@@ class ComedyCentralIE(InfoExtractor)
                                (the-colbert-report-(videos|collections)/(?P<clipID>[0-9]+)/[^/]*/(?P<cntitle>.*?))
                                |(watch/(?P<date>[^/]*)/(?P<tdstitle>.*)))))
                       $"""
 -    IE_NAME = u'comedycentral'
  
      _available_formats = ['3500', '2200', '1700', '1200', '750', '400']
  
      def report_extraction(self, episode_id):
          self._downloader.to_screen(u'[comedycentral] %s: Extracting information' % episode_id)
  
 -    def report_config_download(self, episode_id):
 -        self._downloader.to_screen(u'[comedycentral] %s: Downloading configuration' % episode_id)
 +    def report_config_download(self, episode_id, media_id):
 +        self._downloader.to_screen(u'[comedycentral] %s: Downloading configuration for %s' % (episode_id, media_id))
  
      def report_index_download(self, episode_id):
          self._downloader.to_screen(u'[comedycentral] %s: Downloading show index' % episode_id)
  
 -    def report_player_url(self, episode_id):
 -        self._downloader.to_screen(u'[comedycentral] %s: Determining player URL' % episode_id)
 -
 -
      def _print_formats(self, formats):
          print('Available formats:')
          for x in formats:
          try:
              htmlHandle = compat_urllib_request.urlopen(req)
              html = htmlHandle.read()
 +            webpage = html.decode('utf-8')
          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
                  return
              epTitle = mobj.group('episode')
  
 -        mMovieParams = re.findall('(?:<param name="movie" value="|var url = ")(http://media.mtvnservices.com/([^"]*(?:episode|video).*?:.*?))"', html)
 +        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).*?:.*?)"', html)
 +            altMovieParams = re.findall('data-mgid="([^"]*(?:episode|video).*?:.*?)"', webpage)
              if len(altMovieParams) == 0:
                  self._downloader.trouble(u'ERROR: unable to find Flash URL in webpage ' + url)
                  return
              else:
                  mMovieParams = [("http://media.mtvnservices.com/" + altMovieParams[0], altMovieParams[0])]
  
 -        playerUrl_raw = mMovieParams[0][0]
 -        self.report_player_url(epTitle)
 -        try:
 -            urlHandle = compat_urllib_request.urlopen(playerUrl_raw)
 -            playerUrl = urlHandle.geturl()
 -        except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
 -            self._downloader.trouble(u'ERROR: unable to find out player URL: ' + compat_str(err))
 -            return
 -
          uri = mMovieParams[0][1]
          indexUrl = 'http://shadow.comedycentral.com/feeds/video_player/mrss/?' + compat_urllib_parse.urlencode({'uri': uri})
          self.report_index_download(epTitle)
  
          idoc = xml.etree.ElementTree.fromstring(indexXml)
          itemEls = idoc.findall('.//item')
 -        for itemEl in itemEls:
 +        for partNum,itemEl in enumerate(itemEls):
              mediaId = itemEl.findall('./guid')[0].text
              shortMediaId = mediaId.split(':')[-1]
              showId = mediaId.split(':')[-2].replace('.com', '')
              configUrl = ('http://www.comedycentral.com/global/feeds/entertainment/media/mediaGenEntertainment.jhtml?' +
                          compat_urllib_parse.urlencode({'uri': mediaId}))
              configReq = compat_urllib_request.Request(configUrl)
 -            self.report_config_download(epTitle)
 +            self.report_config_download(epTitle, shortMediaId)
              try:
                  configXml = compat_urllib_request.urlopen(configReq).read()
              except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
                  return
  
              # For now, just pick the highest bitrate
 -            format,video_url = turls[-1]
 +            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, video_url = f, v
 +                    format, rtmp_video_url = f, v
                      break
  
 -            # Patch to download from alternative CDN, which does not
 -            # break on current RTMPDump builds
 -            broken_cdn = "rtmpe://viacomccstrmfs.fplive.net/viacomccstrm/gsp.comedystor/"
 -            better_cdn = "rtmpe://cp10740.edgefcs.net/ondemand/mtvnorigin/gsp.comedystor/"
 -
 -            if video_url.startswith(broken_cdn):
 -                video_url = video_url.replace(broken_cdn, better_cdn)
 +            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
 +            effTitle = showId + u'-' + epTitle + u' part ' + compat_str(partNum+1)
              info = {
                  'id': shortMediaId,
                  'url': video_url,
                  'format': format,
                  'thumbnail': None,
                  'description': officialTitle,
 -                'player_url': None #playerUrl
              }
 -
              results.append(info)
  
          return results
@@@ -2586,6 -2603,7 +2586,6 @@@ class EscapistIE(InfoExtractor)
  
          return [info]
  
 -
  class CollegeHumorIE(InfoExtractor):
      """Information extractor for collegehumor.com"""
  
@@@ -3272,7 -3290,7 +3272,7 @@@ class YoukuIE(InfoExtractor)
  class XNXXIE(InfoExtractor):
      """Information extractor for xnxx.com"""
  
-     _VALID_URL = r'^http://video\.xnxx\.com/video([0-9]+)/(.*)'
+     _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'
@@@ -3524,23 -3542,17 +3524,23 @@@ class JustinTVIE(InfoExtractor)
              return
  
          response = json.loads(webpage)
 +        if type(response) != list:
 +            error_text = response.get('error', 'unknown error')
 +            self._downloader.trouble(u'ERROR: Justin.tv API: %s' % error_text)
 +            return
          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['created_on'][:10])
 +                video_date = re.sub('-', '', clip['start_time'][:10])
 +                video_uploader_id = clip.get('user_id', clip.get('channel_id'))
                  info.append({
                      'id': clip['id'],
                      'url': video_url,
                      'title': clip['title'],
 -                    'uploader': clip.get('user_id', clip.get('channel_id')),
 +                    'uploader': clip.get('channel_name', video_uploader_id),
 +                    'uploader_id': video_uploader_id,
                      'upload_date': video_date,
                      'ext': video_extension,
                  })
              paged = True
              api += '/channel/archives/%s.json'
          else:
 -            api += '/clip/show/%s.json'
 +            api += '/broadcast/by_archive/%s.json'
          api = api % (video_id,)
  
          self.report_extraction(video_id)
@@@ -3699,11 -3711,11 +3699,11 @@@ class SteamIE(InfoExtractor)
                    }
              videos.append(info)
          return videos
 -        
 +
  class UstreamIE(InfoExtractor):
 -    _VALID_URL = r'http://www.ustream.tv/recorded/(?P<videoID>\d+)'
 +    _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')
          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 __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')
+         #self.report_id(video_id)        
+         webpage = self._download_webpage(url, video_id)
+         #self.report_webpage(url)
+         # Get the video title
+         VIDEO_TITLE_RE = r'videoTitleArea">(?P<title>.*)</h1>'
+         result = re.search(VIDEO_TITLE_RE, webpage)
+         if result is None:
+             self._downloader.trouble(u'ERROR: unable to extract video title')
+             return
+         video_title = result.group('title').strip()
+         #self.report_title(video_title)
+         # Get the video date
+         VIDEO_DATE_RE = r'Date:</b>(?P<date>.*)</li>'
+         result = re.search(VIDEO_DATE_RE, webpage)
+         if result is None:
+             self._downloader.trouble(u'ERROR: unable to extract video date')
+             return
+         upload_date = result.group('date').strip()
+         #self.report_upload_date(upload_date)
+         # Get the video uploader
+         VIDEO_UPLOADER_RE = r'Submitted:</b>(?P<uploader>.*)</li>'
+         result = re.search(VIDEO_UPLOADER_RE, webpage)
+         if result is None:
+             self._downloader.trouble(u'ERROR: unable to extract uploader')
+             return
+         video_uploader = result.group('uploader').strip()
+         video_uploader = clean_html( video_uploader )
+         #self.report_uploader(video_uploader)
+         # Get all of the formats available
+         DOWNLOAD_LIST_RE = r'(?s)<ul class="downloadList">(?P<download_list>.*?)</ul>'
+         result = re.search(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').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):
+             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 )
+             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': 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>.+))$'
+     # 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')
+         video_title = mobj.group('title')
+         #self.report_title(video_title);
+         # Get webpage content
+         webpage = self._download_webpage(url, video_id)
+         #self.report_webpage(url)
+         # Get the video URL
+         VIDEO_URL_RE = r'url: "(?P<url>http://video[0-9].pornotube.com/.+\.flv)",'
+         result = re.search(VIDEO_URL_RE, webpage)
+         if result is None:
+             self._downloader.trouble(u'ERROR: unable to extract video url')
+             return
+         video_url = compat_urllib_parse.unquote(result.group('url'))
+         #self.report_extract_entry(video_url)
+         #Get the uploaded date
+         VIDEO_UPLOADED_RE = r'<div class="video_added_by">Added (?P<date>[0-9\/]+) by'
+         result = re.search(VIDEO_UPLOADED_RE, webpage)
+         if result is None:
+             self._downloader.trouble(u'ERROR: unable to extract video title')
+             return
+         upload_date = result.group('date')
+         #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/(?P<videoid>[^.]+).html$'
+     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):
+         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')
+         # Get webpage content
+         webpage = self._download_webpage(url, video_id)
+         #self.report_webpage(url)
+         # Get the video title
+         VIDEO_TITLE_RE = r'<title>(?P<title>.*)</title>'
+         result = re.search(VIDEO_TITLE_RE, webpage)
+         if result is None:
+             self._downloader.trouble(u'ERROR: unable to extract video title')
+             return
+         video_title = result.group('title').strip()
+         #self.report_title(video_title)
+         # Get the embed page
+         EMBED_PAGE_RE = r'http://www.youjizz.com/videos/embed/(?P<videoid>[0-9]+)'
+         result = re.search(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).strip()
+         video_id = result.group('videoid')
+         #self.report_embed_page(embed_page_url)
+     
+         webpage = self._download_webpage(embed_page_url, video_id)
+         # Get the video URL
+         SOURCE_RE = r'so.addVariable\("file",encodeURIComponent\("(?P<source>[^"]+)"\)\);'
+         result = re.search(SOURCE_RE, webpage)
+         if result is None:
+             self._downloader.trouble(u'ERROR: unable to extract video url')
+             return
+         video_url = result.group('source')
+         #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.
          MTVIE(),
          YoukuIE(),
          XNXXIE(),
+         YouJizzIE(),
+         PornotubeIE(),
+         YouPornIE(),
          GooglePlusIE(),
          ArteTvIE(),
          NBAIE(),