#!/usr/bin/env python
"""

Shell-Fm Notify  v 0.2
https://launchpad.net/~macno (Michele Azzolari) - 18/03/2009

Just put this line in your ~/.shell-fm/shell-fm.rc
np-cmd = /path/to/shellfm-notify-osd "%a" "%t" "%l"

History
 0.1 First release
 0.2 Added support to notify-osd
 0.3 Checked for last.fm page error
 0.4 Added Pidgin Status update via dbus 

"""

import pygtk, gtk
pygtk.require('2.0')
import pynotify
import os, hashlib
import sys
import urllib, urllib2
import Image
import cgi
import dbus

class DummyURLopener(urllib.FancyURLopener):
    version = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.7) Gecko/2009030422 Ubuntu/8.10 (intrepid) Firefox/3.0.7"

ICON = u"\u266A "

bus = dbus.SessionBus()
obj = bus.get_object("im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject")
purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")

capabilities = {'actions':             False,
                'body':                False,
                'body-hyperlinks':     False,
                'body-images':         False,
                'body-markup':         False,
                'icon-multi':          False,
                'icon-static':         False,
                'sound':               False,
                'image/svg+xml':       False,
                'private-synchronous': False,
                'append':              False,
                'private-icon-only':   False}


def initCaps ():
        caps = pynotify.get_server_caps ()
        if caps is None:
                print "Failed to receive server caps."
                sys.exit (1)

        for cap in caps:
                capabilities[cap] = True

class ShellFmNotify :

  def __init__(self):
    
    self.cache_dir = '%s/.shell-fm/icons' % os.environ['HOME']
    self.lastfm_url = 'http://www.last.fm/music'
  
  def notify(self):

    if not pynotify.init("shellfm-nofify"):
        sys.exit(1)

    a = ''
    t = ''
    l = ''

    try :
      a=sys.argv[1]
      t=sys.argv[2]
      l=sys.argv[3]
    except Exception, e:
      self.usage()
      sys.exit(1)

    initCaps()

    t=cgi.escape(t)
    a=cgi.escape(a)
    l=cgi.escape(l)

    icon = ''
    if capabilities['icon-static']:
       image_path = self.image_cache(a,l)
       icon = "file://%s" % image_path
    
    msg = ''
    if capabilities['body-markup']:
       msg = "Now playing \"%s\" by <b>%s</b> from <i>%s</i>." % (t , a, l)
    else: msg = "Now playing \"%s\" by \"%s\" from \"%s\"." % (t , a, l)

    if purple :
       self.pidgin_status(msg)
    n = pynotify.Notification("Shell-FM", "\n %s \n" % msg,icon)
    n.set_urgency (pynotify.URGENCY_NORMAL)
    n.connect('closed', self.handle_closed)

    if capabilities['actions']:
       n.add_action("skip", "Skip", self.skip_cb)
       n.add_action("love", "Love", self.love_cb)
       n.add_action("ban", "Ban", self.ban_cb)

    if not n.show():
        print "Failed to send notification"
        sys.exit(1)

    if capabilities['actions']:
       gtk.main()


  def image_cache(self,a,l):
    if not os.path.exists(self.cache_dir):
       print 'Creo directory %s' % self.cache_dir 
       os.makedirs(self.cache_dir)
    image_id= a + ' _' + l
    try:
      encoded_url = hashlib.sha1(image_id).hexdigest()
      if len(encoded_url) > 200: encoded_url = encoded_url[::-1][:200]
      #fmt = self.image_url.split('.')[-1] # jpg/png etc.
      #img_path = os.path.join(self.cache_dir, encoded_url + '.' + fmt).replace("\n","")
      img_path = os.path.join(self.cache_dir, encoded_url).replace("\n","")
    except Exception, e:
      from traceback import format_exc
      print format_exc()

    if not os.path.exists(img_path):

      L = '%s/%s/%s' % (self.lastfm_url, a.replace(' ','+'), l.replace(' ','+') )

      urllib._urlopener = DummyURLopener()
      f =  urllib.urlopen(L)
      page = f.read()
      f.close()

      albumnotfound='Album not found'
      
      try:
         page.index(albumnotfound)
         print 'Hum.. album not found: %s' % L
         return None
      except Exception, e:
         albumnotfound=''

      controlstring=",\"medium\":\"http:"
      controlstringend="\",\"mediumsquare\""

      try: 
        iposstart = page.index(controlstring)
        iposend = page.index(controlstringend,iposstart)
        l_image_url = page[iposstart+11:iposend]
        l_image_url = l_image_url.replace("\\/","/")
      except Exception, e:
         albumnotfound=''
         print e
         return None

      fmt = l_image_url.split('.')[-1] # jpg/png etc.
     
      output = open(img_path, "w+")
      try:
        output.write(urllib2.urlopen(l_image_url).read())
        output.close()
        #try:
        #  image = Image.open(img_path)
        #  (x, y) = image.size
        #  if x != 48 or y != 48:
        #    if image.mode == 'P': # need to upsample limited palette images before resizing
        #      image = image.convert('RGBA')
        #    image = image.resize((48, 48), Image.ANTIALIAS)
        #    image.save(img_path + '.'+ fmt)
        #    os.rename (img_path + '.'+ fmt, img_path)
        #except Exception, e:
        #  from traceback import format_exc
        #  print format_exc()
      except IOError, e:
        if hasattr(e, 'reason'): # URLError
          print 'image_cache URL Error: %s whilst fetching %s' % (e.reason, url)
        elif hasattr(e, 'code') and hasattr(e, 'msg') and hasattr(e, 'url'): # HTTPError
          print 'image_cache HTTP Error %s: %s whilst fetching %s' % (e.code, e.msg, e.url)
        else:
          print e
        # if there were any problems getting the avatar img and it still doesn't then return None
        os.remove(img_path)
        return None

    return img_path

  def love_cb(self,n, action):
     assert action == 'love'
     os.system('/bin/echo love | /bin/nc localhost 54311');
     n.close()
     gtk.main_quit()


  def skip_cb(self,n, action):
     assert action == 'skip'
     os.system('/bin/echo skip | /bin/nc localhost 54311');
     n.close()
     gtk.main_quit()

  def ban_cb(self,n, action):
     assert action == 'ban'
     os.system('/bin/echo ban | /bin/nc localhost 54311');
     n.close()
     gtk.main_quit()

  def handle_closed(self,n):
     n.close()
     gtk.main_quit()

  def usage(self):
     print "Usage:\n\tshellfm-notify <artist> <song> <album>\n"

  def pidgin_status(self,message):
	old_status = purple.PurpleSavedstatusGetCurrent()		# get current status
	status_type = purple.PurpleSavedstatusGetType(old_status)	# get current status type
	new_status = purple.PurpleSavedstatusNew("", status_type)	# create new status with old status type
	purple.PurpleSavedstatusSetMessage(new_status, ICON + message)	# fill new status with status message
	purple.PurpleSavedstatusActivate(new_status)			# activate new status

     
if __name__ == '__main__':
  sfn = ShellFmNotify()
  sfn.notify()
