Merge branch 'feature/dev_plex' of git://github.com/fuzeman/CouchPotatoServer into fuzeman-feature/dev_plex

This commit is contained in:
Ruud committed 2013-10-13 13:56:26 +02:00
commit 97b6cf013f
3 files changed
+240 -168

No files matched your search

@@ -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)
+41 -168
View File
@@ -1,183 +1,68 @@
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
self.client_protocols = {
'http': PlexClientHTTP(self),
'json': PlexClientJSON(self)
}
addEvent('renamer.after', self.addToLibrary) 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.clients_updated = datetime.now()
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'] def getClientNames(self):
base_url = '%s/library/sections' % self.createHost(self.conf('media_server'), port = 32400) return [
refresh_url = '%s/%%s/refresh' % base_url x.strip().lower()
for x in self.conf('clients').split(',')
]
try: def notifyClients(self, message, client_names):
sections_xml = self.urlopen(base_url) success = True
xml_sections = minidom.parseString(sections_xml)
sections = xml_sections.getElementsByTagName('Directory')
for s in sections: while len(client_names):
if s.getAttribute('type') in source_type: client_name = client_names[0]
url = refresh_url % s.getAttribute('key') client_success = False
x = self.urlopen(url) client = self.server.clients.get(client_name)
except: if client and client['found']:
log.error('Plex library update failed for %s, Media Server not running: %s', client_success = fireEvent('notify.plex.notifyClient', client, message, single=True)
(self.conf('media_server'), traceback.format_exc(1)))
return False
return True if client_success:
client_names.pop(0)
def sendHTTP(self, command, client): if not client_success:
url = 'http://%s:%s/xbmcCmds/xbmcHttp/?%s' % ( if self.server.staleClients() or not client:
client['address'], log.info('Failed to send notification to client "%s". '
client['port'], 'Client list is stale, updating the client list and retrying.', client_name)
tryUrlencode(command) self.server.updateClients(self.getClientNames())
) else:
log.warning('Failed to send notification to client %s, skipping this time', client_name)
client_names.pop(0)
success = False
headers = {} return success
try: def notify(self, message = '', data = {}, listener = None):
self.urlopen(url, headers = headers, timeout = 3, show_error = False) return self.notifyClients(message, self.getClientNames())
except Exception, err:
log.error("Couldn't sent command to Plex: %s", err)
return False
return True
def notifyHTTP(self, message = '', data = {}, listener = None):
total = 0
successful = 0
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
return True
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 test(self, **kwargs): def test(self, **kwargs):
@@ -185,24 +70,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 { refresh_success = self.addToLibrary()
'success': success or success2
}
def createHost(self, host, port = None): return {'success': notify_success or refresh_success}
h = cleanHost(host)
p = urlparse(h)
h = h.rstrip('/')
if port and not p.port:
h += ':%s' % port
return h
@@ -0,0 +1,114 @@
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, client_names):
log.info('Searching for clients on Plex Media Server')
self.clients = {}
result = self.request('clients')
if not result:
return
found_clients = [
c for c in result.findall('Server')
if c.get('name') and c.get('name').lower() in client_names
]
# Store client details in cache
for client in found_clients:
name = client.get('name').lower()
self.clients[name] = {
'name': client.get('name'),
'found': True,
'address': client.get('address'),
'port': client.get('port'),
'protocol': client.get('protocol', 'xbmchttp')
}
client_names.remove(name)
# Store dummy info for missing clients
for client_name in client_names:
self.clients[client_name] = {
'found': False
}
if len(client_names) > 0:
log.debug('Unable to find clients: %s', ', '.join(client_names))
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