As I upgraded my home system from Debian 9 (Stretch) to Debian 10 (Buster), I noticed that my long-time music player software Banshee was not able to start its UI any more. The last stable version of Banshee was published in 2014 and the project died after that.
Then why is this worth a blog entry? Before I was using Banshee, I used iTunes on OS X since approximately 2004. In the process of moving my mp3 music archive from OS X to GNU/Linux, I migrated all the meta-data which was not represented within the mp3 files from iTunes to Banshee:
- date added
- last played
- play count
- ratings (one to five stars)
- comments (might covered with mp3 meta-data)
Accumulating my listening meta-data over fifteen years, this meta-data does have some value to me.
Before I join the tedious game of trying to get Banshee to run by down-grading libraries, running some container stuff I don't really want to use, or similar, I decided to move away from this unmaintained project to a maintained one.
Requirements
Since my requirements are not that complicated, several programs might be suitable:
- index and display my mp3 files
- re-using meta-data stored in mp3 files
- display and modify song meta-data via UI
- keep my artist/album/track directory structure
- some kind of dynamic or smart playlist feature such as:
- high rated songs played recently
- high reted songs not played recently
- recently added
- songs with no album
- manual playlists
- navigate via artists and albums
- search for songs with all kinds of queries
- no Internet traffic necessary (sandboxing possible)
Choice of a Tool
Almost any non-trivial music manager should be fine with my requirements. Therefore, I was looking for any migration tool that helps moving away from Banshee.
It was difficult to find anything.
The only promising page I found was this one which describes migration path to Rhythmbox. Rhythmbox seems to be very much alive and widely used. It matches my set of requirements. Ironically, there once was a migration ongoing from Rhythmbox to Banshee because of Rhythmbox was going to die.
Migration
One comment of the article even linked a Python script for migrating ratings and play-count meta-data from Banshee to Rhythmbox. A quick test run showed that this script works.
I had to modify this method so that date added and last played information is migrated as well. So I took a look at the Banshee SQLite data-base format as well as the XML of Rhythmbox.
Then I studied how the Python script works and extended it with the additional meta-data.
If anybody else still used Banshee and needs to migrate to a supported alternative, this blog article should help.
Here are the steps of my migration:
- Locate Banshee database which is usually at:
~/.config/banshee-1/banshee.db - It is crucial that you don't move or rename mp3 files after you stopped using Banshee and before you migrated to Rhythmbox. This is because the absolute file path is used to match meta-data between the two databases.
- Start Rhythmbox.
- Change its music library root to the mp3 library sub-hierarchy.
- Wait until all the mp3 file were indexed and written to its XML file.
- Quit Rhythmbox.
- Locate Rhythmbox XML file which is located at:
~/.local/share/rhythmbox/rhythmdb.xml - Get the Python script and place it in a directory with the two music library files from above.
- Invoke the meta-data migration with
python3 THISPYTHONSCRIPT.py - Move the modified
rhythmdb.xmlto~/.local/share/rhythmbox/and keep a backup of the previous version just to be sure. - Start Rhythmbox
Now you should be able to see the migrated meta-data from Banshee in Rhythmbox.
#!/usr/bin/python
"""
Copyright (c) 2009 Wolfgang Steitz
Additional adaptations by Karl Voit
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""
import sys
import sqlite3
from lxml import etree
RB_DB = 'rhythmdb.xml'
BA_DB = 'banshee.db'
class banshee_db():
def __init__(self, file):
self.con = sqlite3.connect(file)
def get_song_info(self, url):
try:
res = self.con.execute(
'select Rating, Playcount, DateAddedStamp, LastPlayedStamp, Comment from CoreTracks where uri = ?',
(url,) ).fetchone()
if res is None:
return None, None, None, None, None
else:
return res
except:
return None, None, None, None, None
banshee = banshee_db(BA_DB)
tree = etree.parse(RB_DB)
root = tree.getroot()
for song in root:
if song.get("type") == 'song':
#print('song: ' + str(song))
rating = None
playcount = None
dateadded = None ## Rhythmbox: first-seen
lastplayed = None ## Rhythmbox: last-played
comment = None ## Rhythmbox: comment
for attr in song:
if attr.tag == 'location':
location = attr.text
if attr.tag == 'rating':
rating = attr.text
if attr.tag == 'play-count':
playcount = int(attr.text)
song.remove(attr)
if attr.tag == 'first-seen':
dateadded = attr.text
song.remove(attr)
if attr.tag == 'last-played':
lastplayed = attr.text
song.remove(attr)
if attr.tag == 'comment':
comment = attr.text
song.remove(attr)
rating_banshee, playcount_banshee, \
dateadded_banshee, lastplayed_banshee, \
comment_banshee = banshee.get_song_info(location)
if rating is None: # no rating in rhythmbox XML
if not (rating_banshee == 0 or rating_banshee is None):
rating = rating_banshee
#print('set rating to ' + str(rating_banshee))
if not (playcount_banshee == 0 or playcount_banshee is None):
if playcount is None:
playcount = playcount_banshee
#print('set playcount to ' + str(playcount_banshee))
else:
playcount += playcount_banshee
# insert rating into rb db
if rating is not None:
element = etree.Element('rating')
element.text = str(rating)
song.append(element)
# update playcount of rb db
if playcount is not None:
element = etree.Element('play-count')
element.text = str(playcount)
song.append(element)
if dateadded_banshee is not None:
#print('set dateadded to ' + str(dateadded_banshee))
element = etree.Element('first-seen')
element.text = str(dateadded_banshee)
song.append(element)
if lastplayed_banshee is not None:
#print('set last-played to ' + str(lastplayed_banshee))
element = etree.Element('last-played')
element.text = str(lastplayed_banshee)
song.append(element)
if comment_banshee is not None:
#print('set comment to ' + str(comment_banshee))
element = etree.Element('comment')
element.text = str(comment_banshee)
song.append(element)
tree.write(RB_DB)
Initial Opinion on Rhythmbox
It does the trick. However, there are some more or less minor drawbacks.
Rhythmbox does not find search terms within "Search all fields" in comments. I consider this as a bug. Let me see if I'm able to find out about this.
Furthermore, Rhythmbox does not promote the album art images in a way that I can enjoy it in a decent size. It's part of the UI but more or less as a thumbnail. This is a sad situation given the fact that I run Rhythmbox in full screen on a high definition screen with lots of unused screen estate within Rhythmbox.
I could not find out so far, how I may modify the comments of marked tracks of an album at once.
Existing "Automatic Playlists" can not be modified and I can't see how they are defined.
I get mixed feelings when I am searching for Rhythmbox plugins. Every plugin I was interested in was unmaintained or not prepared for the Rhythmbox version 3.4.3 I've got. Parts of the Rhythmbox ecosystem does seem to be dead somehow.