Advertisement
Guest User

Untitled

a guest
Jun 30th, 2012
552
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.61 KB | None | 0 0
  1. [php]# Author: Nic Wolfe <nic@wolfeden.ca>
  2. # URL: http://code.google.com/p/sickbeard/
  3. #
  4. # This file is part of Sick Beard.
  5. #
  6. # Sick Beard is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # Sick Beard is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with Sick Beard.  If not, see <http://www.gnu.org/licenses/>.
  18.  
  19.  
  20. import urllib, urllib2
  21. import socket
  22. import base64
  23. import time, struct
  24.  
  25. import sickbeard
  26.  
  27. from sickbeard import logger
  28. from sickbeard import common
  29. from sickbeard.exceptions import ex
  30. from sickbeard.encodingKludge import fixStupidEncodings
  31.  
  32. try:
  33.     import xml.etree.cElementTree as etree
  34. except ImportError:
  35.     import xml.etree.ElementTree as etree
  36.  
  37. class XBMCNotifier:
  38.  
  39.     def notify_snatch(self, ep_name):
  40.         if sickbeard.XBMC_NOTIFY_ONSNATCH:
  41.             self._notifyXBMC(ep_name, common.notifyStrings[common.NOTIFY_SNATCH])
  42.  
  43.     def notify_download(self, ep_name):
  44.         if sickbeard.XBMC_NOTIFY_ONDOWNLOAD:
  45.             self._notifyXBMC(ep_name, common.notifyStrings[common.NOTIFY_DOWNLOAD])
  46.  
  47.     def test_notify(self, host, username, password):
  48.         return self._notifyXBMC("Testing XBMC notifications from Sick Beard", "Test Notification", host, username, password, force=True)
  49.  
  50.     def update_library(self, show_name):
  51.         if sickbeard.XBMC_UPDATE_LIBRARY:
  52.             for curHost in [x.strip() for x in sickbeard.XBMC_HOST.split(",")]:
  53.                 # do a per-show update first, if possible
  54.                 if not self._update_library(curHost, showName=show_name) and sickbeard.XBMC_UPDATE_FULL:
  55.                     # do a full update if requested
  56.                     logger.log(u"Update of show directory failed on " + curHost + ", trying full update as requested", logger.ERROR)
  57.                     self._update_library(curHost)
  58.  
  59.     def _username(self):
  60.         return sickbeard.XBMC_USERNAME
  61.  
  62.     def _password(self):
  63.         return sickbeard.XBMC_PASSWORD
  64.  
  65.     def _use_me(self):
  66.         return sickbeard.USE_XBMC
  67.  
  68.     def _hostname(self):
  69.         return sickbeard.XBMC_HOST
  70.  
  71.     def _sendToXBMC(self, command, host, username=None, password=None):
  72.         '''
  73.        Handles communication with XBMC servers
  74.    
  75.        command - Dictionary of field/data pairs, encoded via urllib.urlencode and
  76.        passed to /xbmcCmds/xbmcHttp
  77.    
  78.        host - host/ip + port (foo:8080)
  79.        '''
  80.    
  81.         if not username:
  82.             username = self._username()
  83.         if not password:
  84.             password = self._password()
  85.    
  86.         for key in command:
  87.             if type(command[key]) == unicode:
  88.                 command[key] = command[key].encode('utf-8')
  89.    
  90.         enc_command = urllib.urlencode(command)
  91.         logger.log(u"Encoded command is " + enc_command, logger.DEBUG)
  92.         # Web server doesn't like POST, GET is the way to go
  93.         url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command)
  94.    
  95.         try:
  96.             # If we have a password, use authentication
  97.             req = urllib2.Request(url)
  98.             if password:
  99.                 logger.log(u"Adding Password to XBMC url", logger.DEBUG)
  100.                 base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
  101.                 authheader =  "Basic %s" % base64string
  102.                 req.add_header("Authorization", authheader)
  103.    
  104.             logger.log(u"Contacting XBMC via url: " + url, logger.DEBUG)
  105.             handle = urllib2.urlopen(req)
  106.             response = handle.read().decode(sickbeard.SYS_ENCODING)
  107.             logger.log(u"response: " + response, logger.DEBUG)
  108.         except IOError, e:
  109.             logger.log(u"Warning: Couldn't contact XBMC HTTP server at " + fixStupidEncodings(host) + ": " + ex(e))
  110.             response = ''
  111.    
  112.         return response
  113.  
  114.     def _notifyXBMC(self, input, title="Sick Beard", host=None, username=None, password=None, force=False):
  115.    
  116.         if not self._use_me() and not force:
  117.             logger.log("Notification for XBMC not enabled, skipping this notification", logger.DEBUG)
  118.             return False
  119.    
  120.         if not host:
  121.             host = self._hostname()
  122.         if not username:
  123.             username = self._username()
  124.         if not password:
  125.             password = self._password()
  126.    
  127.         logger.log(u"Sending notification for " + input, logger.DEBUG)
  128.    
  129.         fileString = title + "," + input
  130.    
  131.         result = ''
  132.    
  133.         for curHost in [x.strip() for x in host.split(",")]:
  134.             command = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' +fileString + ')' }
  135.             logger.log(u"Sending notification to XBMC via host: "+ curHost +"username: "+ username + " password: " + password, logger.DEBUG)
  136.             if result:
  137.                 result += ', '
  138.             result += curHost + ':' + self._sendToXBMC(command, curHost, username, password)
  139.  
  140.         return result
  141.  
  142.     def _update_library(self, host, showName=None):
  143.    
  144.         if not self._use_me():
  145.             logger.log("Notifications for XBMC not enabled, skipping library update", logger.DEBUG)
  146.             return False
  147.    
  148.         logger.log(u"Updating library in XBMC", logger.DEBUG)
  149.    
  150.         if not host:
  151.             logger.log('No host specified, no updates done', logger.DEBUG)
  152.             return False
  153.    
  154.         # if we're doing per-show
  155.         if showName:
  156.             pathSql = 'select path.strPath from path, tvshow, tvshowlinkpath where ' \
  157.                 'tvshow.c00 = "%s" and tvshowlinkpath.idShow = tvshow.idShow ' \
  158.                 'and tvshowlinkpath.idPath = path.idPath' % (showName)
  159.    
  160.             # Use this to get xml back for the path lookups
  161.             xmlCommand = {'command': 'SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)'}
  162.             # Sql used to grab path(s)
  163.             sqlCommand = {'command': 'QueryVideoDatabase(%s)' % (pathSql)}
  164.             # Set output back to default
  165.             resetCommand = {'command': 'SetResponseFormat()'}
  166.    
  167.             # Set xml response format, if this fails then don't bother with the rest
  168.             request = self._sendToXBMC(xmlCommand, host)
  169.             if not request:
  170.                 return False
  171.    
  172.             sqlXML = self._sendToXBMC(sqlCommand, host)
  173.             request = self._sendToXBMC(resetCommand, host)
  174.    
  175.             if not sqlXML:
  176.                 logger.log(u"Invalid response for " + showName + " on " + host, logger.DEBUG)
  177.                 return False
  178.    
  179.             encSqlXML = urllib.quote(sqlXML,':\\/<>')
  180.             try:
  181.                 et = etree.fromstring(encSqlXML)
  182.             except SyntaxError, e:
  183.                 logger.log("Unable to parse XML returned from XBMC: "+ex(e), logger.ERROR)
  184.                 return False
  185.    
  186.             paths = et.findall('.//field')
  187.    
  188.             if not paths:
  189.                 logger.log(u"No valid paths found for " + showName + " on " + host, logger.DEBUG)
  190.                 return False
  191.    
  192.             for path in paths:
  193.                 # Don't need it double-encoded, gawd this is dumb
  194.                 unEncPath = urllib.unquote(path.text).decode(sickbeard.SYS_ENCODING)
  195.                 logger.log(u"XBMC Updating " + showName + " on " + host + " at " + unEncPath, logger.DEBUG)
  196.                 updateCommand = {'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video, %s)' % (unEncPath)}
  197.                 request = self._sendToXBMC(updateCommand, host)
  198.                 if not request:
  199.                     return False
  200.                 # Sleep for a few seconds just to be sure xbmc has a chance to finish
  201.                 # each directory
  202.                 if len(paths) > 1:
  203.                     time.sleep(5)
  204.         else:
  205.             logger.log(u"XBMC Updating " + host, logger.DEBUG)
  206.             updateCommand = {'command': 'ExecBuiltIn', 'parameter': 'XBMC.updatelibrary(video)'}
  207.             request = self._sendToXBMC(updateCommand, host)
  208.    
  209.             if not request:
  210.                 return False
  211.    
  212.         return True
  213.  
  214. # Wake function
  215. def wakeOnLan(ethernet_address):
  216.     addr_byte = ethernet_address.split(':')
  217.     hw_addr = struct.pack('BBBBBB', int(addr_byte[0], 16),
  218.     int(addr_byte[1], 16),
  219.     int(addr_byte[2], 16),
  220.     int(addr_byte[3], 16),
  221.     int(addr_byte[4], 16),
  222.     int(addr_byte[5], 16))
  223.  
  224.     # Build the Wake-On-LAN "Magic Packet"...
  225.     msg = '\xff' * 6 + hw_addr * 16
  226.  
  227.     # ...and send it to the broadcast address using UDP
  228.     ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  229.     ss.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
  230.     ss.sendto(msg, ('<broadcast>', 9))
  231.     ss.close()
  232.  
  233. # Test Connection function
  234. def isHostUp(host,port):
  235.  
  236.     (family, socktype, proto, garbage, address) = socket.getaddrinfo(host, port)[0] #@UnusedVariable
  237.     s = socket.socket(family, socktype, proto)
  238.  
  239.     try:
  240.         s.connect(address)
  241.         return "Up"
  242.     except:
  243.         return "Down"
  244.  
  245.  
  246. def checkHost(host, port):
  247.  
  248.     # we should try to get this programmatically from the IP
  249.     mac = ""
  250.  
  251.     i=1
  252.     while isHostUp(host,port)=="Down" and i<4:
  253.         wakeOnLan(mac)
  254.         time.sleep(20)
  255.         i=i+1
  256.  
  257. notifier = XBMCNotifier[/php]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement