diff options
Diffstat (limited to 'lib/mpris/cli.vala')
-rw-r--r-- | lib/mpris/cli.vala | 331 |
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; +} +} |