Re: [Rhythmbox-devel] Magnatune catalog/purchasing plugin
- From: Adam Zimmerman <adam_zimmerman sfu ca>
- To: rhythmbox-devel gnome org
- Subject: Re: [Rhythmbox-devel] Magnatune catalog/purchasing plugin
- Date: Sun, 18 Jun 2006 23:44:01 -0700
On Mon, 2006-19-06 at 14:33 +1000, James "Doc" Livingston wrote:
> I've just converted RhythmDBEntry and RhythmDBEntryType to be boxed
> types, which allows Python to use them. By changing
> "rhythmdb.rhythmdb_register_entry_type" to
> "rhythmdb.register_entry_type" in the last patch you posted, it seems to
> work now.
Alright, now we're getting somewhere! The tracks now show up in the
source, and they play :D ! But they have no metadata. The first
self._db.entry_set_uninserted call (and presumably the others as well)
throws an exception with the message "entry should be a RhythmDBEntry".
However, entry is a RhythmDBEntry (checked with "print entry", which
gives something to the effect of <RhythmDBEntry at 0x88307b8>), so I'm
not sure what's going on there.
The other thing that's going weird has to do with the gnomevfs.async
code I'm writing, but it's quite possible I'm doing something wrong
there. I get the following message a bunch of times:
(rhythmbox:7409): libgnomevfs-WARNING **: Unknown job kind 9
(strangely, the UI still seems to block while loading the songs,
although the activate method returns beforehand (or at least, the
gnomevfs.async.open call returns))
and then rhythmbox segfaults:
GLib-ERROR **: gmem.c:135: failed to allocate 524288 bytes
aborting...
Segmentation fault!
Cannot display crash dialogue
The only result I found on google for the libgnomevfs error didn't
really help much.
--
Adam Zimmerman <adam_zimmerman sfu ca>
CREATIVITY - http://mirrors.creativecommons.org/movingimages/Building_on_the_Past.mpg
ALWAYS - http://www.musiccreators.ca/
BUILDS - http://www.ubuntu.com/
ON THE PAST - http://www.theopencd.org/
--
Most people will listen to your unreasonable demands, if you'll consider
their unacceptable offer.
import rhythmdb, rb
import gobject, gtk, gconf, gnomevfs
from gettext import gettext as _
import xml.sax, xml.sax.handler
import urllib
magnatune_partner_id = "rhythmbox" # this needs to be set up with magnatune
################################################
# Class to add Magnatune catalog to the source #
################################################
class TrackListHandler(xml.sax.handler.ContentHandler):
def __init__(self, source, db, entry_type):
xml.sax.handler.ContentHandler.__init__(self)
self._track = {} # temporary dictionary for track info
self._source = source
self._db = db
self._entry_type = entry_type
def startElement(self, name, attrs):
self._text = ""
def endElement(self, name):
if name == "Track":
try:
print "Adding: %s - %s" % (self._track['artist'], self._track['trackname'])
# add the track to the source
entry = self._db.entry_new(self._entry_type, self._track['url'])
self._db.entry_set_uninserted(entry, rhythmdb.PROP_ARTIST, self._track['artist'])
self._db.entry_set_uninserted(entry, rhythmdb.PROP_ALBUM, self._track['albumname'])
self._db.entry_set_uninserted(entry, rhythmdb.PROP_TITLE, self._track['trackname'])
self._db.entry_set_uninserted(entry, rhythmdb.PROP_TRACK_NUMBER, int(self._track['tracknum']))
self._db.entry_set_uninserted(entry, rhythmdb.PROP_YEAR, int(self._track['year']))
self._db.entry_set_uninserted(entry, rhythmdb.PROP_GENRE, self._track['mp3genre'])
self._db.entry_set_uninserted(entry, rhythmdb.PROP_DURATION, int(self._track['seconds']))
# somehow associate the sku with the track as well, so we can buy it.
self._db.commit()
# temporary, until we can properly make proper query models in python
#model = self._source.get_property("query-model")
#model.add_entry(entry, -1)
except Exception,e: # This happens on duplicate uris being added (and now on the set_uninserted call)
print e
self._track = {}
elif name == "AllSongs":
pass # end of the file
else:
self._track[name] = self._text
def characters(self, content):
self._text = self._text + content
################################################
# Main Magnatune Plugin Class #
################################################
class Magnatune(rb.Plugin):
_preferences = None
#
# Core methods
#
def __init__(self):
rb.Plugin.__init__(self)
def activate(self, shell):
self.db = shell.get_property("db")
self.entry_type = rhythmdb.entry_register_type("MagnatuneEntryType")
self.source = gobject.new (MagnatuneSource, shell=shell, name=_("Magnatune"), entry_type=self.entry_type)
shell.register_entry_type_for_source(self.source, self.entry_type)
icon = gtk.gdk.pixbuf_new_from_xpm_data(magnatune_logo_xpm) # Include a flashy Magnatune logo for the source
self.source.set_property("icon", icon)
shell.append_source(self.source, None) # Add the source to the list
# http://magnatune.com/info/song_info.xml
self.parser = xml.sax.make_parser()
self.parser.setContentHandler(TrackListHandler(self.source, self.db, self.entry_type))
#gnomevfs.async.open("/home/adam/Desktop/song_info.xml", self.open_callback)
self.parser.parse("/home/adam/Desktop/song_info.xml")
def deactivate(self, shell):
self.db.entry_delete_by_type(self.entry_type)
self.db.commit()
self.source.delete_thyself()
self.source = None
#
# Callback/helper functions
#
def open_callback(self, handle, exc_type):
times = 0
if not exc_type:
try:
while True:
handle.read(512*1024, self.read_callback) # file is about 5MB
except EOFError:
handle.close(lambda *args: None)
else:
handle.close(lambda *args: None)
def read_callback(self, handle, buf, exc_type, bytes_requested):
self.parser.feed(buf)
class MagnatuneSource(rb.BrowserSource):
def __init__(self):
rb.Source.__init__(self)
gobject.type_register(MagnatuneSource)
################################################
# Purchasing code. Do this later #
################################################
class BuyAlbumHandler(xml.sax.handler.ContentHandler): # Class to download the track, etc.
def __init__(self):
xml.sax.handler.ContentHandler.__init__(self)
def startElement(self, name, attrs):
self._text = ""
def endElement(self, name): # need to figure out the format of what gets returned, there's no documentation on the site.
pass
def characters(self, content):
self._text = self._text + content
def buy_track(track, amount, cc, name, email): # http://magnatune.com/info/api#purchase
client = gconf.client_get_default()
url = "https://magnatune.com/buy/buy_dl_cc_xml?"
url = url + urllib.urlencode({
'id': magnatune_partner_id,
'sku': track['albumsku'],
'amount': amount,
'cc': cc['number'],
'yy': cc['year'],
'mm': cc['month'],
'name': name,
'email':email
})
xml.sax.parse(url, BuyAlbumHandler())
url = "" # get download url
# transfer the track to the library with track-transfer
################################################
# Magnatune Logo. Seems to work well enough... #
################################################
# (converted from http://www.magnatune.com/favicon.ico)
magnatune_logo_xpm = [
"32 32 4 1",
" c None", #Original colours:
". c None", #FFFFFF
"+ c #303030", #C0C0C0
"@ c #000000", #808080
"................................",
"................................",
"................................",
"................................",
"................................",
"................................",
"............++@@@@++............",
"..........+@@@@@@@@@@+..........",
".........+@@@+....+@@@+.........",
"........+@@+...++...+@@+........",
".......+@@+....@@....+@@+.......",
".......@@+.....@@.....+@@.......",
"......+@@......@@......@@+......",
" + + @@ + + ",
"......@@...@@..@@..@@...@@......",
"......@@...@@+.@@.+@@...@@......",
"......@@...@@+.@@.+@@...@@......",
"......@@...@@+.@@.+@@...@@......",
" + + @@+.@@.+@@ + + ",
"......+@@..@@+.@@.+@@..@@+......",
".......@@+.@@+.@@.+@@.+@@.......",
".......+@@+.+..+...+.+@@+.......",
"........+@@+........+@@+........",
".........+@@@+....+@@@+.........",
"..........+@@@@@@@@@@+..........",
"............++@@@@++............",
"................................",
"................................",
"................................",
"................................",
"................................",
"................................"
]
###
### preferences, ugly and gross. Someone else who knows what they're doing should probably fix this
###
# def create_configure_dialog(self): # return a gtk dialog with configure options
# if self._preferences == None:
# client = gconf.client_get_default()
# self._preferences = gtk.Dialog(title=_("Magnatune Preferences"), flags=gtk.DIALOG_MODAL)
#
# label = gtk.Label("<b>Purchase Information</b>")
# self._preferences.vbox.pack_start(label, False, False, 0)
# label.show()
#
# hbox = gtk.HBox()
# label = gtk.Label(_("Name"))
# entry = gtk.Entry()
# self.setup_entry(entry, "name")
# hbox.pack_start(label, False, False, 0)
# hbox.pack_start(entry, False, False, 0)
# label.show()
# entry.show()
# self._preferences.vbox.pack_start(hbox, True, True, 0)
# hbox.show()
#
# hbox = gtk.HBox()
# label = gtk.Label(_("E-mail Address"))
# entry = gtk.Entry()
# self.setup_entry(entry, "email")
# hbox.pack_start(label, False, False, 0)
# hbox.pack_start(entry, False, False, 0)
# label.show()
# entry.show()
# self._preferences.vbox.pack_start(hbox, True, True, 0)
# hbox.show()
#
# button = gtk.CheckButton(_("Remember Credit Card Information"))
# credit_entry = gtk.Entry(max=16)
# month_entry = gtk.Entry(max=2)
# year_entry = gtk.Entry(max=4)
# button.connect("toggled", self.check_toggle, (credit_entry, month_entry, year_entry))
# set = client.get_bool("/apps/rhythmbox/plugins/magnatune/forget")
# if set is not None:
# button.set_active(set)
# self._preferences.vbox.pack_start(button, False, False, 0)
# button.show()
#
# hbox = gtk.HBox()
# label = gtk.Label(_("Credit Card Number"))
# # entry has already been created
# self.setup_entry(credit_entry, "cc_num")
# hbox.pack_start(label, False, False, 0)
# hbox.pack_start(credit_entry, False, False, 0)
# label.show()
# credit_entry.show()
# self._preferences.vbox.pack_start(hbox, True, True, 0)
# hbox.show()
#
# hbox = gtk.HBox()
# label = gtk.Label(_("Expiration: mm/yy "))
# # entries already created
# sep = gtk.Label(" / ")
# self.setup_entry(month_entry, "cc_mm")
# self.setup_entry(year_entry, "cc_yy")
# hbox.pack_start(label, False, False, 0)
# hbox.pack_start(month_entry, False, False, 0)
# hbox.pack_start(sep, False, False, 0)
# hbox.pack_start(year_entry, False, False, 0)
# label.show()
# month_entry.show()
# sep.show()
# year_entry.show()
# self._preferences.vbox.pack_start(hbox, True, True, 0)
# hbox.show()
#
# hbox = gtk.HBox()
# button = gtk.Button(stock=gtk.STOCK_CLOSE)
# button.connect("clicked", self.close_clicked, None)
# self._preferences.action_area.pack_end(button, True, True, 0)
# button.show()
#
# self._preferences.show()
# return self._preferences
#
# def check_toggle(self, widget, data=None):
# active = not widget.get_active() # this method gets called before the widget changes
# client = gconf.client_get_default()
# client.set_bool("/apps/rhythmbox/plugins/magnatune/forget", active)
# if active:
# for entry in data:
# entry.set_text("")
# entry.set_sensitive(False)
# for field in ('cc_num', 'cc_mm', 'cc_yy'):
# client.unset("/apps/rhythmbox/plugins/magnatune/" + field)
# else:
# for entry in data:
# entry.set_sensitive(True)
#
# def pref_changed(self, widget, gdk_event, data=None):
# client = gconf.client_get_default()
# client.set_string("/apps/rhythmbox/plugins/magnatune/" + data, widget.get_text())
#
# def close_clicked(self, widget, data=None):
# self._preferences.hide()
#
# def setup_entry(self, entry, data):
# client = gconf.client_get_default()
# text = client.get_string("/apps/rhythmbox/plugins/magnatune/" + data)
# if text is not None:
# entry.set_text(text)
# entry.connect("focus-out-event", self.pref_changed, data)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]