|Portada|Blog|Space|

[Índice] > Usando DBus desde shell scripts

Holas, como habrán visto ya hay betas de amarok2, el cual trae unas
cuantas cosas buenas, sin embargo hoy no vengo a contarles sobre amarok2
sino sobre dbus.

¿Pero qué es DBus?

DBus es una interfaz "simple" que permite, desde afuera, pedirles a los
programas que realicen cierta tarea devolviendo cierto valor.
Básicamente DBus es una especie de RPC.

¿Y qué tiene que ver amarok2 con dbus?

Resulta que KDE y las aplicaciones de KDE migraron últimamente desde
DCOP a DBus (estandar de freedesktop), y entre las aplicaciones que
migraron a DBus se encuentra amarok2.

Como quería obtener automáticamente desde mi konversation el nombre de
la canción que estaba escuchando en el momento, es que necesité
preguntarle al amarok2 por medio de DBus los datos de la canción actual.

Nota: en particular no necesitaba los datos de la canción actual en
konversation mismo, sino en un plugin de konversation, estos plugins son
independientes al konversation y se pueden realizar en cualquier
lenguaje.

Por eso es que decidí hacerme un muy simple plugin usando shell scripts.

¿Cómo hacer entonces para preguntar por dbus a shell scripts?

Lo más fácil, por lejos, es tener las herramientas de consola adecuadas.
En debian eso se traduce inmediatamente a:

apt-get install libqt4-dbus

Este paquete trae una herramienta llamada qdbus. Al ejecutarla nos va a
mostrar las interfaces a los programas, en particular vamos a necesitar
recorrer la lista de las interfaces, y como no siempre (o debería decir
casi nunca) tenemos al qdbus, debemos hacerlo por la manera difícil:

Ejemplo:

amarok2_dbus_iface=`
  dbus-send --print-reply --dest=org.freedesktop.DBus \
  / org.freedesktop.DBus.ListNames | \
  sed -e 's/ *string "\(org\.kde\.amarok.*\)"/\1/p;d'`

Acá vemos a dbus-send, ésta es la tosca interfaz que viene siempre con
dbus, y que por tanto /deberíamos/ usar desde nuestros shell scripts.

Si quitan la línea del sed y la asignación a la variable van a poder ver
el formato que este tan particular programa tira.

Una vez que ya conocemos el nombre de la interfaz del amarok, vamos a
tener que investigar qué objetos hay en la interfaz y de qué forma
podemos acceder a la información que necesitamos. Nuevamente qdbus viene
a salvarnos:

qdbus $amarok2_dbus_iface

Aquí pongo lo que nos va a mostrar:

/
/AudioOutputs
/AudioOutputs/0
/KBookmarkManager
/KBookmarkManager/amarok
/KBookmarkManager/kfilePlaces
/KDebug
/KIO
/KIO/Scheduler
/MainApplication
/Player
/TrackList
/amarok
/amarok/MainWindow
/amarok/MainWindow/actions
/amarok/MainWindow/actions/options_configure_keybinding
/amarok/MainWindow/actions/options_configure
/amarok/MainWindow/actions/file_quit
/internal
/internal/PhononXine

Obviamente vamos a tener que adivinar que adentro del objeto /TrackList
está lo que andamos necesitando, bueno, adivinar o buscar y buscar hasta
encontrarlo :)

Y adivinen ¿quién vuelve a salvarnos la vida?, sí qdbus nuevamente:

qdbus $amarok2_dbus_iface /TrackList

Lo cual nos muestra entre otras cosas:

method int org.freedesktop.MediaPlayer.GetCurrentTrack()
method QVariantMap org.freedesktop.MediaPlayer.GetMetadata(int)

O casualidad, lo que andabamos necesitando era justamente eso, ver cual
era la pista actual y obtener la metadata de esa pista.

Para ver la canción actual, le volvemos a pedir al qdbus:

pista=`qdbus $amarok2_dbus_iface /TrackList GetCurrentTrack`

y finalmente:

qdbus $amarok2_dbus_iface /TrackList GetMetadata $pista

Ahora bien, ¿qué hacemos si no tenemos el qdbus?, usamos dbus-send de la
siguiente forma, y ahora voy a pegar el script completo para
konversation que permite mostrar por el mismo un hermoso mensaje del
estilo /me is listening to Canción by Artista on Album [amarok2]:

#!/bin/sh

PORT=$1
SERVER=$2
TARGET=$3

amarok2_dbus_iface=` \
	dbus-send --print-reply --dest=org.freedesktop.DBus \
	/ org.freedesktop.DBus.ListNames | \
	sed -e 's/ *string "\(org\.kde\.amarok.*\)"/\1/p;d'`

current_track=` \
	dbus-send --print-reply --dest="$amarok2_dbus_iface" \
	/TrackList org.freedesktop.MediaPlayer.GetCurrentTrack | \
	sed -e '1d;s/.* //'`

eval "` \
	dbus-send --print-reply --dest="$amarok2_dbus_iface" \
	/TrackList org.freedesktop.MediaPlayer.GetMetadata int32:$current_track | \
	sed -e '1,2d;$d;N;N;N;s/.*\n[^"]*"\(.*\)".*\n.*\(string \|int32 \)\(.*\)\n.*/\1=\3/'`"

dcop $PORT default say $SERVER "$TARGET" "/me is listening to $title by $artist on $album [amarok2]"

---------
Los documentos en este sitio se encuentran licenciados bajo la GFDL.
Ver comentarios: [Hay i comentarios]
Para agregar un comentario: agregue a la URL: ?do=show_comment_form (explicación)