Thursday, May 26, 2022

[SOLVED] Unicode decode error when passing a bash script's output to python

Issue

I am trying to pass the output of a shell script into python, it works when I do not have unicode characters inside the string that should be returned. The bash script that gets the currently played music:

player_status=$(playerctl status 2> /dev/null)
if [[ $? -eq 0 ]]; then
    metadata="$(playerctl metadata title 2> /dev/null)"
else
    metadata="No music playing"
fi

# Foreground color formatting tags are optional
if [[ $player_status = "Playing" ]]; then
    echo "$metadata"|cut -c -65       # when playing
elif [[ $player_status = "Paused" ]]; then
    echo "$metadata"|cut -c -65        # when paused
else
    echo "$metadata"|cut -c -65       # when stopped
fi

The python script that uses the return value of the script above

def getMusicName():
        music_name = os.popen('bash /home/nep/Self\ Script/now-playing.sh').read()
        return music_name

The error

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe2 in position 64: invalid continuation byte

Finally the name of the music that it was trying to decode:

IZANAGI 【 イザナギ 】 ☯ Japanese Trap & Bass Type Beat ☯ Trapanese Hip Hop Mix

As a sidenote, this is on a Linux system, but I do not think it should make a difference, also if I run the shell script alone it returns the name like this:

IZANAGI 【 イザナギ 】 ☯ Japanese Trap & Bass Type Beat �
                                                         ⏎   

Solution

To be sure the metadata is using proper UTF-8 encoding, you can filter the output of playerctl with iconv -ct UTF-8//TRANSLIT:

Here is your improved script:

#!/usr/bin/env bash

if player_status="$(playerctl status 2>/dev/null)"; then
  metadata="$(playerctl metadata title 2>/dev/null | iconv -ct UTF-8//TRANSLIT)"
else
  metadata="No music playing"
fi

# Foreground color formatting tags are optional
case "$player_status" in
  Playing)
    printf '%.65s\n' "$metadata" # when playing
    ;;
  Paused)
    printf '%.65s\n' "$metadata" # when paused
    ;;
  *)
    printf '%.65s\n' "$metadata" # when stopped
    ;;
esac


Answered By - Léa Gris
Answer Checked By - Mary Flores (WPSolving Volunteer)