diff options
| author | Fuwn <[email protected]> | 2024-09-03 12:40:18 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2024-09-03 12:40:18 -0700 |
| commit | b4dd851e386a4e50697c32c1582386aa4ed21367 (patch) | |
| tree | d272d11b02ea6ad170721507fcc8e28583c003d8 /pkgs/mediaplayer | |
| parent | re way (diff) | |
| download | nixos-config-b4dd851e386a4e50697c32c1582386aa4ed21367.tar.xz nixos-config-b4dd851e386a4e50697c32c1582386aa4ed21367.zip | |
mediapl
Diffstat (limited to 'pkgs/mediaplayer')
| -rw-r--r-- | pkgs/mediaplayer/default.nix | 28 | ||||
| -rwxr-xr-x | pkgs/mediaplayer/mediaplayer.py | 152 |
2 files changed, 180 insertions, 0 deletions
diff --git a/pkgs/mediaplayer/default.nix b/pkgs/mediaplayer/default.nix new file mode 100644 index 0000000..2defa82 --- /dev/null +++ b/pkgs/mediaplayer/default.nix @@ -0,0 +1,28 @@ +{ pkgs, ... }: +pkgs.stdenv.mkDerivation { + name = "mediaplayer"; + src = ./mediaplayer.py; + dontUnpack = true; + + propagatedBuildInputs = with pkgs; [ + (python3.withPackages (ps: [ ps.pygobject3 ])) + playerctl + gobject-introspection + curl + glib + ]; + + # https://discourse.nixos.org/t/modulenotfounderror-no-module-named-gi/6874/13 + nativeBuildInputs = [ pkgs.wrapGAppsHook ]; + + installPhase = '' + mkdir -p $out/bin + cp $src $out/bin/mediaplayer.py + chmod +x $out/bin/mediaplayer.py + ''; + + shelHook = '' + export GI_TYPELIB_PATH=${pkgs.playerctl}/lib/girepository-1.0:${pkgs.glib.dev}/lib/girepository-1.0 + export PATH=${pkgs.python3}/bin:$PATH + ''; +} diff --git a/pkgs/mediaplayer/mediaplayer.py b/pkgs/mediaplayer/mediaplayer.py new file mode 100755 index 0000000..1efa79f --- /dev/null +++ b/pkgs/mediaplayer/mediaplayer.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 + +import argparse +import logging +import os +import sys +import signal +import gi +import json + +gi.require_version("Playerctl", "2.0") + +from gi.repository import Playerctl, GLib + +logger = logging.getLogger(__name__) + + +def write_output(text, player): + logger.info("Writing output") + + output = { + "text": text, + "class": "custom-" + player.props.player_name, + "alt": player.props.player_name, + "art": player.props.metadata["mpris:artUrl"], + } + + sys.stdout.write(json.dumps(output) + "\n") + sys.stdout.flush() + + +def on_play(player, status, manager): + logger.info("Received new playback status") + on_metadata(player, player.props.metadata, manager) + + +def on_metadata(player, metadata, manager): + logger.info("Received new metadata") + + track_info = "" + + if ( + player.props.player_name == "spotify" + and "mpris:trackid" in metadata.keys() + and ":ad:" in player.props.metadata["mpris:trackid"] + ): + track_info = "AD PLAYING" + elif player.get_artist() != "" and player.get_title() != "": + track_info = "{title} - {artist}".format( + artist=player.get_artist(), title=player.get_title() + ) + else: + track_info = player.get_title() + + if "file://" in player.props.metadata["mpris:artUrl"]: + os.system( + f"cp $(echo '{player.props.metadata['mpris:artUrl']}' | sed -E 's/file:\\/\\///g') /tmp/mediaplayer_art" + ) + else: + os.system( + f"curl --silent $(echo '{player.props.metadata['mpris:artUrl']}' | sed -E 's/file:\\/\\///g') --output /tmp/mediaplayer_art" + ) + + # if player.props.status != 'Playing' and track_info: + # track_info = ' ' + track_info + + write_output(track_info, player) + + +def on_player_appeared(manager, player, selected_player=None): + if player is not None and ( + selected_player is None or player.name == selected_player + ): + init_player(manager, player) + else: + logger.debug("New player appeared, but it's not the selected player, skipping") + + +def on_player_vanished(manager, player): + logger.info("Player has vanished") + sys.stdout.write("\n") + sys.stdout.flush() + os.system("rm /tmp/mediaplayer_art") + + +def init_player(manager, name): + logger.debug("Initialize player: {player}".format(player=name.name)) + + player = Playerctl.Player.new_from_name(name) + + player.connect("playback-status", on_play, manager) + player.connect("metadata", on_metadata, manager) + manager.manage_player(player) + on_metadata(player, player.props.metadata, manager) + + +def signal_handler(sig, frame): + logger.debug("Received signal to stop, exiting") + sys.stdout.write("\n") + sys.stdout.flush() + # loop.quit() + sys.exit(0) + + +def parse_arguments(): + parser = argparse.ArgumentParser() + + parser.add_argument("-v", "--verbose", action="count", default=0) + parser.add_argument("--player") + + return parser.parse_args() + + +def main(): + arguments = parse_arguments() + + logging.basicConfig( + stream=sys.stderr, + level=logging.DEBUG, + format="%(name)s %(levelname)s %(message)s", + ) + logger.setLevel(max((3 - arguments.verbose) * 10, 0)) + logger.debug("Arguments received {}".format(vars(arguments))) + + manager = Playerctl.PlayerManager() + loop = GLib.MainLoop() + + manager.connect( + "name-appeared", lambda *args: on_player_appeared(*args, arguments.player) + ) + manager.connect("player-vanished", on_player_vanished) + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + for player in manager.props.player_names: + if arguments.player is not None and arguments.player != player.name: + logger.debug( + "{player} is not the filtered player, skipping it".format( + player=player.name + ) + ) + + continue + + init_player(manager, player) + + loop.run() + + +if __name__ == "__main__": + main() |