mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-11 15:56:07 -07:00
Add TV posters to Facebook notifications
This commit is contained in:
parent
0fee4fee2a
commit
b1ecff3d10
3 changed files with 160 additions and 26 deletions
107
lib/openanything.py
Normal file
107
lib/openanything.py
Normal 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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue