Browse Source

Cleaned up Plex notifications plugin.

pull/2342/head
Dean Gardiner 12 years ago
parent
commit
d31ca2677e
  1. 85
      couchpotato/core/notifications/plex/client.py
  2. 204
      couchpotato/core/notifications/plex/main.py
  3. 111
      couchpotato/core/notifications/plex/server.py

85
couchpotato/core/notifications/plex/client.py

@ -0,0 +1,85 @@
import json
from couchpotato import CPLog
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import tryUrlencode
import requests
log = CPLog(__name__)
class PlexClientProtocol(object):
def __init__(self, plex):
self.plex = plex
addEvent('notify.plex.notifyClient', self.notify)
def notify(self, client, message):
raise NotImplementedError()
class PlexClientHTTP(PlexClientProtocol):
def request(self, command, client):
url = 'http://%s:%s/xbmcCmds/xbmcHttp/?%s' % (
client['address'],
client['port'],
tryUrlencode(command)
)
headers = {}
try:
self.plex.urlopen(url, headers = headers, timeout = 3, show_error = False)
except Exception, err:
log.error("Couldn't sent command to Plex: %s", err)
return False
return True
def notify(self, client, message):
if client.get('protocol') != 'xbmchttp':
return None
data = {
'command': 'ExecBuiltIn',
'parameter': 'Notification(CouchPotato, %s)' % message
}
return self.request(data, client)
class PlexClientJSON(PlexClientProtocol):
def request(self, method, params, client):
log.debug('sendJSON("%s", %s, %s)', (method, params, client))
url = 'http://%s:%s/jsonrpc' % (
client['address'],
client['port']
)
headers = {
'Content-Type': 'application/json'
}
request = {
'id': 1,
'jsonrpc': '2.0',
'method': method,
'params': params
}
try:
requests.post(url, headers = headers, timeout = 3, data = json.dumps(request))
except Exception, err:
log.error("Couldn't sent command to Plex: %s", err)
return False
return True
def notify(self, client, message):
if client.get('protocol') not in ['xbmcjson', 'plex']:
return None
params = {
'title': 'CouchPotato',
'message': message
}
return self.request('GUI.ShowNotification', params, client)

204
couchpotato/core/notifications/plex/main.py

@ -1,183 +1,59 @@
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import cleanHost
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification from couchpotato.core.notifications.base import Notification
from datetime import datetime from .client import PlexClientHTTP, PlexClientJSON
from urlparse import urlparse from .server import PlexServer
from xml.dom import minidom
import json
import requests
import traceback
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
log = CPLog(__name__) log = CPLog(__name__)
class Plex(Notification): class Plex(Notification):
client_update_time = 5 * 60
http_time_between_calls = 0 http_time_between_calls = 0
def __init__(self): def __init__(self):
super(Plex, self).__init__() super(Plex, self).__init__()
self.clients = {} self.server = PlexServer(self)
self.clients_updated = None
addEvent('renamer.after', self.addToLibrary) self.client_protocols = {
'http': PlexClientHTTP(self),
def updateClients(self, force = False): 'json': PlexClientJSON(self)
if not self.conf('media_server'): }
log.warning("Plex media server hostname is required")
return
since_update = ((datetime.now() - self.clients_updated).total_seconds())\
if self.clients_updated is not None else None
if force or self.clients_updated is None or since_update > self.client_update_time:
self.clients = {}
data = self.urlopen('%s/clients' % self.createHost(self.conf('media_server'), port = 32400))
client_result = etree.fromstring(data)
clients = [x.strip().lower() for x in self.conf('clients').split(',')]
for server in client_result.findall('Server'):
if server.get('name').lower() in clients:
clients.remove(server.get('name').lower())
protocol = server.get('protocol', 'xbmchttp')
if protocol in ['plex', 'xbmcjson', 'xbmchttp']:
self.clients[server.get('name')] = {
'name': server.get('name'),
'address': server.get('address'),
'port': server.get('port'),
'protocol': protocol
}
if len(clients) > 0:
log.info2('Unable to find plex clients: %s', ', '.join(clients))
log.info2('Found hosts: %s', ', '.join(self.clients.keys()))
self.clients_updated = datetime.now() addEvent('renamer.after', self.addToLibrary)
def addToLibrary(self, message = None, group = {}): def addToLibrary(self, message = None, group = {}):
if self.isDisabled(): return if self.isDisabled(): return
log.info('Sending notification to Plex') return self.server.refresh()
source_type = ['movie']
base_url = '%s/library/sections' % self.createHost(self.conf('media_server'), port = 32400)
refresh_url = '%s/%%s/refresh' % base_url
try:
sections_xml = self.urlopen(base_url)
xml_sections = minidom.parseString(sections_xml)
sections = xml_sections.getElementsByTagName('Directory')
for s in sections:
if s.getAttribute('type') in source_type:
url = refresh_url % s.getAttribute('key')
x = self.urlopen(url)
except:
log.error('Plex library update failed for %s, Media Server not running: %s',
(self.conf('media_server'), traceback.format_exc(1)))
return False
return True
def sendHTTP(self, command, client):
url = 'http://%s:%s/xbmcCmds/xbmcHttp/?%s' % (
client['address'],
client['port'],
tryUrlencode(command)
)
headers = {}
try: def notifyClients(self, message, clients):
self.urlopen(url, headers = headers, timeout = 3, show_error = False) success = True
except Exception, err:
log.error("Couldn't sent command to Plex: %s", err)
return False
return True while len(clients):
client = clients[0]
def notifyHTTP(self, message = '', data = {}, listener = None): success = fireEvent('notify.plex.notifyClient', client, message, single=True)
total = 0
successful = 0
data = { if success:
'command': 'ExecBuiltIn', clients.pop(0)
'parameter': 'Notification(CouchPotato, %s)' % message else:
} if self.server.staleClients():
log.info('Failed to send notification to client "%s". '
for name, client in self.clients.items(): 'Client list is stale, updating the client list and retrying.', client['name'])
if client['protocol'] == 'xbmchttp': self.server.updateClients()
total += 1 else:
if self.sendHTTP(data, client): log.warning('Failed to send notification to client %s, skipping this time', client['name'])
successful += 1 clients.pop(0)
success = False
return successful == total break
def sendJSON(self, method, params, client):
log.debug('sendJSON("%s", %s, %s)', (method, params, client))
url = 'http://%s:%s/jsonrpc' % (
client['address'],
client['port']
)
headers = {
'Content-Type': 'application/json'
}
request = {
'id':1,
'jsonrpc': '2.0',
'method': method,
'params': params
}
try:
requests.post(url, headers = headers, timeout = 3, data = json.dumps(request))
except Exception, err:
log.error("Couldn't sent command to Plex: %s", err)
return False
return True return success
def notifyJSON(self, message = '', data = {}, listener = None): def notify(self, message = '', data = {}, listener = None):
total = 0 return self.notifyClients(message, self.server.clients.values())
successful = 0
params = {
'title': 'CouchPotato',
'message': message
}
for name, client in self.clients.items():
if client['protocol'] in ['xbmcjson', 'plex']:
total += 1
if self.sendJSON('GUI.ShowNotification', params, client):
successful += 1
return successful == total
def notify(self, message = '', data = {}, listener = None, force = False):
self.updateClients(force)
http_result = self.notifyHTTP(message, data, listener)
json_result = self.notifyJSON(message, data, listener)
return http_result and json_result
def test(self, **kwargs): def test(self, **kwargs):
@ -185,24 +61,12 @@ class Plex(Notification):
log.info('Sending test to %s', test_type) log.info('Sending test to %s', test_type)
success = self.notify( notify_success = self.notify(
message = self.test_message, message = self.test_message,
data = {}, data = {},
listener = 'test', listener = 'test'
force = True
) )
success2 = self.addToLibrary()
return {
'success': success or success2
}
def createHost(self, host, port = None):
h = cleanHost(host) refresh_success = self.addToLibrary()
p = urlparse(h)
h = h.rstrip('/')
if port and not p.port:
h += ':%s' % port
return h return {'success': notify_success or refresh_success}

111
couchpotato/core/notifications/plex/server.py

@ -0,0 +1,111 @@
from datetime import timedelta, datetime
from couchpotato.core.helpers.variable import cleanHost
from couchpotato import CPLog
from urlparse import urlparse
import traceback
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
log = CPLog(__name__)
class PlexServer(object):
def __init__(self, plex):
self.plex = plex
self.clients = {}
self.last_clients_update = None
def staleClients(self):
if not self.last_clients_update:
return True
return self.last_clients_update + timedelta(minutes=15) < datetime.now()
def request(self, path, data_type='xml'):
if not self.plex.conf('media_server'):
log.warning("Plex media server hostname is required")
return None
if path.startswith('/'):
path = path[1:]
data = self.plex.urlopen('%s/%s' % (
self.createHost(self.plex.conf('media_server'), port = 32400),
path
))
if data_type == 'xml':
return etree.fromstring(data)
else:
return data
def updateClients(self):
log.info('Searching for clients on Plex Media Server')
self.clients = {}
result = self.request('clients')
if not result:
return
notify_clients = [
x.strip().lower()
for x in self.plex.conf('clients').split(',')
]
found_clients = [
c for c in result.findall('Server')
if c.get('name') and c.get('name').lower() in notify_clients
]
for client in found_clients:
name = client.get('name').lower()
self.clients[name] = {
'name': client.get('name'),
'address': client.get('address'),
'port': client.get('port'),
'protocol': client.get('protocol', 'xbmchttp')
}
notify_clients.remove(name)
if len(notify_clients) > 0:
log.debug('Unable to find clients: %s', ', '.join(notify_clients))
self.last_clients_update = datetime.now()
def refresh(self, section_types=None):
if not section_types:
section_types = ['movie']
sections = self.request('library/sections')
try:
for section in sections.findall('Directory'):
if section.get('type') not in section_types:
continue
self.request('library/sections/%s/refresh' % section.get('key'), 'text')
except:
log.error('Plex library update failed for %s, Media Server not running: %s',
(self.plex.conf('media_server'), traceback.format_exc(1)))
return False
return True
def createHost(self, host, port = None):
h = cleanHost(host)
p = urlparse(h)
h = h.rstrip('/')
if port and not p.port:
h += ':%s' % port
return h
Loading…
Cancel
Save