YouTube integration.

Links to YouTube profiles are converted to the corresponding
RSS feeds (http://www.youtube.com/rssls), which aren't available
with the standard feed discovery.

Normal links to YouTube enclosures (*.swf) are now on-the-fly
replaced with links to high quality MP4 videos.  Apparently
links to real enclosures are not permanent, so they can't be
saved in the database.
This commit is contained in:
Justin Forest 2008-10-13 17:28:44 +04:00 committed by Thomas Perl
parent 661a4381e1
commit 47c98633e6
3 changed files with 95 additions and 4 deletions

View File

@ -28,9 +28,11 @@
import feedparser
import re
import time
import gpodder
from gpodder import resolver
from gpodder.liblogger import log
@ -136,6 +138,15 @@ class Cache:
found_alternate_feed = True
break
# YouTube etc feed lookup (after the normal link lookup in case
# they provide a standard feed discovery mechanism in the future).
if not found_alternate_feed:
next = resolver.get_real_channel_url(url)
if next is not None:
parsed_result = feedparser.parse(next, agent=self.user_agent, modified=modified, etag=etag)
found_alternate_feed = True
# We have not found a valid feed - abort here!
if not found_alternate_feed:
return (False, None)

View File

@ -29,6 +29,7 @@ from gpodder.liblogger import log
from gpodder.libgpodder import gl
from gpodder import util
from gpodder import services
from gpodder import resolver
import gpodder
import threading
@ -208,13 +209,19 @@ class DownloadThread(threading.Thread):
return
util.delete_file( self.tempname)
self.downloader.retrieve( self.episode.url, self.tempname, reporthook = self.status_updated)
(unused, headers) = self.downloader.retrieve( resolver.get_real_download_url(self.url), self.tempname, reporthook = self.status_updated)
if 'content-type' in headers and headers['content-type'] != self.episode.mimetype:
log('Correcting mime type: %s => %s', self.episode.mimetype, headers['content-type'])
self.episode.mimetype = headers['content-type']
# File names are constructed with regard to the mime type.
self.filename = self.episode.local_filename()
shutil.move( self.tempname, self.filename)
self.channel.addDownloadedItem( self.episode)
services.download_status_manager.download_completed(self.download_id)
# Get the _real_ filesize once we actually have the file
self.episode.length = os.path.getsize(self.filename)
self.episode.save()
self.channel.addDownloadedItem( self.episode)
services.download_status_manager.download_completed(self.download_id)
# If a user command has been defined, execute the command setting some environment variables
if len(gl.config.cmd_download_complete) > 0:

73
src/gpodder/resolver.py Normal file
View File

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
#
# gPodder - A media aggregator and podcast client
# Copyright (c) 2005-2008 Thomas Perl and the gPodder Team
#
# gPodder is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# gPodder is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# resolver.py -- YouTube and related magic
# Justin Forest <justin.forest@gmail.com> 2008-10-13
#
# TODO:
#
# * Channel covers.
# * Support for Vimeo, maybe blip.tv and others.
import re
from gpodder.liblogger import log
from gpodder.util import proxy_request
rr = {}
def get_real_download_url(url, proxy=None):
if 'youtube-episode' not in rr:
rr['youtube-episode'] = re.compile('http://(?:[a-z]+\.)?youtube\.com/v/.*\.swf', re.IGNORECASE)
if rr['youtube-episode'].match(url):
req = proxy_request(url, proxy)
if 'location' in req.msg:
id, tag = (None, None)
for part in req.msg['location'].split('&'):
if part.startswith('video_id='):
id = part[9:]
elif part.startswith('t='):
tag = part[2:]
if id is not None and tag is not None:
next = 'http://www.youtube.com/get_video?video_id='+ id +'&t='+ tag +'&fmt=18'
log('YouTube link resolved: %s => %s', url, next)
return next
return url
def get_real_channel_url(url):
r = re.compile('http://(?:[a-z]+\.)?youtube\.com/user/([a-z0-9]+)', re.IGNORECASE)
m = r.match(url)
if m is not None:
next = 'http://www.youtube.com/rss/user/'+ m.group(1) +'/videos.rss'
log('YouTube link resolved: %s => %s', url, next)
return next
r = re.compile('http://(?:[a-z]+\.)?youtube\.com/profile?user=([a-z0-9]+)', re.IGNORECASE)
m = r.match(url)
if m is not None:
next = 'http://www.youtube.com/rss/user/'+ m.group(1) +'/videos.rss'
log('YouTube link resolved: %s => %s', url, next)
return next
return url