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.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.variable import cleanHost
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification
from datetime import datetime
from urlparse import urlparse
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
from .client import PlexClientHTTP, PlexClientJSON
from .server import PlexServer
log = CPLog(__name__)
class Plex(Notification):
client_update_time = 5 * 60
http_time_between_calls = 0
def __init__(self):
super(Plex, self).__init__()
self.clients = {}
self.clients_updated = None
self.server = PlexServer(self)
addEvent('renamer.after', self.addToLibrary)
def updateClients(self, force = False):
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.client_protocols = {
'http': PlexClientHTTP(self),
'json': PlexClientJSON(self)
}
self.clients_updated = datetime.now()
addEvent('renamer.after', self.addToLibrary)
def addToLibrary(self, message = None, group = {}):
if self.isDisabled(): return
log.info('Sending notification to Plex')
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 = {}
return self.server.refresh()
try:
self.urlopen(url, headers = headers, timeout = 3, show_error = False)
except Exception, err:
log.error("Couldn't sent command to Plex: %s", err)
return False
def notifyClients(self, message, clients):
success = True
return True
while len(clients):
client = clients[0]
def notifyHTTP(self, message = '', data = {}, listener = None):
total = 0
successful = 0
success = fireEvent('notify.plex.notifyClient', client, message, single=True)
data = {
'command': 'ExecBuiltIn',
'parameter': 'Notification(CouchPotato, %s)' % message
}
for name, client in self.clients.items():
if client['protocol'] == 'xbmchttp':
total += 1
if self.sendHTTP(data, client):
successful += 1
return successful == total
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
if success:
clients.pop(0)
else:
if self.server.staleClients():
log.info('Failed to send notification to client "%s". '
'Client list is stale, updating the client list and retrying.', client['name'])
self.server.updateClients()
else:
log.warning('Failed to send notification to client %s, skipping this time', client['name'])
clients.pop(0)
success = False
break
return True
return success
def notifyJSON(self, message = '', data = {}, listener = None):
total = 0
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 notify(self, message = '', data = {}, listener = None):
return self.notifyClients(message, self.server.clients.values())
def test(self, **kwargs):
@ -185,24 +61,12 @@ class Plex(Notification):
log.info('Sending test to %s', test_type)
success = self.notify(
notify_success = self.notify(
message = self.test_message,
data = {},
listener = 'test',
force = True
listener = 'test'
)
success2 = self.addToLibrary()
return {
'success': success or success2
}
def createHost(self, host, port = None):
h = cleanHost(host)
p = urlparse(h)
h = h.rstrip('/')
if port and not p.port:
h += ':%s' % port
refresh_success = self.addToLibrary()
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