diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 6bdee478..d1c392d5 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -798,6 +798,38 @@ +
+

Plex Media Server

+
+ +
+
+
+ + + Host running Plex Media Server (eg. http://192.168.1.100:32400) +
+
+ + + Host running Plex Client (eg. http://192.168.1.100:3000) +
+
+ + Username of your Plex client API (blank for none) +
+
+ + Password of your Plex client API (blank for none) +
+
+ +
+
+ +
+
+

NotifyMyAndroid

@@ -1119,6 +1151,26 @@ } }); + if ($("#plex").is(":checked")) + { + $("#plexoptions").show(); + } + else + { + $("#plexoptions").hide(); + } + + $("#plex").click(function(){ + if ($("#plex").is(":checked")) + { + $("#plexoptions").slideDown(); + } + else + { + $("#plexoptions").slideUp(); + } + }); + if ($("#nma").is(":checked")) { $("#nmaoptions").show(); diff --git a/headphones/__init__.py b/headphones/__init__.py index 568b0e2e..b3c7bcc5 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -229,6 +229,13 @@ XBMC_USERNAME = None XBMC_PASSWORD = None XBMC_UPDATE = False XBMC_NOTIFY = False +PLEX_ENABLED = False +PLEX_SERVER_HOST = None +PLEX_CLIENT_HOST = None +PLEX_USERNAME = None +PLEX_PASSWORD = None +PLEX_UPDATE = False +PLEX_NOTIFY = False NMA_ENABLED = False NMA_APIKEY = None NMA_PRIORITY = None @@ -324,7 +331,8 @@ def initialize(): TWITTER_ENABLED, TWITTER_ONSNATCH, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, \ MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, \ XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \ - PREFERRED_BITRATE_LOW_BUFFER, PREFERRED_BITRATE_ALLOW_LOSSLESS, CACHE_SIZEMB, JOURNAL_MODE, UMASK, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY + PREFERRED_BITRATE_LOW_BUFFER, PREFERRED_BITRATE_ALLOW_LOSSLESS, CACHE_SIZEMB, JOURNAL_MODE, UMASK, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, \ + PLEX_ENABLED, PLEX_SERVER_HOST, PLEX_CLIENT_HOST, PLEX_USERNAME, PLEX_PASSWORD, PLEX_UPDATE, PLEX_NOTIFY if __INITIALIZED__: return False @@ -346,6 +354,7 @@ def initialize(): CheckSection('Prowl') CheckSection('Pushover') CheckSection('XBMC') + CheckSection('Plex') CheckSection('NMA') CheckSection('Synoindex') CheckSection('Twitter') @@ -522,6 +531,14 @@ def initialize(): XBMC_UPDATE = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update', 0)) XBMC_NOTIFY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify', 0)) + PLEX_ENABLED = bool(check_setting_int(CFG, 'Plex', 'plex_enabled', 0)) + PLEX_SERVER_HOST = check_setting_str(CFG, 'Plex', 'plex_server_host', '') + PLEX_CLIENT_HOST = check_setting_str(CFG, 'Plex', 'plex_client_host', '') + PLEX_USERNAME = check_setting_str(CFG, 'Plex', 'plex_username', '') + PLEX_PASSWORD = check_setting_str(CFG, 'Plex', 'plex_password', '') + PLEX_UPDATE = bool(check_setting_int(CFG, 'Plex', 'plex_update', 0)) + PLEX_NOTIFY = bool(check_setting_int(CFG, 'Plex', 'plex_notify', 0)) + NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0)) NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '') NMA_PRIORITY = check_setting_int(CFG, 'NMA', 'nma_priority', 0) @@ -894,6 +911,15 @@ def config_write(): new_config['XBMC']['xbmc_update'] = int(XBMC_UPDATE) new_config['XBMC']['xbmc_notify'] = int(XBMC_NOTIFY) + new_config['Plex'] = {} + new_config['Plex']['plex_enabled'] = int(PLEX_ENABLED) + new_config['Plex']['plex_server_host'] = PLEX_SERVER_HOST + new_config['Plex']['plex_client_host'] = PLEX_CLIENT_HOST + new_config['Plex']['plex_username'] = PLEX_USERNAME + new_config['Plex']['plex_password'] = PLEX_PASSWORD + new_config['Plex']['plex_update'] = int(PLEX_UPDATE) + new_config['Plex']['plex_notify'] = int(PLEX_NOTIFY) + new_config['NMA'] = {} new_config['NMA']['nma_enabled'] = int(NMA_ENABLED) new_config['NMA']['nma_apikey'] = NMA_APIKEY diff --git a/headphones/notifiers.py b/headphones/notifiers.py index 7a0f61c1..d4921f62 100644 --- a/headphones/notifiers.py +++ b/headphones/notifiers.py @@ -25,6 +25,7 @@ from urllib import urlencode import os.path import subprocess import lib.simplejson as simplejson +from xml.dom import minidom try: from urlparse import parse_qsl #@UnusedImport @@ -192,6 +193,93 @@ class XBMC: except: logger.warn('Error sending notification request to XBMC') +class Plex: + + def __init__(self): + + self.server_hosts = headphones.PLEX_SERVER_HOST + self.client_hosts = headphones.PLEX_CLIENT_HOST + self.username = headphones.PLEX_USERNAME + self.password = headphones.PLEX_PASSWORD + + def _sendhttp(self, host, command): + + username = self.username + password = self.password + + url_command = urllib.urlencode(command) + + url = host + '/xbmcCmds/xbmcHttp/?' + url_command + + req = urllib2.Request(url) + + if password: + base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '') + req.add_header("Authorization", "Basic %s" % base64string) + + logger.info('Plex url: %s' % url) + + try: + handle = urllib2.urlopen(req) + except Exception, e: + logger.warn('Error opening Plex url: %s' % e) + return + + response = handle.read().decode(headphones.SYS_ENCODING) + + return response + + def update(self): + + # From what I read you can't update the music library on a per directory or per path basis + # so need to update the whole thing + + hosts = [x.strip() for x in self.server_hosts.split(',')] + + for host in hosts: + logger.info('Sending library update command to Plex Media Server@ '+host) + url = "%s/library/sections" % host + try: + xml_sections = minidom.parse(urllib.urlopen(url)) + except IOError, e: + logger.warn("Error while trying to contact Plex Media Server: %s" % e) + return False + + sections = xml_sections.getElementsByTagName('Directory') + if not sections: + logger.info(u"Plex Media Server not running on: " + host) + return False + + for s in sections: + if s.getAttribute('type') == "artist": + url = "%s/library/sections/%s/refresh" % (host, s.getAttribute('key')) + try: + urllib.urlopen(url) + except Exception, e: + logger.warn("Error updating library section for Plex Media Server: %s" % e) + return False + + def notify(self, artist, album, albumartpath): + + hosts = [x.strip() for x in self.client_hosts.split(',')] + + header = "Headphones" + message = "%s - %s added to your library" % (artist, album) + time = "3000" # in ms + + for host in hosts: + logger.info('Sending notification command to Plex Media Server @ '+host) + try: + notification = header + "," + message + "," + time + "," + albumartpath + notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification('+notification+')'} + request = self._sendhttp(host, notifycommand) + + if not request: + raise Exception + + except: + logger.warn('Error sending notification request to Plex Media Server') + class NMA: def __init__(self): @@ -434,4 +522,4 @@ class TwitterNotifier: return self._send_tweet(prefix+": "+message) -notifier = TwitterNotifier \ No newline at end of file +notifier = TwitterNotifier diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index 4841bcf4..18c8cbb6 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -420,6 +420,13 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list, if headphones.XBMC_NOTIFY: xbmc.notify(release['ArtistName'], release['AlbumTitle'], album_art_path) + if headphones.PLEX_ENABLED: + plex = notifiers.Plex() + if headphones.PLEX_UPDATE: + plex.update() + if headphones.PLEX_NOTIFY: + plex.notify(release['ArtistName'], release['AlbumTitle'], album_art_path) + if headphones.NMA_ENABLED: nma = notifiers.NMA() nma.notify(release['ArtistName'], release['AlbumTitle']) diff --git a/headphones/webserve.py b/headphones/webserve.py index 6c080bca..8f10d58b 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -933,6 +933,13 @@ class WebInterface(object): "xbmc_password": headphones.XBMC_PASSWORD, "xbmc_update": checked(headphones.XBMC_UPDATE), "xbmc_notify": checked(headphones.XBMC_NOTIFY), + "plex_enabled": checked(headphones.PLEX_ENABLED), + "plex_server_host": headphones.PLEX_SERVER_HOST, + "plex_client_host": headphones.PLEX_CLIENT_HOST, + "plex_username": headphones.PLEX_USERNAME, + "plex_password": headphones.PLEX_PASSWORD, + "plex_update": checked(headphones.PLEX_UPDATE), + "plex_notify": checked(headphones.PLEX_NOTIFY), "nma_enabled": checked(headphones.NMA_ENABLED), "nma_apikey": headphones.NMA_APIKEY, "nma_priority": int(headphones.NMA_PRIORITY), @@ -988,7 +995,8 @@ class WebInterface(object): xbmc_update=0, xbmc_notify=0, nma_enabled=False, nma_apikey=None, nma_priority=0, nma_onsnatch=0, synoindex_enabled=False, pushover_enabled=0, pushover_onsnatch=0, pushover_keys=None, pushover_priority=0, twitter_enabled=0, twitter_onsnatch=0, mirror=None, customhost=None, customport=None, customsleep=None, hpuser=None, hppass=None, preferred_bitrate_high_buffer=None, preferred_bitrate_low_buffer=None, preferred_bitrate_allow_lossless=0, cache_sizemb=None, - enable_https=0, https_cert=None, https_key=None, file_permissions=None, folder_permissions=None, **kwargs): + enable_https=0, https_cert=None, https_key=None, file_permissions=None, folder_permissions=None, plex_enabled=0, plex_server_host=None, plex_client_host=None, plex_username=None, + plex_password=None, plex_update=0, plex_notify=0, **kwargs): headphones.HTTP_HOST = http_host headphones.HTTP_PORT = http_port @@ -1107,6 +1115,13 @@ class WebInterface(object): headphones.XBMC_PASSWORD = xbmc_password headphones.XBMC_UPDATE = xbmc_update headphones.XBMC_NOTIFY = xbmc_notify + headphones.PLEX_ENABLED = plex_enabled + headphones.PLEX_SERVER_HOST = plex_server_host + headphones.PLEX_CLIENT_HOST = plex_client_host + headphones.PLEX_USERNAME = plex_username + headphones.PLEX_PASSWORD = plex_password + headphones.PLEX_UPDATE = plex_update + headphones.PLEX_NOTIFY = plex_notify headphones.NMA_ENABLED = nma_enabled headphones.NMA_APIKEY = nma_apikey headphones.NMA_PRIORITY = nma_priority