from couchpotato.core.helpers.variable import splitString from couchpotato.core.logger import CPLog from couchpotato.core.notifications.base import Notification from urllib2 import URLError import base64 import json import socket import traceback import urllib log = CPLog(__name__) class XBMC(Notification): listen_to = ['renamer.after', 'movie.snatched'] use_json_notifications = {} http_time_between_calls = 0 def notify(self, message = '', data = None, listener = None): if not data: data = {} hosts = splitString(self.conf('host')) successful = 0 max_successful = 0 for host in hosts: if self.use_json_notifications.get(host) is None: self.getXBMCJSONversion(host, message = message) if self.use_json_notifications.get(host): calls = [ ('GUI.ShowNotification', {'title': self.default_title, 'message': message, 'image': self.getNotificationImage('small')}), ] if data and data.get('destination_dir') and (not self.conf('only_first') or hosts.index(host) == 0): param = {} if self.conf('remote_dir_scan') or socket.getfqdn('localhost') == socket.getfqdn(host.split(':')[0]): param = {'directory': data['destination_dir']} calls.append(('VideoLibrary.Scan', param)) max_successful += len(calls) response = self.request(host, calls) else: response = self.notifyXBMCnoJSON(host, {'title':self.default_title, 'message':message}) if data and data.get('destination_dir') and (not self.conf('only_first') or hosts.index(host) == 0): response += self.request(host, [('VideoLibrary.Scan', {})]) max_successful += 1 max_successful += 1 try: for result in response: if result.get('result') and result['result'] == 'OK': successful += 1 elif result.get('error'): log.error('XBMC error; %s: %s (%s)', (result['id'], result['error']['message'], result['error']['code'])) except: log.error('Failed parsing results: %s', traceback.format_exc()) return successful == max_successful def getXBMCJSONversion(self, host, message = ''): success = False # XBMC JSON-RPC version request response = self.request(host, [ ('JSONRPC.Version', {}) ]) for result in response: if result.get('result') and type(result['result']['version']).__name__ == 'int': # only v2 and v4 return an int object # v6 (as of XBMC v12(Frodo)) is required to send notifications xbmc_rpc_version = str(result['result']['version']) log.debug('XBMC JSON-RPC Version: %s ; Notifications by JSON-RPC only supported for v6 [as of XBMC v12(Frodo)]', xbmc_rpc_version) # disable JSON use self.use_json_notifications[host] = False # send the text message resp = self.notifyXBMCnoJSON(host, {'title':self.default_title, 'message':message}) for result in resp: if result.get('result') and result['result'] == 'OK': log.debug('Message delivered successfully!') success = True break elif result.get('error'): log.error('XBMC error; %s: %s (%s)', (result['id'], result['error']['message'], result['error']['code'])) break elif result.get('result') and type(result['result']['version']).__name__ == 'dict': # XBMC JSON-RPC v6 returns an array object containing # major, minor and patch number xbmc_rpc_version = str(result['result']['version']['major']) xbmc_rpc_version += '.' + str(result['result']['version']['minor']) xbmc_rpc_version += '.' + str(result['result']['version']['patch']) log.debug('XBMC JSON-RPC Version: %s', xbmc_rpc_version) # ok, XBMC version is supported self.use_json_notifications[host] = True # send the text message resp = self.request(host, [('GUI.ShowNotification', {'title':self.default_title, 'message':message, 'image': self.getNotificationImage('small')})]) for result in resp: if result.get('result') and result['result'] == 'OK': log.debug('Message delivered successfully!') success = True break elif result.get('error'): log.error('XBMC error; %s: %s (%s)', (result['id'], result['error']['message'], result['error']['code'])) break # error getting version info (we do have contact with XBMC though) elif result.get('error'): log.error('XBMC error; %s: %s (%s)', (result['id'], result['error']['message'], result['error']['code'])) log.debug('Use JSON notifications: %s ', self.use_json_notifications) return success def notifyXBMCnoJSON(self, host, data): server = 'http://%s/xbmcCmds/' % host # Notification(title, message [, timeout , image]) cmd = "xbmcHttp?command=ExecBuiltIn(Notification(%s,%s,'',%s))" % (urllib.quote(data['title']), urllib.quote(data['message']), urllib.quote(self.getNotificationImage('medium'))) server += cmd # I have no idea what to set to, just tried text/plain and seems to be working :) headers = { 'Content-Type': 'text/plain', } # authentication support if self.conf('password'): base64string = base64.encodestring('%s:%s' % (self.conf('username'), self.conf('password'))).replace('\n', '') headers['Authorization'] = 'Basic %s' % base64string try: log.debug('Sending non-JSON-type request to %s: %s', (host, data)) # response wil either be 'OK': # #