diff --git a/lib/openanything.py b/lib/openanything.py deleted file mode 100644 index 413f576d..00000000 --- a/lib/openanything.py +++ /dev/null @@ -1,107 +0,0 @@ -'''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 - diff --git a/plexpy/helpers.py b/plexpy/helpers.py index c360638c..710449b8 100644 --- a/plexpy/helpers.py +++ b/plexpy/helpers.py @@ -13,23 +13,25 @@ # You should have received a copy of the GNU General Public License # along with PlexPy. If not, see . -from IPy import IP +import base64 import datetime import fnmatch from functools import wraps +from IPy import IP import json -import os import math from operator import itemgetter +import os import re import shutil import socket import sys import time -from xml.dom import minidom import unicodedata - +import urllib, urllib2 +from xml.dom import minidom import xmltodict + import plexpy from api2 import API2 @@ -523,3 +525,37 @@ def anon_url(*url): Return a URL string consisting of the Anonymous redirect URL and an arbitrary number of values appended. """ return '' if None in url else '%s%s' % (plexpy.CONFIG.ANON_REDIRECT, ''.join(str(s) for s in url)) + +def uploadToImgur(imgPath, imgTitle=''): + from plexpy import logger + + client_id = '743b1a443ccd2b0' + img_url = '' + + try: + with open(imgPath, 'rb') as imgFile: + img = imgFile.read() + except IOError as e: + logger.error(u"PlexPy Helpers :: Unable to read image file for Imgur: %s" % e) + return img_url + + headers = {'Authorization': 'Client-ID %s' % client_id} + data = {'type': 'base64', + 'image': base64.b64encode(img)} + if imgTitle: + data['title'] = imgTitle + data['name'] = imgTitle + '.jpg' + + request = urllib2.Request('https://api.imgur.com/3/image', headers=headers, data=urllib.urlencode(data)) + response = urllib2.urlopen(request) + response = json.loads(response.read()) + + if response.get('status') == 200: + logger.debug(u"PlexPy Helpers :: Image uploaded to Imgur.") + img_url = response.get('data').get('link', '') + elif response.get('status') >= 400 and response.get('status') < 500: + logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur: %s" % response.reason) + else: + logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur.") + + return img_url \ No newline at end of file diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index 45903513..fe782f68 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -15,12 +15,10 @@ import arrow -import json -from httplib import HTTPConnection -import openanything +import os import re import time -import urllib2 +import urllib from plexpy import logger, config, notifiers, database, helpers, plextv, pmsconnect import plexpy @@ -157,7 +155,8 @@ def notify(stream_data=None, notify_action=None): subject=notify_strings[0], body=notify_strings[1], notify_action=notify_action, - script_args=notify_strings[2]) + script_args=notify_strings[2], + metadata=notify_strings[3]) # Set the notification state in the db set_notify_state(session=stream_data, state=notify_action, agent_info=agent) @@ -169,7 +168,8 @@ def notify(stream_data=None, notify_action=None): subject=notify_strings[0], body=notify_strings[1], notify_action=notify_action, - script_args=notify_strings[2]) + script_args=notify_strings[2], + metadata=notify_strings[3]) # Set the notification state in the db set_notify_state(session=stream_data, state=notify_action, agent_info=agent) @@ -181,7 +181,8 @@ def notify(stream_data=None, notify_action=None): subject=notify_strings[0], body=notify_strings[1], notify_action=notify_action, - script_args=notify_strings[2]) + script_args=notify_strings[2], + metadata=notify_strings[3]) # Set the notification state in the db set_notify_state(session=stream_data, state=notify_action, agent_info=agent) @@ -193,7 +194,8 @@ def notify(stream_data=None, notify_action=None): subject=notify_strings[0], body=notify_strings[1], notify_action=notify_action, - script_args=notify_strings[2]) + script_args=notify_strings[2], + metadata=notify_strings[3]) # Set the notification state in the db set_notify_state(session=stream_data, state=notify_action, agent_info=agent) @@ -205,7 +207,8 @@ def notify(stream_data=None, notify_action=None): subject=notify_strings[0], body=notify_strings[1], notify_action=notify_action, - script_args=notify_strings[2]) + script_args=notify_strings[2], + metadata=notify_strings[3]) # Set the notification state in the db set_notify_state(session=stream_data, state=notify_action, agent_info=agent) @@ -499,46 +502,21 @@ def build_notify_text(session=None, timeline=None, state=None): metadata['lastfm_id'] = metadata['guid'].split('lastfm://')[1].rsplit('/', 1)[0] metadata['lastfm_url'] = 'https://www.last.fm/music/' + metadata['lastfm_id'] - # Get posters (only IMDB and TheTVDB supported) - if metadata['media_type'] == 'movie' and metadata.get('imdb_id', ''): - uri = '/?i=' + metadata['imdb_id'] + if metadata['media_type'] == 'movie' or metadata['media_type'] == 'show' or metadata['media_type'] == 'artist': + thumb = metadata['thumb'] + elif metadata['media_type'] == 'episode': + thumb = metadata['grandparent_thumb'] + elif metadata['media_type'] == 'track': + thumb = metadata['parent_thumb'] + else: + thumb = None - # Get poster using OMDb API - http_handler = HTTPConnection("www.omdbapi.com") - http_handler.request('GET', uri) - response = http_handler.getresponse() - request_status = response.status - - if request_status == 200: - data = json.loads(response.read()) - poster_url = data.get('Poster', '') - metadata['poster_url'] = poster_url if poster_url != 'N/A' else '' - elif request_status >= 400 and request_status < 500: - logger.warn(u"PlexPy Notifiers :: Unable to retrieve IMDB poster: %s" % response.reason) - else: - 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.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', '') - metadata['poster_url'] = 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 thumb: + # Retrieve the poster from Plex and cache to file + urllib.urlretrieve(plexpy.CONFIG.PMS_URL + thumb + '?X-Plex-Token=' + plexpy.CONFIG.PMS_TOKEN, + os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg')) + # Upload thumb to Imgur and get link + metadata['poster_url'] = helpers.uploadToImgur(os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg'), full_title) # Fix metadata params for notify recently added grandparent if state == 'created' and plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT: diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index 772b7d84..6831f011 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -19,8 +19,7 @@ import json import cherrypy from email.mime.text import MIMEText import email.utils -from httplib import HTTPSConnection, HTTPConnection -import openanything +from httplib import HTTPSConnection import os import shlex import smtplib @@ -2129,19 +2128,35 @@ class FacebookNotifier(object): if self.incl_poster and 'metadata' in kwargs: metadata = kwargs['metadata'] poster_url = metadata.get('poster_url','') - caption = 'View in Plex Web.' - - if metadata['media_type'] == 'movie' or 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 poster_url: + if metadata['media_type'] == 'movie' or metadata['media_type'] == 'show': + title = metadata['title'] + subtitle = metadata['year'] + rating_key = metadata['rating_key'] + + elif metadata['media_type'] == 'episode': + title = '%s - %s' % (metadata['grandparent_title'], metadata['title']) + subtitle = 'S%s %s E%s' % (metadata['parent_media_index'], + '\xc2\xb7'.decode('utf8'), + metadata['media_index']) + rating_key = metadata['rating_key'] + + elif metadata['media_type'] == 'artist': + title = metadata['title'] + subtitle = '' + rating_key = metadata['rating_key'] + + elif metadata['media_type'] == 'track': + title = '%s - %s' % (metadata['grandparent_title'], metadata['title']) + subtitle = metadata['parent_title'] + rating_key = metadata['parent_rating_key'] + + caption = 'View in Plex Web.' + + # Build Facebook post attachment attachment['link'] = 'http://app.plex.tv/web/app#!/server/' + plexpy.CONFIG.PMS_IDENTIFIER + \ - '/details/%2Flibrary%2Fmetadata%2F' + metadata['rating_key'] + '/details/%2Flibrary%2Fmetadata%2F' + rating_key attachment['picture'] = poster_url attachment['name'] = title attachment['description'] = subtitle