Skip to content

Commit

Permalink
Merge pull request #32 from Keeper-of-the-Keys/episode-artwork
Browse files Browse the repository at this point in the history
Episode artwork
  • Loading branch information
Keeper-of-the-Keys authored Apr 7, 2020
2 parents 24f0938 + 857a4cc commit f5b6422
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 16 deletions.
2 changes: 1 addition & 1 deletion share/man/man1/gpo.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH GPO "1" "March 2020" "gpodder 4.10.0" "User Commands"
.TH GPO "1" "March 2020" "gpodder 4.11.0" "User Commands"
.SH NAME
gpo \- gPodder command-line interface
.SH SYNOPSIS
Expand Down
6 changes: 3 additions & 3 deletions src/gpodder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
# This metadata block gets parsed by setup.py - use single quotes only
__tagline__ = 'Media and podcast aggregator'
__author__ = 'Thomas Perl <[email protected]>'
__version__ = '4.10.0'
__date__ = '2020-03-03'
__relname__ = 'Matar'
__version__ = '4.11.0'
__date__ = '2020-03-31'
__relname__ = 'Geshem'
__copyright__ = '© 2005-2020 Thomas Perl and the gPodder Team'
__license__ = 'ISC / GPLv3 or later'
__url__ = 'http://gpodder.org/'
Expand Down
23 changes: 17 additions & 6 deletions src/gpodder/coverart.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,21 @@ class CoverDownloader(object):
def __init__(self, core):
self.core = core

def get_cover(self, podcast, download=False):
filename = podcast.cover_file
cover_url = podcast.cover_url
def get_cover(self, podcast, download=False, episode=None):
if episode:
# Get episode art.
filename = episode.art_file
cover_url = episode.episode_art_url
else:
# Get podcast cover.
filename = podcast.cover_file
cover_url = podcast.cover_url

if not cover_url:
return None

username = podcast.auth_username
password = podcast.auth_password

# Return already existing files
for extension in self.EXTENSIONS:
Expand All @@ -62,8 +74,7 @@ def get_cover(self, podcast, download=False):

# We have to add username/password, because password-protected
# feeds might keep their cover art also protected (bug 1521)
cover_url = util.url_add_authentication(cover_url, podcast.auth_username,
podcast.auth_password)
cover_url = util.url_add_authentication(cover_url, username, password)

try:
logger.info('Downloading cover art: %s', cover_url)
Expand All @@ -80,7 +91,7 @@ def get_cover(self, podcast, download=False):
extension = filetype
break

if extension is None:
if not extension:
msg = 'Unknown file type: %s (%r)' % (cover_url, data[:6])
raise ValueError(msg)

Expand Down
37 changes: 33 additions & 4 deletions src/gpodder/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class EpisodeModelFields(minidb.Model):
chapters = minidb.JSON
subtitle = str
description_html = str
episode_art_url = str


class PodcastModelFields(minidb.Model):
Expand Down Expand Up @@ -148,6 +149,7 @@ class __minidb_defaults__:
current_position = 0
current_position_updated = 0
last_playback = 0
episode_art_url = ''

def __init__(self, channel):
self._parent = channel
Expand Down Expand Up @@ -462,6 +464,17 @@ def update_from_dict(self, episode_dict):
if k in episode_dict:
setattr(self, k, episode_dict[k])

@property
def art_file(self):
if self.episode_art_url:
filename, extension = util.filename_from_url(self.episode_art_url)

if not filename:
filename = hashlib.sha512(self.episode_art_url.encode('utf-8')).hexdigest()

return os.path.join(self.podcast.save_dir, filename)
return None


class PodcastChannel(PodcastModelFields, PodcastModelMixin):
_common_prefix = str
Expand Down Expand Up @@ -553,9 +566,15 @@ def check_download_folder(self):

known_files.add(filename)

known_files.update(os.path.join(self.save_dir, 'folder' + ext)
known_files.update(os.path.join(self.cover_file + ext)
for ext in coverart.CoverDownloader.EXTENSIONS)

for episode in self.episodes:
filename = episode.art_file
if filename:
known_files.update(os.path.join(episode.art_file + ext)
for ext in coverart.CoverDownloader.EXTENSIONS)

existing_files = {filename for filename in
glob.glob(os.path.join(self.save_dir, '*'))
if not filename.endswith('.partial')}
Expand Down Expand Up @@ -737,6 +756,10 @@ def _consume_custom_feed(self, custom_feed):
# Add new episodes to episodes
self.episodes.extend(new_episodes)

# Verify that all episode art is up-to-date
for episode in self.episodes:
self.model.core.cover_downloader.get_cover(self, download=True, episode=episode)

# Sort episodes by pubdate, descending
self.episodes.sort(key=lambda e: e.published, reverse=True)

Expand All @@ -753,8 +776,9 @@ def update(self):
logger.info('URL updated: {} -> {}'.format(old_url, self.url))
self._consume_custom_feed(result)

# Download the cover art if it's not yet available
self.model.core.cover_downloader.get_cover(self, download=True)
# Download the cover art if it's not yet available, don't run if no save_dir was created yet.
if self.save_dir:
self.model.core.cover_downloader.get_cover(self, download=True)

self.save()

Expand Down Expand Up @@ -920,7 +944,12 @@ def remove_downloaded(self):

@property
def cover_file(self):
return os.path.join(self.save_dir, 'folder')
if self.cover_url:
filename, extension = util.filename_from_url(self.cover_url)
if not filename:
filename = hashlib.sha512(self.cover_url.encode('utf-8')).hexdigest()
return os.path.join(self.save_dir, filename)
return None


class Model(object):
Expand Down
14 changes: 12 additions & 2 deletions src/gpodder/plugins/soundcloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,12 @@ def get_user_info(self):

def get_coverart(self):
user_info = self.get_user_info()
return user_info.get('avatar_url', None)
avatar_url = user_info.get('avatar_url', None)
if avatar_url:
# Soundcloud API by default returns the URL to "large" artwork - 100x100
# by replacing "-large" with "-original" in the URL we get unresized files.
return avatar_url.replace("-large", "-original")
return avatar_url

def get_user_id(self):
user_info = self.get_user_info()
Expand Down Expand Up @@ -159,7 +164,7 @@ def get_tracks(self, feed, channel):
for track in tracks:
# Prefer stream URL (MP3), fallback to download URL
base_url = track.get('stream_url') if track['streamable'] else track.get('download_url')
if base_url != None:
if base_url:
url = base_url + '?consumer_key=%(consumer_key)s' % {'consumer_key': CONSUMER_KEY}
else:
logger.debug('Skipping track with no base_url')
Expand All @@ -174,6 +179,10 @@ def get_tracks(self, feed, channel):
filetype = self.cache['episodes'][track_guid]['filetype']
read_from_cache += 1

artwork_url = track.get('artwork_url')
if artwork_url:
artwork_url = artwork_url.replace("-large", "-original")

yield {
'title': track.get('title', track.get('permalink')) or ('Unknown track'),
'link': track.get('permalink_url') or 'https://soundcloud.com/' + self.username,
Expand All @@ -184,6 +193,7 @@ def get_tracks(self, feed, channel):
'guid': track_guid,
'published': soundcloud_parsedate(track.get('created_at', None)),
'total_time': int(track.get('duration') / 1000),
'episode_art_url' : artwork_url,
}

logger.debug('Read %d episodes from %d cached episodes', read_from_cache, len(self.cache['episodes']))
Expand Down

0 comments on commit f5b6422

Please sign in to comment.