home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 February / maximum-cd-2011-02.iso / DiscContents / digsby_setup85.exe / lib / plugins / nowplaying / winamp.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-11-24  |  11.2 KB  |  401 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. __all__ = [
  5.     'WinampSongChecker']
  6. import sys
  7. from util.ffi import cimport, Struct
  8. from ctypes.wintypes import DWORD
  9. from ctypes import byref, create_string_buffer, create_unicode_buffer, WinError, c_int, c_char_p, addressof, c_char
  10. from path import path
  11. from traceback import print_exc
  12. from nowplaying import SongChecker, register
  13. import logging
  14. log = logging.getLogger('nowplaying.winamp')
  15.  
  16. class WinampSongChecker(SongChecker):
  17.     PROCESS_NAME = 'winamp.exe'
  18.     app_name = 'Winamp'
  19.     name_id = 'winamp'
  20.     CLASS_NAME = u'Winamp v1.x'
  21.     important_keys = ('title', 'artist')
  22.     
  23.     def __init__(self):
  24.         SongChecker.__init__(self)
  25.         self.hwnd = None
  26.         self.hProcess = None
  27.         self.WinampData = None
  28.         self.methods = [
  29.             self._currentSongFromMetadata,
  30.             self._currentSongFromPlaylistTitle,
  31.             self._currentSongFromAppTitle]
  32.  
  33.     
  34.     def running(self, processes = None):
  35.         
  36.         try:
  37.             self.get_instance()
  38.         except:
  39.             self.release()
  40.             return False
  41.  
  42.         return True
  43.  
  44.     
  45.     def WASend(self, *a):
  46.         return SendMessageW(self.hwnd, WM_WA_IPC, *a)
  47.  
  48.     
  49.     def WAWrite(self, what, towhere):
  50.         if type(what) is str:
  51.             buf = create_string_buffer(what)
  52.         else:
  53.             buf = what
  54.         outsize = c_int()
  55.         success = WriteProcessMemory(self.hProcess, towhere._ptr, addressof(buf), len(buf), byref(outsize))
  56.         if not success:
  57.             raise WinError()
  58.         success
  59.         if len(buf) != outsize.value:
  60.             raise Exception("Didn't write enough data (wrote %d, should have written %d)", len(buf), outsize.value)
  61.         len(buf) != outsize.value
  62.  
  63.     
  64.     def WARead(self, address, bufsize = 512):
  65.         if not self.hProcess:
  66.             return None
  67.         if address in (0, 1, -1):
  68.             raise AssertionError('invalid address')
  69.         address in (0, 1, -1)
  70.         string = create_string_buffer(bufsize)
  71.         if not ReadProcessMemory(self.hProcess, address, byref(string), bufsize, 0):
  72.             raise WinError()
  73.         ReadProcessMemory(self.hProcess, address, byref(string), bufsize, 0)
  74.         return string.value
  75.  
  76.     
  77.     def get_metadata(self, filename, metaname):
  78.         if not self.hProcess:
  79.             return None
  80.         metaname = metaname.upper()
  81.         WinampData = self.WinampData
  82.         WAWrite = self.WAWrite
  83.         WASend = self.WASend
  84.         WARead = self.WARead
  85.         efiRemote = None
  86.         fileNameRemote = None
  87.         fieldRemote = None
  88.         resultRemote = None
  89.         efiRemote = WinampData(extendedFileInfoStruct())
  90.         fileNameRemote = WinampData(len(filename) + 1)
  91.         fieldRemote = WinampData(len(metaname) + 1)
  92.         resultRemote = WinampData(512)
  93.         WAWrite(filename, fileNameRemote)
  94.         WAWrite(metaname, fieldRemote)
  95.         WAWrite(extendedFileInfoStruct(filename = fileNameRemote._ptr, metadata = fieldRemote._ptr, ret = resultRemote._ptr, retlen = 512), efiRemote)
  96.         if not WASend(efiRemote._ptr, IPC.GET_EXTENDED_FILE_INFO):
  97.             err = WinError()
  98.             if err.winerror != 0:
  99.                 raise err
  100.             err.winerror != 0
  101.         
  102.         result = WARead(resultRemote._ptr)
  103.         return result
  104.  
  105.     
  106.     def _currentSong(self):
  107.         if not self.hProcess:
  108.             return None
  109.         WinampData = self.WinampData
  110.         WAWrite = self.WAWrite
  111.         WASend = self.WASend
  112.         WARead = self.WARead
  113.         (filename, position) = self.get_current_filename()
  114.         info = dict(status = isplaying.get(WASend(1, IPC.ISPLAYING), 'stopped'), length = WASend(1, IPC.GETOUTPUTTIME), playlist_position = position)
  115.         extrainfo = { }
  116.         errors = { }
  117.         print_errors = False
  118.         for method in self.methods[:]:
  119.             
  120.             try:
  121.                 moreinfo = method(filename, position)
  122.                 for k, v in moreinfo.iteritems():
  123.                     if v:
  124.                         extrainfo[k] = v
  125.                         continue
  126.                     self.hProcess
  127.             except Exception:
  128.                 self.hProcess
  129.                 e = self.hProcess
  130.                 errors[method] = e
  131.                 del e
  132.             except:
  133.                 self.hProcess
  134.  
  135.             if (all,)((lambda .0: for key in .0:
  136. key in extrainfo)(self.important_keys)):
  137.                 break
  138.                 continue
  139.             self.hProcess
  140.         else:
  141.             print_errors = True
  142.         if (sys.DEV or print_errors) and errors:
  143.             for method, error in errors.items():
  144.                 log.info('Exception calling %r: %r', method, error)
  145.             
  146.             del method
  147.             del error
  148.         
  149.         del errors
  150.         if not extrainfo:
  151.             return None
  152.         if filename:
  153.             filepath = path(filename.decode(sys.getfilesystemencoding()))
  154.             extrainfo.update(filepath = unicode(filepath), filename = filepath.namebase)
  155.         
  156.         info.update(extrainfo)
  157.         return info
  158.  
  159.     
  160.     def _currentSongFromAppTitle(self, filename = None, position = None):
  161.         if not self.hProcess:
  162.             return { }
  163.         
  164.         try:
  165.             title = fix_title(GetWindowText(self.hwnd)).decode('fuzzy utf8')
  166.         except WindowsError:
  167.             self.hProcess
  168.             e = self.hProcess
  169.             if e.winerror == 1400:
  170.                 log.debug('invalid window handle for winamp. releasing process handles, etc.')
  171.                 self._release()
  172.                 return { }
  173.             raise e
  174.         except:
  175.             e.winerror == 1400
  176.  
  177.         if re.match('Winamp [0-9]\\.[0-9]+', title):
  178.             return { }
  179.         
  180.         try:
  181.             (artist, title) = title.split(' - ', 1)
  182.         except ValueError:
  183.             re.match('Winamp [0-9]\\.[0-9]+', title)
  184.             re.match('Winamp [0-9]\\.[0-9]+', title)
  185.             e.winerror == 1400
  186.             return { }
  187.  
  188.         return dict(artist = artist, title = title)
  189.  
  190.     
  191.     def _currentSongFromPlaylistTitle(self, filename = None, position = None):
  192.         if not filename and position:
  193.             (filename, position) = self.get_current_filename()
  194.         
  195.         
  196.         try:
  197.             playlist_title = self.WARead(self.WASend(position, IPC.GETPLAYLISTTITLE)).decode('fuzzy utf8')
  198.             if not playlist_title:
  199.                 raise Exception("Couldn't get playlist title")
  200.             playlist_title
  201.         except Exception:
  202.             e = None
  203.             return { }
  204.  
  205.         
  206.         try:
  207.             (artist, title) = playlist_title.split(' - ', 1)
  208.         except ValueError:
  209.             return { }
  210.  
  211.         return dict(artist = artist, title = title)
  212.  
  213.     
  214.     def _currentSongFromMetadata(self, filename = None, position = None):
  215.         if not self.hProcess:
  216.             return { }
  217.         metas = 'title artist genre album comment length year'.split()
  218.         metainfo = { }
  219.         for meta in metas:
  220.             
  221.             try:
  222.                 metainfo[meta] = self.get_metadata(filename, meta).decode('fuzzy utf8')
  223.             continue
  224.             except Exception:
  225.                 None if not filename and position else self.hProcess
  226.                 e = None if not filename and position else self.hProcess
  227.                 if sys.DEV:
  228.                     print_exc()
  229.                 
  230.                 return { }
  231.             
  232.  
  233.         
  234.         return metainfo
  235.  
  236.     
  237.     def get_current_filename(self):
  238.         WASend = self.WASend
  239.         WARead = self.WARead
  240.         filename = None
  241.         position = WASend(0, IPC.GETLISTPOS)
  242.         playlist_length = WASend(0, IPC.GETLISTLENGTH)
  243.         if playlist_length:
  244.             filename = WARead(WASend(position, IPC.GETPLAYLISTFILE))
  245.         
  246.         return (filename, position)
  247.  
  248.     
  249.     def get_instance(self):
  250.         if self.hwnd and self.hProcess:
  251.             return None
  252.         hwnd = FindWindowW(self.CLASS_NAME, None)
  253.         if not hwnd:
  254.             log.debug("couldn't get window handle for winamp")
  255.             self.release()
  256.             raise Exception('No instance found for %r', self)
  257.         hwnd
  258.         self.hwnd = hwnd
  259.         processId = DWORD()
  260.         GetWindowThreadProcessId(hwnd, byref(processId))
  261.         hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, 0, processId)
  262.         if not hProcess:
  263.             pass
  264.         hProcess = None
  265.         if not hProcess:
  266.             log.debug("couldn't get process handle for winamp")
  267.             self.release()
  268.         else:
  269.             self.hProcess = hProcess
  270.             self.WinampData = MakeIPCDatatype(hProcess)
  271.  
  272.     
  273.     def release(self):
  274.         if self.hProcess is not None:
  275.             CloseHandle(self.hProcess)
  276.             self.hwnd = None
  277.             self.hProcess = None
  278.             self.WinampData = None
  279.         
  280.  
  281.  
  282. register(WinampSongChecker)
  283. import re
  284. num_matcher = re.compile('^([0-9]+\\. )')
  285.  
  286. def fix_title(s):
  287.     idx = s.find(' - Winamp')
  288.     if idx >= 0:
  289.         s = s[:idx]
  290.     
  291.     match = num_matcher.match(s)
  292.     if match:
  293.         s = s[len(match.group()):]
  294.     
  295.     return s
  296.  
  297. gwt_buffer = create_unicode_buffer(256)
  298.  
  299. def GetWindowText(hwnd):
  300.     if not GetWindowTextW(hwnd, byref(gwt_buffer), 256):
  301.         raise WinError()
  302.     GetWindowTextW(hwnd, byref(gwt_buffer), 256)
  303.     return gwt_buffer.value
  304.  
  305. cimport(user32 = [
  306.     'SendMessageW',
  307.     'FindWindowW',
  308.     'GetWindowTextW',
  309.     'GetWindowThreadProcessId'], kernel32 = [
  310.     'ReadProcessMemory',
  311.     'WriteProcessMemory',
  312.     'VirtualAllocEx',
  313.     'VirtualFreeEx',
  314.     'OpenProcess',
  315.     'CloseHandle'])
  316.  
  317. def MakeIPCDatatype(hProcess):
  318.     
  319.     class IPCData((object,)):
  320.         HPROCESS = hProcess
  321.         
  322.         def __init__(self, sz, datatype = None):
  323.             if type(sz) is int:
  324.                 if datatype is None:
  325.                     datatype = c_char * sz()
  326.                 
  327.             else:
  328.                 datatype = sz
  329.                 sz = len(datatype)
  330.             self._sz = sz
  331.             self._ptr = VirtualAllocEx(self.HPROCESS, None, sz, MEM_COMMIT, PAGE_READWRITE)
  332.             if not self._ptr:
  333.                 print >>sys.stderr, 'the following WindowsError occurred when callingVirtualAllocEx(%s, None, %s, MEM_COMMIT, PAGE_READWRITE)' % (self.HPROCESS, sz)
  334.                 raise WinError()
  335.             self._ptr
  336.             self._value = type(datatype).from_address(self._ptr)
  337.  
  338.         
  339.         def free(self):
  340.             if self._ptr is not None:
  341.                 if not VirtualFreeEx(self.HPROCESS, self._ptr, 0, MEM_RELEASE):
  342.                     raise WinError()
  343.                 VirtualFreeEx(self.HPROCESS, self._ptr, 0, MEM_RELEASE)
  344.                 self._ptr = None
  345.             
  346.  
  347.         __del__ = free
  348.  
  349.     return IPCData
  350.  
  351.  
  352. class extendedFileInfoStruct(Struct):
  353.     _fields_ = [
  354.         ('filename', c_char_p),
  355.         ('metadata', c_char_p),
  356.         ('ret', c_char_p),
  357.         ('retlen', c_int)]
  358.  
  359. WM_WA_IPC = 1024
  360. PROCESS_ALL_ACCESS = 0
  361. PROCESS_VM_OPERATION = 8
  362. PROCESS_VM_READ = 16
  363. PROCESS_VM_WRITE = 32
  364. MEM_COMMIT = 4096
  365. MEM_DECOMMIT = 16384
  366. MEM_RELEASE = 32768
  367. PAGE_READWRITE = 4
  368.  
  369. class IPC:
  370.     GETVERSION = 0
  371.     ISPLAYING = 104
  372.     GETOUTPUTTIME = 105
  373.     GETLISTLENGTH = 124
  374.     GETLISTPOS = 125
  375.     GETINFO = 126
  376.     GETPLAYLISTFILE = 211
  377.     GETPLAYLISTTITLE = 212
  378.     GET_EXTENDED_FILE_INFO = 290
  379.     GET_EXTENDED_FILE_INFO_HOOKABLE = 296
  380.  
  381. isplaying = {
  382.     0: 'stopped',
  383.     1: 'playing',
  384.     3: 'paused' }
  385. if __name__ == '__main__':
  386.     logging.basicConfig()
  387.     from time import clock
  388.     before = clock()
  389.     checker = WinampSongChecker()
  390.     checker.get_instance()
  391.     print GetWindowText(checker.hwnd)
  392.     for i in range(1):
  393.         print 'apptitle %r' % checker._currentSongFromAppTitle()
  394.         print 'playlist %r' % checker._currentSongFromPlaylistTitle()
  395.         print 'metadata %r' % checker._currentSongFromMetadata()
  396.     
  397.     checker.release()
  398.     duration = clock() - before
  399.     print 'duration', duration
  400.  
  401.