Search code examples
pythonunicodeencodingutf-8dbus

Python; How to replace escaped non-unicode characters with their respective 'real' utf-8


I am relatively new to programming, and I have a small problem writing a python equivalent of Snip for spotify for ubuntu(linux) Somehow i can encode the title correctly, but am unable to encode the artist the same way

when i try to encode the artist in the same fashion i get this:

File "./songfinder.py", line 11, in currentplaying
    artiststr = str((metadata['xesam:artist']).encode('utf-8'))
AttributeError: 'dbus.Array' object has no attribute 'encode'

however the title is done exactly the same and that is working.

Code so far IS working but has for example \xd8 instead of Ø, and similar:

import dbus
session_bus = dbus.SessionBus()
spotify_bus = session_bus.get_object("org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2")
spotify_properties = dbus.Interface(spotify_bus, "org.freedesktop.DBus.Properties")

def currentplaying():
    metadata = spotify_properties.Get("org.mpris.MediaPlayer2.Player", "Metadata")
    title =  str((metadata['xesam:title']).encode('utf-8'))
    artiststr = str((metadata['xesam:artist']))
    if ("dbus.string" in artiststr.lower()):
        artists = artiststr.split("(u")
        artist = artists[1]
        artists = artist.split(")],")
        artist = artists[0]
        artist = artist.replace("(u", "")
    else:
        artist = "'unknown'"

    artist = (artist.replace("'",""))

    playing = (artist + " - " + title + "             ")
    return playing

#save playing to file.txt

relevant qna's: Replace non-ascii chars from a unicode string in Python

Why it does not resolve my problem: I would like to print/save the actual character, not replace it with similar ones


Solution

  • Looking at your question metadata contains at least something like this with Unicode strings. The artist field seems to be some sort of iterable the begins with the artist. Something like this (feel free to post actual metadata content):

    metadata = {'xesam:title':u'title','xesam:artist':[u'artist']}
    

    In the title assignment line, str is unnecessary since encoding a Unicode string returns a str anyway, but no need to encode it either. Unicode strings represent text, so leave it that way:

    title =  metadata['xesam:title']
    

    Similar for artist assignment, but get the first element of the iterable:

    artist = metadata['xesam:artist'][0]
    

    Next, in your song-updating logic, use io.open to open the files with a UTF-8 encoding. This lets Unicode strings (text) be written directly and the file will handle the encoding. Also use a with statement to automatically close the file when the with ends.

    Program with recommended changes:

    import time
    import dbus
    import io
    session_bus = dbus.SessionBus()
    spotify_bus = session_bus.get_object("org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2")
    spotify_properties = dbus.Interface(spotify_bus, "org.freedesktop.DBus.Properties")
    
    def currentplaying():
        metadata = spotify_properties.Get("org.mpris.MediaPlayer2.Player", "Metadata")
        title =  metadata['xesam:title']
        artist = metadata['xesam:artist'][0]
        playing = artist + " - " + title + "             "
        return playing
    
    while True:
        with io.open('currentsongspotify.txt', encoding='utf8') as filetxt:
            oldtitle = filetxt.read()
        newtitle = currentplaying()
        if newtitle == oldtitle:
            time.sleep(1)
        else:
            with io.open('currentsongspotify.txt','w',encoding='utf8') as filetxt: # save newtitle to file, overwriting existing data
                filetxt.write(newtitle)
            print 'new file saved:',newtitle