Offload image processing to the Plex server

This commit is contained in:
JonnyWong16 2018-03-17 14:03:27 -07:00
parent 003e890844
commit 1f7be7a4d5
10 changed files with 96 additions and 158 deletions

View file

@ -2,7 +2,6 @@
<%! <%!
import json import json
from plexpy import helpers, notifiers from plexpy import helpers, notifiers
from plexpy.notification_handler import PILLOW
email_notifiers = [n for n in notifiers.get_notifiers() if n['agent_name'] == 'email'] email_notifiers = [n for n in notifiers.get_notifiers() if n['agent_name'] == 'email']
sorted(email_notifiers, key=lambda k: (k['agent_label'], k['friendly_name'], k['id'])) sorted(email_notifiers, key=lambda k: (k['agent_label'], k['friendly_name'], k['id']))

View file

@ -1,6 +1,5 @@
% if data: % if data:
<% <%
from plexpy.notification_handler import PILLOW
recently_added = data['recently_added'] recently_added = data['recently_added']
%> %>
<!doctype html> <!doctype html>
@ -351,26 +350,11 @@
margin: 3px auto !important; margin: 3px auto !important;
} }
.card-background { .card-background {
background-color: #3F4245;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.card-background-preview {
background-color: #3F4245;
background-position: center;
background-size: cover;
opacity: 0.25;
-webkit-filter: blur(3px);
filter: blur(3px);
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 0;
}
.card-poster-container { .card-poster-container {
width: 150px; width: 150px;
margin: 3px; margin: 3px;
@ -387,7 +371,7 @@
height: 150px; height: 150px;
} }
.card-poster { .card-poster {
background-color: #3F4245; background-color: #282828;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
height: 100%; height: 100%;
@ -617,19 +601,14 @@
% else: % else:
<div class="card-instance movie" style="float: left;width: 500px;margin: 3px;border: 1px solid rgba(255,255,255,.1);-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;font-size: 12px;overflow: hidden;position: relative;height: 235px;"> <div class="card-instance movie" style="float: left;width: 500px;margin: 3px;border: 1px solid rgba(255,255,255,.1);-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;font-size: 12px;overflow: hidden;position: relative;height: 235px;">
% endif % endif
% if PILLOW:
% if preview: % if preview:
<div class="card-background" style="background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;"> <div class="card-background" style="background-image: url(${'pms_image_proxy?img=' + movie['art'] + '&width=500&height=280&opacity=25&background=282828&blur=3&fallback=art&refresh=true'});background-position: center;background-size: cover;width: 100%;height: 100%;">
<div class="card-background-preview" style="background-image: url(${'pms_image_proxy?img=' + movie['art'] + '&width=500&height=280&fallback=art&refresh=true'});background-color: #3F4245;background-position: center;background-size: cover;opacity: 0.25;-webkit-filter: blur(3px);filter: blur(3px);position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: 0;"></div>
% else: % else:
<div class="card-background" style="background-image: url(${movie['art_url']});background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;"> <div class="card-background" style="background-image: url(${movie['art_url']});background-position: center;background-size: cover;width: 100%;height: 100%;">
% endif
% else:
<div class="card-background" style="background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;">
% endif % endif
<div class="card-poster-container" style="width: 150px;margin: 3px;border: 1px solid rgba(255,255,255,.1);float: left;position: relative;z-index: 1;height: 225px;"> <div class="card-poster-container" style="width: 150px;margin: 3px;border: 1px solid rgba(255,255,255,.1);float: left;position: relative;z-index: 1;height: 225px;">
<a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${movie['rating_key']}" title="${movie['title']}" target="_blank" style="color: #3498db;text-decoration: underline;"> <a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${movie['rating_key']}" title="${movie['title']}" target="_blank" style="color: #3498db;text-decoration: underline;">
<div class="card-poster" style="background-image: url(${'pms_image_proxy?img=' + movie['thumb'] + '&width=300&height=450&fallback=poster&refresh=true' if preview else movie['poster_url']});background-color: #3F4245;background-position: center;background-size: cover;height: 100%;width: 100%;"> <div class="card-poster" style="background-image: url(${'pms_image_proxy?img=' + movie['thumb'] + '&width=300&height=450&fallback=poster&refresh=true' if preview else movie['poster_url']});background-color: #282828;background-position: center;background-size: cover;height: 100%;width: 100%;">
<div class="card-poster-overlay" style="background: url(https://cdn.discordapp.com/attachments/334355557706235906/401064397780287489/newsletter-view-on-plex-flat.png) bottom right no-repeat;width: 100%;height: 100%;"></div> <div class="card-poster-overlay" style="background: url(https://cdn.discordapp.com/attachments/334355557706235906/401064397780287489/newsletter-view-on-plex-flat.png) bottom right no-repeat;width: 100%;height: 100%;"></div>
</div> </div>
</a> </a>
@ -705,19 +684,14 @@
% else: % else:
<div class="card-instance show" style="float: left;width: 500px;margin: 3px;border: 1px solid rgba(255,255,255,.1);-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;font-size: 12px;overflow: hidden;position: relative;height: 235px;"> <div class="card-instance show" style="float: left;width: 500px;margin: 3px;border: 1px solid rgba(255,255,255,.1);-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;font-size: 12px;overflow: hidden;position: relative;height: 235px;">
% endif % endif
% if PILLOW:
% if preview: % if preview:
<div class="card-background" style="background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;"> <div class="card-background" style="background-image: url(${'pms_image_proxy?img=' + show['art'] + '&width=500&height=280&opacity=25&background=282828&blur=3&fallback=art&refresh=true'});background-position: center;background-size: cover;width: 100%;height: 100%;">
<div class="card-background-preview" style="background-image: url(${'pms_image_proxy?img=' + show['art'] + '&width=500&height=280&fallback=art&refresh=true'});background-color: #3F4245;background-position: center;background-size: cover;opacity: 0.25;-webkit-filter: blur(3px);filter: blur(3px);position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: 0;"></div>
% else: % else:
<div class="card-background" style="background-image: url(${show['art_url']});background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;"> <div class="card-background" style="background-image: url(${show['art_url']});background-position: center;background-size: cover;width: 100%;height: 100%;">
% endif
% else:
<div class="card-background" style="background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;">
% endif % endif
<div class="card-poster-container" style="width: 150px;margin: 3px;border: 1px solid rgba(255,255,255,.1);float: left;position: relative;z-index: 1;height: 225px;"> <div class="card-poster-container" style="width: 150px;margin: 3px;border: 1px solid rgba(255,255,255,.1);float: left;position: relative;z-index: 1;height: 225px;">
<a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${link_rating_key}" title="${link_title}" target="_blank" style="color: #3498db;text-decoration: underline;"> <a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${link_rating_key}" title="${link_title}" target="_blank" style="color: #3498db;text-decoration: underline;">
<div class="card-poster" style="background-image: url(${'pms_image_proxy?img=' + show['thumb'] + '&width=300&height=450&fallback=poster&refresh=true' if preview else show['poster_url']});background-color: #3F4245;background-position: center;background-size: cover;height: 100%;width: 100%;"> <div class="card-poster" style="background-image: url(${'pms_image_proxy?img=' + show['thumb'] + '&width=300&height=450&fallback=poster&refresh=true' if preview else show['poster_url']});background-color: #282828;background-position: center;background-size: cover;height: 100%;width: 100%;">
<div class="card-poster-overlay" style="background: url(https://cdn.discordapp.com/attachments/334355557706235906/401064397780287489/newsletter-view-on-plex-flat.png) bottom right no-repeat;width: 100%;height: 100%;"></div> <div class="card-poster-overlay" style="background: url(https://cdn.discordapp.com/attachments/334355557706235906/401064397780287489/newsletter-view-on-plex-flat.png) bottom right no-repeat;width: 100%;height: 100%;"></div>
</div> </div>
</a> </a>
@ -815,19 +789,14 @@
% else: % else:
<div class="card-instance album" style="float: left;width: 500px;margin: 3px;border: 1px solid rgba(255,255,255,.1);-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;font-size: 12px;overflow: hidden;position: relative;height: 160px;"> <div class="card-instance album" style="float: left;width: 500px;margin: 3px;border: 1px solid rgba(255,255,255,.1);-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;font-size: 12px;overflow: hidden;position: relative;height: 160px;">
% endif % endif
% if PILLOW:
% if preview: % if preview:
<div class="card-background" style="background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;"> <div class="card-background-preview" style="background-image: url(${'pms_image_proxy?img=' + album['art'] + '&width=500&height=280&opacity=25&background=282828&blur=3&fallback=art&refresh=true'});">
<div class="card-background-preview" style="background-image: url(${'pms_image_proxy?img=' + album['art'] + '&width=500&height=280&fallback=art&refresh=true'});background-color: #3F4245;background-position: center;background-size: cover;opacity: 0.25;-webkit-filter: blur(3px);filter: blur(3px);position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: 0;"></div>
% else: % else:
<div class="card-background" style="background-image: url(${album['art_url']});background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;"> <div class="card-background" style="background-image: url(${album['art_url']});background-position: center;background-size: cover;width: 100%;height: 100%;">
% endif
% else:
<div class="card-background" style="background-color: #3F4245;background-position: center;background-size: cover;width: 100%;height: 100%;">
% endif % endif
<div class="card-poster-container" style="width: 150px;margin: 3px;border: 1px solid rgba(255,255,255,.1);float: left;position: relative;z-index: 1;height: 150px;"> <div class="card-poster-container" style="width: 150px;margin: 3px;border: 1px solid rgba(255,255,255,.1);float: left;position: relative;z-index: 1;height: 150px;">
<a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${album['rating_key']}" title="${album['title']}" target="_blank" style="color: #3498db;text-decoration: underline;"> <a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${album['rating_key']}" title="${album['title']}" target="_blank" style="color: #3498db;text-decoration: underline;">
<div class="card-poster" style="background-image: url(${'pms_image_proxy?img=' + album['thumb'] + '&width=300&height=450&fallback=poster&refresh=true' if preview else album['poster_url']});background-color: #3F4245;background-position: center;background-size: cover;height: 100%;width: 100%;"> <div class="card-poster" style="background-image: url(${'pms_image_proxy?img=' + album['thumb'] + '&width=300&height=450&fallback=poster&refresh=true' if preview else album['poster_url']});background-color: #282828;background-position: center;background-size: cover;height: 100%;width: 100%;">
<div class="card-poster-overlay" style="background: url(https://cdn.discordapp.com/attachments/334355557706235906/401064397780287489/newsletter-view-on-plex-flat.png) bottom right no-repeat;width: 100%;height: 100%;"></div> <div class="card-poster-overlay" style="background: url(https://cdn.discordapp.com/attachments/334355557706235906/401064397780287489/newsletter-view-on-plex-flat.png) bottom right no-repeat;width: 100%;height: 100%;"></div>
</div> </div>
</a> </a>

View file

@ -1,6 +1,5 @@
% if data: % if data:
<% <%
from plexpy.notification_handler import PILLOW
recently_added = data['recently_added'] recently_added = data['recently_added']
%> %>
<!doctype html> <!doctype html>
@ -351,26 +350,11 @@
margin: 3px auto !important; margin: 3px auto !important;
} }
.card-background { .card-background {
background-color: #3F4245;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.card-background-preview {
background-color: #3F4245;
background-position: center;
background-size: cover;
opacity: 0.25;
-webkit-filter: blur(3px);
filter: blur(3px);
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 0;
}
.card-poster-container { .card-poster-container {
width: 150px; width: 150px;
margin: 3px; margin: 3px;
@ -617,15 +601,10 @@
% else: % else:
<div class="card-instance movie"> <div class="card-instance movie">
% endif % endif
% if PILLOW:
% if preview: % if preview:
<div class="card-background"> <div class="card-background" style="background-image: url(${'pms_image_proxy?img=' + movie['art'] + '&width=500&height=280&opacity=25&background=282828&blur=3&fallback=art&refresh=true'});">
<div class="card-background-preview" style="background-image: url(${'pms_image_proxy?img=' + movie['art'] + '&width=500&height=280&fallback=art&refresh=true'});"></div>
% else: % else:
<div class="card-background" style="background-image: url(${movie['art_url']});"> <div class="card-background" style="background-image: url(${movie['art_url']});">
% endif
% else:
<div class="card-background">
% endif % endif
<div class="card-poster-container"> <div class="card-poster-container">
<a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${movie['rating_key']}" title="${movie['title']}" target="_blank"> <a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${movie['rating_key']}" title="${movie['title']}" target="_blank">
@ -705,15 +684,10 @@
% else: % else:
<div class="card-instance show"> <div class="card-instance show">
% endif % endif
% if PILLOW:
% if preview: % if preview:
<div class="card-background"> <div class="card-background" style="background-image: url(${'pms_image_proxy?img=' + show['art'] + '&width=500&height=280&opacity=25&background=282828&blur=3&fallback=art&refresh=true'});">
<div class="card-background-preview" style="background-image: url(${'pms_image_proxy?img=' + show['art'] + '&width=500&height=280&fallback=art&refresh=true'});"></div>
% else: % else:
<div class="card-background" style="background-image: url(${show['art_url']});"> <div class="card-background" style="background-image: url(${show['art_url']});">
% endif
% else:
<div class="card-background">
% endif % endif
<div class="card-poster-container"> <div class="card-poster-container">
<a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${link_rating_key}" title="${link_title}" target="_blank"> <a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${link_rating_key}" title="${link_title}" target="_blank">
@ -815,15 +789,10 @@
% else: % else:
<div class="card-instance album"> <div class="card-instance album">
% endif % endif
% if PILLOW:
% if preview: % if preview:
<div class="card-background"> <div class="card-background-preview" style="background-image: url(${'pms_image_proxy?img=' + album['art'] + '&width=500&height=280&opacity=25&background=282828&blur=3&fallback=art&refresh=true'});">
<div class="card-background-preview" style="background-image: url(${'pms_image_proxy?img=' + album['art'] + '&width=500&height=280&fallback=art&refresh=true'});"></div>
% else: % else:
<div class="card-background" style="background-image: url(${album['art_url']});"> <div class="card-background" style="background-image: url(${album['art_url']});">
% endif
% else:
<div class="card-background">
% endif % endif
<div class="card-poster-container"> <div class="card-poster-container">
<a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${album['rating_key']}" title="${album['title']}" target="_blank"> <a href="${parameters['pms_web_url']}#!/server/${parameters['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${album['rating_key']}" title="${album['title']}" target="_blank">

View file

@ -649,7 +649,7 @@ def dbcheck():
# art_urls table :: This table keeps record of the notification art urls # art_urls table :: This table keeps record of the notification art urls
c_db.execute( c_db.execute(
'CREATE TABLE IF NOT EXISTS art_urls (id INTEGER PRIMARY KEY AUTOINCREMENT, ' 'CREATE TABLE IF NOT EXISTS art_urls (id INTEGER PRIMARY KEY AUTOINCREMENT, '
'rating_key INTEGER, art_title TEXT, art_url TEXT, blur_art_url TEXT)' 'rating_key INTEGER, art_title TEXT, art_url TEXT, delete_hash TEXT, blur INTEGER DEFAULT 0)'
) )
# recently_added table :: This table keeps record of recently added items # recently_added table :: This table keeps record of recently added items

View file

@ -1106,7 +1106,7 @@ class DataFactory(object):
return ip_address return ip_address
def get_poster_info(self, rating_key='', metadata=None, art=False): def get_poster_info(self, rating_key='', metadata=None, art=False, blur=None):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
poster_key = '' poster_key = ''
@ -1125,31 +1125,31 @@ class DataFactory(object):
if poster_key: if poster_key:
try: try:
if art: if art:
query = 'SELECT art_title, art_url, blur_art_url FROM art_urls ' \ query = 'SELECT art_title, art_url, blur FROM art_urls ' \
'WHERE rating_key = ?' 'WHERE rating_key = ? AND blur = ?'
args = [poster_key, int(blur is not None)]
else: else:
query = 'SELECT poster_title, poster_url FROM poster_urls ' \ query = 'SELECT poster_title, poster_url FROM poster_urls ' \
'WHERE rating_key = ?' 'WHERE rating_key = ?'
poster_info = monitor_db.select_single(query, args=[poster_key]) args = [poster_key]
poster_info = monitor_db.select_single(query, args=args)
except Exception as e: except Exception as e:
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_poster_url: %s." % e) logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_poster_url: %s." % e)
return poster_info return poster_info
def set_poster_url(self, rating_key='', poster_title='', poster_url='', delete_hash='', art=False, blur=False): def set_poster_url(self, rating_key='', poster_title='', poster_url='', delete_hash='', art=False, blur=None):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
if str(rating_key).isdigit(): if str(rating_key).isdigit():
keys = {'rating_key': int(rating_key)} keys = {'rating_key': int(rating_key)}
if art: if art:
keys['blur'] = int(blur is not None)
table = 'art_urls' table = 'art_urls'
values = {'art_title': poster_title, values = {'art_title': poster_title,
'art_url': poster_url,
'delete_hash': delete_hash} 'delete_hash': delete_hash}
if blur:
values['blur_art_url'] = poster_url
else:
values['art_url'] = poster_url
else: else:
table = 'poster_urls' table = 'poster_urls'
values = {'poster_title': poster_title, values = {'poster_title': poster_title,

View file

@ -30,7 +30,7 @@ import logger
import newsletter_handler import newsletter_handler
import notification_handler import notification_handler
import pmsconnect import pmsconnect
from notification_handler import PILLOW, get_poster_info from notification_handler import get_poster_info
from notifiers import send_notification, EMAIL from notifiers import send_notification, EMAIL
@ -542,16 +542,16 @@ class RecentlyAdded(Newsletter):
if poster_info: if poster_info:
item['poster_url'] = poster_info['poster_url'] or common.ONLINE_POSTER_THUMB item['poster_url'] = poster_info['poster_url'] or common.ONLINE_POSTER_THUMB
art_info = {} art_info = get_poster_info(poster_thumb=item['art'],
if PILLOW: poster_key=item['rating_key'],
art_info = get_poster_info(poster_thumb=item['art'], poster_title=item['title'],
poster_key=item['rating_key'], art=True,
poster_title=item['title'], width='500',
art=True, height='280',
width='500', opacity='25',
height='280', background='282828',
blur=True) blur='3')
item['art_url'] = art_info.get('blur_art_url', '') item['art_url'] = art_info.get('art_url', '')
self.data['recently_added'] = recently_added self.data['recently_added'] = recently_added
@ -600,19 +600,4 @@ class RecentlyAdded(Newsletter):
} }
] ]
if not PILLOW:
pillow_message = {
'label': 'Background Art',
'description': 'The Pillow library is missing. '
'Background art on the newsletter media cards will not be included.<br>'
'Install the Pillow library to add background art. '
'Instructions can be found in the '
'<a href="' + helpers.anon_url('https://github.com/%s/plexpy/wiki/'
'Frequently-Asked-Questions-(FAQ)#notifications-pillow'
% plexpy.CONFIG.GIT_USER) + '" target="_blank">FAQ</a>.',
'name': 'recently_added_pillow',
'input_type': 'help'
}
config_option.insert(0, pillow_message)
return config_option return config_option

View file

@ -26,12 +26,6 @@ from string import Formatter
import threading import threading
import time import time
try:
from PIL import Image, ImageFilter
PILLOW = True
except ImportError:
PILLOW = False
import plexpy import plexpy
import activity_processor import activity_processor
import common import common
@ -1071,53 +1065,42 @@ 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_poster_info(poster_thumb='', poster_key='', poster_title='', art=False, width='', height='', blur=False): def get_poster_info(poster_thumb='', poster_key='', poster_title='', art=False,
width='', height='', opacity=None, background=None, blur=None):
default_poster_info = {'poster_title': '', 'poster_url': ''} default_poster_info = {'poster_title': '', 'poster_url': ''}
default_art_info = {'art_title': '', 'art_url': ''} default_art_info = {'art_title': '', 'art_url': ''}
# Try to retrieve poster info from the database # Try to retrieve poster info from the database
data_factory = datafactory.DataFactory() data_factory = datafactory.DataFactory()
poster_info = data_factory.get_poster_info(rating_key=poster_key, art=art) poster_info = data_factory.get_poster_info(rating_key=poster_key, art=art, blur=blur)
# If no previous poster info # If no previous poster info
if not poster_info and poster_thumb: if not poster_info and poster_thumb:
try: try:
thread_name = str(threading.current_thread().ident) thread_name = str(threading.current_thread().ident)
poster_file = os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-image-%s.jpg' % thread_name) poster_file = os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-image-%s.png' % thread_name)
# Retrieve the poster from Plex and cache to file # Retrieve the poster from Plex and cache to file
pms_connect = pmsconnect.PmsConnect() pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_image(img=poster_thumb, width=width, height=height) result = pms_connect.get_image(img=poster_thumb,
width=width,
height=height,
opacity=opacity,
background=background,
blur=blur)
if result and result[0]: if result and result[0]:
with open(poster_file, 'wb') as f: with open(poster_file, 'wb') as f:
f.write(result[0]) f.write(result[0])
else: else:
raise Exception(u'PMS image request failed') raise Exception(u'PMS image request failed')
if blur and PILLOW:
img = Image.open(poster_file)
img = img.convert("RGBA")
img = img.filter(ImageFilter.GaussianBlur(3)) # 3px blur
img.putalpha(64) # 40% opacity
# Save as a png
poster_file_blur = os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-image-%s.png' % thread_name)
img.save(poster_file_blur)
# Upload poster_thumb to Imgur and get link # Upload poster_thumb to Imgur and get link
if blur: poster_url, delete_hash = helpers.upload_to_imgur(poster_file, poster_title)
poster_url, delete_hash = helpers.upload_to_imgur(poster_file_blur, poster_title)
else:
poster_url, delete_hash = helpers.upload_to_imgur(poster_file, poster_title)
if poster_url: if poster_url:
# Create poster info # Create poster info
if art: if art:
poster_info = {'art_title': poster_title} poster_info = {'art_title': poster_title, 'art_url': poster_url}
if blur:
poster_info['blur_art_url'] = poster_url
else:
poster_info['art_url'] = poster_url
else: else:
poster_info = {'poster_title': poster_title, 'poster_url': poster_url} poster_info = {'poster_title': poster_title, 'poster_url': poster_url}
@ -1131,8 +1114,6 @@ def get_poster_info(poster_thumb='', poster_key='', poster_title='', art=False,
# Delete the cached poster # Delete the cached poster
os.remove(poster_file) os.remove(poster_file)
if blur:
os.remove(poster_file_blur)
except Exception as e: except Exception as e:
logger.error(u"Tautulli NotificationHandler :: Unable to retrieve poster for rating_key %s: %s." logger.error(u"Tautulli NotificationHandler :: Unable to retrieve poster for rating_key %s: %s."
% (poster_key, e)) % (poster_key, e))

View file

@ -1656,7 +1656,7 @@ class GROUPME(Notifier):
if poster_content: if poster_content:
headers = {'X-Access-Token': self.config['access_token'], headers = {'X-Access-Token': self.config['access_token'],
'Content-Type': 'image/jpeg'} 'Content-Type': 'image/png'}
r = requests.post('https://image.groupme.com/pictures', headers=headers, data=poster_content) r = requests.post('https://image.groupme.com/pictures', headers=headers, data=poster_content)
@ -2643,9 +2643,9 @@ class PUSHBULLET(Notifier):
logger.error(u"Tautulli Notifiers :: Unable to retrieve image for {name}.".format(name=self.NAME)) logger.error(u"Tautulli Notifiers :: Unable to retrieve image for {name}.".format(name=self.NAME))
if poster_content: if poster_content:
poster_filename = 'poster_{}.jpg'.format(pretty_metadata.parameters['rating_key']) poster_filename = 'poster_{}.png'.format(pretty_metadata.parameters['rating_key'])
file_json = {'file_name': poster_filename, 'file_type': 'image/jpeg'} file_json = {'file_name': poster_filename, 'file_type': 'image/png'}
files = {'file': (poster_filename, poster_content, 'image/jpeg')} files = {'file': (poster_filename, poster_content, 'image/png')}
r = requests.post('https://api.pushbullet.com/v2/upload-request', headers=headers, json=file_json) r = requests.post('https://api.pushbullet.com/v2/upload-request', headers=headers, json=file_json)
@ -2799,8 +2799,8 @@ class PUSHOVER(Notifier):
logger.error(u"Tautulli Notifiers :: Unable to retrieve image for {name}.".format(name=self.NAME)) logger.error(u"Tautulli Notifiers :: Unable to retrieve image for {name}.".format(name=self.NAME))
if poster_content: if poster_content:
poster_filename = 'poster_{}.jpg'.format(pretty_metadata.parameters['rating_key']) poster_filename = 'poster_{}.png'.format(pretty_metadata.parameters['rating_key'])
files = {'attachment': (poster_filename, poster_content, 'image/jpeg')} files = {'attachment': (poster_filename, poster_content, 'image/png')}
headers = {} headers = {}
return self.make_request('https://api.pushover.net/1/messages.json', headers=headers, data=data, files=files) return self.make_request('https://api.pushover.net/1/messages.json', headers=headers, data=data, files=files)
@ -3327,8 +3327,8 @@ class TELEGRAM(Notifier):
logger.error(u"Tautulli Notifiers :: Unable to retrieve image for {name}.".format(name=self.NAME)) logger.error(u"Tautulli Notifiers :: Unable to retrieve image for {name}.".format(name=self.NAME))
if poster_content: if poster_content:
poster_filename = 'poster_{}.jpg'.format(pretty_metadata.parameters['rating_key']) poster_filename = 'poster_{}.png'.format(pretty_metadata.parameters['rating_key'])
files = {'photo': (poster_filename, poster_content, 'image/jpeg')} files = {'photo': (poster_filename, poster_content, 'image/png')}
data['caption'] = text data['caption'] = text
return self.make_request('https://api.telegram.org/bot{}/sendPhoto'.format(self.config['bot_token']), return self.make_request('https://api.telegram.org/bot{}/sendPhoto'.format(self.config['bot_token']),

View file

@ -2425,7 +2425,8 @@ class PmsConnect(object):
return labels_list return labels_list
def get_image(self, img=None, width='1000', height='1500', clip=False): def get_image(self, img=None, width='1000', height='1500', opacity=None, background=None, blur=None, img_format='png',
clip=False):
""" """
Return image data as array. Return image data as array.
Array contains the image content type and image binary Array contains the image content type and image binary
@ -2433,6 +2434,9 @@ class PmsConnect(object):
Parameters required: img { Plex image location } Parameters required: img { Plex image location }
Optional parameters: width { the image width } Optional parameters: width { the image width }
height { the image height } height { the image height }
opacity { the image opacity 0-100 }
background { the image background HEX }
blur { the image blur 0-100 }
Output: array Output: array
""" """
@ -2447,6 +2451,14 @@ class PmsConnect(object):
params['width'] = width params['width'] = width
params['height'] = height params['height'] = height
params['format'] = img_format
if opacity:
params['opacity'] = opacity
if background:
params['background'] = background
if blur:
params['blur'] = blur
uri = '/photo/:/transcode?%s' % urllib.urlencode(params) uri = '/photo/:/transcode?%s' % urllib.urlencode(params)
result = self.request_handler.make_request(uri=uri, result = self.request_handler.make_request(uri=uri,

View file

@ -3816,6 +3816,7 @@ class WebInterface(object):
@addtoapi('pms_image_proxy') @addtoapi('pms_image_proxy')
def real_pms_image_proxy(self, img='', rating_key=None, width='0', height='0', def real_pms_image_proxy(self, img='', rating_key=None, width='0', height='0',
opacity=None, background=None, blur=None, img_format='png',
fallback=None, refresh=False, clip=False, **kwargs): fallback=None, refresh=False, clip=False, **kwargs):
""" Gets an image from the PMS and saves it to the image cache directory. """ Gets an image from the PMS and saves it to the image cache directory.
@ -3826,8 +3827,12 @@ class WebInterface(object):
rating_key (str): 54321 rating_key (str): 54321
Optional parameters: Optional parameters:
width (str): 150 width (str): 300
height (str): 255 height (str): 450
opacity (str): 25
background (str): 282828
blur (str): 3
img_format (str): png
fallback (str): "poster", "cover", "art" fallback (str): "poster", "cover", "art"
refresh (bool): True or False whether to refresh the image cache refresh (bool): True or False whether to refresh the image cache
@ -3843,9 +3848,20 @@ class WebInterface(object):
img = '/library/metadata/%s/thumb/1337' % rating_key img = '/library/metadata/%s/thumb/1337' % rating_key
img_string = img.rsplit('/', 1)[0] if '/library/metadata' in img else img img_string = img.rsplit('/', 1)[0] if '/library/metadata' in img else img
img_string += '%s%s' % (width, height)
if width:
img_string += width
if height:
img_string += height
if opacity:
img_string += opacity
if background:
img_string += background
if blur:
img_string += blur
fp = hashlib.md5(img_string).hexdigest() fp = hashlib.md5(img_string).hexdigest()
fp += '.jpg' # we want to be able to preview the thumbs fp += '.%s' % img_format # we want to be able to preview the thumbs
c_dir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images') c_dir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images')
ffp = os.path.join(c_dir, fp) ffp = os.path.join(c_dir, fp)
@ -3858,13 +3874,20 @@ class WebInterface(object):
if not plexpy.CONFIG.CACHE_IMAGES or refresh or 'indexes' in img: if not plexpy.CONFIG.CACHE_IMAGES or refresh or 'indexes' in img:
raise NotFound raise NotFound
return serve_file(path=ffp, content_type='image/jpeg') return serve_file(path=ffp, content_type='image/png')
except NotFound: except NotFound:
# the image does not exist, download it from pms # the image does not exist, download it from pms
try: try:
pms_connect = pmsconnect.PmsConnect() pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_image(img, width, height, clip=clip) result = pms_connect.get_image(img=img,
width=width,
height=height,
opacity=opacity,
background=background,
blur=blur,
img_format=img_format,
clip=clip)
if result and result[0]: if result and result[0]:
cherrypy.response.headers['Content-type'] = result[1] cherrypy.response.headers['Content-type'] = result[1]