3 changed files with 230 additions and 170 deletions
@ -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) |
@ -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…
Reference in new issue