+++ /dev/null
-import hildon
-import gtk
-import gobject
-from album_art_thread import MussorgskyAlbumArt
-
-RESPONSE_CLICK = 1
-
-import i18n
-_ = i18n.language.gettext
-
-class ClickableImage (gtk.EventBox):
-
- def __init__ (self, isRemoveOption=False):
- gtk.EventBox.__init__ (self)
-
- self.isRemoveOption = isRemoveOption
-
- self.img = gtk.Image ()
- self.img.set_size_request (124, 124)
- self.add (self.img)
- self.set_sensitive (False)
-
- self.img_path = None
- self.thumb_path = None
-
- if (self.isRemoveOption):
- self.img.set_from_icon_name ("mediaplayer_default_album",
- gtk.ICON_SIZE_MENU)
- self.img.set_pixel_size (124)
- self.set_sensitive (True)
-
- def set_image (self, tmp_img, tmp_thumb):
- assert not self.isRemoveOption
- self.img_path = tmp_img
- self.thumb_path = tmp_thumb
- self.img.set_from_file (self.thumb_path)
- self.set_sensitive (True)
-
- def set_default_image (self):
- self.img.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
-
- def get_paths (self):
- return self.img_path, self.thumb_path
-
- def is_remove_option (self):
- return self.isRemoveOption
-
-
-class AlbumArtSelectionDialog (gtk.Dialog):
-
- def __init__ (self, parent, artist, album, size, downloader=None):
- """
- parent window, amount of images to offer
- Optionally downloader (for testing porpouses)
- """
- gtk.Dialog.__init__ (self,
- _("Select album art"), parent,
- gtk.DIALOG_DESTROY_WITH_PARENT,
- (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
- self.artist = artist
- self.album = album
- self.size = size
- self.__create_view (size)
- self.cancel = False
- self.connect ("response", self.handle_response)
-
- if (downloader):
- self.downloader = downloader
- else:
- self.downloader = MussorgskyAlbumArt ()
-
- gobject.idle_add (self.__get_alternatives_async)
- self.selection_img = None
- self.selection_thumb = None
- hildon.hildon_gtk_window_set_progress_indicator (self, 1)
-
-
- def __create_view (self, size):
- hbox = gtk.HBox (homogeneous=True)
-
- self.images = []
- for i in range (0, size):
- image = ClickableImage ()
- image.connect ("button-release-event", self.click_on_img)
- self.images.append (image)
- hbox.pack_start (image, expand=False, fill=True)
-
- # default empty option
- image = ClickableImage (isRemoveOption=True)
- image.connect ("button-release-event", self.click_on_img)
- self.images.append (image)
- hbox.pack_start (image, expand=False, fill=True)
- self.vbox.pack_start (hbox, padding=24)
-
- label = gtk.Label (_("New search:"))
- self.entry = hildon.Entry (gtk.HILDON_SIZE_FINGER_HEIGHT)
- self.entry.set_text (self.artist + " " + self.album)
-
- img = gtk.Image ()
- img.set_from_icon_name ("general_search", gtk.ICON_SIZE_LARGE_TOOLBAR)
- button = hildon.Button (gtk.HILDON_SIZE_FINGER_HEIGHT,
- hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
- button.set_image (img)
- button.connect ("clicked", self.user_text_search_cb, self.entry)
- self.hbox_research = gtk.HBox (homogeneous=False, spacing=6)
- self.hbox_research.pack_start (label, expand=False)
- self.hbox_research.pack_start (self.entry)
- self.hbox_research.pack_start (button, expand=False)
- self.hbox_research.set_sensitive (False)
- self.vbox.pack_start (self.hbox_research, padding=6)
-
- def __get_alternatives_async (self):
- results = self.downloader.get_alternatives (self.album,
- self.artist,
- self.size)
- self.__show_results (results)
-
- def __show_results (self, generator):
- counter = 0
- for (path, thumb) in generator:
- print path, thumb
- if (self.cancel):
- return False
- if (thumb):
- print "Setting", thumb, "as image"
- self.images[counter].set_image (path, thumb)
- else:
- continue
- counter += 1
- while (gtk.events_pending()):
- gtk.main_iteration()
-
- while (counter < self.size):
- self.images[counter].set_default_image ()
- counter += 1
-
- hildon.hildon_gtk_window_set_progress_indicator (self, 0)
- self.hbox_research.set_sensitive (True)
- self.entry.grab_focus ()
- self.entry.select_region (0, -1)
-
- def user_text_search_cb (self, w, entry):
- user_text = entry.get_text ()
- if user_text and len (user_text) > 0:
- hildon.hildon_gtk_window_set_progress_indicator (self, 1)
- for ev in self.images[:-1]:
- ev.set_sensitive (False)
- self.hbox_research.set_sensitive (False)
- while (gtk.events_pending()):
- gtk.main_iteration()
-
- results = self.downloader.get_alternatives_free_text (user_text,
- self.size)
- self.__show_results (results)
-
-
- def click_on_img (self, image, event):
- if (image.is_remove_option ()):
- self.selection_img = None
- self.selection_thumb = None
- self.downloader.reset_alternative (self.artist, self.album)
- else:
- tmp_img, tmp_thumb = image.get_paths ()
- img, thumb = self.downloader.save_alternative (self.artist,
- self.album,
- tmp_img,
- tmp_thumb)
- self.selection_img, self.selection_thumb = img, thumb
- self.response (RESPONSE_CLICK)
-
- def get_selection (self):
- return (self.selection_img, self.selection_thumb)
-
- def handle_response (self, widget, response_id):
- self.cancel = True
- # Return False to continue propagating the signal
- return False
-
-if __name__ == "__main__":
-
- import time
- class MockDownloader:
- def __init__ (self):
- self.alt = [("../hendrix.jpeg", "../thumb1.124.jpeg"),
- ("../hoover.jpeg", "../thumb2.124.jpeg"),
- ("../backbeat.jpeg", "../thumb3.124.jpeg"),
- ("../dylan.jpeg", "../thumb5.jpeg")]
- def get_alternatives (self, album, artist, amount):
- for a in self.alt:
- time.sleep (1)
- yield a
- def get_alternatives_free_text (self, user_text, amount=4):
- for a in [("free%d" % i, "thumb%d" %i) for i in range (0, amount)]:
- time.sleep (1)
- yield a
- def save_alternative (self, artist, album, img, thumb):
- return ("/home/user/.cache/media-art/" + img, "/home/user/.thumbnails/normal/" + thumb)
- def reset_alternative (self, artist, album):
- print "Removing the album-art and the thumbnail"
-
-
- def clicked_button (self):
- aadd = AlbumArtSelectionDialog (w, "joe henderson", "blue note", 4, MockDownloader ())
- aadd.show_all ()
- response = aadd.run ()
- if response == gtk.RESPONSE_CLOSE or response == gtk.RESPONSE_DELETE_EVENT or response == gtk.RESPONSE_REJECT:
- print "Noooo"
- else:
- print "RESPONSE_CLICK", response == RESPONSE_CLICK
- print "Selected", aadd.get_selection ()
- aadd.hide ()
-
- w = gtk.Window ()
- w.connect ("destroy", gtk.main_quit)
- box = gtk.VBox ()
-
- button = gtk.Button ("click")
- button.connect ("clicked", clicked_button)
- box.add (button)
-
- w.add (box)
- w.show_all ()
-
-
- gtk.main ()
-
+++ /dev/null
-#!/usr/bin/env python2.5
-import hildon
-import gtk, gobject
-import os
-from album_art_spec import getCoverArtThumbFileName
-from download_dialog import MussorgskyAlbumArtDownloadDialog
-from utils import escape_html
-from aa_selection_dialog import AlbumArtSelectionDialog, RESPONSE_CLICK
-
-import time
-
-EMPTY_PIXBUF = gtk.gdk.Pixbuf (gtk.gdk.COLORSPACE_RGB, False, 8, 64, 64)
-
-import i18n
-_ = i18n.language.gettext
-
-class MussorgskyAlbumArtPanel (hildon.StackableWindow):
-
- def __init__ (self, album_artists):
- hildon.StackableWindow.__init__ (self)
- self.set_title (_("Album art selection"))
- self.set_border_width (12)
- self.__create_view ()
- self.downloader = None
- # Visible string, image, artist, album, painted!
- self.model = gtk.ListStore (str, gtk.gdk.Pixbuf, str, str, bool)
- for p in album_artists:
- if (not p[0]):
- continue
- t = (None, None, p[1], p[0], False)
- self.model.append (t)
-
- self.treeview.set_model (self.model)
-
- def __create_view (self):
- self.treeview = gtk.TreeView ()
- self.treeview.connect ("row-activated", self.row_activated_cb)
-
- artist_column = gtk.TreeViewColumn ("Artist", gtk.CellRendererText (), markup=0)
- artist_column.set_expand (True)
- self.treeview.append_column (artist_column)
-
- renderer = gtk.CellRendererPixbuf ()
- album_art = gtk.TreeViewColumn ("Album art", renderer, pixbuf=1)
- # This doesn't have real effect:
- album_art.set_sizing (gtk.TREE_VIEW_COLUMN_FIXED)
- album_art.set_fixed_width (64)
-
- album_art.set_cell_data_func (renderer, self.album_art_cell_data_cb)
- self.treeview.append_column (album_art)
-
- pannable_area = hildon.PannableArea ()
- pannable_area.add (self.treeview)
- self.add (pannable_area)
-
- # Menu
- menu = hildon.AppMenu ()
- automatic_retrieval = hildon.Button (hildon.BUTTON_STYLE_NORMAL,
- hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
- automatic_retrieval.set_title (_("Automatic download"))
- automatic_retrieval.connect ("clicked", self.get_all_album_art)
- menu.append (automatic_retrieval)
- menu.show_all ()
- self.set_app_menu (menu)
-
- def album_art_cell_data_cb (self, column, cell, model, iter):
- text, pixbuf, artist, album, not_first_time = model.get (iter, 0, 1, 2, 3, 4)
- if (not_first_time):
- if (text == None):
- text = "".join (["<b>", escape_html (album),"</b>\n<small>",
- escape_html(artist), "</small>"])
- model.set (iter, 0, text)
-
- if (pixbuf == None):
- #print "Calling album art cell data cb", model.get (iter, 3)
- album_art_path = getCoverArtThumbFileName (album)
- if (os.path.exists (album_art_path)):
- pxb = gtk.gdk.pixbuf_new_from_file_at_size (album_art_path, 64, 64)
- model.set (iter, 1, pxb)
- else:
- #print "Cannot find thumbnail in '%s'" % (album_art_path)
- model.set (iter, 1, EMPTY_PIXBUF)
-
- else:
- model.set (iter, 4, True)
-
- def get_all_album_art (self, user_data):
- dialog = MussorgskyAlbumArtDownloadDialog (self)
- dialog.show_all ()
- dialog.do_the_job (self.model)
-
- def row_activated_cb (self, treeview, path, view_colum):
- it = treeview.get_model ().get_iter (path)
- artist = treeview.get_model ().get_value (it, 2)
- album = treeview.get_model ().get_value (it, 3)
- if (artist.find ('|') != -1):
- artist = "Various artists"
-
- dialog = AlbumArtSelectionDialog (self, artist, album, 5)
- dialog.show_all ()
-
- response = dialog.run ()
- if (response == RESPONSE_CLICK):
- (img, thumb) = dialog.get_selection ()
- if img and thumb:
- pixbuf = gtk.gdk.pixbuf_new_from_file_at_size (thumb, 64, 64)
- treeview.get_model ().set (it, 1, pixbuf)
- else:
- treeview.get_model ().set (it, 1, EMPTY_PIXBUF)
- dialog.destroy ()
-
-
-if __name__ == "__main__":
- import random
-
- artists_albums = [("Artist %d|artist Y" % i, "Album <%d>" % i) for i in range (0, 10)]
-
- # Overwrite the get thumb path for testing
- def local_file (path):
- return "../thumb%d.124.jpeg" % (random.randint (0, 3))
-
- global getCoverArtThumbFileName
- getCoverArtThumbFileName = local_file
-
- window = MussorgskyAlbumArtPanel (artists_albums)
- window.connect ("destroy", gtk.main_quit )
- window.show_all ()
- gtk.main ()
+++ /dev/null
-import os
-import md5
-import unicodedata
-import string
-
-COVERS_LOCATION = os.getenv ("HOME") + "/.cache/media-art/"
-THUMBS_LOCATION = os.getenv ("HOME") + "/.thumbnails/cropped/"
-
-# Hardcoded locations for testing in scratchbox
-#
-#COVERS_LOCATION = "/home/user/.cache/media-art/"
-#THUMBS_LOCATION = "/home/user/.thumbnails/cropped/"
-
-# Do this only once...
-import ctypes
-clib = ctypes.CDLL ("libhildonthumbnail.so.0")
-
-album_art_func = clib.hildon_albumart_get_path
-album_art_func.restype = ctypes.c_char_p
-
-def getCoverArtFileName (album):
- return album_art_func (None, album, "album")
-
-def getCoverArtThumbFileName (album):
- artFile = getCoverArtFileName (album)
- if not artFile.startswith ("file://"):
- artFile = "file://" + artFile
- thumbFile = THUMBS_LOCATION + md5.new (artFile).hexdigest() + ".jpeg"
- return thumbFile
-
-def get_thumb_filename_for_path (path):
- if not path.startswith ("file://"):
- path = "file://" + path
- thumbnail = THUMBS_LOCATION + md5.new (path).hexdigest () + ".jpeg"
- return thumbnail
-
-if __name__ == "__main__":
- import sys
- from optparse import OptionParser
-
- parser = OptionParser()
- parser.add_option ("-a", "--artist", dest="artist", type="string",
- help="ARTIST to look for", metavar="ARTIST")
- parser.add_option ("-b", "--album", dest="album", type="string",
- help="ALBUM to look for", metavar="ALBUM")
-
- (options, args) = parser.parse_args ()
- print options
- if (not options.artist and not options.album):
- parser.print_help ()
- sys.exit (-1)
-
- print "Album art :", getCoverArtFileName (options.album)
- print "Thumbnail (album):", getCoverArtThumbFileName (options.album)
- print "Thumbnail (path) :", get_thumb_filename_for_path (getCoverArtFileName(options.album))
+++ /dev/null
-#!/usr/bin/env python2.5
-import os
-from album_art_spec import getCoverArtFileName, getCoverArtThumbFileName, get_thumb_filename_for_path
-from utils import UrllibWrapper
-import dbus, time
-import string
-import urllib
-
-try:
- import libxml2
- libxml_available = True
-except ImportError:
- libxml_available = False
-
-try:
- import PIL
- import Image
-except ImportError:
- import sys
- print "Please install python-imaging package"
- sys.exit (-1)
-
-
-LASTFM_APIKEY = "1e1d53528c86406757a6887addef0ace"
-BASE_LASTFM = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo"
-
-
-BASE_MSN = "http://www.bing.com/images/search?q="
-MSN_MEDIUM = "+filterui:imagesize-medium"
-MSN_SMALL = "+filterui:imagesize-medium"
-MSN_SQUARE = "+filterui:aspect-square"
-MSN_PHOTO = "+filterui:photo-graphics"
-
-CACHE_LOCATION = os.path.join (os.getenv ("HOME"), ".cache", "mussorgsky")
-# LastFM:
-# http://www.lastfm.es/api/show?service=290
-#
-
-
-import threading
-class AADownloadThread (threading.Thread):
-
- def __init__ (self, url, counter):
- threading.Thread.__init__ (self, target=self.grab_image, args=(url,))
- self.thumbnailer = LocalThumbnailer ()
- self.counter = counter
- self.image_path = None
- self.thumb_path = None
- self.urllib_wrapper = UrllibWrapper ()
-
- def grab_image (self, image_url):
- print "Working", self.counter
- image = self.urllib_wrapper.get_url (image_url)
- if (image):
- self.image_path = os.path.join (CACHE_LOCATION, "alternative-" + str(self.counter))
- self.thumb_path = os.path.join (CACHE_LOCATION, "alternative-" + str(self.counter) + "thumb")
- self.urllib_wrapper.save_content_into_file (image, self.image_path)
- self.thumbnailer.create (self.image_path, self.thumb_path)
-
- def get_result (self):
- return self.image_path, self.thumb_path
-
-
-
-class MussorgskyAlbumArt:
-
- def __init__ (self):
- bus = dbus.SessionBus ()
-
- if (not os.path.exists (CACHE_LOCATION)):
- os.makedirs (CACHE_LOCATION)
-
- self.thumbnailer = LocalThumbnailer ()
- self.urllib_wrapper = UrllibWrapper ()
-
- def get_album_art (self, artist, album, force=False):
- """
- Return a tuple (album_art, thumbnail_album_art)
- """
- filename = getCoverArtFileName (album)
- thumbnail = getCoverArtThumbFileName (album)
-
- album_art_available = False
- if (os.path.exists (filename) and not force):
- print "Album art already there " + filename
- album_art_available = True
- else:
- results_page = self.__msn_images (artist, album)
- for online_resource in self.__get_url_from_msn_results_page (results_page):
- print "Choosed:", online_resource
- content = self.urllib_wrapper.get_url (online_resource)
- if (content):
- print "Albumart: %s " % (filename)
- self.urllib_wrapper.save_content_into_file (content, filename)
- album_art_available = True
- break
-
- if (not album_art_available):
- return (None, None)
-
- if (not os.path.exists (thumbnail) or force or album_art_available):
- if (not self.__request_thumbnail (filename)):
- print "Failed doing thumbnail. Probably album art is not an image!"
- os.remove (filename)
- return (None, None)
- else:
- print "Thumbnail exists (and probably valid) " + thumbnail
-
- return (filename, thumbnail)
-
-
- def get_alternatives (self, artist, album, max_alternatives=4):
- """
- return a list of paths of possible album arts
- """
- results_page = self.__msn_images (artist, album)
- return self.__process_results_page (results_page, max_alternatives)
-
- def get_alternatives_free_text (self, search_text, max_alternatives=4):
- results_page = self.__msn_images_free_text (search_text)
- return self.__process_results_page (results_page, max_alternatives)
-
- def __process_results_page (self, results_page, max_alternatives):
- counter = 0
- threads = []
- for image_url in self.__get_url_from_msn_results_page (results_page):
- if (not image_url):
- # Some searches doesn't return anything at all!
- break
-
- if (counter >= max_alternatives):
- break
-
- t = AADownloadThread (image_url, counter)
- t.start ()
- threads.append (t)
- counter += 1
-
- for t in threads:
- t.join (5)
- if (t.isAlive ()):
- yield (None, None)
- else:
- yield t.get_result ()
-
-
- def save_alternative (self, artist, album, img_path, thumb_path):
- if not os.path.exists (img_path) or not os.path.exists (thumb_path):
- print "**** CRITICAL **** image in path", path, "doesn't exist!"
- return (None, None)
-
- filename = getCoverArtFileName (album)
- thumbnail = getCoverArtThumbFileName (album)
-
- os.rename (img_path, filename)
- os.rename (thumb_path, thumbnail)
-
- return (filename, thumbnail)
-
- def reset_alternative (self, artist, album):
-
- for filepath in [getCoverArtFileName (album),
- getCoverArtThumbFileName (album)]:
- if os.path.exists (filepath):
- os.remove (filepath)
-
- def __msn_images (self, artist, album):
-
- good_artist = self.__clean_string_for_search (artist)
- good_album = self.__clean_string_for_search (album)
-
- if (good_album and good_artist):
- full_try = BASE_MSN + good_album + "+" + good_artist + MSN_MEDIUM + MSN_SQUARE
- print "Searching (album + artist): %s" % (full_try)
- result = self.urllib_wrapper.get_url (full_try)
- if (result and result.find ("no_results") == -1):
- return result
-
- if (album):
- if (album.lower ().find ("greatest hit") != -1):
- print "Ignoring '%s': too generic" % (album)
- pass
- else:
- album_try = BASE_MSN + good_album + MSN_MEDIUM + MSN_SQUARE
- print "Searching (album): %s" % (album_try)
- result = self.urllib_wrapper.get_url (album_try)
- if (result and result.find ("no_results") == -1):
- return result
-
- if (artist):
- artist_try = BASE_MSN + good_artist + "+CD+music" + MSN_SMALL + MSN_SQUARE + MSN_PHOTO
- print "Searching (artist CD): %s" % (artist_try)
- result = self.urllib_wrapper.get_url (artist_try)
- if (result and result.find ("no_results") == -1):
- return result
-
- return None
-
- def __msn_images_free_text (self, search_text):
- full_try = BASE_MSN + self.__clean_string_for_search (search_text) + MSN_MEDIUM + MSN_SQUARE
- result = self.urllib_wrapper.get_url (full_try)
- return result
-
-
- def __get_url_from_msn_results_page (self, page):
- if (not page):
- return
-
- current_option = None
- starting_at = 0
-
- # 500 is just a safe limit
- for i in range (0, 500):
- # Iterate until find a jpeg
- start = page.find ("imgurl:"", starting_at)
- if (start == -1):
- yield None
- end = page.find ("&", start + len ("imgurl:""))
- current_option = page [start + len ("imgurl:""): end].replace ("amp;", "")
- if (current_option.lower().endswith (".jpg") or
- current_option.lower().endswith (".jpeg")):
- yield current_option
- starting_at = end
-
-
- def __clean_string_for_search (self, text):
- if (not text or len (text) < 1):
- return None
-
- bad_stuff = "_:?\\-~"
- clean = text
- for c in bad_stuff:
- clean = clean.replace (c, " ")
-
- clean.replace ("/", "%2F")
- clean = clean.replace (" CD1", "").replace(" CD2", "")
- return urllib.quote(clean)
-
- def __request_thumbnail (self, filename):
- thumbFile = get_thumb_filename_for_path (filename)
- return self.thumbnailer.create (filename, thumbFile)
-
-
-
-class LocalThumbnailer:
- def __init__ (self):
- self.THUMBNAIL_SIZE = (124,124)
-
- def create (self, fullCoverFileName, thumbFile):
- if (os.path.exists (fullCoverFileName)):
- try:
- image = Image.open (fullCoverFileName)
- image = image.resize (self.THUMBNAIL_SIZE, Image.ANTIALIAS )
- image.save (thumbFile, "JPEG")
- print "Thumbnail: " + thumbFile
- except IOError, e:
- print e
- return False
- return True
-
-
-
-if __name__ == "__main__":
- import sys
- from optparse import OptionParser
-
- parser = OptionParser()
- parser.add_option ("-p", "--print", dest="print_paths",
- action="store_true", default=True,
- help="Print the destination paths")
- parser.add_option ("-r", "--retrieve", dest="retrieve",
- action="store_true", default=False,
- help="Try to retrieve the online content")
- parser.add_option ("-m", "--multiple", dest="multiple",
- action="store_true", default=False,
- help="Show more than one option")
- parser.add_option ("-a", "--artist", dest="artist", type="string",
- help="ARTIST to look for", metavar="ARTIST")
- parser.add_option ("-b", "--album", dest="album", type="string",
- help="ALBUM to look for", metavar="ALBUM")
-
- (options, args) = parser.parse_args ()
- print options
- if (not options.artist and not options.album):
- parser.print_help ()
- sys.exit (-1)
-
- if (options.multiple and options.retrieve):
- print "Multiple and retrieve are incompatible"
- parser.print_help ()
- sys.exit (-1)
-
- if options.print_paths and not options.retrieve:
- print "Album art:", getCoverArtFileName (options.album)
- print "Thumbnail:", getCoverArtThumbFileName (options.album)
-
- if options.retrieve:
- maa = MussorgskyAlbumArt ()
- maa.get_album_art (options.artist, options.album)
-
- if options.multiple:
- start = time.time ()
- maa = MussorgskyAlbumArt ()
- for (img, thumb) in maa.get_alternatives (options.artist, options.album, 5):
- print img
- print thumb
- end = time.time ()
- print end - start
+++ /dev/null
-#!/usr/bin/env python2.5
-import hildon
-import gtk, gobject, glib
-from edit_panel_tm import MussorgskyEditPanel
-from utils import escape_html, Set, is_empty
-
-# Shared with edit_panel_tm
-URI_COLUMN = 0
-ARTIST_COLUMN = 2
-TITLE_COLUMN = 3
-ALBUM_COLUMN = 4
-MIME_COLUMN = 5
-UI_COLUMN = 6
-SEARCH_COLUMN = 7
-
-SHOW_ALL = 1
-SHOW_UNCOMPLETE = 2
-SHOW_MATCH = 3
-
-import time
-import i18n
-_ = i18n.language.gettext
-
-class MussorgskyBrowsePanel (hildon.StackableWindow):
-
- def __init__ (self, songs_list):
- hildon.StackableWindow.__init__ (self)
- self.set_title (_("All music"))
- self.set_border_width (12)
- self.__create_view ()
-
- # Prepare cache of artists and albums
- self.artist_set = Set ()
- self.albums_set = Set ()
-
- # (uri, "Music", artist, title, album, mimetype) + "string" + search_string
- full_model = gtk.ListStore (str, str, str, str, str, str, str, str)
- for (uri, category, artist, title, album, mime) in songs_list:
- if is_empty (artist) and is_empty (title) and is_empty (album):
- text = "<small>%s</small>" % (escape_html (uri))
- else:
- text = "<b>%s</b>\n<small>%s</small>" % (escape_html (title),
- escape_html (artist) + " / " + escape_html (album))
- search_str = " ".join ([artist.lower (),
- title.lower (),
- album.lower ()])
- full_model.append ((uri, None, artist, title, album, mime, text, search_str))
- self.artist_set.insert (artist)
- self.albums_set.insert (album)
-
- self.filtered_model = full_model.filter_new ()
- self.treeview.set_model (self.filtered_model)
- self.filter_mode = SHOW_ALL
- self.filtered_model.set_visible_func (self.filter_entry)
- self.__set_filter_mode (None, SHOW_ALL)
-
- self.kpid = self.connect ("key-press-event", self.key_pressed_cb)
- self.fpid = None
-
- def __create_view (self):
- vbox = gtk.VBox (homogeneous=False)
-
- menu = hildon.AppMenu ()
- self.all_items = gtk.RadioButton (None, _("All"))
- self.all_items.set_mode (False)
- self.all_items.connect_after ("toggled", self.__set_filter_mode, SHOW_ALL)
- menu.add_filter (self.all_items)
- self.broken_items = gtk.RadioButton (self.all_items, _("Incomplete"))
- self.broken_items.set_mode (False)
- self.broken_items.connect_after ("toggled",
- self.__set_filter_mode, SHOW_UNCOMPLETE)
- menu.add_filter (self.broken_items)
- menu.show_all ()
- self.set_app_menu (menu)
-
- self.treeview = gtk.TreeView ()
- self.treeview.connect ("row-activated", self.row_activated_cb)
- desc_column = gtk.TreeViewColumn ("Song", gtk.CellRendererText (), markup=6)
- desc_column.set_expand (True)
- self.treeview.append_column (desc_column)
-
- pannable_area = hildon.PannableArea ()
- pannable_area.add (self.treeview)
-
- vbox.pack_start (pannable_area, expand=True)
-
- self.search_hbox = gtk.HBox ()
- self.search_entry = hildon.Entry (gtk.HILDON_SIZE_FINGER_HEIGHT)
- self.search_hbox.pack_start (self.search_entry, expand=True)
-
- self.search_close = gtk.Button (stock=gtk.STOCK_CLOSE)
- self.search_hbox.pack_start (self.search_close, expand=False)
- self.search_close.connect ("clicked", self.close_search_cb)
-
- # Hide it when the window is created
- self.search_box_visible = False
- self.search_hbox.set_no_show_all (True)
- self.search_hbox.hide ()
- vbox.pack_start (self.search_hbox, expand=False)
- self.add (vbox)
-
- def search_refilter_cb (self):
- self.treeview.set_model (None)
- self.filtered_model.refilter ()
- self.treeview.set_model (self.filtered_model)
- self.fpid = None
- return False
-
- def search_type (self, widget):
- if (self.fpid):
- glib.source_remove (self.fpid)
- self.fpid = glib.timeout_add (300, self.search_refilter_cb)
-
- def close_search_cb (self, widget):
- assert not self.search_box_visible
- self.search_hbox.hide_all ()
- self.search_entry.set_text ("")
- self.search_box_visible = False
- if (self.all_items.get_active ()):
- self.filter_mode = SHOW_ALL
- else:
- self.filter_mode = SHOW_UNCOMPLETE
- self.filtered_model.refilter ()
- self.kpid = self.connect ("key-press-event", self.key_pressed_cb)
-
- def key_pressed_cb (self, widget, event):
- if (event.type == gtk.gdk.KEY_PRESS):
- if (event.keyval == gtk.gdk.keyval_from_name ("Alt_L")):
- return
-
- if (not self.search_box_visible ):
- self.filter_mode = SHOW_MATCH
- self.search_hbox.set_no_show_all (False)
- self.search_hbox.show_all ()
-
- self.search_entry.grab_focus ()
- self.search_entry.connect ("changed", self.search_type)
- self.disconnect (self.kpid)
-
-
- def row_activated_cb (self, treeview, path, view_colum):
- edit_view = MussorgskyEditPanel ()
- edit_view.set_artist_alternatives (self.artist_set.as_list ())
- edit_view.set_album_alternatives (self.albums_set.as_list ())
- edit_view.set_model (self.treeview.get_model (), self.treeview.get_model ().get_iter (path))
- edit_view.show_all ()
-
- def __update_title_with_filter (self, filter_mode):
- if self.filter_mode == SHOW_ALL:
- self.set_title (_("All music"))
- elif self.filter_mode == SHOW_UNCOMPLETE:
- self.set_title (_("Music with uncomplete metadata"))
- elif self.filter_mode == SHOW_MATCH:
- self.set_title (_("Search results"))
-
-
- def __set_filter_mode (self, button, filter_mode):
- """
- Parameter to use it as callback as well as regular function
- """
- if (filter_mode == self.filter_mode):
- # Don't refilter if there is no change!
- return
- self.filter_mode = filter_mode
- self.__update_title_with_filter (self.filter_mode)
- self.treeview.set_model (None)
- self.filtered_model.refilter ()
- self.treeview.set_model (self.filtered_model)
-
- def filter_entry (self, model, it):
- if self.filter_mode == SHOW_ALL:
- return True
- elif self.filter_mode == SHOW_UNCOMPLETE:
- return self.entry_uncomplete (model, it)
- elif self.filter_mode == SHOW_MATCH:
- return self.entry_with_text (model, it)
-
- def entry_with_text (self, model, it):
- t = self.search_entry.get_text ()
- #return t.lower () in model.get_value (it, SEARCH_COLUMN)
- return model.get_value (it, SEARCH_COLUMN).find (t.lower ()) != -1
-
- def entry_uncomplete (self, model, it):
- r = filter (lambda x: not x or len(x.strip()) == 0,
- model.get (it, ARTIST_COLUMN, TITLE_COLUMN, ALBUM_COLUMN))
- return len (r) > 0
-
-if __name__ == "__main__":
-
- import random
- def get_random_path ():
- path = "file://"
- for i in range (0, random.randint (1, 8)):
- path = path + "/" + ("x"* random.randint (4, 12))
- return path
-
- def get_some_empty_titles (i):
- if random.randint (0, 5) <= 1:
- return ""
- else:
- return "Title <%d>" % i
-
-
- songs = [(get_random_path (),
- "Music",
- "Artist%d" % i,
- get_some_empty_titles (i),
- "album <%d>" % i,
- "audio/mpeg") for i in range (0, 10000)]
-
- songs.append (("file:///no/metadata/at/all",
- "music",
- "",
- "",
- "",
- "audio/mpeg"))
-
- window = MussorgskyBrowsePanel (songs)
- window.connect ("destroy", gtk.main_quit )
- window.show_all ()
- gtk.main ()
+++ /dev/null
-#!/usr/bin/env python2.5
-import gtk, gobject
-from album_art_thread import MussorgskyAlbumArt
-from utils import escape_html
-
-class MussorgskyAlbumArtDownloadDialog (gtk.Dialog):
-
- def __init__ (self, parent, downloader=None):
- gtk.Dialog.__init__ (self,
- "Downloading album art", parent,
- gtk.DIALOG_DESTROY_WITH_PARENT,
- (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
- )
- if (downloader):
- self.downloader = downloader
- else:
- self.downloader = MussorgskyAlbumArt ()
-
- self.set_title ("Downloading album art")
- self.connect ("response", self.handle_response)
- self.__create_view ()
- self.cancel = False
-
- def __create_view (self):
-
- hbox = gtk.HBox (homogeneous=False)
-
- self.album_art = gtk.Image ()
- self.album_art.set_size_request (124, 124)
-
- hbox.pack_start (self.album_art, expand=False, fill=True)
-
- labels = gtk.VBox ()
- self.previous_label = gtk.Label ("")
- labels.pack_start (self.previous_label)
- self.current_label = gtk.Label ("")
- labels.pack_start (self.current_label)
-
- hbox.pack_start (labels, expand=True, fill=False)
-
- self.vbox.add (hbox)
-
-
- def do_the_job (self, artist_albums_model):
- """
- each row: ("Visible text", pixbuf, Artist, Album)
- """
- TOTAL = len (artist_albums_model)
- current = 1
-
- it = artist_albums_model.get_iter_first ()
- while (it):
- while (gtk.events_pending()):
- gtk.main_iteration()
-
- if (self.cancel):
- break
-
- artist = artist_albums_model.get_value (it, 2)
- album = artist_albums_model.get_value (it, 3)
-
- if (artist.find ('|') != -1):
- real_artist = "Various artists"
- else:
- real_artist = artist
- self.current_label.set_markup ("<small>Trying: %s - %s</small>" % (escape_html(real_artist),
- escape_html(album)))
-
- try:
- while (gtk.events_pending()):
- gtk.main_iteration()
-
- if (self.cancel):
- break
-
- (image, thumb) = self.downloader.get_album_art (real_artist, album)
- if thumb:
- pixbuf = gtk.gdk.pixbuf_new_from_file_at_size (thumb, 64, 64)
- artist_albums_model.set_value (it, 1, pixbuf)
- except Exception, e:
- print "Error processing %s - %s" % (artist, album)
- print str(e)
- thumb = None
-
- self.set_title ("Downloading album art (%d/%d)" % (current, TOTAL))
- self.previous_label.set_markup ("<b>%s - %s</b>" % (escape_html(real_artist), escape_html(album)))
-
- if (thumb):
- self.album_art.set_from_file (thumb)
- else:
- self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
-
- current += 1
- it = artist_albums_model.iter_next (it)
-
-
- def handle_response (self, widget, response_id):
- if (response_id == gtk.RESPONSE_DELETE_EVENT):
- print "Cancel the work!"
- self.cancel = True
- self.destroy ()
-
-if __name__ == "__main__":
-
- import time
- import random
- class MockDownloader:
- def __init__ (self):
- self.alt = [("../hendrix.jpeg", "../hendrix-thumb.jpeg"),
- ("../hoover.jpeg", "../hoover-thumb.jpeg"),
- ("../backbeat.jpeg", "../backbeat-thumb.jpeg"),
- ("../dylan.jpeg", "../dylan-thumb.jpeg")]
- self.counter = 0
- def get_album_art (self, artist, album, force=False):
- time.sleep (3)
- return self.alt [random.randint (0, len (self.alt)-1)]
-
- PAIRS_store = gtk.ListStore (str, gtk.gdk.Pixbuf, str, str)
- for i in range (0, 100):
- PAIRS_store.append (("blablabal", None, "Artist %d" % i, "Album %d" %i))
-
- def clicked_button (self):
- aadd = MussorgskyAlbumArtDownloadDialog (w, MockDownloader ())
- aadd.show_all ()
- aadd.do_the_job (PAIRS_store)
-
- w = gtk.Window ()
- box = gtk.VBox ()
-
- button = gtk.Button ("click")
- button.connect ("clicked", clicked_button)
- box.add (button)
-
- w.add (box)
- w.show_all ()
-
-
- gtk.main ()
+++ /dev/null
-#!/usr/bin/env python2.5
-import hildon
-import gtk, gobject
-from mutagen_backend import MutagenBackend
-from player_backend import MediaPlayer
-from utils import escape_html
-import album_art_spec
-import os
-
-# Fields in the tuple!
-# Shared with browse_panel
-URI_COLUMN = 0
-ARTIST_COLUMN = 2
-TITLE_COLUMN = 3
-ALBUM_COLUMN = 4
-MIME_COLUMN = 5
-UI_COLUMN = 6
-SEARCH_COLUMN = 7
-
-THEME_PATH = "/usr/share/themes/default"
-
-import i18n
-_ = i18n.language.gettext
-
-class MussorgskyEditPanel (hildon.StackableWindow):
-
- def __init__ (self):
- hildon.StackableWindow.__init__ (self)
- self.set_border_width (12)
- self.album_change_handler = -1
- self.artist_change_handler = -1
- self.writer = MutagenBackend ()
- self.player = MediaPlayer ()
- self.__create_view ()
- self.data_loaded = False
- self.artist_list = None
- self.albums_list = None
- self.current = None
- self.connect ("delete-event", self.close_function)
-
- def close_function (self, widget, event):
- if (not self.data_loaded):
- return
-
- if self.__is_view_dirty ():
- self.save_metadata ()
-
-
- def update_title (self):
- self.set_title (_("Edit song") + " (%d/%d)" % (self.model.get_path (self.current)[0] + 1,
- len (self.model)))
-
- def get_current_row (self):
- if (not self.current):
- return 6 * (None,)
- return self.model.get (self.current, 0, 1, 2, 3, 4, 5)
-
- def set_model (self, model, current=None):
- assert type(model) == gtk.TreeModelFilter
- try:
- if self.artists_list or self.albums_list:
- pass
- except AttributeError, e:
- print "**** Set album and artist alternatives before setting a model"
- raise e
-
- self.model = model
- if (current):
- self.current = current
- else:
- self.current = self.model.get_iter_first ()
- self.data_loaded = True
- self.set_data_in_view (self.get_current_row ())
- self.update_title ()
-
- def set_current (self, current):
- """
- Iterator to current element
- """
- self.current = current
- self.set_data_in_view (self.get_current_row ())
- self.update_title ()
-
-
- def set_artist_alternatives (self, alternatives):
- self.artists_list = alternatives
- artist_selector = hildon.TouchSelectorEntry (text=True)
- for a in self.artists_list:
- artist_selector.append_text (a)
- self.artist_button.set_selector (artist_selector)
-
- def set_album_alternatives (self, alternatives):
- self.albums_list = alternatives
- album_selector = hildon.TouchSelectorEntry (text=True)
- for a in self.albums_list:
- album_selector.append_text (a)
- self.album_button.set_selector (album_selector)
-
-
- def press_back_cb (self, widget):
- if (self.player.is_playing ()):
- self.player.stop ()
-
- if self.__is_view_dirty ():
- print "Modified data. Save!"
- self.save_metadata ()
-
- path = self.model.get_path (self.current)
- if (path[0] == 0):
- self.destroy ()
- else:
- new_path = ( path[0] -1, )
- self.current = self.model.get_iter (new_path)
- self.set_data_in_view (self.get_current_row ())
- self.update_title ()
-
- def press_next_cb (self, widget):
- if (self.player.is_playing ()):
- self.player.stop ()
-
- if self.__is_view_dirty ():
- print "Modified data. Save!"
- self.save_metadata ()
-
- self.current = self.model.iter_next (self.current)
- if (not self.current):
- self.destroy ()
- else:
- self.set_data_in_view (self.get_current_row ())
- self.update_title ()
-
-
- def save_metadata (self):
- # Save the data in the online model to show the appropiate data
- # in the UI while tracker process the update.
-
- # 0 - filename -> doesn't change
- # 1 - "Music" -> doesn't change
- # 5 - mimetype -> doesn't change
- m = self.model.get_model ()
- c = self.model.convert_iter_to_child_iter (self.current)
-
- artist = self.artist_button.get_value ()
- title = self.title_entry.get_text ()
- album = self.album_button.get_value ()
- text = "<b>%s</b>\n<small>%s</small>" % (escape_html (title),
- escape_html (artist) + " / " + escape_html (album))
- search_str = artist.lower () + " " + title.lower () + " " + album.lower ()
-
- uri, mime = m.get (c, URI_COLUMN, MIME_COLUMN)
- m.set (c,
- ARTIST_COLUMN, artist,
- TITLE_COLUMN, title,
- ALBUM_COLUMN, album,
- UI_COLUMN, text,
- SEARCH_COLUMN, search_str)
- try:
- self.writer.save_metadata_on_file (uri,
- mime,
- self.artist_button.get_value (),
- self.title_entry.get_text (),
- self.album_button.get_value ())
- except IOError, e:
- # This error in case of tracker returning unexistent files.
- # Uhm.... for instance after removing a memory card we are editing!
- pass
-
-
- def __is_view_dirty (self):
- """
- True if the data has been modified in the widgets
- """
- song = self.get_current_row ()
-
- return not (self.filename_data.get_text() == song[URI_COLUMN] and
- self.artist_button.get_value () == song[ARTIST_COLUMN] and
- self.title_entry.get_text () == song[TITLE_COLUMN] and
- self.album_button.get_value () == song[ALBUM_COLUMN] )
-
-
- def __create_view (self):
- view_vbox = gtk.VBox (homogeneous=False, spacing = 12)
-
- filename_row = gtk.HBox ()
- self.filename_data = gtk.Label ("")
- filename_row.pack_start (self.filename_data, expand=True)
-
- #filename_row.pack_start (play_button, expand=False, fill=False)
- view_vbox.pack_start (filename_row, expand=False);
-
- central_panel = gtk.HBox (spacing=12)
-
- table = gtk.Table (3, 2, False)
- table.set_col_spacings (12)
- table.set_row_spacings (12)
-
- central_panel.pack_start (table, fill=True)
- view_vbox.pack_start (central_panel, expand=True, fill=True)
-
- # Title row
- label_title = gtk.Label (_("Title:"))
- table.attach (label_title, 0, 1, 0, 1, 0)
- self.title_entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
- table.attach (self.title_entry, 1, 2, 0, 1)
-
- # Artist row
- self.artist_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
- hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
- self.artist_button.set_title (_("Artist:"))
- # Set data will set the selector
- table.attach (self.artist_button, 0, 2, 1, 2)
-
-
- # Album row
- self.album_button = hildon.PickerButton (gtk.HILDON_SIZE_THUMB_HEIGHT,
- hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
- self.album_button.set_title (_("Album:"))
- # set_data will set the selector
- table.attach (self.album_button, 0, 2, 2, 3)
-
-
- # Album art space
- self.album_art = gtk.Image ()
- self.album_art.set_size_request (124, 124)
- central_panel.pack_start (self.album_art, expand=False, fill=False)
-
- # Buttons row
- button_box = gtk.Toolbar ()
- play_image = os.path.join (THEME_PATH, "mediaplayer", "Play.png")
- play_button = gtk.ToolButton (gtk.image_new_from_file (play_image))
- play_button.connect ("clicked", self.clicked_play)
- play_button.set_expand (True)
- button_box.insert (play_button, -1)
-
- separator = gtk.SeparatorToolItem ()
- separator.set_expand (True)
- button_box.insert (separator, -1)
-
- back_image = os.path.join (THEME_PATH, "mediaplayer", "Back.png")
- back_button = gtk.ToolButton (gtk.image_new_from_file (back_image))
- back_button.connect ("clicked", self.press_back_cb)
- back_button.set_expand (True)
- button_box.insert (back_button, -1)
-
- next_image = os.path.join (THEME_PATH, "mediaplayer", "Forward.png")
- next_button = gtk.ToolButton (gtk.image_new_from_file (next_image))
- next_button.connect ("clicked", self.press_next_cb)
- next_button.set_expand (True)
- button_box.insert (next_button, -1)
-
- self.add_toolbar (button_box)
-
- self.add (view_vbox)
-
-
- def set_data_in_view (self, song):
- """
- Place in the screen the song information.
- Song is a tuple like (filename, 'Music', title, artist, album, mime)
- """
- assert len (song) == 6
-
- self.filename_data.set_markup ("<small>" + song[URI_COLUMN] + "</small>")
- self.title_entry.set_text (song[TITLE_COLUMN])
-
-
- # Disconnect the value-change signal to avoid extra album art retrievals
- if (self.album_button.handler_is_connected (self.album_change_handler)):
- self.album_button.disconnect (self.album_change_handler)
-
- if (self.artist_button.handler_is_connected (self.artist_change_handler)):
- self.artist_button.disconnect (self.artist_change_handler)
-
- # Set values in the picker buttons
- try:
- self.artist_button.set_active (self.artists_list.index(song[ARTIST_COLUMN]))
- except ValueError:
- print "'%s' not in artist list!?" % (song[ARTIST_COLUMN])
- self.artist_button.set_value ("")
- except AttributeError:
- print "WARNING: Use set_artist_alternatives method to set a list of artists"
-
- try:
- self.album_button.set_active (self.albums_list.index (song[ALBUM_COLUMN]))
- except ValueError:
- print "'%s' is not in the album list!?" % (song[ALBUM_COLUMN])
- self.album_button.set_value ("")
- except AttributeError:
- print "WARNING: Use set_album_alternatives method to set a list of artists"
-
- # Reconnect the signals!
- self.album_change_handler = self.album_button.connect ("value-changed",
- self.album_selection_cb)
-
- self.artist_change_handler = self.artist_button.connect ("value-changed",
- self.artist_selection_cb)
-
- # Set the album art given the current data
- self.set_album_art (song[ALBUM_COLUMN])
-
- if (not song[MIME_COLUMN] in self.writer.get_supported_mimes ()):
- self.artist_button.set_sensitive (False)
- self.album_button.set_sensitive (False)
- self.title_entry.set_sensitive (False)
- else:
- self.artist_button.set_sensitive (True)
- self.album_button.set_sensitive (True)
- self.title_entry.set_sensitive (True)
-
- def set_album_art (self, album):
- has_album = False
- if (album):
- thumb = album_art_spec.getCoverArtThumbFileName (album)
- print "%s -> %s" % (album, thumb)
- if (os.path.exists (thumb)):
- self.album_art.set_from_file (thumb)
- has_album = True
-
- if (not has_album):
- self.album_art.set_from_stock (gtk.STOCK_CDROM, gtk.ICON_SIZE_DIALOG)
-
-
- def clicked_play (self, widget):
- if (self.player.is_playing ()):
- self.player.stop ()
- else:
- song = self.get_current_row ()
- self.player.play ("file://" + song[URI_COLUMN])
-
- def album_selection_cb (self, widget):
- """
- On album change, add the album the local list of albums and the selector
- if it doesn't exist already. So we show the new entry in the selector next time.
- """
- song = self.get_current_row ()
- if (not widget.get_value () in self.albums_list):
- print "Inserting ", widget.get_value ()
- widget.get_selector ().prepend_text (widget.get_value ())
- self.albums_list.insert (0, widget.get_value ())
- self.set_album_art (widget.get_value ())
-
- def artist_selection_cb (self, widget):
- """
- On artist change, add the artist the local list of artists and the selector
- if it doesn't exist already. So we show the new entry in the selector next time
- """
- song = self.get_current_row ()
- if (not widget.get_value () in self.artists_list):
- print "Inserting artist", widget.get_value ()
- widget.get_selector ().prepend_text (widget.get_value ())
- self.artists_list.insert (0, widget.get_value ())
-
-# Testing porpuses
-if __name__ == "__main__":
-
- TEST_DATA = [("/a/b/c/%d.mp3" %i, "Music",
- "Artist %d" % i, "Title %d" % i, "Album %d" % (i*100),
- "audio/mpeg",
- "artist %d album %d" % (i, i*100),
- "text to be searched artist %d album %d" % (i, i*100)) for i in range (0, 4)]
-
- model = gtk.ListStore (str, str, str, str, str, str, str, str)
- for t in TEST_DATA:
- print t
- model.append (t)
-
- window = MussorgskyEditPanel ()
- window.set_artist_alternatives (["Artist %d" % i for i in range (0, 4)])
- window.set_album_alternatives (["Album %d" % (i*100) for i in range (0, 4)])
- window.set_model (model.filter_new ())
- window.connect ("destroy", gtk.main_quit)
- window.show_all ()
- gtk.main ()
+++ /dev/null
-import gtk
-import gobject
-
-BUTTON_HILIGHT_FILE_NAME = "/etc/hildon/theme/mediaplayer/Button.png"
-
-fancy_button_highlight_pb = None
-
-class FancyButton (gtk.EventBox):
-
- __gsignals__ = {
- 'clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ())
- }
-
- def __init__ (self, image, text):
- gtk.EventBox.__init__ (self)
-
- self.pressed = False
-
- vbox = gtk.VBox ()
- self.image = image
- self.label = gtk.Label (text)
-
- align = gtk.Alignment (xalign=0.5, yalign=0.5)
- align.add (self.image)
-
- vbox.pack_start (align, expand=False, fill=False)
- vbox.pack_start (self.label, expand=False, fill=False)
-
- self.add (vbox)
- self.set_visible_window (False)
- self.set_above_child (True)
-
- self.connect ("button-press-event", self.custom_button_press_event)
- self.connect ("button-release-event", self.custom_button_release_event)
- self.connect ("enter-notify-event", self.custom_enter_notify_event)
- self.connect ("leave-notify-event", self.custom_leave_notify_event)
- self.image.connect ("expose-event", self.image_expose_event)
-
-
- def custom_button_press_event (self, p, q):
- self.image.set_state (gtk.STATE_ACTIVE)
- self.pressed = True
- print "OK"
-
- def custom_button_release_event (self, p, q):
-
- if (self.pressed and self.image.state == gtk.STATE_ACTIVE):
- self.emit ("clicked")
-
- self.image.set_state (gtk.STATE_NORMAL)
- self.pressed = False
-
- def custom_enter_notify_event (self, p, q):
- if (self.pressed):
- self.image.set_state (gtk.STATE_ACTIVE)
-
- def custom_leave_notify_event (self, p, q):
- self.image.set_state (gtk.STATE_NORMAL)
-
- def image_expose_event (self, widget, event):
- global fancy_button_highlight_pb
-
- if (widget.state == gtk.STATE_ACTIVE):
- if (fancy_button_highlight_pb):
- widget.window.draw_pixbuf (None,
- fancy_button_highlight_pb,
- 0, 0,
- widget.allocation.x,
- widget.allocation.y)
- else:
- gtk.Style.paint_flat_box (widget.style,
- event.window,
- gtk.STATE_ACTIVE,
- gtk.SHADOW_NONE,
- event.area,
- widget,
- "eventbox",
- event.area.x,
- event.area.y,
- event.area.width,
- event.area.height)
-
-
-def settings_changed (obj, spec):
- global fancy_button_highlight_pb
- try:
- fancy_button_highlight_pb = gtk.gdk.pixbuf_new_from_file (BUTTON_HILIGHT_FILE_NAME)
- except Exception, e:
- print str(e)
- fancy_button_highlight_pb = None
-
-if __name__ == "__main__":
-
- w = gtk.Window ()
-
- settings = gtk.settings_get_default ()
- settings.connect ("notify", settings_changed)
- settings_changed (None, None)
-
-
- frame = gtk.Frame ()
- frame.add (FancyButton ())
-
- align = gtk.Alignment (xalign=0.5, yalign=0.5)
- align.add (frame)
-
-
- w.add (align)
- w.show_all ()
- w.connect ("delete-event", gtk.main_quit)
- gtk.main ()
-
-
+++ /dev/null
-import os, sys
-import locale
-import gettext
-
-# Change this variable to your app name!
-# The translation files will be under
-# @LOCALE_DIR@/@LANGUAGE@/LC_MESSAGES/@APP_NAME@.mo
-#
-APP_NAME = "mussorgsky"
-
-# This is ok for maemo. Not sure in a regular desktop:
-#
-APP_DIR = os.path.join (sys.prefix,
- 'share')
-LOCALE_DIR = os.path.join(APP_DIR, 'locale')
-
-
-# Now we need to choose the language. We will provide a list, and gettext
-# will use the first translation available in the list
-#
-# In maemo it is in the LANG environment variable
-# (on desktop is usually LANGUAGES)
-#
-DEFAULT_LANGUAGES = os.environ.get('LANG', '').split(':')
-DEFAULT_LANGUAGES += ['en_US']
-
-# Try to get the languages from the default locale
-languages = []
-lc, encoding = locale.getdefaultlocale()
-if lc:
- languages = [lc]
-
-# Concat all languages (env + default locale),
-# and here we have the languages and location of the translations
-#
-languages += DEFAULT_LANGUAGES
-mo_location = LOCALE_DIR
-
-# Lets tell those details to gettext
-# (nothing to change here for you)
-gettext.install (True)
-gettext.bindtextdomain (APP_NAME,
- mo_location)
-gettext.textdomain (APP_NAME)
-language = gettext.translation (APP_NAME,
- mo_location,
- languages = languages,
- fallback = True)
-
-# And now in your modules you can do:
-#
-# import i18n
-# _ = i18n.language.gettext
-#
-
+++ /dev/null
-#!/usr/bin/env python2.5
-import hildon
-import gtk, gobject
-from tracker_backend import TrackerBackend
-from album_art_panel import MussorgskyAlbumArtPanel
-from browse_panel import MussorgskyBrowsePanel
-from fancy_button import FancyButton, settings_changed
-
-import i18n
-_ = i18n.language.gettext
-
-class MussorgskyMainWindow (hildon.StackableWindow):
-
- def __init__ (self):
- hildon.StackableWindow.__init__ (self)
-
-
-
- self.tracker = TrackerBackend ()
- self.set_title ("MussOrgsky")
- self.set_border_width (12)
- self.connect ("destroy", gtk.main_quit)
- self.__create_view ()
- self.show_all ()
-
- def show_browse_panel (self, songs):
- panel = MussorgskyBrowsePanel (songs)
- panel.show_all ()
-
- def broken_files_clicked (self, widget):
- list_songs = self.tracker.get_all_broken_songs ()
- self.show_browse_panel (list_songs)
-
- def browse_clicked (self, widget):
- list_songs = self.tracker.get_all_songs ()
- self.show_browse_panel (list_songs)
-
- def album_art_clicked (self, widget):
- album_artists = self.tracker.get_all_pairs_album_artist ()
- panel = MussorgskyAlbumArtPanel (album_artists)
- panel.show_all ()
-
- def __create_view (self):
-
- image1 = gtk.Image ()
- # "app_install_applications" "app_install_browse"
- image1.set_from_icon_name ("app_install_applications", gtk.ICON_SIZE_MENU)
- image1.set_pixel_size (164)
-
- image2 = gtk.Image ()
- image2.set_from_icon_name ("app_install_browse", gtk.ICON_SIZE_MENU)
- image2.set_pixel_size (164)
-
- hbox = gtk.HBox ()
-
- align1 = gtk.Alignment (xalign=0.5, yalign=0.5)
- button1 = FancyButton (image1, _("Metadata"))
- button1.connect ("clicked", self.browse_clicked)
- align1.add (button1)
- hbox.pack_start (align1)
-
- align2 = gtk.Alignment (xalign=0.5, yalign=0.5)
- button2 = FancyButton(image2, _("Album art"))
- button2.connect ("clicked", self.album_art_clicked)
- align2.add (button2)
- hbox.pack_start (align2)
-
- self.add (hbox)
-
-
-if __name__ == "__main__":
-
-
- try:
- window = MussorgskyMainWindow ()
-
- settings = gtk.settings_get_default ()
- settings.connect ("notify", settings_changed)
- settings_changed (None, None)
-
- gtk.main ()
- except Exception, e:
- dialog = gtk.MessageDialog (None,
- gtk.DIALOG_DESTROY_WITH_PARENT,
- gtk.MESSAGE_ERROR,
- gtk.BUTTONS_CLOSE,
- "Error (%s)" % str(e));
- dialog.run ()
-
GROUP BY ?album
"""
+SONGS = """
+SELECT ?u nmm:artistName(?artist) nmm:albumTitle(?album) WHERE
+{
+ ?u a nmm:MusicPiece ;
+ nmm:performer ?artist ;
+ nmm:musicAlbum ?album .
+}
+"""
+
class TrackerBackendDBus:
def __init__ (self):
results = self.resources.SparqlQuery (ALBUM_ARTISTS_COUNTER)
return self.__iter_results (results)
+ def get_all_songs (self):
+ results = self.resources.SparqlQuery (SONGS)
+ for uri, artist, album in results:
+ yield (uri, artist, album)
+
def __iter_results (self, results):
for (title, artist, counter) in results:
print "Executed the yield", counter
if __name__ == "__main__":
b = TrackerBackendDBus ()
- for pair in b.get_all_albums ():
+ for pair in b.get_all_songs ():
print "Outter loop"
print pair
print "ok"
+++ /dev/null
-#!/usr/bin/env python2.5
-import dbus
-import os
-
-TRACKER = 'org.freedesktop.Tracker'
-TRACKER_OBJ = '/org/freedesktop/Tracker/Metadata'
-TRACKER_SEARCH_OBJ = '/org/freedesktop/Tracker/Search'
-
-RDF_NO_PROPX = """
-<rdfq:Condition>
- <rdfq:and>
- <rdfq:equals>
- <rdfq:Property name="%s" />
- <rdf:String></rdf:String>
- </rdfq:equals>
- </rdfq:and>
-</rdfq:Condition>
-"""
-
-RDF_NO_ARTIST = RDF_NO_PROPX % "Audio:Artist"
-RDF_NO_ALBUM = RDF_NO_PROPX % "Audio:Album"
-RDF_NO_TITLE = RDF_NO_PROPX % "Audio:Title"
-
-RDF_ANY_MISSING_METADATA = """
-<rdfq:Condition>
- <rdfq:or>
- <rdfq:equals>
- <rdfq:Property name="Audio:Artist" />
- <rdf:String></rdf:String>
- </rdfq:equals>
- <rdfq:equals>
- <rdfq:Property name="Audio:Title" />
- <rdf:String></rdf:String>
- </rdfq:equals>
- <rdfq:equals>
- <rdfq:Property name="Audio:Album" />
- <rdf:String></rdf:String>
- </rdfq:equals>
- </rdfq:or>
-</rdfq:Condition>
-"""
-
-
-class TrackerBackend:
-
- def __init__ (self):
- print "Tracker backend up"
- bus = dbus.SessionBus ()
- self.tracker_metadata = bus.get_object (TRACKER, TRACKER_OBJ)
- self.iface_metadata = dbus.Interface (self.tracker_metadata,
- "org.freedesktop.Tracker.Metadata")
-
- self.tracker_search = bus.get_object (TRACKER, TRACKER_SEARCH_OBJ)
- self.iface_search = dbus.Interface (self.tracker_search,
- "org.freedesktop.Tracker.Search")
-
- def count_songs_wo_artist (self):
- return self.iface_metadata.GetCount ("Music", "*", RDF_NO_ARTIST)
-
- def count_songs_wo_title (self):
- return self.iface_metadata.GetCount ("Music", "*", RDF_NO_TITLE)
-
- def count_songs_wo_album (self):
- return self.iface_metadata.GetCount ("Music", "*", RDF_NO_ALBUM)
-
- def __run_rdf_query (self, rdf_query):
- results = self.iface_search.Query (-1, "Music",
- ["Audio:Artist",
- "Audio:Title",
- "Audio:Album",
- "File:Mime"],
- "", [], rdf_query, False,
- ["Audio:DateAdded"], False, 0, 32000)
- return results
-
- def get_all_broken_songs (self):
- """
- Return tuples with the following fields:
- (uri, "Music", artist, title, album, mimetype)
- """
- return self.__run_rdf_query (RDF_ANY_MISSING_METADATA)
-
- def get_all_songs (self):
- """
- Return tuples with the following fields:
- (uri, "Music", artist, title, album, mimetype)
- """
- return self.__run_rdf_query ("")
-
-
- def get_list_of_known_albums (self):
- return self.iface_metadata.GetUniqueValues ("Music",
- ["Audio:Album"],
- "", False, 0, 32000)
-
- def get_list_of_known_artists (self):
- return self.iface_metadata.GetUniqueValues ("Music",
- ["Audio:Artist"],
- "", False, 0, 32000)
-
- def get_all_pairs_album_artist (self):
- return self.iface_metadata.GetUniqueValuesWithAggregates ("Music",
- ["Audio:Album"],
- "",
- ["CONCAT"],
- ["Audio:Artist"],
- False, 0, 32000)
-
-# Test
-if __name__ == "__main__":
-
- import sys
- from optparse import OptionParser
-
- parser = OptionParser()
- parser.add_option ("-n", "--numbers", dest="print_numbers",
- action="store_true", default=True,
- help="Print stats about broken files")
-
- parser.add_option ("-p", "--pairs", dest="pairs_artist_album",
- action="store_true", default=True,
- help="Print all pairs (album, artist)")
-
- (options, args) = parser.parse_args ()
-
- if (not options.print_numbers and not options.pairs_artist_album):
- parser.print_help ()
- sys.exit (-1)
-
- tracker = TrackerBackend ()
- if (options.print_numbers):
- print tracker.count_songs_wo_artist (), "Songs without artist"
- print tracker.count_songs_wo_title (), "Songs without title"
- print tracker.count_songs_wo_album (), "Songs without album"
-
- if (options.pairs_artist_album):
- for (album, artist) in tracker.get_all_pairs_artist_album ():
- print album,"-",artist
-
-
+++ /dev/null
-import gobject
-
-def escape_html (text, max_length=40):
- if (len (text) > max_length):
- cutpoint = text.find (' ', max_length-10)
- if (cutpoint == -1 or cutpoint > max_length):
- cutpoint = max_length
- text = text [0:cutpoint] + "..."
- return gobject.markup_escape_text (text)
-
-def is_empty (text):
- return not text or len (text.strip ()) == 0
-
-# Set socket timeout
-import socket
-import urllib2
-
-timeout = 5
-socket.setdefaulttimeout(timeout)
-
-class UrllibWrapper ():
-
- def save_content_into_file (self, content, filename):
- output = open (filename, 'w')
- output.write (content)
- output.close ()
-
- def get_url (self, url):
- request = urllib2.Request (url)
- request.add_header ('User-Agent', 'Mussorgsky/0.1 Test')
- opener = urllib2.build_opener ()
- try:
- return opener.open (request).read ()
- except:
- return None
-
-
-
-class Set:
-
- def __init__ (self):
- self.d = {}
- self.k = None
-
- def insert (self, element):
- if (not self.d.has_key (element)):
- self.d[element] = 1
- self.k = None
-
- def as_list (self):
- if (self.k):
- return self.k
-
- self.k = self.d.keys ()
- self.k.sort ()
- return self.k
-
-
-