The 'link' property might not exist, for example when a user is not a Cloud subscriber.
144 lines
5.0 KiB
Python
Executable File
144 lines
5.0 KiB
Python
Executable File
import os.path
|
|
|
|
from .resource import List
|
|
from .resource import Find
|
|
from .resource import Create
|
|
from .resource import Post
|
|
from .resource import Update
|
|
from .resource import Delete
|
|
from .resource import Replace
|
|
|
|
from . import utils
|
|
|
|
THUMBNAIL_SIZES = 'sbtmlh'
|
|
|
|
|
|
class File(List, Find, Create, Post, Update, Delete, Replace):
|
|
"""Node class wrapping the REST nodes endpoint
|
|
"""
|
|
path = "files"
|
|
file_server_path = "file_storage/file"
|
|
build_previews_server_path = "file_storage/build_previews"
|
|
ensure_query_projections = {'backend': 1, 'file_path': 1, 'project': 1, 'content_type': 1,
|
|
'link': 1, 'link_expires': 1}
|
|
|
|
def post_file(self, file_path, name=None, api=None):
|
|
"""Stores a file on the database or static folder.
|
|
:param file: A file object
|
|
"""
|
|
api = api or self.api
|
|
url = utils.join_url(self.file_server_path)
|
|
file_ = open(file_path, 'rb')
|
|
files = {'data': file_}
|
|
api.post(url, {"name": name}, {}, files)
|
|
file_.close()
|
|
# self.error = None
|
|
# self.merge(new_attributes)
|
|
return self.success()
|
|
|
|
def build_previews(self, path, api=None):
|
|
"""Stores a file on the database or static folder.
|
|
:param path: A file path
|
|
"""
|
|
api = api or self.api
|
|
url = utils.join_url(self.build_previews_server_path, path)
|
|
api.get(url)
|
|
return self.success()
|
|
|
|
# def children(self, api=None):
|
|
# """Collect children (variations) of the current file. Used to connect
|
|
# different resolutions of the same picture, or multiple versions of the
|
|
# same video in different formats/containers.
|
|
|
|
# TODO: add params to support pagination.
|
|
# """
|
|
# api = api or self.api
|
|
# files = self.all({'where': '{"parent": "%s"}' % self._id}, api=api)
|
|
# if not files._items:
|
|
# return None
|
|
# return files
|
|
|
|
def thumbnail(self, size, api=None):
|
|
"""Utility to replace a component of an image link so that it points to
|
|
a thumbnail, without querying the database.
|
|
"""
|
|
|
|
if size not in THUMBNAIL_SIZES:
|
|
raise ValueError("Size should be in ({}), not {}"
|
|
.format(', '.join(THUMBNAIL_SIZES), size))
|
|
|
|
if self.variations:
|
|
thumbnail = next((item for item in self['variations']
|
|
if item['size'] == size), None)
|
|
if thumbnail:
|
|
return thumbnail['link']
|
|
|
|
if self.backend == 'gcs':
|
|
thumbnail_link = self.thumbnail_file(size, api=api)
|
|
return thumbnail_link
|
|
|
|
if self.link:
|
|
root, ext = os.path.splitext(self.link)
|
|
return "{0}-{1}.jpg".format(root, size)
|
|
|
|
return None
|
|
|
|
def thumbnail_file(self, size, api=None):
|
|
"""Delivers a single thumbnail (child) file for an image. Before returning
|
|
we check that the parent is actually an image.
|
|
:param path: the size (s, b, t, m, l, h)
|
|
|
|
@returns: a link to the thumbnail, or None if there is no thumbnail
|
|
@rtype: str
|
|
"""
|
|
api = api or self.api
|
|
|
|
if size not in THUMBNAIL_SIZES:
|
|
raise ValueError("Size should be in ({}), not {}"
|
|
.format(', '.join(THUMBNAIL_SIZES), size))
|
|
|
|
# We check from the content_type if the file is an image
|
|
if self.content_type.split('/')[0] != 'image':
|
|
# File is not an image, so no thumbnail available
|
|
return None
|
|
|
|
if self.variations:
|
|
thumbnail = next((item for item in self['variations']
|
|
if item['size'] == size), None)
|
|
if thumbnail:
|
|
return thumbnail['link']
|
|
else:
|
|
thumbnail = self.find_first(
|
|
{'where': {"parent": self._id, "size": size}},
|
|
api=api)
|
|
return thumbnail.link
|
|
|
|
def stream_thumb_to_file(self, directory, desired_size, api=None):
|
|
"""Streams a thumbnail to a file.
|
|
|
|
@param directory: the directory to save the file to.
|
|
@param desired_size: thumbnail size
|
|
@return: the absolute path of the downloaded file.
|
|
"""
|
|
|
|
api = api or self.api
|
|
thumb_link = self.thumbnail_file(desired_size, api=api)
|
|
|
|
if thumb_link is None:
|
|
raise ValueError("File {} has no thumbnail of size {}"
|
|
.format(self._id, desired_size))
|
|
|
|
root, ext = os.path.splitext(self.file_path)
|
|
thumb_fname = "{0}-{1}.jpg".format(root, desired_size)
|
|
|
|
# thumb is now a dict like:
|
|
# {'content_type': 'image/jpeg', 'height': 160, 'length': 5846,
|
|
# 'link': 'https://storage.googleapis.com/asdlajsdhaukihuwefiuh',
|
|
# 'width': 160, 'size': 'b', 'file_path': '65b526639295c0dd9dc99cf54a0a606cd4924f1d-b.jpg',
|
|
# 'md5': '--', 'format': 'jpg'},
|
|
|
|
thumb_path = os.path.abspath(os.path.join(directory, thumb_fname))
|
|
utils.download_to_file(thumb_link, thumb_path)
|
|
|
|
return thumb_path
|