Determine episode duration (bug 811)

This patch adds two methods for detecting the
episode length (time units, not bytes):

 * iTunes-specific "duration" in the RSS feed
 * GStreamer-based length detection after download

The patch also adds duration information to the
tooltip in the episode list as a first step for
displaying this information in the UI.
This commit is contained in:
Thomas Perl 2010-06-04 20:43:38 +02:00
parent 7917c78ee8
commit 7c20ffd167
3 changed files with 85 additions and 9 deletions

View File

@ -237,25 +237,25 @@ class EpisodeListModel(gtk.ListStore):
show_missing = False
status_icon = None
status_icon_to_build_from_file = False
tooltip = ''
tooltip = []
view_show_undeleted = True
view_show_downloaded = False
view_show_unplayed = False
icon_theme = gtk.icon_theme_get_default()
if downloading is not None and downloading(episode):
tooltip = _('Downloading')
tooltip.append(_('Downloading'))
status_icon = self.ICON_DOWNLOADING
view_show_downloaded = True
view_show_unplayed = True
else:
if episode.state == gpodder.STATE_DELETED:
tooltip = _('Deleted')
tooltip.append(_('Deleted'))
status_icon = self.ICON_DELETED
view_show_undeleted = False
elif episode.state == gpodder.STATE_NORMAL and \
not episode.is_played:
tooltip = _('New episode')
tooltip.append(_('New episode'))
status_icon = self.ICON_NEW
view_show_downloaded = True
view_show_unplayed = True
@ -322,9 +322,14 @@ class EpisodeListModel(gtk.ListStore):
tooltip.append(_('deletion prevented'))
if episode.total_time > 0 and episode.current_position:
tooltip.append('%d%%' % (100.*float(episode.current_position)/float(episode.total_time)))
tooltip.append('%d%%' % (100.*float(episode.current_position)/float(episode.total_time),))
tooltip = ', '.join(tooltip)
if episode.total_time:
total_time = util.format_time(episode.total_time)
if total_time:
tooltip.append(total_time)
tooltip = ', '.join(tooltip)
if status_icon is not None:
status_icon = self._get_tree_icon(status_icon, show_bullet, \

View File

@ -28,6 +28,7 @@ from gpodder import util
from gpodder import feedcore
from gpodder import youtube
from gpodder import corestats
from gpodder import gstreamer
from gpodder.liblogger import log
@ -690,6 +691,13 @@ class PodcastEpisode(PodcastModelObject):
episode.link = entry.get('link', '')
episode.description = entry.get('summary', '')
try:
# Parse iTunes-specific podcast duration metadata
total_time = util.parse_time(entry.get('itunes_duration', ''))
episode.total_time = total_time
except:
pass
# Fallback to subtitle if summary is not available0
if not episode.description:
episode.description = entry.get('subtitle', '')
@ -804,7 +812,7 @@ class PodcastEpisode(PodcastModelObject):
# Time attributes
self.total_time = 0
self.current_position = 0
self.current_position_updated = time.time()
self.current_position_updated = 0
def get_is_locked(self):
return self._is_locked
@ -823,6 +831,22 @@ class PodcastEpisode(PodcastModelObject):
self.state = gpodder.STATE_DOWNLOADED
self.is_played = False
self.length = os.path.getsize(filename)
if not self.total_time:
try:
length = gstreamer.get_track_length(filename)
if length is not None:
length = int(length/1000)
log('Detected media length: %d seconds', length, \
sender=self)
self.total_time = length
self.db.save_episode(self)
self.db.commit()
return
except Exception, e:
log('Error while detecting media length: %s', str(e), \
sender=self)
self.db.save_downloaded_episode(self)
self.db.commit()

View File

@ -1039,8 +1039,55 @@ def bluetooth_send_file(filename):
else:
log('Cannot send file. Please install "bluetooth-sendto" or "gnome-obex-send".')
return False
def format_time(value):
"""Format a seconds value to a string
>>> format_time(0)
'00:00'
>>> format_time(20)
'00:20'
>>> format_time(3600)
'01:00:00'
>>> format_time(10921)
'03:02:01'
"""
dt = datetime.datetime.utcfromtimestamp(value)
if dt.hour == 0:
return dt.strftime('%M:%S')
else:
return dt.strftime('%H:%M:%S')
def parse_time(value):
"""Parse a time string into seconds
>>> parse_time('00:00')
0
>>> parse_time('00:00:00')
0
>>> parse_time('00:20')
20
>>> parse_time('00:00:20')
20
>>> parse_time('01:00:00')
3600
>>> parse_time('03:02:01')
10921
"""
if not value:
raise ValueError('Invalid value: %s' % (str(value),))
for format in ('%H:%M:%S', '%M:%S'):
try:
t = time.strptime(value, format)
return (t.tm_hour * 60 + t.tm_min) * 60 + t.tm_sec
except ValueError, ve:
continue
return int(value)
def format_seconds_to_hour_min_sec(seconds):
"""
Take the number of seconds and format it into a