2

My intention is to notify-send a message if an unrated song is about to come to end. I am using Rhythmbox with the MPRIS plugin and I found following scripts :

#Get position
gdbus call \
 --session \
 --dest org.mpris.MediaPlayer2.rhythmbox \
 --object-path /org/mpris/MediaPlayer2 \
 --method org.freedesktop.DBus.Properties.Get \
     org.mpris.MediaPlayer2.Player Position

#Get metadata such as song length and user song rating
gdbus call \
 --session \
 --dest org.mpris.MediaPlayer2.rhythmbox \
 --object-path /org/mpris/MediaPlayer2 \
 --method org.freedesktop.DBus.Properties.Get \
     org.mpris.MediaPlayer2.Player Metadata

Output : (<int64 77000000>,) (in microseconds) for the first one, and for the second one : (<{'mpris:trackid': <'/org/mpris/MediaPlayer2/Track/4782'>, 'xesam:url': <'file:///path-to-the-mp4-file'>, 'xesam:title': <'Song title'>, 'xesam:artist': <['Artist name']>, 'xesam:album': <'Album name'>, 'xesam:genre': <['Genre name']>, 'xesam:audioBitrate': <214016>, 'xesam:contentCreated': <'2017-01-01T00:00:00Z'>, 'xesam:lastUsed': <'2017-09-12T13:41:52Z'>, 'mpris:length': <int64 189000000>, 'xesam:trackNumber': <15>, 'xesam:useCount': <6>, 'xesam:userRating': <0.80000000000000004>, 'mpris:artUrl': <'file:///path-to-an-image-i-guess'>}>,) ('mpris:length' is what matters)

But I don't know how to use the results, espetially how to parse them to check there are less than 10 seconds left (I need the remaining time as int value and don't know how to achieve it in a script...).

There over, I am not sure how to implement that. I was thinking about a .sh file, which I would run from a terminal and which would check every few seconds what the playing state is.

Can you give some pieces of advice and/or the begining of a script (which has at least an infinite loop or a recursion -what is the best?- and the remaining time refreshed in a variable) ?

Thank you very much in advance !

Johannes Lemonde
  • 1,561
  • 1
  • 11
  • 20
  • PS : there is a link to the manual for MPRIS MediaPlayer2 I have used, but I don't think it's pertinent, because we already have everything we need from that website : https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html – Johannes Lemonde Oct 07 '17 at 13:20
  • It'll likely be easier using the `python` dbus bindings - maybe you can modify / build on this example? [spotify-parser.py](https://gist.github.com/Jackevansevo/526311958c14c763bea205d66a4070d0) – steeldriver Oct 07 '17 at 14:17
  • @steeldriver : Oh, nice !! Apart from the fact I've never used Python neither, that seems much easier and I should get around. I fear, I don't know how to call a bash script from a Python script (because I need bash inside the loop). But I will browse for that. Thanks !! – Johannes Lemonde Oct 07 '17 at 17:12
  • It shouldn't be necessary to shell out - see [pydbus - Send a desktop notification](https://github.com/LEW21/pydbus#send-a-desktop-notification) or [Desktop Notifications in Python with Libnotify](http://www.devdungeon.com/content/desktop-notifications-python-libnotify) for example – steeldriver Oct 07 '17 at 17:23
  • Thank you very much @steeldriver !! I was able to make what I wanted to :) But I effectively called a shell script from inside my python code instead of calling a library. But thank to you I also began to learn some Python :) – Johannes Lemonde Oct 07 '17 at 19:52
  • Well done - and thanks for posting your solution – steeldriver Oct 07 '17 at 21:22

1 Answers1

1

I post here what I finally made, so that if it interests somebody, he could use it. Thank you to @steeldriver.

# first : have python-dbus installed
# sudo apt-get install python-dbus

# run like this : python filename.py --notiftwenty --loop


import json
import sys
import os
import subprocess
from argparse import ArgumentParser

import dbus


session_bus = dbus.SessionBus()
bus_data = ("org.mpris.MediaPlayer2.rhythmbox", "/org/mpris/MediaPlayer2")
rhythmbox_bus = session_bus.get_object(*bus_data)
interface = dbus.Interface(rhythmbox_bus, "org.freedesktop.DBus.Properties")
metadata = interface.Get("org.mpris.MediaPlayer2.Player", "Metadata")
position = interface.Get("org.mpris.MediaPlayer2.Player", "Position")

parser = ArgumentParser()
parser.add_argument('--artist', action='store_true')
parser.add_argument('--song', action='store_true')
parser.add_argument('--album', action='store_true')
parser.add_argument('--position', action='store_true')
parser.add_argument('--duration', action='store_true')
parser.add_argument('--remaining', action='store_true')
parser.add_argument('--loop', action='store_true')
parser.add_argument('--notiftwenty', action='store_true')
parser.add_argument('--rating', action='store_true')
parser.add_argument('--format', default='json')

def main():
    args = parser.parse_args()

    data = dict()

    if args.position:
        data['position'] = str(position)

    if args.duration:
        data['duration'] = str(metadata['mpris:length'])

    if args.remaining:
        data['remaining'] = str(metadata['mpris:length'] - position)

    if args.rating:
        data['rating'] = str(metadata['xesam:userRating'] * 5)

    if args.notiftwenty:
        if metadata['xesam:userRating'] * 5 < 0.5:
            if metadata['mpris:length'] - position == 20000000:
                data['notiftwenty'] = str('true')
                subprocess.check_output(["notify-send",
                                         "Rhythmbox : notez cette piste !",
                                         "Ce morceau n'a actuellement pas de note...",
                                         "--icon=rhythmbox"])
        if args.loop:
            data['loop'] = str('true')
            subprocess.check_output("sleep 1 && python "+ os.path.realpath(__file__) +" --notiftwenty --loop", shell=True)


    if args.artist:
        data['artist'] = str(next(iter(metadata['xesam:albumArtist'])))

    if args.song:
        data['song'] = str(metadata['xesam:title'])

    if args.album:
        data['album'] = str(metadata['xesam:album'])

    sys.stdout.write(json.dumps(data))


if __name__ == '__main__':
    main()
Johannes Lemonde
  • 1,561
  • 1
  • 11
  • 20