Skip to content

Instantly share code, notes, and snippets.

@stpettersens
Created February 16, 2026 15:49
Show Gist options
  • Select an option

  • Save stpettersens/075908c8b8e73cd165a471f7258080ea to your computer and use it in GitHub Desktop.

Select an option

Save stpettersens/075908c8b8e73cd165a471f7258080ea to your computer and use it in GitHub Desktop.
Simple program that prints the current playing song from Rhythmbox.
import std.conv;
import std.file;
import std.stdio;
import std.string;
import std.process;
import core.time;
import core.thread;
import core.sys.posix.unistd; // getlogin
void create_working_dir() {
string dir = "/tmp/rb";
if (!exists(dir)) {
string user = fromStringz(getlogin()).idup;
executeShell(format("doas -u %s mkdir -p %s", user, dir));
}
}
void kill_get_song_loop(string pid_file) {
if (exists(pid_file)) {
auto f = File(pid_file, "r");
string pid = strip(f.readln());
executeShell(format("kill %s", pid));
remove(pid_file);
}
}
void print_song(string playing_file) {
if (exists(playing_file)) {
auto f = File(playing_file, "r");
string song = strip(f.readln());
writeln(song);
return;
}
writeln("...");
}
void spawn_get_song_loop() {
string pid_file = "/tmp/rb/pid";
string playing_file = "/tmp/rb/playing";
bool rb_running = false;
auto processes = executeShell("pgrep rhythmbox | xargs printf '%d,'");
string[] pids = chop(strip(processes.output)).split(",");
foreach (pid; pids) {
uint p = to!uint(pid);
if (p != 0) rb_running = true;
break;
}
if (rb_running && !exists(pid_file)) {
auto pid = spawnProcess("rb_get_song");
auto fo = File(pid_file, "w");
fo.write(pid.processID.to!string);
fo.flush();
Thread.sleep(5.seconds);
}
else if (!rb_running) {
if (exists(playing_file)) {
remove(playing_file);
}
kill_get_song_loop(pid_file);
}
print_song(playing_file);
}
int main() {
create_working_dir();
spawn_get_song_loop();
return 0;
}
#!/usr/bin/env python3
# This Python program will get the current song from Rhythmbox.
# It should be invoked as a process by now_playing.
import dbus
import dbus.mainloop.glib
from gi.repository import GLib
playing_file = '/tmp/rb/playing'
_artist = ''
def dump_playing_file():
with open(playing_file, 'w') as f:
f.write('...')
if __name__ == "__main__":
dump_playing_file()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()
player = bus.get_object("org.mpris.MediaPlayer2.rhythmbox", "/org/mpris/MediaPlayer2")
iface = dbus.Interface(player, "org.freedesktop.DBus.Properties")
def on_metadata_changed(interface, changed_props, invalidated_props):
if "Metadata" in changed_props:
meta = changed_props["Metadata"]
artist = meta.get(dbus.String("xesam:artist"), "")
title = meta.get(dbus.String("xesam:title"), "")
global _artist
_artist = str(artist).split(".String('")[1]
_artist = _artist.split("'")[0]
try:
if _artist != "":
with open(playing_file, 'w') as f:
f.write(f'{_artist} - {title}')
except:
pass
iface.connect_to_signal("PropertiesChanged", on_metadata_changed)
GLib.MainLoop().run()
@stpettersens
Copy link
Author

This program will be rewritten to support any player (including Chromium browsers for YouTube) which supports MPRIS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment