For this, file downloader objects have a method that allows
InfoExtractors to be registered in a given order. When it is passed
a URL, the file downloader handles it to the first InfoExtractor it
- finds that reports being able to handle it. The InfoExtractor returns
- all the information to the FileDownloader and the latter downloads the
- file or does whatever it's instructed to do.
+ finds that reports being able to handle it. The InfoExtractor extracts
+ all the information about the video or videos the URL refers to, and
+ asks the FileDownloader to process the video information, possibly
+ downloading the video.
File downloaders accept a lot of parameters. In order not to saturate
the object constructor with arguments, it receives a dictionary of
def to_stdout(self, message, skip_eol=False):
"""Print message to stdout if not in quiet mode."""
if not self.params.get('quiet', False):
- print u'%s%s' % (message, [u'\n', u''][skip_eol]),
+ print (u'%s%s' % (message, [u'\n', u''][skip_eol])).encode(locale.getpreferredencoding()),
sys.stdout.flush()
def to_stderr(self, message):
"""Process a single dictionary returned by an InfoExtractor."""
# Forced printings
if self.params.get('forcetitle', False):
- print info_dict['title']
+ print info_dict['title'].encode(locale.getpreferredencoding())
if self.params.get('forceurl', False):
- print info_dict['url']
+ print info_dict['url'].encode(locale.getpreferredencoding())
# Do nothing else if in simulate mode
if self.params.get('simulate', False):
Information extractors are the classes that, given a URL, extract
information from the video (or videos) the URL refers to. This
information includes the real video URL, the video title and simplified
- title, author and others. It is returned in a list of dictionaries when
- calling its extract() method. It is a list because a URL can refer to
- more than one video (think of playlists). The dictionaries must include
+ 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.
_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'
_youtube_ie = None
def __init__(self, youtube_ie, downloader=None):
'filters': '0',
'submit': "Continue - I'm over 18",
}
- request = urllib2.Request('http://www.metacafe.com/', urllib.urlencode(disclaimer_form), std_headers)
+ request = urllib2.Request(self._FILTER_POST, urllib.urlencode(disclaimer_form), std_headers)
try:
self.report_age_confirmation()
disclaimer = urllib2.urlopen(request).read()
# Extract URL, uploader and title from webpage
self.report_extraction(video_id)
- mobj = re.search(r'(?m)"mediaURL":"(http.*?\.flv)"', webpage)
+ mobj = re.search(r'(?m)&mediaURL=(http.*?\.flv)', webpage)
if mobj is None:
self._downloader.trouble(u'ERROR: unable to extract media URL')
return
- mediaURL = mobj.group(1).replace('\\', '')
+ mediaURL = urllib.unquote(mobj.group(1))
- mobj = re.search(r'(?m)"gdaKey":"(.*?)"', webpage)
+ mobj = re.search(r'(?m)&gdaKey=(.*?)&', webpage)
if mobj is None:
self._downloader.trouble(u'ERROR: unable to extract gdaKey')
return
return
video_title = mobj.group(1).decode('utf-8')
- mobj = re.search(r'(?m)<li id="ChnlUsr">.*?Submitter:<br />(.*?)</li>', webpage)
+ mobj = re.search(r'(?ms)<li id="ChnlUsr">.*?Submitter:.*?<a .*?>(.*?)<', webpage)
if mobj is None:
self._downloader.trouble(u'ERROR: unable to extract uploader nickname')
return
- video_uploader = re.sub(r'<.*?>', '', mobj.group(1))
+ video_uploader = mobj.group(1)
# Process video information
self._downloader.process_info({
"""Run the PostProcessor.
The "information" argument is a dictionary like the ones
- returned by InfoExtractors. The only difference is that this
+ composed by InfoExtractors. The only difference is that this
one has an extra field called "filepath" that points to the
downloaded file.
batchurls = []
if opts.batchfile is not None:
try:
- batchurls = [line.strip() for line in open(opts.batchfile, 'r')]
+ batchurls = open(opts.batchfile, 'r').readlines()
+ batchurls = [x.strip() for x in batchurls]
+ batchurls = [x for x in batchurls if len(x) > 0]
except IOError:
sys.exit(u'ERROR: batch file could not be read')
all_urls = batchurls + args
youtube_search_ie = YoutubeSearchIE(youtube_ie)
# File downloader
- charset = locale.getpreferredencoding()
- if charset is None:
- charset = 'ascii'
fd = FileDownloader({
'usenetrc': opts.usenetrc,
'username': opts.username,
'forcetitle': opts.gettitle,
'simulate': (opts.simulate or opts.geturl or opts.gettitle),
'format': opts.format,
- 'outtmpl': ((opts.outtmpl is not None and opts.outtmpl.decode(charset))
+ 'outtmpl': ((opts.outtmpl is not None and opts.outtmpl.decode(locale.getpreferredencoding()))
or (opts.usetitle and u'%(stitle)s-%(id)s.%(ext)s')
or (opts.useliteral and u'%(title)s-%(id)s.%(ext)s')
or u'%(id)s.%(ext)s'),