mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-10 07:22:37 -07:00
Transform images on Cloudinary
This commit is contained in:
parent
87b1118e98
commit
0d7ade8ca4
4 changed files with 106 additions and 25 deletions
|
@ -1693,7 +1693,7 @@ def dbcheck():
|
||||||
|
|
||||||
for row in result:
|
for row in result:
|
||||||
img_hash = notification_handler.set_hash_image_info(
|
img_hash = notification_handler.set_hash_image_info(
|
||||||
rating_key=row['rating_key'], width=600, height=1000, fallback='poster')
|
rating_key=row['rating_key'], width=1000, height=1500, fallback='poster')
|
||||||
data_factory.set_imgur_info(img_hash=img_hash, imgur_title=row['poster_title'],
|
data_factory.set_imgur_info(img_hash=img_hash, imgur_title=row['poster_title'],
|
||||||
imgur_url=row['poster_url'], delete_hash=row['delete_hash'],
|
imgur_url=row['poster_url'], delete_hash=row['delete_hash'],
|
||||||
service='imgur')
|
service='imgur')
|
||||||
|
|
|
@ -17,6 +17,7 @@ import base64
|
||||||
import cloudinary
|
import cloudinary
|
||||||
from cloudinary.api import delete_resources_by_tag
|
from cloudinary.api import delete_resources_by_tag
|
||||||
from cloudinary.uploader import upload
|
from cloudinary.uploader import upload
|
||||||
|
from cloudinary.utils import cloudinary_url
|
||||||
import datetime
|
import datetime
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import geoip2.database, geoip2.errors
|
import geoip2.database, geoip2.errors
|
||||||
|
@ -720,14 +721,13 @@ def get_img_service(include_self=False):
|
||||||
|
|
||||||
def upload_to_imgur(img_data, img_title='', rating_key='', fallback=''):
|
def upload_to_imgur(img_data, img_title='', rating_key='', fallback=''):
|
||||||
""" Uploads an image to Imgur """
|
""" Uploads an image to Imgur """
|
||||||
client_id = plexpy.CONFIG.IMGUR_CLIENT_ID
|
|
||||||
img_url = delete_hash = ''
|
img_url = delete_hash = ''
|
||||||
|
|
||||||
if not client_id:
|
if not plexpy.CONFIG.IMGUR_CLIENT_ID:
|
||||||
logger.error(u"Tautulli Helpers :: Cannot upload image to Imgur. No Imgur client id specified in the settings.")
|
logger.error(u"Tautulli Helpers :: Cannot upload image to Imgur. No Imgur client id specified in the settings.")
|
||||||
return img_url, delete_hash
|
return img_url, delete_hash
|
||||||
|
|
||||||
headers = {'Authorization': 'Client-ID %s' % client_id}
|
headers = {'Authorization': 'Client-ID %s' % plexpy.CONFIG.IMGUR_CLIENT_ID}
|
||||||
data = {'image': base64.b64encode(img_data),
|
data = {'image': base64.b64encode(img_data),
|
||||||
'title': img_title.encode('utf-8'),
|
'title': img_title.encode('utf-8'),
|
||||||
'name': str(rating_key) + '.png',
|
'name': str(rating_key) + '.png',
|
||||||
|
@ -755,9 +755,11 @@ def upload_to_imgur(img_data, img_title='', rating_key='', fallback=''):
|
||||||
|
|
||||||
def delete_from_imgur(delete_hash, img_title='', fallback=''):
|
def delete_from_imgur(delete_hash, img_title='', fallback=''):
|
||||||
""" Deletes an image from Imgur """
|
""" Deletes an image from Imgur """
|
||||||
client_id = plexpy.CONFIG.IMGUR_CLIENT_ID
|
if not plexpy.CONFIG.IMGUR_CLIENT_ID:
|
||||||
|
logger.error(u"Tautulli Helpers :: Cannot delete image from Imgur. No Imgur client id specified in the settings.")
|
||||||
|
return False
|
||||||
|
|
||||||
headers = {'Authorization': 'Client-ID %s' % client_id}
|
headers = {'Authorization': 'Client-ID %s' % plexpy.CONFIG.IMGUR_CLIENT_ID}
|
||||||
|
|
||||||
response, err_msg, req_msg = request.request_response2('https://api.imgur.com/3/image/%s' % delete_hash, 'DELETE',
|
response, err_msg, req_msg = request.request_response2('https://api.imgur.com/3/image/%s' % delete_hash, 'DELETE',
|
||||||
headers=headers)
|
headers=headers)
|
||||||
|
@ -775,17 +777,18 @@ def delete_from_imgur(delete_hash, img_title='', fallback=''):
|
||||||
|
|
||||||
def upload_to_cloudinary(img_data, img_title='', rating_key='', fallback=''):
|
def upload_to_cloudinary(img_data, img_title='', rating_key='', fallback=''):
|
||||||
""" Uploads an image to Cloudinary """
|
""" Uploads an image to Cloudinary """
|
||||||
cloudinary.config(
|
|
||||||
cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME,
|
|
||||||
api_key=plexpy.CONFIG.CLOUDINARY_API_KEY,
|
|
||||||
api_secret=plexpy.CONFIG.CLOUDINARY_API_SECRET
|
|
||||||
)
|
|
||||||
img_url = ''
|
img_url = ''
|
||||||
|
|
||||||
if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET:
|
if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET:
|
||||||
logger.error(u"Tautulli Helpers :: Cannot upload image to Cloudinary. Cloudinary settings not specified in the settings.")
|
logger.error(u"Tautulli Helpers :: Cannot upload image to Cloudinary. Cloudinary settings not specified in the settings.")
|
||||||
return img_url
|
return img_url
|
||||||
|
|
||||||
|
cloudinary.config(
|
||||||
|
cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME,
|
||||||
|
api_key=plexpy.CONFIG.CLOUDINARY_API_KEY,
|
||||||
|
api_secret=plexpy.CONFIG.CLOUDINARY_API_SECRET
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = upload('data:image/png;base64,{}'.format(base64.b64encode(img_data)),
|
response = upload('data:image/png;base64,{}'.format(base64.b64encode(img_data)),
|
||||||
public_id='{}_{}'.format(fallback, rating_key),
|
public_id='{}_{}'.format(fallback, rating_key),
|
||||||
|
@ -801,6 +804,10 @@ def upload_to_cloudinary(img_data, img_title='', rating_key='', fallback=''):
|
||||||
|
|
||||||
def delete_from_cloudinary(rating_key):
|
def delete_from_cloudinary(rating_key):
|
||||||
""" Deletes an image from Cloudinary """
|
""" Deletes an image from Cloudinary """
|
||||||
|
if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET:
|
||||||
|
logger.error(u"Tautulli Helpers :: Cannot delete image from Cloudinary. Cloudinary settings not specified in the settings.")
|
||||||
|
return False
|
||||||
|
|
||||||
cloudinary.config(
|
cloudinary.config(
|
||||||
cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME,
|
cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME,
|
||||||
api_key=plexpy.CONFIG.CLOUDINARY_API_KEY,
|
api_key=plexpy.CONFIG.CLOUDINARY_API_KEY,
|
||||||
|
@ -813,6 +820,47 @@ def delete_from_cloudinary(rating_key):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def cloudinary_transform(rating_key=None, width=1000, height=1500, opacity=100, background='000000', blur=0,
|
||||||
|
img_format='png', img_title='', fallback=None):
|
||||||
|
url = ''
|
||||||
|
|
||||||
|
if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET:
|
||||||
|
logger.error(u"Tautulli Helpers :: Cannot transform image on Cloudinary. Cloudinary settings not specified in the settings.")
|
||||||
|
return url
|
||||||
|
|
||||||
|
cloudinary.config(
|
||||||
|
cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME,
|
||||||
|
api_key=plexpy.CONFIG.CLOUDINARY_API_KEY,
|
||||||
|
api_secret=plexpy.CONFIG.CLOUDINARY_API_SECRET
|
||||||
|
)
|
||||||
|
|
||||||
|
img_options = {}
|
||||||
|
|
||||||
|
if width != 1000:
|
||||||
|
img_options['width'] = width
|
||||||
|
img_options['crop'] = 'fill'
|
||||||
|
if height != 1500:
|
||||||
|
img_options['height'] = height
|
||||||
|
img_options['crop'] = 'fill'
|
||||||
|
if opacity != 100:
|
||||||
|
img_options['opacity'] = opacity
|
||||||
|
if background != '000000':
|
||||||
|
img_options['background'] = 'rgb:{}'.format(background)
|
||||||
|
if blur != 0:
|
||||||
|
img_options['effect'] = 'blur:{}'.format(blur * 100)
|
||||||
|
|
||||||
|
if img_options:
|
||||||
|
img_options['format'] = img_format
|
||||||
|
|
||||||
|
try:
|
||||||
|
url, options = cloudinary_url('{}_{}'.format(fallback, rating_key), **img_options)
|
||||||
|
logger.debug(u"Tautulli Helpers :: Image '{}' ({}) transformed on Cloudinary.".format(img_title, fallback))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(u"Tautulli Helpers :: Unable to transform image '{}' ({}) on Cloudinary: {}".format(img_title, fallback, e))
|
||||||
|
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
def cache_image(url, image=None):
|
def cache_image(url, image=None):
|
||||||
"""
|
"""
|
||||||
Saves an image to the cache directory.
|
Saves an image to the cache directory.
|
||||||
|
|
|
@ -1077,7 +1077,7 @@ def format_group_index(group_keys):
|
||||||
return ','.join(num) or '0', ','.join(num00) or '00'
|
return ','.join(num) or '0', ','.join(num00) or '00'
|
||||||
|
|
||||||
|
|
||||||
def get_img_info(img=None, rating_key=None, title='', width=600, height=1000,
|
def get_img_info(img=None, rating_key=None, title='', width=1000, height=1500,
|
||||||
opacity=100, background='000000', blur=0, fallback=None):
|
opacity=100, background='000000', blur=0, fallback=None):
|
||||||
img_info = {'img_title': '', 'img_url': ''}
|
img_info = {'img_title': '', 'img_url': ''}
|
||||||
|
|
||||||
|
@ -1094,6 +1094,26 @@ def get_img_info(img=None, rating_key=None, title='', width=600, height=1000,
|
||||||
img = '/'.join(img_split[:5])
|
img = '/'.join(img_split[:5])
|
||||||
rating_key = rating_key or img_split[3]
|
rating_key = rating_key or img_split[3]
|
||||||
|
|
||||||
|
service = helpers.get_img_service()
|
||||||
|
|
||||||
|
if service == 'cloudinary':
|
||||||
|
if fallback == 'cover':
|
||||||
|
w, h = 1000, 1000
|
||||||
|
elif fallback == 'art':
|
||||||
|
w, h = 1920, 1080
|
||||||
|
else:
|
||||||
|
w, h = 1000, 1500
|
||||||
|
|
||||||
|
image_info = {'img': img,
|
||||||
|
'rating_key': rating_key,
|
||||||
|
'width': w,
|
||||||
|
'height': h,
|
||||||
|
'opacity': 100,
|
||||||
|
'background': '000000',
|
||||||
|
'blur': 0,
|
||||||
|
'fallback': fallback}
|
||||||
|
|
||||||
|
else:
|
||||||
image_info = {'img': img,
|
image_info = {'img': img,
|
||||||
'rating_key': rating_key,
|
'rating_key': rating_key,
|
||||||
'width': width,
|
'width': width,
|
||||||
|
@ -1103,8 +1123,6 @@ def get_img_info(img=None, rating_key=None, title='', width=600, height=1000,
|
||||||
'blur': blur,
|
'blur': blur,
|
||||||
'fallback': fallback}
|
'fallback': fallback}
|
||||||
|
|
||||||
service = helpers.get_img_service()
|
|
||||||
|
|
||||||
# Try to retrieve poster info from the database
|
# Try to retrieve poster info from the database
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
database_img_info = data_factory.get_img_info(service=service, **image_info)
|
database_img_info = data_factory.get_img_info(service=service, **image_info)
|
||||||
|
@ -1140,10 +1158,25 @@ def get_img_info(img=None, rating_key=None, title='', width=600, height=1000,
|
||||||
|
|
||||||
img_info = {'img_title': title, 'img_url': img_url}
|
img_info = {'img_title': title, 'img_url': img_url}
|
||||||
|
|
||||||
|
if img_info['img_url'] and service == 'cloudinary':
|
||||||
|
# Transform image using Cloudinary
|
||||||
|
image_info = {'rating_key': rating_key,
|
||||||
|
'width': width,
|
||||||
|
'height': height,
|
||||||
|
'opacity': opacity,
|
||||||
|
'background': background,
|
||||||
|
'blur': blur,
|
||||||
|
'fallback': fallback,
|
||||||
|
'img_title': title}
|
||||||
|
|
||||||
|
transformed_url = helpers.cloudinary_transform(**image_info)
|
||||||
|
if transformed_url:
|
||||||
|
img_info['img_url'] = transformed_url
|
||||||
|
|
||||||
return img_info
|
return img_info
|
||||||
|
|
||||||
|
|
||||||
def set_hash_image_info(img=None, rating_key=None, width=600, height=1000,
|
def set_hash_image_info(img=None, rating_key=None, width=750, height=1000,
|
||||||
opacity=100, background='000000', blur=0, fallback=None):
|
opacity=100, background='000000', blur=0, fallback=None):
|
||||||
if not rating_key and not img:
|
if not rating_key and not img:
|
||||||
return fallback
|
return fallback
|
||||||
|
|
|
@ -2435,7 +2435,7 @@ class PmsConnect(object):
|
||||||
|
|
||||||
return labels_list
|
return labels_list
|
||||||
|
|
||||||
def get_image(self, img=None, width=600, height=1000, opacity=None, background=None, blur=None,
|
def get_image(self, img=None, width=1000, height=1500, opacity=None, background=None, blur=None,
|
||||||
img_format='png', clip=False, **kwargs):
|
img_format='png', clip=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Return image data as array.
|
Return image data as array.
|
||||||
|
@ -2450,8 +2450,8 @@ class PmsConnect(object):
|
||||||
Output: array
|
Output: array
|
||||||
"""
|
"""
|
||||||
|
|
||||||
width = width or 600
|
width = width or 1000
|
||||||
height = height or 1000
|
height = height or 1500
|
||||||
|
|
||||||
if img:
|
if img:
|
||||||
if clip:
|
if clip:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue