Friday, September 24, 2010

My Attempt at PyQt4 Programming Part 1

I have decided that I should learn a bit about python and PyQt. First I needed to find a suitable reason to develop an application. Fairly recently I found a great piece of software called clamz. http://code.google.com/p/clamz/

Clamz is a command line tool to download Amazon MP3 music. It inputs the amz file and saves the music files, including albums, into a directory based on the meta data. Although this works very well, it is a cli tool and opens a terminal window. This does not fit in well with my KDE desktop.

I decided to write a nice front-end to this command line tool. I am not going to recreate any of the logic of decoding the amz file from Amazon. Instead, I plan to use QProcess to redirect output from the command and update a nice tree/list view with the download status. Then I can use Phonon to play the media from within the application.

In order to help to understand the QTreeView and the model, I have found a program called flacon. I found it on kde-apps. Here is the link. It is a very good CD-ripping application and it has a very full tree view.

Here is what I have done so far:

1. Parse the information from the amz file and store it. For this I am using the command line switch -x to output to xml. Then I am parsing the xml using QXmlStreamReader. For the first part, I manually ran clamz -x to generate the file, redirecting to a file called amazon.xml.

#!/usr/bin/python # -*- coding: utf-8 -*- # Project : Simple XML Parser # File : main.py # (c) David Greengas dave.greengas@gmail.com # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 3 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. from PyQt4.QtCore import QXmlStreamReader from PyQt4.QtCore import QFile, QIODevice, QString class Track: def __init__(self): self._title = None self._image = None self._duration = None self._trackNum = None self._creator = None self.album = None self._fieldTitle = QString(u'title') self._fieldImage = QString(u'image') self._fieldCreator = QString(u'creator') self._fieldAlbum = QString(u'album') self._fieldDuration = QString(u'duration') self._fieldTrackNum = QString(u'trackNum') def setTitle(self, title): self._title = title def getTitle(self): return self._title def setImage(self, image): self._image = image def getImage(self): return self._image def setDuration(self, duration): self._duration = duration def getDuration(self): return self._duration def setTrackNum(self, tracknum): self._trackNum = tracknum def getTrackNum(self): return self._trackNum def setCreator(self, creator): self._creator = creator def getCreator(self): return self._creator def setAlbum(self, album): self._album = album def getAlbum(self): return self._album def setValue(self, fieldname, fieldvalue): if fieldname == self._fieldAlbum: self.setAlbum( fieldvalue ) elif fieldname == self._fieldCreator: self.setCreator( fieldvalue ) elif fieldname == self._fieldDuration: self.setDuration( fieldvalue ) elif fieldname == self._fieldImage: self.setImage( fieldvalue ) elif fieldname == self._fieldTitle: self.setTitle( fieldvalue ) elif fieldname == self._fieldTrackNum: self.setTrackNum( fieldvalue ) class TrackReader(): def __init__(self): self.emptyfield = QString(u'') self.trackelement = "track" def readTracks(self, filename = None): myfile = QFile(filename) tracks = list() currenttrack = None if myfile == None: #error pass else: myfile.open(QIODevice.ReadOnly) reader = QXmlStreamReader(myfile) lastelement = None currenttext = None while ( not reader.atEnd() ): reader.readNext() #if ( reader.isStartElement() ): if reader.isStartElement(): lastelement = reader.name().toString() #print lastelement if lastelement == self.trackelement: #append a new track to the list print("adding new track") currenttrack = Track() tracks.append( currenttrack ) elif reader.isCharacters(): currenttext = reader.text().toString() if currenttext.trimmed() != self.emptyfield: if currenttrack != None: currenttrack.setValue( lastelement, currenttext.trimmed() ) if ( myfile != None): myfile.close() return tracks if __name__ == "__main__": currenttrack = None reader = TrackReader() tracks = reader.readTracks("amazon.xml") for currenttrack in tracks: print ('%(track)s\t|%(creator)s\t|%(album)s') % \ {"track": currenttrack.getTrackNum(), "creator": currenttrack.getCreator(), \ "album": currenttrack.getAlbum() }