Repository: ytdl-org/youtube-dl

Issue:
Blip.tv no longer works
Downloading any video from blip.tv results in a 38370 byte file which is unplayable. Running wget `youtube-dl -g URL` does work, however.

example: 

$ ./youtube-dl http://blip.tv/adg/episode-81-animal-quest-6059945
[blip.tv] /adg/episode-81-animal-quest-6059945: Extracting information
[download] Destination: 6043128.m4v
[download] 100.0% of 37.47k at   85.19k/s ETA 00:00
$ ls -l 6043128.m4v
-rw-r--r-- 1 jspenguin jspenguin 38370 2012-02-16 14:58 6043128.m4v
$ ./youtube-dl -g http://blip.tv/adg/episode-81-animal-quest-6059945
http://blip.tv/file/get/Gemini000-Episode81AnimalQuest501.m4v
$ wget http://blip.tv/file/get/Gemini000-Episode81AnimalQuest501.m4v
--2012-04-02 12:08:11--  http://blip.tv/file/get/Gemini000-Episode81AnimalQuest501.m4v
Resolving blip.tv... 74.122.174.250
Connecting to blip.tv|74.122.174.250|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://a66.video2.blip.tv/13330010626287/Gemini000-Episode81AnimalQuest501.m4v?brs=559&bri=7.6 [following]
--2012-04-02 12:09:11--  http://a66.video2.blip.tv/13330010626287/Gemini000-Episode81AnimalQuest501.m4v?brs=559&bri=7.6
Resolving a66.video2.blip.tv... 208.44.23.83, 208.44.23.73
Connecting to a66.video2.blip.tv|208.44.23.83|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 53466360 (51M) [video/mp4]
Saving to: `Gemini000-Episode81AnimalQuest501.m4v'

2012-04-02 12:13:05 (69.9 kB/s) - `Gemini000-Episode81AnimalQuest501.m4v' saved [53466360]



Discussion:
Umh... confused by the redirect?
On it.

I've been searching on this and came across this page. Blip.tv is only allowing certain user agent strings to prevent downloading. currently iTunes/10.6.1 works

Note that the current version of get_flash_videos currently supports Blip.tv.  I'd love to have support in youtube-dl, though.


Resolving patch:
diff --git a/youtube_dl/InfoExtractors.py b/youtube_dl/InfoExtractors.py
--- a/youtube_dl/InfoExtractors.py
+++ b/youtube_dl/InfoExtractors.py
@@ -1614,6 +1614,98 @@ def _real_extract(self, url):
 			self._downloader.download(['http://www.youtube.com/watch?v=%s' % video_id])
 
 
+class BlipTVUserIE(InfoExtractor):
+	"""Information Extractor for blip.tv users."""
+
+	_VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?blip\.tv/)|bliptvuser:)([^/]+)/*$'
+	_PAGE_SIZE = 10
+	IE_NAME = u'blip.tv:user'
+
+	def __init__(self, downloader=None):
+		InfoExtractor.__init__(self, downloader)
+
+	def report_download_page(self, username, pagenum):
+		"""Report attempt to download user page."""
+		self._downloader.to_screen(u'[%s] user %s: Downloading video ids from page %d' %
+				(self.IE_NAME, username, pagenum))
+
+	def _real_extract(self, url):
+		# Extract username
+		mobj = re.match(self._VALID_URL, url)
+		if mobj is None:
+			self._downloader.trouble(u'ERROR: invalid url: %s' % url)
+			return
+
+		username = mobj.group(1)
+
+		page_base = None
+
+		request = urllib2.Request(url)
+
+		try:
+			page = urllib2.urlopen(request).read().decode('utf-8')
+			mobj = re.search(r'data-source-url="([^"]+)"', page)
+			page_base = "http://blip.tv" + unescapeHTML(mobj.group(1))
+		except (urllib2.URLError, httplib.HTTPException, socket.error), err:
+			self._downloader.trouble(u'ERROR: unable to download webpage: %s' % str(err))
+			return
+
+
+		# Download video ids using BlipTV Page API. Result size per
+		# query is limited (currently to 10 videos) so we need to query
+		# page by page until there are no video ids - it means we got
+		# all of them.
+
+		video_ids = []
+		pagenum = 0
+
+		while True:
+			self.report_download_page(username, pagenum)
+
+			request = urllib2.Request( page_base + "&page=" + str(pagenum+1) )
+
+			try:
+				page = urllib2.urlopen(request).read().decode('utf-8')
+			except (urllib2.URLError, httplib.HTTPException, socket.error), err:
+				self._downloader.trouble(u'ERROR: unable to download webpage: %s' % str(err))
+				return
+
+			# Extract video identifiers
+			ids_in_page = []
+
+			for mobj in re.finditer(r'href="/([^"]+)"', page):
+				if mobj.group(1) not in ids_in_page:
+					ids_in_page.append(unescapeHTML(mobj.group(1)))
+
+			video_ids.extend(ids_in_page)
+
+			# A little optimization - if current page is not
+			# "full", ie. does not contain PAGE_SIZE video ids then
+			# we can assume that this page is the last one - there
+			# are no more ids on further pages - no need to query
+			# again.
+
+			if len(ids_in_page) < self._PAGE_SIZE:
+				break
+
+			pagenum += 1
+
+		all_ids_count = len(video_ids)
+		playliststart = self._downloader.params.get('playliststart', 1) - 1
+		playlistend = self._downloader.params.get('playlistend', -1)
+
+		if playlistend == -1:
+			video_ids = video_ids[playliststart:]
+		else:
+			video_ids = video_ids[playliststart:playlistend]
+
+		self._downloader.to_screen(u"[%s] user %s: Collected %d video ids (downloading %d of them)" %
+				(self.IE_NAME, username, all_ids_count, len(video_ids)))
+
+		for video_id in video_ids:
+			self._downloader.download([u'http://blip.tv/'+video_id])
+
+
 class DepositFilesIE(InfoExtractor):
 	"""Information extractor for depositfiles.com"""
 
diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py
--- a/youtube_dl/__init__.py
+++ b/youtube_dl/__init__.py
@@ -338,6 +338,7 @@ def gen_extractors():
 		YahooSearchIE(),
 		DepositFilesIE(),
 		FacebookIE(),
+		BlipTVUserIE(),
 		BlipTVIE(),
 		VimeoIE(),
 		MyVideoIE(),
diff --git a/youtube_dl/utils.py b/youtube_dl/utils.py
--- a/youtube_dl/utils.py
+++ b/youtube_dl/utils.py
@@ -19,7 +19,7 @@
 	import StringIO
 
 std_headers = {
-	'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:5.0.1) Gecko/20100101 Firefox/5.0.1',
+	'User-Agent': 'iTunes/10.6.1',
 	'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
 	'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 	'Accept-Encoding': 'gzip, deflate',


Test patch: