[pitivi] medialibrary: Move thumbnails logic to AssetThumbnail
- From: Alexandru Băluț <alexbalut src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] medialibrary: Move thumbnails logic to AssetThumbnail
- Date: Thu, 6 Oct 2016 12:26:01 +0000 (UTC)
commit 043e6479dc77ad7d2a9a4a089a29fe3ced0458e8
Author: Alexandru Băluț <alexandru balut gmail com>
Date: Wed Oct 5 17:05:11 2016 +0200
medialibrary: Move thumbnails logic to AssetThumbnail
Reviewed-by: Thibault Saunier <tsaunier gnome org>
Differential Revision: https://phabricator.freedesktop.org/D1355
pitivi/medialibrary.py | 224 +++++++++++++++++++++++++----------------------
pitivi/utils/ui.py | 4 +
2 files changed, 123 insertions(+), 105 deletions(-)
---
diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py
index 67d7638..adf9ec9 100644
--- a/pitivi/medialibrary.py
+++ b/pitivi/medialibrary.py
@@ -58,6 +58,8 @@ from pitivi.utils.ui import beautify_length
from pitivi.utils.ui import FILE_TARGET_ENTRY
from pitivi.utils.ui import fix_infobar
from pitivi.utils.ui import info_name
+from pitivi.utils.ui import LARGE_THUMB_WIDTH
+from pitivi.utils.ui import SMALL_THUMB_WIDTH
from pitivi.utils.ui import SPACING
from pitivi.utils.ui import URI_TARGET_ENTRY
@@ -168,7 +170,9 @@ class FileChooserExtraWidget(Gtk.Grid, Loggable):
self.app.settings.proxyingStrategy = ProxyingStrategy.AUTOMATIC
-class ThumbnailsDecorator(Loggable):
+class AssetThumbnail(Loggable):
+ """Provider of decorated thumbnails for an asset."""
+
EMBLEMS = {}
PROXIED = "asset-proxied"
NO_PROXY = "no-proxy"
@@ -177,19 +181,123 @@ class ThumbnailsDecorator(Loggable):
DEFAULT_ALPHA = 255
+ icons_by_name = {}
+
for status in [PROXIED, IN_PROGRESS, ASSET_PROXYING_ERROR]:
EMBLEMS[status] = []
for size in [32, 64]:
EMBLEMS[status].append(GdkPixbuf.Pixbuf.new_from_file_at_size(
os.path.join(get_pixmap_dir(), "%s.svg" % status), size, size))
- def __init__(self, thumbs, asset, proxy_manager):
+ def __init__(self, asset, proxy_manager):
Loggable.__init__(self)
- self.src_64, self.src_128 = thumbs
self.__asset = asset
+ self.src_small, self.src_large = self.__get_thumbnails()
self.proxy_manager = proxy_manager
self.decorate()
+ def __get_thumbnails(self):
+ """Gets the base source thumbnails.
+
+ Returns:
+ List[GdkPixbuf.Pixbuf]: The small thumbnail and the large thumbnail
+ to be decorated.
+ """
+ video_streams = [
+ stream_info
+ for stream_info in self.__asset.get_info().get_stream_list()
+ if isinstance(stream_info, GstPbutils.DiscovererVideoInfo)]
+ if video_streams:
+ # Check if the files have thumbnails in the user's cache directory.
+ # https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html#DIRECTORY
+ real_uri = get_proxy_target(self.__asset).props.id
+ quoted_uri = quote_uri(real_uri)
+ thumbnail_hash = md5(quoted_uri.encode()).hexdigest()
+ small_thumb, large_thumb = (None, None)
+ try:
+ thumb_dir = os.path.join(os.environ["XDG_CACHE_HOME"], "thumbnail")
+ small_thumb, large_thumb = self.__get_thumbnail_in_dir(
+ thumb_dir, thumbnail_hash)
+ except KeyError:
+ pass
+ if not small_thumb:
+ thumb_dir = os.path.expanduser("~/.cache/thumbnails/")
+ small_thumb, large_thumb = self.__get_thumbnail_in_dir(
+ thumb_dir, thumbnail_hash)
+ if not small_thumb:
+ # Older version of the spec also mentioned $HOME/.thumbnails
+ thumb_dir = os.path.expanduser("~/.thumbnails/")
+ small_thumb, large_thumb = self.__get_thumbnail_in_dir(
+ thumb_dir, thumbnail_hash)
+
+ if not small_thumb:
+ if self.__asset.is_image():
+ small_thumb, large_thumb = self.__get_icons("image-x-generic")
+ else:
+ # Build or reuse a ThumbnailCache.
+ thumb_cache = ThumbnailCache.get(self.__asset)
+ small_thumb = thumb_cache.getPreviewThumbnail()
+ if not small_thumb:
+ small_thumb, large_thumb = self.__get_icons("video-x-generic")
+ else:
+ large_thumb = small_thumb.scale_simple(
+ 128, small_thumb.get_height() * 2,
+ GdkPixbuf.InterpType.BILINEAR)
+ else:
+ small_thumb, large_thumb = self.__get_icons("audio-x-generic")
+ return small_thumb, large_thumb
+
+ def __get_thumbnail_in_dir(self, dir, hash):
+ """Gets pixbufs for the specified thumbnail.
+
+ Args:
+ dir (str): The directory where the thumbnails can be found.
+ hash (str): The hash identifying the image.
+
+ Returns:
+ List[GdkPixbuf.Pixbuf]: The small thumbnail and the large thumbnail
+ if available, otherwise (None, None).
+ """
+ path_128 = dir + "normal/" + hash + ".png"
+ interpolation = GdkPixbuf.InterpType.BILINEAR
+
+ # The cache dirs might have resolutions of 256 and/or 128,
+ # while we need 128 (for iconview) and 64 (for listview).
+ # First, try the 128 version since that's the native resolution we want.
+ try:
+ large_thumb = GdkPixbuf.Pixbuf.new_from_file(path_128)
+ w, h = large_thumb.get_width(), large_thumb.get_height()
+ small_thumb = large_thumb.scale_simple(w / 2, h / 2, interpolation)
+ return small_thumb, large_thumb
+ except GLib.GError:
+ # path_128 doesn't exist, try the 256 version.
+ path_256 = dir + "large/" + hash + ".png"
+ try:
+ thumb_256 = GdkPixbuf.Pixbuf.new_from_file(path_256)
+ w, h = thumb_256.get_width(), thumb_256.get_height()
+ large_thumb = thumb_256.scale_simple(w / 2, h / 2, interpolation)
+ small_thumb = thumb_256.scale_simple(w / 4, h / 4, interpolation)
+ return small_thumb, large_thumb
+ except GLib.GError:
+ return None, None
+
+ @classmethod
+ def __get_icons(cls, icon_name):
+ if icon_name not in cls.icons_by_name:
+ small_icon = cls.__get_icon(icon_name, SMALL_THUMB_WIDTH)
+ large_icon = cls.__get_icon(icon_name, LARGE_THUMB_WIDTH)
+ cls.icons_by_name[icon_name] = (small_icon, large_icon)
+ return cls.icons_by_name[icon_name]
+
+ @classmethod
+ def __get_icon(cls, icon_name, size):
+ icon_theme = Gtk.IconTheme.get_default()
+ try:
+ icon = icon_theme.load_icon(icon_name, size, 0)
+ except GLib.Error:
+ icon = icon_theme.load_icon("dialog-question", size, 0)
+ return icon
+
def __setState(self):
asset = self.__asset
target = asset.get_proxy_target()
@@ -206,13 +314,13 @@ class ThumbnailsDecorator(Loggable):
def decorate(self):
self.__setState()
if self.state == self.NO_PROXY:
- self.thumb_64 = self.src_64
- self.thumb_128 = self.src_128
+ self.small_thumb = self.src_small
+ self.large_thumb = self.src_large
return
- self.thumb_64 = self.src_64.copy()
- self.thumb_128 = self.src_128.copy()
- for thumb, src in zip([self.thumb_64, self.thumb_128],
+ self.small_thumb = self.src_small.copy()
+ self.large_thumb = self.src_large.copy()
+ for thumb, src in zip([self.small_thumb, self.large_thumb],
self.EMBLEMS[self.state]):
# We need to set dest_y == offset_y for the source image
# not to be cropped, that API is weird.
@@ -577,14 +685,6 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
text = GLib.markup_escape_text(text)
return text in model.get_value(iter, COL_INFOTEXT).lower()
- def _getIcon(self, icon_name, size):
- icontheme = Gtk.IconTheme.get_default()
- try:
- icon = icontheme.load_icon(icon_name, size, 0)
- except GLib.Error:
- icon = icontheme.load_icon("dialog-question", size, 0)
- return icon
-
def _connectToProject(self, project):
"""Connects signal handlers to the specified project."""
project.connect("asset-added", self._assetAddedCb)
@@ -664,45 +764,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
dialog.show()
- def _getThumbnailInDir(self, dir, hash):
- """Gets pixbufs for the specified thumbnail.
-
- Args:
- dir (str): The directory where the thumbnails can be found.
- hash (str): The hash identifying the image.
-
- Returns:
- List[GdkPixbuf.Pixbuf]: The thumb_64 and thumb_128 if available,
- None otherwise.
- """
- path_128 = dir + "normal/" + hash + ".png"
- interpolation = GdkPixbuf.InterpType.BILINEAR
-
- # The cache dirs might have resolutions of 256 and/or 128,
- # while we need 128 (for iconview) and 64 (for listview).
- # First, try the 128 version since that's the native resolution we want.
- try:
- thumb_128 = GdkPixbuf.Pixbuf.new_from_file(path_128)
- w, h = thumb_128.get_width(), thumb_128.get_height()
- thumb_64 = thumb_128.scale_simple(w / 2, h / 2, interpolation)
- return thumb_64, thumb_128
- except GLib.GError:
- # path_128 doesn't exist, try the 256 version.
- path_256 = dir + "large/" + hash + ".png"
- try:
- thumb_256 = GdkPixbuf.Pixbuf.new_from_file(path_256)
- w, h = thumb_256.get_width(), thumb_256.get_height()
- thumb_128 = thumb_256.scale_simple(w / 2, h / 2, interpolation)
- thumb_64 = thumb_256.scale_simple(w / 4, h / 4, interpolation)
- return thumb_64, thumb_128
- except GLib.GError:
- return None, None
-
def _addAsset(self, asset):
- # 128 is the normal size for thumbnails, but for *icons* it looks
- # insane
- SMALL_SIZE = 48
- LARGE_SIZE = 96
info = asset.get_info()
if self.app.proxy_manager.is_proxy_asset(asset) and \
@@ -713,59 +775,11 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
self.debug("Adding asset %s", asset.props.id)
- # The code below tries to read existing thumbnails from the freedesktop
- # thumbnails directory (~/.thumbnails). The filenames are simply
- # the file URI hashed with md5, so we can retrieve them easily.
- video_streams = [
- stream_info for stream_info in info.get_stream_list()
- if isinstance(stream_info, GstPbutils.DiscovererVideoInfo)]
- real_uri = get_proxy_target(asset).props.id
- if video_streams:
- # From the freedesktop spec: "if the environment variable
- # $XDG_CACHE_HOME is set and not blank then the directory
- # $XDG_CACHE_HOME/thumbnails will be used, otherwise
- # $HOME/.cache/thumbnails will be used."
- # Older version of the spec also mentioned $HOME/.thumbnails
- quoted_uri = quote_uri(real_uri)
- thumbnail_hash = md5(quoted_uri.encode()).hexdigest()
- try:
- thumb_dir = os.path.join(os.environ["XDG_CACHE_HOME"], "thumbnail")
- thumb_64, thumb_128 = self._getThumbnailInDir(
- thumb_dir, thumbnail_hash)
- except KeyError:
- thumb_64, thumb_128 = (None, None)
- if thumb_64 is None:
- thumb_dir = os.path.expanduser("~/.cache/thumbnails/")
- thumb_64, thumb_128 = self._getThumbnailInDir(
- thumb_dir, thumbnail_hash)
- if thumb_64 is None:
- thumb_dir = os.path.expanduser("~/.thumbnails/")
- thumb_64, thumb_128 = self._getThumbnailInDir(
- thumb_dir, thumbnail_hash)
- if thumb_64 is None:
- if asset.is_image():
- thumb_64 = self._getIcon("image-x-generic", SMALL_SIZE)
- thumb_128 = self._getIcon("image-x-generic", LARGE_SIZE)
- else:
- thumb_cache = ThumbnailCache.get(asset)
- thumb_64 = thumb_cache.getPreviewThumbnail()
- if not thumb_64:
- thumb_64 = self._getIcon("video-x-generic", SMALL_SIZE)
- thumb_128 = self._getIcon("video-x-generic", LARGE_SIZE)
- else:
- thumb_128 = thumb_64.scale_simple(
- 128, thumb_64.get_height() * 2,
- GdkPixbuf.InterpType.BILINEAR)
- else:
- thumb_64 = self._getIcon("audio-x-generic", SMALL_SIZE)
- thumb_128 = self._getIcon("audio-x-generic", LARGE_SIZE)
-
- thumbs_decorator = ThumbnailsDecorator([thumb_64, thumb_128], asset,
- self.app.proxy_manager)
+ thumbs_decorator = AssetThumbnail(asset, self.app.proxy_manager)
duration = beautify_length(info.get_duration())
name = info_name(asset)
- self.pending_rows.append((thumbs_decorator.thumb_64,
- thumbs_decorator.thumb_128,
+ self.pending_rows.append((thumbs_decorator.small_thumb,
+ thumbs_decorator.large_thumb,
beautify_asset(asset),
asset,
asset.props.id,
diff --git a/pitivi/utils/ui.py b/pitivi/utils/ui.py
index 84ab335..a580479 100644
--- a/pitivi/utils/ui.py
+++ b/pitivi/utils/ui.py
@@ -59,6 +59,10 @@ SNAPBAR_WIDTH = 5
SNAPBAR_COLOR = (127, 153, 204)
LAYER_HEIGHT = 130
+SMALL_THUMB_WIDTH = 64
+# 128 is the normal size for thumbnails, but for *icons* it looks insane.
+LARGE_THUMB_WIDTH = 96
+
# Drag and drop
FILE_TARGET_ENTRY = Gtk.TargetEntry.new("text/plain", 0, 0)
URI_TARGET_ENTRY = Gtk.TargetEntry.new("text/uri-list", 0, 0)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]