WIP: File Preview support

This commit is contained in:
Eibriel
2015-05-08 11:28:58 -03:00
parent 7c68cb7fb4
commit 405b3c0a3d
3 changed files with 141 additions and 38 deletions

View File

@@ -178,7 +178,7 @@ class ValidateCustomFields(Validator):
def post_item(entry, data): def post_item(entry, data):
post_internal(entry, data) return post_internal(entry, data)
app = Eve(validator=ValidateCustomFields, auth=CustomTokenAuth) app = Eve(validator=ValidateCustomFields, auth=CustomTokenAuth)

View File

@@ -1,19 +1,45 @@
import os import os
import hashlib
from flask import Blueprint from flask import Blueprint
from flask import request from flask import request
from application import app from application import app
from application import post_item
from datetime import datetime
from PIL import Image from PIL import Image
from bson import ObjectId
RFC1123_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
file_server = Blueprint('file_server', __name__, file_server = Blueprint('file_server', __name__,
template_folder='templates', template_folder='templates',
static_folder='static/storage') static_folder='static/storage')
@file_server.route('/file/thumbnail/<file_name>') def hashfile(afile, hasher, blocksize=65536):
def thumbnail(file_name=None): buf = afile.read(blocksize)
while len(buf) > 0:
hasher.update(buf)
buf = afile.read(blocksize)
return hasher.hexdigest()
@file_server.route('/build_previews/<file_name>')
def build_previews(file_name=None):
from pymongo import MongoClient
# Get File
client = MongoClient()
db = client.eve
file_ = db.files.find({"path": "{0}".format(file_name)})
file_ = file_[0]
user = file_['user']
folder_name = file_name[:2] folder_name = file_name[:2]
file_folder_path = os.path.join(app.config['FILE_STORAGE'], file_folder_path = os.path.join(app.config['FILE_STORAGE'],
folder_name) folder_name)
@@ -22,49 +48,108 @@ def thumbnail(file_name=None):
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
return "", 404 return "", 404
format_ = "jpeg"
formats = ["jpeg", "png"]
size = "s"
sizes = ["xs", "s", "m", "l", "xl"] sizes = ["xs", "s", "m", "l", "xl"]
size_dict= { size_dict = {
"xs": (32, 32), "xs": (32, 32),
"s": (64, 64), "s": (64, 64),
"m": (128, 128), "m": (128, 128),
"l": (640, 480), "l": (640, 480),
"xl": (1024, 768) "xl": (1024, 768)
} }
if "format" in request.args:
if request.args['format'] in formats:
format_ = request.args['format']
if "size" in request.args:
if request.args['size'] in sizes:
size = request.args['size']
# The Thumbnail already exist?
thumbnail_folder_path = os.path.join(file_folder_path, size)
thumbnail_file_path = os.path.join(thumbnail_folder_path, file_name)
if os.path.isfile(thumbnail_file_path):
file_static_path = os.path.join("", folder_name, size, file_name)
return file_server.send_static_file(file_static_path)
# Create thumbnail # Generate
if not os.path.exists(thumbnail_folder_path): preview_list = []
os.mkdir(thumbnail_folder_path) for size in sizes:
if not os.path.isfile(thumbnail_file_path): resized_file_name = "{0}_{1}".format(size, file_name)
try: resized_file_path = os.path.join(
im = Image.open(file_path) app.config['FILE_STORAGE'],
except IOError: resized_file_name)
return "", 500
im.thumbnail(size_dict[size]) # Create thumbnail
try: if not os.path.isfile(resized_file_path):
im.save(thumbnail_file_path) try:
except IOError: im = Image.open(file_path)
raise except IOError:
return "", 500 return "", 500
im.thumbnail(size_dict[size])
try:
im.save(resized_file_path)
except IOError:
return "", 500
# file_static_path = os.path.join("", folder_name, size, file_name)
picture_file_file = open(resized_file_path, 'rb')
hash_ = hashfile(picture_file_file, hashlib.md5())
name = "{0}{1}".format(hash_,
os.path.splitext(file_name)[1])
picture_file_file.close()
description = "Thumbnail {0} for file {1}".format(
size, file_name)
prop = {}
prop['name'] = resized_file_name
prop['description'] = description
prop['user'] = user
prop['is_preview'] = True
prop['preview_name'] = "{0}_png".format(size)
# TODO set proper contentType and length
prop['contentType'] = 'image/png'
prop['length'] = 0
prop['uploadDate'] = datetime.strftime(
datetime.now(), RFC1123_DATE_FORMAT)
prop['md5'] = hash_
prop['filename'] = resized_file_name
prop['backend'] = 'attract'
prop['path'] = name
entry = post_item ('files', prop)
if entry[0]['_status'] == 'ERR':
entry = db.files.find({"path": name})
entry = entry[0]
prop['_id'] = entry['_id']
new_folder_name = name[:2]
new_folder_path = os.path.join(
app.config['FILE_STORAGE'],
new_folder_name)
new_file_path = os.path.join(
new_folder_path,
name)
if not os.path.exists(new_folder_path):
os.makedirs(new_folder_path)
# Clean up temporary file
os.rename(
resized_file_path,
new_file_path)
preview_list.append(str(prop['_id']))
#print (new_file_path)
# Add previews to file
previews = []
try:
previews = file_['previews']
except KeyError:
pass
preview_list = preview_list + previews
#print (previews)
#print (preview_list)
#print (file_['_id'])
file_ = db.files.update(
{"_id": ObjectId(file_['_id'])},
{"$set": {"previews": preview_list}}
)
#print (file_)
return "", 200
file_static_path = os.path.join("", folder_name, size, file_name)
return file_server.send_static_file(file_static_path)
return "", 500
@file_server.route('/file', methods=['POST']) @file_server.route('/file', methods=['POST'])
@file_server.route('/file/<file_name>') @file_server.route('/file/<file_name>')

View File

@@ -9,7 +9,7 @@ RESOURCE_METHODS = ['GET', 'POST', 'DELETE']
# individual items (defaults to read-only item access). # individual items (defaults to read-only item access).
ITEM_METHODS = ['GET', 'PUT', 'DELETE', 'PATCH'] ITEM_METHODS = ['GET', 'PUT', 'DELETE', 'PATCH']
PAGINATION_LIMIT = 100 PAGINATION_LIMIT = 999
# To be implemented on Eve 0.6 # To be implemented on Eve 0.6
# RETURN_MEDIA_AS_URL = True # RETURN_MEDIA_AS_URL = True
@@ -144,6 +144,12 @@ files_schema = {
'type': 'string', 'type': 'string',
'required': True, 'required': True,
}, },
'is_preview': {
'type': 'boolean'
},
'preview_name': {
'type': 'string'
},
'user': { 'user': {
'type': 'objectid', 'type': 'objectid',
'required': True, 'required': True,
@@ -176,6 +182,18 @@ files_schema = {
'path': { 'path': {
'type': 'string', 'type': 'string',
'required': True, 'required': True,
'unique': True,
},
'previews': {
'type': 'list',
'schema': {
'type': 'objectid',
'data_relation': {
'resource': 'files',
'field': '_id',
'embeddable': True
}
}
} }
} }