Ceci est une ancienne révision du document !
Last month we ended on a happy note, with all the information we needed to attempt to solve the issue at stake. What was it? I wanted to be able to enter sort information in Rhythmbox in an easier way than to do it manually track by track. Which is boring when all the tracks on the same album share the the same data, plus it was frustrating that at times they even got lost (maybe a bug, maybe only my case). We figure out that an xml file contains the data we want to manipulate and python offers an xml library ready to do it. So what is next?
I had to decide if I wanted to write a command line interface program (CLI) or a graphical user interface (GUI). The former are the text only ones you launch from the terminal, like grep or mp3diags, the latter ones are with windows and icons like audacity or Gnome text editor (gedit).
Surely enough a GUI program is nicer and looks like the preferable choice. As I said in the introduction my programming knowledge needed a brush up and I had no experience in linux / gnome graphic environment. Add to that it would be my first python program I was very sceptical on going down that road.
I have also seen that some linux applications are CLI based and then they also have GUI version, which looked like it was using the command based program to do the job. For example some software management application, like the graphical updater, are invoking a terminal command (apt) and then rendering the output in a more friendly way. Thus my decision was made. I was going to write a CLI based program and eventually I’d write a GUI interface on top of it.
I called it fixrhy on the assumption that it was fixing something that rhythmbox wasn’t doing the way I wanted it. I know it’s arguable but hey, my application, my name!
Ready to start my first ever python program I launched the Gnome text editor which I figured was more than enough for the task at hand.
The logic of the program is very simple. As input it requires the name of the artist, the name of the album, the sorting name of the artist and the sorting name of the album. After writing the basic code I added a fifth parameter which I’ll talk about later. The output would be just some confirmation messages, while the real action is actually manipulating the xml file that rhythmbox uses to store its database. The full code of the final version is available here: https://pastebin.com/zBuhmi1y and I would like to go through it not to teach python or programming but to share the logic and its development. I will stop only on significant parts of the program.
Line 14 is: #!/usr/bin/python
Technically this is needed to execute the code as a Python program. To me it is the statement that I wanted to put in practice something I learned on Full Circle pages, and knowing that if I need help there’ll be a community out there ready to help. I could have used C (or C++) that I already knew, but that would have taken away a bit of the fun. Learning something new it is always challenging and it offers more opportunity of reaching out for others and live in the community. Case in point, I eventually wrote to Greg Walter and Ronnie Tucker (I’ll come back to it later on).
Line 18 is: import xml.etree.ElementTree as ET
This is required to be able to use the ElementTree library to parse XML files. I could have parsed it myself, but it would have been more work for no good reason. If tomorrow the XML specifications change or evolve you can also count on the library to update along. This means that there are great chances that your code will still work as it is. For that reason note that if you google “python xml” that ElementTree comes at the top in the official Python documentation. That gave me the peace of mind that I was working with a fully supported library.
Line 22 is: sys.setdefaultencoding( “UTF-8” )
If I recall correctly this became necessary after struggling with accented letters (as in Beyoncé) that are quite common in names.
Next I have to check if I have enough information to go on. Remember we said we need 4 pieces of data, 2 to identify an album (artist and album name) and 2 to set their respective sort values. The fifth parameter is option (to override existing sorting information). We do it at line 25:
if len(sys.argv) < 5:
Note that we check for 5 since the first value is always the script name (check https://docs.python.org/2/library/sys.html). Lines 26 to 30 print out a little help. I wrote them to be consistent with typical Linux programs, although in the beginning this script was mainly for me. I tried to think about others and follow standards everyone could relate to. Moving along you’ll see that in lines 32 to 35 we save the input data and 37-40 are to check if there is the extra flag “force”.
Line 42 and 43 looks like debugging lines: print “Looking for”, lk_alb, “by”,lk_art
print “Sorting as”, sr_alb, “by”, sr_art
and indeed they were at the beginning. I kept them there because again I thought that tomorrow I (or someone else) could write a GUI program on top of it, and that could help if being parsed.
From 45 to 50 we set everything up, loading the Rhytmbox database into a tree (47) and declaring a couple of counting variables.
The real processing starts at line 52 where go through every entry in the tree. Here is just a simple sequence of checks, is it a song? Is it the right artist? Is it the right album?
if entry.attrib == {'type': 'song'}: if entry.find('artist').text == lk_art:
if entry.find('album').text == lk_alb:
If any of them is false we can discard that given entry since we don’t need to amend it.
From line 58 we check if the artist sort information is already there. The reason being that if the field is missing we need to create it new (60), if it is already there we have to change it (or leave it unchanged). Former case we could not modify something not existing, latter case we should not create something that is already there.
The rest of the code builds on that, and there is a similar part of the album sort information. The only two points I want to make here are that I put in the code the parameter to choose if to modify existing data or not. Personally I would always change it, but I wanted to write a program that eventually could be used by others, maybe with different needs. Also note that since I couldn’t change the element if existing I destroy and create a new one (68-70). Most of the print commands are there for debug originally and then to be used by GUI as I said before about line 42/43.
Finally before saving we make a backup copy (always important!):
shutil.copy2(filename,backup)
and the tree that has been so long in the memory goes in the file.
tree.write(filename, xml_declaration=True)
I am quite happy with my first Python program ever. It does what it says on the tin but there is room for much improvements. Amongst them surely pass the file position as a parameter (like this you should run the script in the folder with the Rhythmbox DB file). The parsing maybe not the most efficient and fast. The naming could be done automatically, for example a clever program could learn that “The Doors” should be “Doors, The” without entering it every single time. And many more, including having a GUI. And that’s where we are heading to…