You are not logged in.

#1 2009-10-07 12:16:59

lswest
Member
From: Munich, Germany
Registered: 2008-06-14
Posts: 456
Website

[SOLVED]Python sort question (list of tuples)

Hey,

I'm in the process of writing a quick script to compile a list of all the music on my computer and storing the information in a tuple per song (title, artist, album), inside a list, so it can eventually be print out into a file.  The reason why I want to do this is in order to a) have a list of songs I own, b) figure out if I have duplicates anywhere, and c) as practice in python. I'm using eyeD3 (from the python-eyed3 package in the extras repo), and it pulls the information from the mp3's fairly well.  My problem is mainly with how best to sort it (I want it by artist, alphabetically, but (if possible) split into groups by album)).  Also, there's the "u" before the actual title/song/artist, which seems to be simply the way eyed3 displays the information, but I can replace that value later when printing it out to a file, so it can just be ignored by anyone trying to help if they don't feel like offering tips on that (it seems like when printing it the "u" and the single quotes aren't printed, therefore it should be the same when writing to a file, right?).

*UPDATE* I solved most of the problems, the only question that remains is #3, which is if anyone knows a decent tag reader for m4a/wma files for python.  I am leaving the solutions in this long post for anyone who might have the same issues in the future.

My questions are these:
1. Is there a more efficient id3 parser?
2. How best should I sort the list of tuples?  Should I just put the artist info in the first position and let python sort it like that? (I believe Python's default sort of a list sorts it by first position, then second, etc., and would so organize it by artist. -- SOLVED
3. Does anyone know what I can use to parse the rest of the audio files that aren't mp3? (just wma and m4a files, might only be m4a).
*update* 4. I'm still googling this, but I figure I could stick the question here too, is there any way to make a clean list where it lines up the text as best as possible?  For the moment it's all over the place (since the titles/artists are all varying lengths).  I've decided to go with string formatting in order to set a number of characters for each string, by using this code:

print '{0:45} - {1:20} {2:20}'.format(x[0],x[1],"("+x[2]+")")

However, this results in the error (after about 17 successful prints):

File "Dropbox/Scripts/pyMusicCatalog", line 45, in tags
    print '{0:45} - {1:20} {2:20}'.format(x[0],x[1],"("+x[2]+")")
UnicodeEncodeError: 'ascii' codec can't encode character u'\xbb' in position 16: ordinal not in range(128)

Found a solution by using

sys.setdefaultencoding("latin-1")

About the attempted sorting in the script, I found it online and honestly don't quite understand how to use lambda, or if it's even applicable to strings.  I left it in there in order to give people an idea of what I want to achieve, but I realize it's incorrect (due to the error message), but don't know how best to fix it.

Thanks in advance for any pointers, and I'll happily post any more info anyone requires,
Lswest

  1 #/usr/bin/env python
  2 # Script to create a "catalog" of music on a computer
  3 import os
  4 import optparse
  5 import eyeD3
  6 
  7 
  8 def main():
  9     usage="usage: %prog [options] args"
 10     # Configure the command-line options to take in the location of the music directory, the output file (intermedi    ary list of filepaths for debug purposes), and the catalog's location (end file)
 11     p=optparse.OptionParser()
 12     p.add_option('--origin', '-o', help="The location of the directory to search.", default=os.path.join(os.path.ex    panduser('~'), "Music"))
 13     p.add_option('--output', '-f', help="The location of the output file.", default=os.path.join(os.path.expanduser    ('~'),"musicList.txt"))
 14     p.add_option('--catalog', '-c', help="The location of the end catalog of artist, title and album")
 15     options, arguments=p.parse_args()
 16     print options.origin
 17     # Open what will become the intermediary file for writing.
 18     ff=open(options.output, "wt")
 19     #Recursively follow the filetree of the music folder, and write the filepath to any audio file out to the inter
    mediary file.
 20     for root, dirs, files in os.walk(options.origin, followlinks=True):
 21          for infile in [f for f in files if f.endswith(('.mp3', '.MP3','.wma','.WMA','.m4a','.M4A'))]:
 22               ff.write(os.path.abspath(os.path.join(root,infile)))
 23               ff.write('\n')
 24     ff.close() # close file
 25     tags(options.output) # move on to pulling the ID3 tag info from the mp3's using the debug file.
 26 
 27 def tags(file):
 28     catalog=[] #empty list which will contain the tuples of song info
 29     nonMP3=[] # a list of all non-mp3 files that need to have their info pulled differently.
 30     tag=eyeD3.Tag() # initiate the tag instance of the eyeD3 module
 31     ff=open(file, "r") # open the debug file as read-only.
 32     for x in ff: # for each file path, strip off any extra new-line characters, then check to see if it's an mp3.  
    If so, store the ID3 tag info in the tuple and list, otherwise add the filepath to the non-mp3 list.
 33         x=x.strip()
 34         if x.endswith('.mp3'):
 35             print x.strip()
 36             try:
 37                 tag.link(x)
 38             except:
 39                 print "FAILED -" + x.strip()
 40             print tag.getTitle() # debugging print in order to ensure that eyed3 is taking in the info properly.
 41             songInfo=[str(tag.getTitle()), str(tag.getArtist()), str(tag.getAlbum())] # add the info into the tuple
 42             catalog.append(songInfo) # add tuple to list
 43         else:
 44             print x.strip() # print out the filepath, again, for debugging purposes in case it crashes.
 45             nonMP3.append(x.strip()) # add filepath to nonMP3 list.
 46     print catalog[0] # print out the first entry in order to check the result (debug purpose)
 47     finalCatalog=sorted(catalog, key=lambda x,y:cmp(string.lower(x), string.lower(y))) # Attempt to sort the lists 
    of tuples by second value of tuples (artist)
 48     for x in finalCatalog: # print out the info as Title - Artist off Album.
 49         print x[0] + "-" + x[1] + "off" + x[2]
 50 
 51 
 52 
 53 if __name__=='__main__':
 54         main()
/home/lswest/Music/Hyperion/Peter Frampton/Peter Frampton Gold/09 Holding On To You.mp3 # example to show that the filepath is recognized correctly and printed by the debug print statement I used
Holding On To You # example of how the printing of Tag.getTitle() works that I used for debug purposes).
/home/lswest/Music/Hyperion/Peter Frampton/Peter Frampton Gold/13 (I'll Give You) Money.mp3
(I'll Give You) Money
[u'She Says', u'Howie Day', u'Stop All the World Now']
Traceback (most recent call last):
  File "Dropbox/Scripts/pyMusicCatalog", line 54, in <module>
    main()
  File "Dropbox/Scripts/pyMusicCatalog", line 25, in main
    tags(options.output) # move on to pulling the ID3 tag info from the mp3's using the debug file.
  File "Dropbox/Scripts/pyMusicCatalog", line 47, in tags
    finalCatalog=sorted(catalog, key=lambda x,y:cmp(string.lower(x), string.lower(y))) # Attempt to sort the lists of tuples by second value of tuples (artist)
TypeError: <lambda>() takes exactly 2 arguments (1 given)

Last edited by lswest (2009-10-07 15:34:55)


Lswest <- the first letter of my username is a lowercase "L".
"...the Linux philosophy is "laugh in the face of danger". Oops. Wrong one. "Do it yourself". That's it." - Linus Torvalds

Offline

#2 2009-10-07 12:51:56

raf_kig
Member
Registered: 2008-11-28
Posts: 143

Re: [SOLVED]Python sort question (list of tuples)

You obiously messed something up with the key argument to sorted.

I could go into the details here but there is a very nice explanation here: http://wiki.python.org/moin/HowTo/Sorting

Regarding lambda: Thats just a way to define an anonymous function. It works like that:
lambda [arguments] : [function body]

A sum function could look like that: lambda x,y : x+y
Or a function to select the first and third element of a tripple: lambda (x,y,z) : (x,y)

And so on...

Regards,

raf

Offline

#3 2009-10-07 12:55:00

lswest
Member
From: Munich, Germany
Registered: 2008-06-14
Posts: 456
Website

Re: [SOLVED]Python sort question (list of tuples)

Thanks for the explanation, much more understandable than what I found tongue  Thanks for the link too (it's always easier when you know where to look for information).

That's solved the sorting process (short of two files without album info, but I can change that easily), now all I have left is finding a way to read the tags off an m4a/wma file.  Thanks so much for the help!

Last edited by lswest (2009-10-07 13:03:02)


Lswest <- the first letter of my username is a lowercase "L".
"...the Linux philosophy is "laugh in the face of danger". Oops. Wrong one. "Do it yourself". That's it." - Linus Torvalds

Offline

#4 2009-10-07 15:31:48

pointone
Wiki Admin
From: Waterloo, ON
Registered: 2008-02-21
Posts: 379

Re: [SOLVED]Python sort question (list of tuples)

http://code.google.com/p/mutagen/

Arch package: mutagen [extra]

Handles M4A... Not sure about WMA.

(Shameless plug: Feel free to check out <http://github.com/desmondgc/projectmusic> -- my own 'music library organization' script that uses Mutagen).


M*cr*s*ft: Who needs quality when you have marketing?

Offline

#5 2009-10-07 15:34:39

lswest
Member
From: Munich, Germany
Registered: 2008-06-14
Posts: 456
Website

Re: [SOLVED]Python sort question (list of tuples)

Thanks, I'll be sure to have a look at that!  The WMA isn't required, turns out they had all been converted to mp3 already, and I just hadn't gotten rid of the wma files tongue  I'll have a look at the projectmusic later.

Thanks again,
Lswest

*Edit* looks like mutagen is a bash command, and not a module for python, which is fine, but I would still like to know if there are any python modules that can handle that.

Last edited by lswest (2009-10-07 15:48:31)


Lswest <- the first letter of my username is a lowercase "L".
"...the Linux philosophy is "laugh in the face of danger". Oops. Wrong one. "Do it yourself". That's it." - Linus Torvalds

Offline

#6 2009-10-07 16:44:58

raf_kig
Member
Registered: 2008-11-28
Posts: 143

Re: [SOLVED]Python sort question (list of tuples)

Offline

#7 2009-10-07 16:46:35

lswest
Member
From: Munich, Germany
Registered: 2008-06-14
Posts: 456
Website

Re: [SOLVED]Python sort question (list of tuples)

Thanks Raf, that's what I was looking for!  Ironically, I just took the time to convert the m4a files to mp3's using pacpl, but I will keep this recipe stored for the future.

Thanks again for all the quick and efficient replies, I'd say the thread is completely solved now!

Lswest

Last edited by lswest (2009-10-07 16:46:48)


Lswest <- the first letter of my username is a lowercase "L".
"...the Linux philosophy is "laugh in the face of danger". Oops. Wrong one. "Do it yourself". That's it." - Linus Torvalds

Offline

#8 2009-10-07 16:53:12

raf_kig
Member
Registered: 2008-11-28
Posts: 143

Re: [SOLVED]Python sort question (list of tuples)

You are welcome :-)

Offline

#9 2009-10-07 17:30:36

pointone
Wiki Admin
From: Waterloo, ON
Registered: 2008-02-21
Posts: 379

Re: [SOLVED]Python sort question (list of tuples)

lswest wrote:

*Edit* looks like mutagen is a bash command, and not a module for python, which is fine, but I would still like to know if there are any python modules that can handle that.

I'd take a closer look if I were you...


M*cr*s*ft: Who needs quality when you have marketing?

Offline

Board footer

Powered by FluxBB