summaryrefslogtreecommitdiff
path: root/lib/mpris/cli.vala
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mpris/cli.vala')
-rw-r--r--lib/mpris/cli.vala331
1 files changed, 331 insertions, 0 deletions
diff --git a/lib/mpris/cli.vala b/lib/mpris/cli.vala
new file mode 100644
index 0000000..b71def9
--- /dev/null
+++ b/lib/mpris/cli.vala
@@ -0,0 +1,331 @@
+namespace AstalMpris {
+static bool help;
+static bool version;
+static bool list;
+static bool raw;
+[CCode (array_length = false, array_null_terminated = true)]
+static string[] players;
+
+const OptionEntry[] options = {
+ { "version", 'v', OptionFlags.NONE, OptionArg.NONE, ref version, null, null },
+ { "help", 'h', OptionFlags.NONE, OptionArg.NONE, ref help, null, null },
+ { "player", 'p', OptionFlags.NONE, OptionArg.STRING_ARRAY, ref players, null, null },
+ { "list", 'l', OptionFlags.NONE, OptionArg.NONE, ref list, null, null },
+ { "raw", 'r', OptionFlags.NONE, OptionArg.NONE, ref raw, null, null },
+ { null },
+};
+
+int main(string[] argv) {
+ try {
+ var opts = new OptionContext();
+ opts.add_main_entries(options, null);
+ opts.set_help_enabled(false);
+ opts.set_ignore_unknown_options(false);
+ opts.parse(ref argv);
+ } catch (OptionError err) {
+ printerr(err.message);
+ return 1;
+ }
+
+ if (help) {
+ print("Usage:\n");
+ print(" %s [flags] [command]\n\n", argv[0]);
+ print("Flags:\n");
+ print(" -h, --help Print this help and exit\n");
+ print(" -v, --version Print version number and exit\n");
+ print(" -l, --list List available players\n");
+ print(" -p, --player Operate on given player\n");
+ print(" -r, --raw Print single line json info\n");
+ print("\nCommands:\n");
+ print(" info Print info about player\n");
+ print(" monitor Monitor changes\n");
+ print(" play Play track\n");
+ print(" pause Pause track\n");
+ print(" play-pause Play if paused, Pause if playing\n");
+ print(" stop Stop player\n");
+ print(" next Play next track\n");
+ print(" previous Play previous track\n");
+ print(" quit Quit player\n");
+ print(" raise Ask compositor to raise the player\n");
+ print(" position [OFFSET][+/-/%] Set position of player\n");
+ print(" volume [LEVEL][+/-/%] Set volume of player\n");
+ print(" loop [STATUS] One of: \"None\", \"Track\", \"Playlist\"\n");
+ print(" shuffle [STATUS] One of: \"On\", \"Off\", \"Toggle\"\n");
+ return 0;
+ }
+
+ if (version) {
+ print(VERSION);
+ return 0;
+ }
+
+ var mpris = new Mpris();
+ var mpris_players = new List<Player>();
+
+ if (list) {
+ foreach (var p in mpris.players)
+ print("%s\n", p.bus_name.replace(Mpris.PREFIX, ""));
+
+ return 0;
+ }
+
+ if (players.length > 0) {
+ foreach (var name in players)
+ mpris_players.append(new Player(name));
+ } else {
+ foreach (var p in mpris.players)
+ mpris_players.append(p);
+ }
+
+ var cmd = argv[1];
+ var arg = argv[2];
+
+ switch (cmd) {
+ case "monitor":
+ return do_monitor(mpris);
+
+ case "info":
+ print_players(mpris_players.copy());
+ break;
+
+ case "play":
+ foreach (var player in mpris_players)
+ player.play();
+ break;
+
+ case "pause":
+ foreach (var player in mpris_players)
+ player.pause();
+ break;
+
+ case "play-pause":
+ foreach (var player in mpris_players)
+ player.play_pause();
+ break;
+
+ case "stop":
+ foreach (var player in mpris_players)
+ player.stop();
+ break;
+
+ case "next":
+ foreach (var player in mpris_players)
+ player.next();
+ break;
+
+ case "previous":
+ foreach (var player in mpris_players)
+ player.previous();
+ break;
+
+ case "raise":
+ foreach (var player in mpris_players)
+ player.raise();
+ break;
+
+ case "quit":
+ foreach (var player in mpris_players)
+ player.quit();
+ break;
+
+ case "position":
+ foreach (var player in mpris_players) {
+ if (do_position(player, arg) != 0)
+ return 1;
+ }
+ break;
+
+ case "volume":
+ foreach (var player in mpris_players) {
+ if (do_volume(player, arg) != 0)
+ return 1;
+ }
+ break;
+
+ case "loop":
+ foreach (var player in mpris_players) {
+ if (do_loop(player, arg) != 0)
+ return 1;
+ }
+ break;
+
+ case "shuffle":
+ foreach (var player in mpris_players) {
+ if (do_shuffle(player, arg) != 0)
+ return 1;
+ }
+ break;
+
+ case "open":
+ if (arg == null) {
+ stderr.printf("missing open arg");
+ return 1;
+ }
+
+ foreach (var player in mpris_players)
+ player.open_uri(arg);
+ break;
+
+ default:
+ if (cmd == null)
+ stderr.printf("missing command\n");
+ else
+ stderr.printf(@"unknown command \"$cmd\"\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+Json.Node to_json(Player p) {
+ var uris = new Json.Builder().begin_array();
+ foreach (var uri in p.supported_uri_schemas)
+ uris.add_string_value(uri);
+
+ uris.end_array();
+
+ return new Json.Builder().begin_object()
+ .set_member_name("bus_name").add_string_value(p.bus_name)
+ .set_member_name("available").add_boolean_value(p.available)
+ .set_member_name("identity").add_string_value(p.identity)
+ .set_member_name("entry").add_string_value(p.entry)
+ .set_member_name("supported_uri_schemas").add_value(uris.get_root())
+ .set_member_name("loop_status").add_string_value(p.loop_status.to_string())
+ .set_member_name("shuffle_status").add_string_value(p.shuffle_status.to_string())
+ .set_member_name("rate").add_double_value(p.rate)
+ .set_member_name("volume").add_double_value(p.volume)
+ .set_member_name("position").add_double_value(p.position)
+ .set_member_name("cover_art").add_string_value(p.cover_art)
+ .set_member_name("metadata").add_value(Json.gvariant_serialize(
+ p.metadata != null ? p.metadata : new HashTable<string, Variant>(str_hash, str_equal)))
+ .end_object()
+ .get_root();
+}
+
+void print_players(List<weak Player> players) {
+ var json = new Json.Builder().begin_array();
+
+ foreach (var p in players)
+ json.add_value(to_json(p));
+
+ stdout.printf("%s\n", Json.to_string(json.end_array().get_root(), !raw));
+ stdout.flush();
+}
+
+int do_monitor(Mpris mpris) {
+ print_players(mpris.players);
+ foreach (var player in mpris.players) {
+ player.notify.connect(() => print_players(mpris.players));
+ }
+
+ mpris.player_added.connect((player) => {
+ player.notify.connect(() => print_players(mpris.players));
+ });
+
+ mpris.player_closed.connect(() => {
+ print_players(mpris.players);
+ });
+
+ new MainLoop(null, false).run();
+ return 0;
+}
+
+int do_position(Player player, string? arg) {
+ if (arg == null) {
+ stderr.printf("missing position argument\n");
+ return 1;
+ }
+
+ else if (arg.has_suffix("%")) {
+ var percent = double.parse(arg.slice(0, -1)) / 100;
+ player.position = player.length * percent;
+ }
+
+ else if (arg.has_suffix("-")) {
+ player.position += double.parse(arg.slice(0, -1)) * -1;
+ }
+
+ else if (arg.has_suffix("+")) {
+ player.position += double.parse(arg.slice(0, -1));
+ }
+
+ else {
+ player.position = double.parse(arg);
+ }
+
+ return 0;
+}
+
+int do_volume(Player player, string? arg) {
+ if (arg == null) {
+ stderr.printf("missing volume argument\n");
+ return 1;
+ }
+
+ else if (arg.has_suffix("%")) {
+ player.volume = double.parse(arg.slice(0, -1)) / 100;
+ }
+
+ else if (arg.has_suffix("-")) {
+ player.volume += (double.parse(arg.slice(0, -1)) * -1) / 100;
+ }
+
+ else if (arg.has_suffix("+")) {
+ player.volume += double.parse(arg.slice(0, -1)) / 100;
+ }
+
+ else {
+ player.volume = double.parse(arg);
+ }
+
+ return 0;
+}
+
+int do_loop(Player player, string? arg) {
+ if (arg == null) {
+ player.loop();
+ return 0;
+ }
+
+ switch (arg) {
+ case "None":
+ player.loop_status = Loop.NONE;
+ break;
+ case "Track":
+ player.loop_status = Loop.TRACK;
+ break;
+ case "Playlist":
+ player.loop_status = Loop.PLAYLIST;
+ break;
+ default:
+ stderr.printf(@"unknown shuffle status \"$arg\"");
+ return 1;
+ }
+
+ return 0;
+}
+
+int do_shuffle(Player player, string? arg) {
+ if (arg == null) {
+ player.shuffle();
+ return 1;
+ }
+
+ switch (arg) {
+ case "On":
+ player.shuffle_status = Shuffle.ON;
+ break;
+ case "Off":
+ player.shuffle_status = Shuffle.OFF;
+ break;
+ case "Toggle":
+ player.shuffle();
+ break;
+ default:
+ stderr.printf(@"unknown shuffle status \"$arg\"");
+ return 1;
+ }
+
+ return 0;
+}
+}