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:
parent
661a4381e1
commit
47c98633e6
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue