Krzysztof Kurzawski 992376b
#!/usr/bin/env python
Krzysztof Kurzawski 992376b
#
Krzysztof Kurzawski 992376b
# Copyright (c) 2006-2008 Ricardo Garcia Gonzalez
Krzysztof Kurzawski 992376b
#
Krzysztof Kurzawski 992376b
# Permission is hereby granted, free of charge, to any person obtaining a
Krzysztof Kurzawski 992376b
# copy of this software and associated documentation files (the "Software"),
Krzysztof Kurzawski 992376b
# to deal in the Software without restriction, including without limitation
Krzysztof Kurzawski 992376b
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
Krzysztof Kurzawski 992376b
# and/or sell copies of the Software, and to permit persons to whom the
Krzysztof Kurzawski 992376b
# Software is furnished to do so, subject to the following conditions:
Krzysztof Kurzawski 992376b
# 
Krzysztof Kurzawski 992376b
# The above copyright notice and this permission notice shall be included
Krzysztof Kurzawski 992376b
# in all copies or substantial portions of the Software.
Krzysztof Kurzawski 992376b
# 
Krzysztof Kurzawski 992376b
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Krzysztof Kurzawski 992376b
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Krzysztof Kurzawski 992376b
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Krzysztof Kurzawski 992376b
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
Krzysztof Kurzawski 992376b
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
Krzysztof Kurzawski 992376b
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
Krzysztof Kurzawski 992376b
# OTHER DEALINGS IN THE SOFTWARE.
Krzysztof Kurzawski 992376b
# 
Krzysztof Kurzawski 992376b
# Except as contained in this notice, the name(s) of the above copyright
Krzysztof Kurzawski 992376b
# holders shall not be used in advertising or otherwise to promote the
Krzysztof Kurzawski 992376b
# sale, use or other dealings in this Software without prior written
Krzysztof Kurzawski 992376b
# authorization.
Krzysztof Kurzawski 992376b
#
Krzysztof Kurzawski 992376b
import getpass
Krzysztof Kurzawski 992376b
import httplib
Krzysztof Kurzawski 992376b
import math
Krzysztof Kurzawski 992376b
import netrc
Krzysztof Kurzawski 992376b
import optparse
Krzysztof Kurzawski 992376b
import os
Krzysztof Kurzawski 992376b
import re
Krzysztof Kurzawski 992376b
import socket
Krzysztof Kurzawski 992376b
import string
Krzysztof Kurzawski 992376b
import sys
Krzysztof Kurzawski 992376b
import time
Krzysztof Kurzawski 992376b
import urllib2
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Global constants
Krzysztof Kurzawski 992376b
const_1k = 1024
Krzysztof Kurzawski 992376b
const_initial_block_size = 10 * const_1k
Krzysztof Kurzawski 992376b
const_epsilon = 0.0001
Krzysztof Kurzawski 992376b
const_timeout = 120
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
const_video_url_str = 'http://www.youtube.com/watch?v=%s'
Krzysztof Kurzawski 992376b
const_video_url_re = re.compile(r'^((?:http://)?(?:\w+\.)?youtube\.com/(?:v/|(?:watch(?:\.php)?)?\?(?:.+&)?v=))?([0-9A-Za-z_-]+)(?(1)[&/].*)?$')
Krzysztof Kurzawski 992376b
const_login_url_str = 'http://www.youtube.com/login?next=/watch%%3Fv%%3D%s'
Krzysztof Kurzawski 992376b
const_login_post_str = 'current_form=loginForm&next=%%2Fwatch%%3Fv%%3D%s&username=%s&password=%s&action_login=Log+In'
Krzysztof Kurzawski 992376b
const_age_url_str = 'http://www.youtube.com/verify_age?next_url=/watch%%3Fv%%3D%s'
Krzysztof Kurzawski 992376b
const_age_post_str = 'next_url=%%2Fwatch%%3Fv%%3D%s&action_confirm=Confirm'
Krzysztof Kurzawski 992376b
const_url_t_param_re = re.compile(r', "t": "([^"]+)"')
Krzysztof Kurzawski 992376b
const_video_url_real_str = 'http://www.youtube.com/get_video?video_id=%s&t=%s'
Krzysztof Kurzawski 992376b
const_video_title_re = re.compile(r'<title>YouTube - ([^<]*)</title>', re.M | re.I)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Print error message, followed by standard advice information, and then exit
Krzysztof Kurzawski 992376b
def error_advice_exit(error_text):
Krzysztof Kurzawski 992376b
	sys.stderr.write('Error: %s.\n' % error_text)
Krzysztof Kurzawski 992376b
	sys.stderr.write('Try again several times. It may be a temporary problem.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('Other typical problems:\n\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('* Video no longer exists.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('* Video requires age confirmation but you did not provide an account.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('* You provided the account data, but it is not valid.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('* The connection was cut suddenly for some reason.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('* YouTube changed their system, and the program no longer works.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('\nTry to confirm you are able to view the video using a web browser.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('Use the same video URL and account information, if needed, with this program.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('When using a proxy, make sure http_proxy has http://host:port format.\n')
Krzysztof Kurzawski 992376b
	sys.stderr.write('Try again several times and contact me if the problem persists.\n')
Krzysztof Kurzawski 992376b
	sys.exit('\n')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Wrapper to create custom requests with typical headers
Krzysztof Kurzawski 992376b
def request_create(url, data=None):
Krzysztof Kurzawski 992376b
	retval = urllib2.Request(url)
Krzysztof Kurzawski 992376b
	if data is not None:
Krzysztof Kurzawski 992376b
		retval.add_data(data)
Krzysztof Kurzawski 992376b
	# Try to mimic Firefox, at least a little bit
Krzysztof Kurzawski 992376b
	retval.add_header('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11')
Krzysztof Kurzawski 992376b
	retval.add_header('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7')
Krzysztof Kurzawski 992376b
	retval.add_header('Accept', 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5')
Krzysztof Kurzawski 992376b
	retval.add_header('Accept-Language', 'en-us,en;q=0.5')
Krzysztof Kurzawski 992376b
	return retval
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Perform a request, process headers and return response
Krzysztof Kurzawski 992376b
def perform_request(url, data=None):
Krzysztof Kurzawski 992376b
	request = request_create(url, data)
Krzysztof Kurzawski 992376b
	response = urllib2.urlopen(request)
Krzysztof Kurzawski 992376b
	return response
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Conditional print
Krzysztof Kurzawski 992376b
def cond_print(str):
Krzysztof Kurzawski 992376b
	global cmdl_opts
Krzysztof Kurzawski 992376b
	if not (cmdl_opts.quiet or cmdl_opts.get_url):
Krzysztof Kurzawski 992376b
		sys.stdout.write(str)
Krzysztof Kurzawski 992376b
		sys.stdout.flush()
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Title string normalization
Krzysztof Kurzawski 992376b
def title_string_norm(title):
Krzysztof Kurzawski 992376b
	title = ''.join((x in string.ascii_letters or x in string.digits) and x or ' ' for x in title)
Krzysztof Kurzawski 992376b
	title = '_'.join(title.split())
Krzysztof Kurzawski 992376b
	title = title.lower()
Krzysztof Kurzawski 992376b
	return title
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Generic download step
Krzysztof Kurzawski 992376b
def download_step(return_data_flag, step_title, step_error, url, post_data=None):
Krzysztof Kurzawski 992376b
	try:
Krzysztof Kurzawski 992376b
		cond_print('%s... ' % step_title)
Krzysztof Kurzawski 992376b
		data = perform_request(url, post_data).read()
Krzysztof Kurzawski 992376b
		cond_print('done.\n')
Krzysztof Kurzawski 992376b
		if return_data_flag:
Krzysztof Kurzawski 992376b
			return data
Krzysztof Kurzawski 992376b
		return None
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	except (urllib2.URLError, ValueError, httplib.HTTPException, TypeError, socket.error):
Krzysztof Kurzawski 992376b
		cond_print('failed.\n')
Krzysztof Kurzawski 992376b
		error_advice_exit(step_error)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	except KeyboardInterrupt:
Krzysztof Kurzawski 992376b
		sys.exit('\n')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Generic extract step
Krzysztof Kurzawski 992376b
def extract_step(step_title, step_error, regexp, data):
Krzysztof Kurzawski 992376b
	try:
Krzysztof Kurzawski 992376b
		cond_print('%s... ' % step_title)
Krzysztof Kurzawski 992376b
		match = regexp.search(data)
Krzysztof Kurzawski 992376b
		
Krzysztof Kurzawski 992376b
		if match is None:
Krzysztof Kurzawski 992376b
			cond_print('failed.\n')
Krzysztof Kurzawski 992376b
			error_advice_exit(step_error)
Krzysztof Kurzawski 992376b
		
Krzysztof Kurzawski 992376b
		extracted_data = match.group(1)
Krzysztof Kurzawski 992376b
		cond_print('done.\n')
Krzysztof Kurzawski 992376b
		return extracted_data
Krzysztof Kurzawski 992376b
	
Krzysztof Kurzawski 992376b
	except KeyboardInterrupt:
Krzysztof Kurzawski 992376b
		sys.exit('\n')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Calculate new block size based on previous block size
Krzysztof Kurzawski 992376b
def new_block_size(before, after, bytes):
Krzysztof Kurzawski 992376b
	new_min = max(bytes / 2.0, 1.0)
Krzysztof Kurzawski 992376b
	new_max = max(bytes * 2.0, 1.0)
Krzysztof Kurzawski 992376b
	dif = after - before
Krzysztof Kurzawski 992376b
	if dif < const_epsilon:
Krzysztof Kurzawski 992376b
		return int(new_max)
Krzysztof Kurzawski 992376b
	rate = bytes / dif
Krzysztof Kurzawski 992376b
	if rate > new_max:
Krzysztof Kurzawski 992376b
		return int(new_max)
Krzysztof Kurzawski 992376b
	if rate < new_min:
Krzysztof Kurzawski 992376b
		return int(new_min)
Krzysztof Kurzawski 992376b
	return int(rate)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Get optimum 1k exponent to represent a number of bytes
Krzysztof Kurzawski 992376b
def optimum_k_exp(num_bytes):
Krzysztof Kurzawski 992376b
	global const_1k
Krzysztof Kurzawski 992376b
	if num_bytes == 0:
Krzysztof Kurzawski 992376b
		return 0
Krzysztof Kurzawski 992376b
	return long(math.log(num_bytes, const_1k))
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Get optimum representation of number of bytes
Krzysztof Kurzawski 992376b
def format_bytes(num_bytes):
Krzysztof Kurzawski 992376b
	global const_1k
Krzysztof Kurzawski 992376b
	try:
Krzysztof Kurzawski 992376b
		exp = optimum_k_exp(num_bytes)
Krzysztof Kurzawski 992376b
		suffix = 'bkMGTPEZY'[exp]
Krzysztof Kurzawski 992376b
		if exp == 0:
Krzysztof Kurzawski 992376b
			return '%s%s' % (num_bytes, suffix)
Krzysztof Kurzawski 992376b
		converted = float(num_bytes) / float(const_1k**exp)
Krzysztof Kurzawski 992376b
		return '%.2f%s' % (converted, suffix)
Krzysztof Kurzawski 992376b
	except IndexError:
Krzysztof Kurzawski 992376b
		sys.exit('Error: internal error formatting number of bytes.')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Calculate ETA and return it in string format as MM:SS
Krzysztof Kurzawski 992376b
def calc_eta(start, now, total, current):
Krzysztof Kurzawski 992376b
	dif = now - start
Krzysztof Kurzawski 992376b
	if current == 0 or dif < const_epsilon:
Krzysztof Kurzawski 992376b
		return '--:--'
Krzysztof Kurzawski 992376b
	rate = float(current) / dif
Krzysztof Kurzawski 992376b
	eta = long((total - current) / rate)
Krzysztof Kurzawski 992376b
	(eta_mins, eta_secs) = divmod(eta, 60)
Krzysztof Kurzawski 992376b
	if eta_mins > 99:
Krzysztof Kurzawski 992376b
		return '--:--'
Krzysztof Kurzawski 992376b
	return '%02d:%02d' % (eta_mins, eta_secs)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Calculate speed and return it in string format
Krzysztof Kurzawski 992376b
def calc_speed(start, now, bytes):
Krzysztof Kurzawski 992376b
	dif = now - start
Krzysztof Kurzawski 992376b
	if bytes == 0 or dif < const_epsilon:
Krzysztof Kurzawski 992376b
		return 'N/A b'
Krzysztof Kurzawski 992376b
	return format_bytes(float(bytes) / dif)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Title string minimal transformation
Krzysztof Kurzawski 992376b
def title_string_touch(title):
Krzysztof Kurzawski 992376b
	return title.replace(os.sep, '%')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Create the command line options parser and parse command line
Krzysztof Kurzawski 992376b
cmdl_usage = 'usage: %prog [options] video_url'
Krzysztof Kurzawski 992376b
cmdl_version = '2008.01.24'
Krzysztof Kurzawski 992376b
cmdl_parser = optparse.OptionParser(usage=cmdl_usage, version=cmdl_version, conflict_handler='resolve')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-h', '--help', action='help', help='print this help text and exit')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-v', '--version', action='version', help='print program version and exit')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-u', '--username', dest='username', metavar='USERNAME', help='account username')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-p', '--password', dest='password', metavar='PASSWORD', help='account password')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-o', '--output', dest='outfile', metavar='FILE', help='output video file name')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='activates quiet mode')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-s', '--simulate', action='store_true', dest='simulate', help='do not download video')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-t', '--title', action='store_true', dest='use_title', help='use title in file name')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-l', '--literal', action='store_true', dest='use_literal', help='use literal title in file name')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-n', '--netrc', action='store_true', dest='use_netrc', help='use .netrc authentication data')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-g', '--get-url', action='store_true', dest='get_url', help='print final video URL only')
Krzysztof Kurzawski 992376b
cmdl_parser.add_option('-2', '--title-too', action='store_true', dest='get_title', help='used with -g, print title too')
Krzysztof Kurzawski 992376b
(cmdl_opts, cmdl_args) = cmdl_parser.parse_args()
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Set socket timeout
Krzysztof Kurzawski 992376b
socket.setdefaulttimeout(const_timeout)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Get video URL
Krzysztof Kurzawski 992376b
if len(cmdl_args) != 1:
Krzysztof Kurzawski 992376b
	cmdl_parser.print_help()
Krzysztof Kurzawski 992376b
	sys.exit('\n')
Krzysztof Kurzawski 992376b
video_url_cmdl = cmdl_args[0]
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Verify video URL format and convert to "standard" format
Krzysztof Kurzawski 992376b
video_url_mo = const_video_url_re.match(video_url_cmdl)
Krzysztof Kurzawski 992376b
if video_url_mo is None:
Krzysztof Kurzawski 992376b
	sys.exit('Error: URL does not seem to be a youtube video URL. If it is, report a bug.')
Krzysztof Kurzawski 992376b
video_url_id = video_url_mo.group(2)
Krzysztof Kurzawski 992376b
video_url = const_video_url_str % video_url_id
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Check conflicting options
Krzysztof Kurzawski 992376b
if cmdl_opts.outfile is not None and (cmdl_opts.simulate or cmdl_opts.get_url):
Krzysztof Kurzawski 992376b
	sys.stderr.write('Warning: video file name given but will not be used.\n')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
if cmdl_opts.outfile is not None and (cmdl_opts.use_title or cmdl_opts.use_literal):
Krzysztof Kurzawski 992376b
	sys.exit('Error: using the video title conflicts with using a given file name.')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
if cmdl_opts.use_title and cmdl_opts.use_literal:
Krzysztof Kurzawski 992376b
	sys.exit('Error: cannot use title and literal title at the same time.')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
if cmdl_opts.quiet and cmdl_opts.get_url:
Krzysztof Kurzawski 992376b
	sys.exit('Error: cannot be quiet and print final URL at the same time.')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Incorrect option formatting
Krzysztof Kurzawski 992376b
if cmdl_opts.username is None and cmdl_opts.password is not None:
Krzysztof Kurzawski 992376b
	sys.exit('Error: password give but username is missing.')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
if cmdl_opts.use_netrc and (cmdl_opts.username is not None or cmdl_opts.password is not None):
Krzysztof Kurzawski 992376b
	sys.exit('Error: cannot use netrc and username/password at the same time.')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
if cmdl_opts.get_url is None and cmdl_opts.get_title is not None:
Krzysztof Kurzawski 992376b
	sys.exit('Error: getting title requires getting URL.')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Get account information if any
Krzysztof Kurzawski 992376b
account_username = None
Krzysztof Kurzawski 992376b
account_password = None
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
if cmdl_opts.use_netrc:
Krzysztof Kurzawski 992376b
	try:
Krzysztof Kurzawski 992376b
		info = netrc.netrc().authenticators('youtube')
Krzysztof Kurzawski 992376b
		if info is None:
Krzysztof Kurzawski 992376b
			sys.exit('Error: no authenticators for machine youtube.')
Krzysztof Kurzawski 992376b
		account_username = info[0]
Krzysztof Kurzawski 992376b
		account_password = info[2]
Krzysztof Kurzawski 992376b
	except IOError:
Krzysztof Kurzawski 992376b
		sys.exit('Error: unable to read .netrc file.')
Krzysztof Kurzawski 992376b
	except netrc.NetrcParseError:
Krzysztof Kurzawski 992376b
		sys.exit('Error: unable to parse .netrc file.')
Krzysztof Kurzawski 992376b
else:
Krzysztof Kurzawski 992376b
	account_username = cmdl_opts.username
Krzysztof Kurzawski 992376b
	if account_username is not None:
Krzysztof Kurzawski 992376b
		if cmdl_opts.password is None:
Krzysztof Kurzawski 992376b
			account_password = getpass.getpass('Type YouTube password and press return: ')
Krzysztof Kurzawski 992376b
		else:
Krzysztof Kurzawski 992376b
			account_password = cmdl_opts.password
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Get output file name 
Krzysztof Kurzawski 992376b
if cmdl_opts.outfile is None:
Krzysztof Kurzawski 992376b
	video_filename = '%s.flv' % video_url_id
Krzysztof Kurzawski 992376b
else:
Krzysztof Kurzawski 992376b
	video_filename = cmdl_opts.outfile
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Install cookie and proxy handlers
Krzysztof Kurzawski 992376b
urllib2.install_opener(urllib2.build_opener(urllib2.ProxyHandler()))
Krzysztof Kurzawski 992376b
urllib2.install_opener(urllib2.build_opener(urllib2.HTTPCookieProcessor()))
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Log in and confirm age if needed
Krzysztof Kurzawski 992376b
if account_username is not None:
Krzysztof Kurzawski 992376b
	url = const_login_url_str % video_url_id
Krzysztof Kurzawski 992376b
	post = const_login_post_str % (video_url_id, account_username, account_password)
Krzysztof Kurzawski 992376b
	download_step(False, 'Logging in', 'unable to log in', url, post)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	url = const_age_url_str % video_url_id
Krzysztof Kurzawski 992376b
	post = const_age_post_str % video_url_id
Krzysztof Kurzawski 992376b
	download_step(False, 'Confirming age', 'unable to confirm age', url, post)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Retrieve video webpage
Krzysztof Kurzawski 992376b
video_webpage = download_step(True, 'Retrieving video webpage', 'unable to retrieve video webpage', video_url)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Extract video title if needed
Krzysztof Kurzawski 992376b
if cmdl_opts.use_title or cmdl_opts.use_literal or cmdl_opts.get_title:
Krzysztof Kurzawski 992376b
	video_title = extract_step('Extracting video title', 'unable to extract video title', const_video_title_re, video_webpage)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Extract needed video URL parameters
Krzysztof Kurzawski 992376b
video_url_t_param = extract_step('Extracting URL "t" parameter', 'unable to extract URL "t" parameter', const_url_t_param_re, video_webpage)
Krzysztof Kurzawski 992376b
video_url_real = const_video_url_real_str % (video_url_id, video_url_t_param)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Rebuild filename if needed
Krzysztof Kurzawski 992376b
if cmdl_opts.use_title or cmdl_opts.use_literal:
Krzysztof Kurzawski 992376b
	if cmdl_opts.use_title:
Krzysztof Kurzawski 992376b
		prefix = title_string_norm(video_title)
Krzysztof Kurzawski 992376b
	else:
Krzysztof Kurzawski 992376b
		prefix = title_string_touch(video_title)
Krzysztof Kurzawski 992376b
	video_filename = '%s-%s.flv' % (prefix, video_url_id)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Check name
Krzysztof Kurzawski 992376b
if not video_filename.lower().endswith('.flv'):
Krzysztof Kurzawski 992376b
	sys.stderr.write('Warning: video file name does not end in .flv\n')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Retrieve video data
Krzysztof Kurzawski 992376b
try:
Krzysztof Kurzawski 992376b
	cond_print('Requesting video file... ')
Krzysztof Kurzawski 992376b
	video_data = perform_request(video_url_real)
Krzysztof Kurzawski 992376b
	cond_print('done.\n')
Krzysztof Kurzawski 992376b
	cond_print('Video data found at %s\n' % video_data.geturl())
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	if cmdl_opts.get_title:
Krzysztof Kurzawski 992376b
		print video_title
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	if cmdl_opts.get_url:
Krzysztof Kurzawski 992376b
		print video_data.geturl()
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	if cmdl_opts.simulate or cmdl_opts.get_url:
Krzysztof Kurzawski 992376b
		sys.exit()
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	try:
Krzysztof Kurzawski 992376b
		video_file = open(video_filename, 'wb')
Krzysztof Kurzawski 992376b
	except (IOError, OSError):
Krzysztof Kurzawski 992376b
		sys.exit('Error: unable to open "%s" for writing.' % video_filename)
Krzysztof Kurzawski 992376b
	try:
Krzysztof Kurzawski 992376b
		video_len = long(video_data.info()['Content-length'])
Krzysztof Kurzawski 992376b
		video_len_str = format_bytes(video_len)
Krzysztof Kurzawski 992376b
	except KeyError:
Krzysztof Kurzawski 992376b
		video_len = None
Krzysztof Kurzawski 992376b
		video_len_str = 'N/A'
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	byte_counter = 0
Krzysztof Kurzawski 992376b
	block_size = const_initial_block_size
Krzysztof Kurzawski 992376b
	start_time = time.time()
Krzysztof Kurzawski 992376b
	while True:
Krzysztof Kurzawski 992376b
		if video_len is not None:
Krzysztof Kurzawski 992376b
			percent = float(byte_counter) / float(video_len) * 100.0
Krzysztof Kurzawski 992376b
			percent_str = '%.1f' % percent
Krzysztof Kurzawski 992376b
			eta_str = calc_eta(start_time, time.time(), video_len, byte_counter)
Krzysztof Kurzawski 992376b
		else:
Krzysztof Kurzawski 992376b
			percent_str = '---.-'
Krzysztof Kurzawski 992376b
			eta_str = '--:--'
Krzysztof Kurzawski 992376b
		counter = format_bytes(byte_counter)
Krzysztof Kurzawski 992376b
		speed_str = calc_speed(start_time, time.time(), byte_counter)
Krzysztof Kurzawski 992376b
		cond_print('\rRetrieving video data: %5s%% (%8s of %s) at %8s/s ETA %s ' % (percent_str, counter, video_len_str, speed_str, eta_str))
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
		before = time.time()
Krzysztof Kurzawski 992376b
		video_block = video_data.read(block_size)
Krzysztof Kurzawski 992376b
		after = time.time()
Krzysztof Kurzawski 992376b
		dl_bytes = len(video_block)
Krzysztof Kurzawski 992376b
		if dl_bytes == 0:
Krzysztof Kurzawski 992376b
			break
Krzysztof Kurzawski 992376b
		byte_counter += dl_bytes
Krzysztof Kurzawski 992376b
		video_file.write(video_block)
Krzysztof Kurzawski 992376b
		block_size = new_block_size(before, after, dl_bytes)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	if video_len is not None and byte_counter != video_len:
Krzysztof Kurzawski 992376b
		error_advice_exit('server did not send the expected ammount of data')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
	video_file.close()
Krzysztof Kurzawski 992376b
	cond_print('done.\n')
Krzysztof Kurzawski 992376b
	cond_print('Video data saved to %s\n' % video_filename)
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
except (urllib2.URLError, ValueError, httplib.HTTPException, TypeError, socket.error):
Krzysztof Kurzawski 992376b
	cond_print('failed.\n')
Krzysztof Kurzawski 992376b
	error_advice_exit('unable to download video data')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
except KeyboardInterrupt:
Krzysztof Kurzawski 992376b
	sys.exit('\n')
Krzysztof Kurzawski 992376b
Krzysztof Kurzawski 992376b
# Finish
Krzysztof Kurzawski 992376b
sys.exit()