Add TV posters to Facebook notifications

This commit is contained in:
JonnyWong16 2016-02-18 18:52:07 -08:00
parent 0fee4fee2a
commit b1ecff3d10
3 changed files with 160 additions and 26 deletions

107
lib/openanything.py Normal file
View file

@ -0,0 +1,107 @@
'''OpenAnything: a kind and thoughtful library for HTTP web services
This program is part of 'Dive Into Python', a free Python book for
experienced programmers. Visit http://diveintopython.org/ for the
latest version.
'''
__author__ = 'Mark Pilgrim (mark@diveintopython.org)'
__version__ = '$Revision: 1.6 $'[11:-2]
__date__ = '$Date: 2004/04/16 21:16:24 $'
__copyright__ = 'Copyright (c) 2004 Mark Pilgrim'
__license__ = 'Python'
import urllib2, urlparse, gzip
from StringIO import StringIO
USER_AGENT = 'OpenAnything/%s +http://diveintopython.org/http_web_services/' % __version__
class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_301(self, req, fp, code, msg, headers):
result = urllib2.HTTPRedirectHandler.http_error_301(
self, req, fp, code, msg, headers)
result.status = code
return result
def http_error_302(self, req, fp, code, msg, headers):
result = urllib2.HTTPRedirectHandler.http_error_302(
self, req, fp, code, msg, headers)
result.status = code
return result
class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler):
def http_error_default(self, req, fp, code, msg, headers):
result = urllib2.HTTPError(
req.get_full_url(), code, msg, headers, fp)
result.status = code
return result
def openAnything(source, etag=None, lastmodified=None, agent=USER_AGENT):
"""URL, filename, or string --> stream
This function lets you define parsers that take any input source
(URL, pathname to local or network file, or actual data as a string)
and deal with it in a uniform manner. Returned object is guaranteed
to have all the basic stdio read methods (read, readline, readlines).
Just .close() the object when you're done with it.
If the etag argument is supplied, it will be used as the value of an
If-None-Match request header.
If the lastmodified argument is supplied, it must be a formatted
date/time string in GMT (as returned in the Last-Modified header of
a previous request). The formatted date/time will be used
as the value of an If-Modified-Since request header.
If the agent argument is supplied, it will be used as the value of a
User-Agent request header.
"""
if hasattr(source, 'read'):
return source
if source == '-':
return sys.stdin
if urlparse.urlparse(source)[0] == 'http':
# open URL with urllib2
request = urllib2.Request(source)
request.add_header('User-Agent', agent)
if lastmodified:
request.add_header('If-Modified-Since', lastmodified)
if etag:
request.add_header('If-None-Match', etag)
request.add_header('Accept-encoding', 'gzip')
opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler())
return opener.open(request)
# try to open with native open function (if source is a filename)
try:
return open(source)
except (IOError, OSError):
pass
# treat source as string
return StringIO(str(source))
def fetch(source, etag=None, lastmodified=None, agent=USER_AGENT):
'''Fetch data and metadata from a URL, file, stream, or string'''
result = {}
f = openAnything(source, etag, lastmodified, agent)
result['data'] = f.read()
if hasattr(f, 'headers'):
# save ETag, if the server sent one
result['etag'] = f.headers.get('ETag')
# save Last-Modified header, if the server sent one
result['lastmodified'] = f.headers.get('Last-Modified')
if f.headers.get('content-encoding') == 'gzip':
# data came back gzip-compressed, decompress it
result['data'] = gzip.GzipFile(fileobj=StringIO(result['data'])).read()
if hasattr(f, 'url'):
result['url'] = f.url
result['status'] = 200
if hasattr(f, 'status'):
result['status'] = f.status
f.close()
return result

View file

@ -88,6 +88,7 @@ _CONFIG_DEFINITIONS = {
'FACEBOOK_APP_SECRET': (str, 'Facebook', ''), 'FACEBOOK_APP_SECRET': (str, 'Facebook', ''),
'FACEBOOK_TOKEN': (str, 'Facebook', ''), 'FACEBOOK_TOKEN': (str, 'Facebook', ''),
'FACEBOOK_GROUP': (str, 'Facebook', ''), 'FACEBOOK_GROUP': (str, 'Facebook', ''),
'FACEBOOK_INCL_POSTER': (int, 'Facebook', 1),
'FACEBOOK_INCL_SUBJECT': (int, 'Facebook', 1), 'FACEBOOK_INCL_SUBJECT': (int, 'Facebook', 1),
'FACEBOOK_ON_PLAY': (int, 'Facebook', 0), 'FACEBOOK_ON_PLAY': (int, 'Facebook', 0),
'FACEBOOK_ON_STOP': (int, 'Facebook', 0), 'FACEBOOK_ON_STOP': (int, 'Facebook', 0),

View file

@ -20,6 +20,7 @@ import cherrypy
from email.mime.text import MIMEText from email.mime.text import MIMEText
import email.utils import email.utils
from httplib import HTTPSConnection, HTTPConnection from httplib import HTTPSConnection, HTTPConnection
import openanything
import os import os
import shlex import shlex
import smtplib import smtplib
@ -2069,9 +2070,11 @@ class FacebookNotifier(object):
def __init__(self): def __init__(self):
self.redirect_uri = plexpy.CONFIG.FACEBOOK_REDIRECT_URI self.redirect_uri = plexpy.CONFIG.FACEBOOK_REDIRECT_URI
self.access_token = plexpy.CONFIG.FACEBOOK_TOKEN
self.app_id = plexpy.CONFIG.FACEBOOK_APP_ID self.app_id = plexpy.CONFIG.FACEBOOK_APP_ID
self.app_secret = plexpy.CONFIG.FACEBOOK_APP_SECRET self.app_secret = plexpy.CONFIG.FACEBOOK_APP_SECRET
self.group_id = plexpy.CONFIG.FACEBOOK_GROUP self.group_id = plexpy.CONFIG.FACEBOOK_GROUP
self.incl_poster = plexpy.CONFIG.FACEBOOK_INCL_POSTER
self.incl_subject = plexpy.CONFIG.FACEBOOK_INCL_SUBJECT self.incl_subject = plexpy.CONFIG.FACEBOOK_INCL_SUBJECT
def notify(self, subject, message, **kwargs): def notify(self, subject, message, **kwargs):
@ -2118,39 +2121,24 @@ class FacebookNotifier(object):
return True return True
def _post_facebook(self, message=None, **kwargs): def _post_facebook(self, message=None, **kwargs):
access_token = plexpy.CONFIG.FACEBOOK_TOKEN if self.group_id:
group_id = plexpy.CONFIG.FACEBOOK_GROUP api = facebook.GraphAPI(access_token=self.access_token, version='2.5')
if group_id:
api = facebook.GraphAPI(access_token=access_token, version='2.5')
attachment = {} attachment = {}
if 'metadata' in kwargs: if self.incl_poster and 'metadata' in kwargs:
poster = ''
caption = 'View in Plex Web.'
metadata = kwargs['metadata'] metadata = kwargs['metadata']
if metadata['media_type'] == 'movie' and metadata['imdb_id']: if metadata['media_type'] == 'movie' and metadata.get('imdb_id', ''):
uri = 'i=' + metadata['imdb_id']
title = metadata['title'] title = metadata['title']
subtitle = metadata['year'] subtitle = metadata['year']
elif metadata['media_type'] == 'show': uri = '/?i=' + metadata['imdb_id']
uri = 't=' + metadata['title'] + '&y=' + metadata['year']
title = metadata['title']
subtitle = metadata['year']
elif metadata['media_type'] == 'episode':
uri = 't=' + metadata['grandparent_title']
title = metadata['grandparent_title'] + ' - ' + metadata['title']
subtitle = 'S' + metadata['parent_media_index'] + ' ' + '\xc2\xb7'.decode('utf8') + ' E' + metadata['media_index']
else:
uri = ''
title = ''
subtitle = ''
# Get poster using OMDb API # Get poster using OMDb API
poster = ''
if uri:
http_handler = HTTPConnection("www.omdbapi.com") http_handler = HTTPConnection("www.omdbapi.com")
http_handler.request('GET', '/?' + uri) http_handler.request('GET', uri)
response = http_handler.getresponse() response = http_handler.getresponse()
request_status = response.status request_status = response.status
@ -2162,15 +2150,46 @@ class FacebookNotifier(object):
else: else:
logger.warn(u"PlexPy Notifiers :: Unable to retrieve IMDB poster.") logger.warn(u"PlexPy Notifiers :: Unable to retrieve IMDB poster.")
elif (metadata['media_type'] == 'show' or metadata['media_type'] == 'episode') \
and (metadata.get('imdb_id', '') or metadata.get('thetvdb_id', '')):
if metadata['media_type'] == 'show':
title = metadata['title']
subtitle = metadata['year']
elif metadata['media_type'] == 'episode':
title = metadata['grandparent_title'] + ' - ' + metadata['title']
subtitle = 'S' + metadata['parent_media_index'] + ' ' + '\xc2\xb7'.decode('utf8') + \
' E' + metadata['media_index']
if metadata.get('imdb_id', ''):
uri = '/lookup/shows?imdb=' + metadata['imdb_id']
elif metadata.get('thetvdb_id', ''):
uri = '/lookup/shows?thetvdb=' + metadata['thetvdb_id']
# Get poster using TVmaze API
request = urllib2.Request('http://api.tvmaze.com' + uri)
opener = urllib2.build_opener(openanything.SmartRedirectHandler())
response = opener.open(request)
request_status = response.status
if request_status == 301:
data = json.loads(response.read())
image = data.get('image', '')
poster = image.get('original', image.get('medium',''))
elif request_status >= 400 and request_status < 500:
logger.warn(u"PlexPy Notifiers :: Unable to retrieve TVmaze poster: %s" % response.reason)
else:
logger.warn(u"PlexPy Notifiers :: Unable to retrieve TVmaze poster.")
if poster and poster != 'N/A': if poster and poster != 'N/A':
attachment['link'] = 'http://app.plex.tv/web/app#!/server/' + plexpy.CONFIG.PMS_IDENTIFIER + \ attachment['link'] = 'http://app.plex.tv/web/app#!/server/' + plexpy.CONFIG.PMS_IDENTIFIER + \
'/details/%2Flibrary%2Fmetadata%2F' + metadata['rating_key'] '/details/%2Flibrary%2Fmetadata%2F' + metadata['rating_key']
attachment['picture'] = poster attachment['picture'] = poster
attachment['name'] = title attachment['name'] = title
attachment['description'] = subtitle attachment['description'] = subtitle
attachment['caption'] = caption
try: try:
api.put_wall_post(profile_id=group_id, message=message, attachment=attachment) api.put_wall_post(profile_id=self.group_id, message=message, attachment=attachment)
logger.info(u"PlexPy Notifiers :: Facebook notification sent.") logger.info(u"PlexPy Notifiers :: Facebook notification sent.")
except Exception as e: except Exception as e:
logger.warn(u"PlexPy Notifiers :: Error sending Facebook post: %s" % e) logger.warn(u"PlexPy Notifiers :: Error sending Facebook post: %s" % e)
@ -2227,6 +2246,13 @@ class FacebookNotifier(object):
'description': 'Your Facebook Group ID.', 'description': 'Your Facebook Group ID.',
'input_type': 'text' 'input_type': 'text'
}, },
{'label': 'Include Poster Image',
'value': self.incl_poster,
'name': 'facebook_incl_poster',
'description': 'Include a poster in the notifications. \
(PMS agent must be Freebase or TheTVDB. TheMovieDb is currently not supported.)',
'input_type': 'checkbox'
},
{'label': 'Include Subject Line', {'label': 'Include Subject Line',
'value': self.incl_subject, 'value': self.incl_subject,
'name': 'facebook_incl_subject', 'name': 'facebook_incl_subject',