summaryrefslogtreecommitdiff
path: root/pkgs/mediaplayer
diff options
context:
space:
mode:
authorFuwn <[email protected]>2024-09-03 12:40:18 -0700
committerFuwn <[email protected]>2024-09-03 12:40:18 -0700
commitb4dd851e386a4e50697c32c1582386aa4ed21367 (patch)
treed272d11b02ea6ad170721507fcc8e28583c003d8 /pkgs/mediaplayer
parentre way (diff)
downloadnixos-config-b4dd851e386a4e50697c32c1582386aa4ed21367.tar.xz
nixos-config-b4dd851e386a4e50697c32c1582386aa4ed21367.zip
mediapl
Diffstat (limited to 'pkgs/mediaplayer')
-rw-r--r--pkgs/mediaplayer/default.nix28
-rwxr-xr-xpkgs/mediaplayer/mediaplayer.py152
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()