From c158ac57f118f2722c6c34acadb1be7e279188b2 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Thu, 14 Aug 2014 00:15:39 -0500 Subject: [PATCH] Alternative implementation in Vala This implementation does not include key bindings or a status icon, because I wanted to keep it small, and both of those require linking with and initializing GTK+. --- Makefile.am | 30 ++ autogen.sh | 13 + configure.ac | 36 ++ src/albumart.vala | 120 +++++++ src/mpdnotify.vala | 14 + src/notifier.vala | 153 +++++++++ vapi/libmpdclient.vapi | 760 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1126 insertions(+) create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 src/albumart.vala create mode 100644 src/mpdnotify.vala create mode 100644 src/notifier.vala create mode 100644 vapi/libmpdclient.vapi diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..8f2a0f2 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,30 @@ +bin_PROGRAMS = mpdnotify + +mpdnotify_VALASOURCES = \ + src/albumart.vala \ + src/notifier.vala \ + src/mpdnotify.vala + +mpdnotify_SOURCES = $(mpdnotify_VALASOURCES) + +mpdnotify_VALAFLAGS = \ + --target-glib=@TARGET_GLIB@ \ + --vapidir $(top_srcdir)/vapi \ + --pkg json-glib-1.0 \ + --pkg libmpdclient \ + --pkg libnotify \ + --pkg libsoup-2.4 + +LIBS = @LIBS@ \ + @glib_LIBS@ \ + @jsonglib_LIBS@ \ + @libmpdclient_LIBS@ \ + @libnotify_LIBS@ \ + @libsoup_LIBS@ + +AM_CFLAGS = \ + @glib_CFLAGS@ \ + @jsonglib_CFLAGS@ \ + @libmpdclient_CFLAGS@ \ + @libnotify_CFLAGS@ \ + @libsoup_CFLAGS@ diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..7ee7d98 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +srcdir=$(dirname $0) +test -z "${srcdir}" && srcdir=. + +for f in COPYING NEWS README AUTHORS ChangeLog; do + test -f ${srcdir}/$f || touch ${srcdir}/$f +done + +rm -f .version +autoreconf -v --install ${srcdir} || exit $? + +test -z "${NOCONFIGURE}" && "${srcdir}"/configure "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..393aa71 --- /dev/null +++ b/configure.ac @@ -0,0 +1,36 @@ +AC_INIT([mpdnotify], [0.2], [dustin@hatch.name]) +AM_INIT_AUTOMAKE([1.11 subdir-objects no-dist-gzip dist-xz tar-pax]) +AC_CONFIG_SRCDIR([src/mpdnotify.vala]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile]) + +AC_PROG_CC +AM_PROG_CC_C_O +AM_PROG_VALAC + +TARGET_GLIB=2.32 +PKG_CHECK_MODULES([glib], [ + glib-2.0 >= $TARGET_GLIB + gobject-2.0 >= $TARGET_GLIB +]) +AC_SUBST(TARGET_GLIB) +AC_SUBST(glib_LIBS) +AC_SUBST(glib_CFLAGS) + +PKG_CHECK_MODULES([jsonglib], [json-glib-1.0]) +AC_SUBST(jsonglib_LIBS) +AC_SUBST(jsonglib_CFLAGS) + +PKG_CHECK_MODULES([libmpdclient], [libmpdclient]) +AC_SUBST(libmpdclient_LIBS) +AC_SUBST(libmpdclient_CFLAGS) + +PKG_CHECK_MODULES([libnotify], [libnotify]) +AC_SUBST(libnotify_LIBS) +AC_SUBST(libnotify_CFLAGS) + +PKG_CHECK_MODULES([libsoup], [libsoup-2.4]) +AC_SUBST(libsoup_LIBS) +AC_SUBST(libsoup_CFLAGS) + +AC_OUTPUT diff --git a/src/albumart.vala b/src/albumart.vala new file mode 100644 index 0000000..1b976d2 --- /dev/null +++ b/src/albumart.vala @@ -0,0 +1,120 @@ +using Soup; + +namespace MpdNotify { + + class AlbumArt { + private const string LASTFM_API_KEY = + "929dc7a1779b10b09f9c3e375b43463c"; + private const string LASTFM_API_URL = + "http://ws.audioscrobbler.com/2.0"; + + private static static Mutex mtx = Mutex(); + private static string cache_dir = Path.build_path( + Path.DIR_SEPARATOR_S, + Environment.get_user_cache_dir(), + "album-art" + ); + + public signal void download_complete(bool success); + + public string artist { get; private set; } + public string album { get; private set; } + public string filename { get; private set; } + public bool cached { + get { + return FileUtils.test(filename, FileTest.EXISTS); + } + } + + public AlbumArt(string artist, string album) { + this.artist = artist; + this.album = album; + var key = string.join(":", artist, album); + this.filename = Path.build_filename( + cache_dir, + Checksum.compute_for_string(ChecksumType.SHA1, key) + ); + } + + public void fetch() { + uint response; + URI url; + Soup.Session session; + Soup.Message message; + + if (!mtx.trylock()) { + return; + } + + session = new Soup.Session(); + url = new URI(LASTFM_API_URL); + var data = Datalist(); + data.set_data("method", "album.getInfo"); + data.set_data("api_key", LASTFM_API_KEY); + data.set_data("artist", artist); + data.set_data("album", album); + data.set_data("format", "json"); + url.set_query(Form.encode_datalist(data)); + message = new Soup.Message("GET", url.to_string(false)); + response = session.send_message(message); + if (response < 200 || response >= 300) { + stderr.printf("Last.fm API call failed with status %u\b", + response); + finish(false); + return; + } + + var parser = new Json.Parser(); + try { + parser.load_from_data((string) message.response_body.data); + } catch { + stderr.printf("Failed to parse Last.fm album info response\n"); + finish(false); + return; + } + unowned Json.Object root = parser.get_root().get_object(); + unowned Json.Object alb = root.get_object_member("album"); + unowned Json.Array images = alb.get_array_member("image"); + string img_url = null; + foreach (unowned Json.Node n in images.get_elements()) { + unowned Json.Object img = n.get_object(); + unowned string size = img.get_string_member("size"); + unowned string text = img.get_string_member("#text"); + if (size != "large" || text == null || text == "") { + continue; + } else { + img_url = text; + break; + } + } + if (img_url == null || img_url == "") { + stderr.printf("No album art available for %s - %s\n", + artist, album); + finish(false); + return; + } + message = new Soup.Message("GET", img_url); + response = session.send_message(message); + if (response < 200 || response >= 300) { + stderr.printf("Fetching album art failed with status %u\n", + response); + finish(false); + return; + } + + var stream = FileStream.open(filename, "w"); + stream.write(message.response_body.data); + finish(true); + } + + private void finish(bool success) { + Idle.add(() => { + download_complete(success); + return false; + }); + mtx.unlock(); + } + + } + +} diff --git a/src/mpdnotify.vala b/src/mpdnotify.vala new file mode 100644 index 0000000..58592d4 --- /dev/null +++ b/src/mpdnotify.vala @@ -0,0 +1,14 @@ +namespace MpdNotify { + + void main() { + var loop = new MainLoop(); + Unix.signal_add(2, () => { + loop.quit(); + return false; + }); + var notifier = new Notifier("/run/mpd/socket", 0); + notifier.start(); + loop.run(); + } + +} diff --git a/src/notifier.vala b/src/notifier.vala new file mode 100644 index 0000000..f98bac8 --- /dev/null +++ b/src/notifier.vala @@ -0,0 +1,153 @@ +using Mpd; + +namespace MpdNotify { + + class Notifier { + private const int RECONNECT_INTERVAL = 1; + + private string host; + private int port; + private string? password; + private Connection conn; + private Notify.Notification? notif = null; + + public Notifier(string host, int port = 0, string? password = null) { + this.host = host; + this.port = port; + this.password = password; + } + + public void start() { + if (!connect()) { + stderr.printf("Failed to connect to %s, will retry " + + "in %d second(s)\n", host, RECONNECT_INTERVAL); + reconnect(); + } else { + notify(); + conn.send_idle_mask(Mpd.Idle.PLAYER); + } + } + + private bool connect() { + conn = new Connection(host, port); + if (conn.error != Mpd.Error.SUCCESS) { + return false; + } + if (password != null) { + conn.run_password(password); + } + var chan = new IOChannel.unix_new(conn.fd); + chan.add_watch(IOCondition.IN, changed); + return true; + } + + private void reconnect() { + var timer = new TimeoutSource(RECONNECT_INTERVAL * 1000); + timer.set_callback(() => { + if (!connect()) { + return true; + } + notify(); + conn.send_idle_mask(Mpd.Idle.PLAYER); + return false; + }); + timer.attach(null); + } + + private bool changed(IOChannel src, IOCondition cond) { + var res = conn.recv_idle(false); + if (res == 0) { + send_notification( + "Disconnected", + "Lost connection to MPD, reconnecting...", + "audio-x-generic" + ); + reconnect(); + return false; + } else { + notify(); + conn.send_idle_mask(Mpd.Idle.PLAYER); + return true; + } + } + + private void send_notification(string summary, string? body = null, + string? icon = null, int timeout = 2000) { + if (notif == null) { + if (Notify.is_initted()) { + Notify.uninit(); + } + Notify.init("mpdnotify"); + notif = new Notify.Notification(summary, body, icon); + notif.set_timeout(timeout); + notif.closed.connect(() => { + notif = null; + }); + } else { + notif.update(summary, body, icon); + } + try { + notif.show(); + } catch { + stderr.printf("Failed to show notification!\n"); + notif = null; + } + } + + private void notify() { + string title; + string artist; + string album; + string duration; + string summary; + string body; + + var status = conn.run_status(); + var song = conn.run_current_song(); + + title = song.get_tag(TagType.TITLE); + switch (status.state) { + case State.PAUSE: + summary = "%s (Paused)".printf(title); + break; + case State.STOP: + summary = "%s (Stopped)".printf(title); + break; + default: + summary = title; + break; + } + + artist = song.get_tag(TagType.ARTIST); + album = song.get_tag(TagType.ALBUM); + duration = "%u:%02u".printf(song.duration / 60, + song.duration % 60); + + body = "from %s by %s (%s)".printf( + album, + artist, + duration + ); + + var art = new AlbumArt(artist, album); + string icon; + if (art.cached) { + icon = art.filename; + } else { + icon = "audio-x-generic"; + art.download_complete.connect((s) => { + if (s && notif != null) { + conn.run_noidle(); + notify(); + conn.send_idle_mask(Mpd.Idle.PLAYER); + } + }); + new Thread(null, (ThreadFunc) art.fetch); + } + + send_notification(summary, body, icon); + } + + } + +} diff --git a/vapi/libmpdclient.vapi b/vapi/libmpdclient.vapi new file mode 100644 index 0000000..dcd1493 --- /dev/null +++ b/vapi/libmpdclient.vapi @@ -0,0 +1,760 @@ +[CCode (cprefix = "mpd_", cheader_filename = "mpd/client.h")] + +namespace Mpd { + [CCode (cname = "enum mpd_error")] + public enum Error { + SUCCESS = 0, + OOM, + ARGUMENT, + STATE, + TIMEOUT, + SYSTEM, + RESOLVER, + MALFORMED, + CLOSED, + SERVER + } + + [CCode (cname = "enum mpd_async_event")] + public enum AsyncEvent { + READ = 1, + WRITE = 2, + HUP = 4, + ERROR = 8 + } + + [CCode (cname = "enum mpd_server_error")] + public enum ServerError { + UNK = -1, + NOT_LIST = 1, + ARG = 2, + PASSWORD = 3, + PERMISSION = 4, + UNKNOWN_CMD = 5, + NO_EXIST = 50, + PLAYLIST_MAX = 51, + SYSTEM = 52, + PLAYLIST_LOAD = 53, + UPDATE_ALREADY = 54, + PLAYER_SYNC = 55, + ERROR_EXIST = 56 + } + + [CCode (cname = "enum mpd_entity_type")] + public enum EntityType { + UNKNOWN, + DIRECTORY, + SONG, + PLAYLIST + } + + [CCode (cname = "enum mpd_idle")] + public enum Idle { + DATABASE = 0x1, + STORED_PLAYLIST = 0x2, + QUEUE = 0x4, + PLAYLIST = QUEUE, + PLAYER = 0x8, + MIXER = 0x10, + OUTPUT = 0x20, + OPTIONS = 0x40, + UPDATE = 0x80, + STICKER = 0x100, + SUBSCRIPTION = 0x200, + MESSAGE = 0x400 + } + + [CCode (cname = "enum mpd_parser_result")] + public enum ParserResult { + MALFORMED, + SUCCESS, + ERROR, + PAIR + } + + [CCode (cname = "enum mpd_operator")] + public enum Operator { + DEFAULT + } + + [CCode (cname = "enum mpd_tag_type", + cprefix = "MPD_TAG_")] + public enum TagType { + UNKNOWN = -1, + ARTIST, + ALBUM, + ALBUM_ARTIST, + TITLE, + TRACK, + NAME, + GENRE, + DATE, + COMPOSER, + PERFORMER, + COMMENT, + DISC, + MUSICBRAINZ_ARTISTID, + MUSICBRAINZ_ALBUMID, + MUSICBRAINZ_ALBUMARTISTID, + MUSICBRAINZ_TRACKID, + COUNT + } + + [CCode (cname = "enum mpd_state")] + public enum State { + UNKNOWN = 0, + STOP = 1, + PLAY = 2, + PAUSE = 3 + } + + [CCode (cname = "struct mpd_async", + free_function = "mpd_async_free")] + [Compact] + public class Async { + public Mpd.Error error { get; } + public string? error_message { get; } + public int system_error { get; } + public int fd { get; } + + public Async(int fd); + public Mpd.Error get_error(); + public unowned string? get_error_message(); + public int get_system_error(); + public int get_fd(); + public Mpd.AsyncEvent events(); + public bool async_io(Mpd.AsyncEvent events); + public bool send_command_v(string command, va_list args); + public bool send_command(string command, ...); + public string? recv_line(); + } + + [CCode (cname = "struct mpd_audio_format")] + [Compact] + public class AudioFormat { + public uint8 bits; + public uint8 channels; + public uint32 sample_rate; + } + + [CCode (cname = "struct mpd_connection", + free_function="mpd_connection_free")] + [Compact] + public class Connection { + public int fd { get; } + public Mpd.Async async { get; } + public Mpd.Error error { get; } + public string error_message { get; } + public Mpd.ServerError server_error { get; } + public int system_error { get; } + [CCode (array_null_terminated = true)] + public unowned uint[] server_version { get; } + public uint server_error_location { get; } + public uint timeout { set; } + public Settings settings { get; } + + public Connection(string? host = null, uint port = 0, uint timeout_ms = 0); + [CCode (cname = "mpd_connection_new_async")] + public Connection.from_async(Mpd.Async async, string welcome); + public void set_timeout(uint timeout_ms); + public int get_fd(); + public Mpd.Async get_async(); + public Mpd.Error get_error(); + public unowned string get_error_message(); + public Mpd.ServerError get_server_error(); + public uint get_server_error_location(); + public int get_system_error(); + public bool clear_error(); + [CCode (array_null_terminated = true)] + public unowned uint[] get_server_version(); + public int cmp_server_version(uint major, uint minor, uint patch); + public Settings get_settings(); + [CCode (cname = "mpd_recv_directory")] + public Directory? recv_directory(); + [CCode (cname = "mpd_recv_entity")] + public Entity? recv_entity(); + [CCode (cname = "mpd_command_list_begin")] + public bool command_list_begin(bool discrete_ok = false); + [CCode (cname = "mpd_command_list_end")] + public bool command_list_end(); + [CCode (cname = "mpd_send_set_volume")] + public bool send_set_volume(uint volume); + [CCode (cname = "mpd_run_set_volume")] + public bool run_set_volume(uint volume); + [CCode (cname = "mpd_send_outputs")] + public bool send_outputs(); + [CCode (cname = "mpd_recv_output")] + public Output recv_output(); + [CCode (cname = "mpd_send_enable_output")] + public bool send_enable_output(uint output_id); + [CCode (cname = "mpd_run_enable_output")] + public bool run_enable_output(uint output_id); + [CCode (cname = "mpd_send_disable_output")] + public bool send_disable_output(uint output_id); + [CCode (cname = "mpd_run_disable_output")] + public bool run_disable_output(uint output_id); + [CCode (cname = "mpd_send_password")] + public bool send_password(string password); + [CCode (cname = "mpd_run_password")] + public bool run_password(string password); + [CCode (cname = "mpd_recv_playlist")] + public Playlist recv_playlist(); + [CCode (cname = "mpd_send_list_playlist")] + public bool send_list_playlist(string name); + [CCode (cname = "mpd_send_list_playlist_meta")] + public bool send_list_playlist_meta(string name); + [CCode (cname = "mpd_send_playlist_clear")] + public bool send_playlist_clear(string name); + [CCode (cname = "mpd_run_playlist_clear")] + public bool run_playlist_clear(string name); + [CCode (cname = "mpd_send_playlist_add")] + public bool send_playlist_add(string name, string path); + [CCode (cname = "mpd_run_playlist_add")] + public bool run_playlist_add(string name, string path); + [CCode (cname = "mpd_send_playlist_move")] + public bool send_playlist_move(string name, uint from, uint to); + [CCode (cname = "mpd_send_playlist_delete")] + public bool send_playlist_delete(string name, uint pos); + [CCode (cname = "mpd_run_playlist_delete")] + public bool run_playlist_delete(string name, uint pos); + [CCode (cname = "mpd_send_save")] + public bool send_save(string name); + [CCode (cname = "mpd_run_save")] + public bool run_save(string name); + [CCode (cname = "mpd_send_load")] + public bool send_load(string name); + [CCode (cname = "mpd_run_load")] + public bool run_load(string name); + [CCode (cname = "mpd_send_rename")] + public bool send_rename(string from, string to); + [CCode (cname = "mpd_run_rename")] + public bool run_rename(string from, string to); + [CCode (cname = "mpd_send_rm")] + public bool send_rm(string name); + [CCode (cname = "mpd_run_rm")] + public bool run_rm(string name); + [CCode (cname = "mpd_recv_pair")] + public Pair recv_pair(); + [CCode (cname = "mpd_recv_pair_named")] + public Pair recv_pair_named(string name); + [CCode (cname = "mpd_return_pair")] + public void return_pair(Pair pair); + [CCode (cname = "mpd_enqueue_pair")] + public void enqueue_pair(Pair pair); + [CCode (cname = "mpd_response_finish")] + public bool response_finish(); + [CCode (cname = "mpd_response_next")] + public bool response_next(); + [CCode (cname = "mpd_search_db_songs")] + public bool search_db_songs(bool exact); + [CCode (cname = "mpd_search_add_db_songs")] + public bool search_add_db_songs(bool exact); + [CCode (cname = "mpd_search_queue_songs")] + public bool search_queue_songs(bool exact); + [CCode (cname = "mpd_search_db_tags")] + public bool search_db_tags(TagType type); + [CCode (cname = "mpd_count_db_songs")] + public bool count_db_songs(); + [CCode (cname = "mpd_search_add_uri_constraint")] + public bool search_add_uri_constraint(Operator oper, string value); + [CCode (cname = "mpd_search_add_tag_constraint")] + public bool search_add_tag_constraint(Operator oper, TagType type, string value); + [CCode (cname = "mpd_search_add_any_tag_constraint")] + public bool search_add_any_tag_constraint(Operator oper, string value); + [CCode (cname = "mpd_search_commit")] + public bool search_commit(); + [CCode (cname = "mpd_search_cancel")] + public bool search_cancel(); + [CCode (cname = "mpd_recv_pair_tag")] + public Pair recv_pair_tag(TagType type); + [CCode (cname = "mpd_send_command")] + public bool send_command(string command, ...); + [CCode (cname = "mpd_recv_song")] + public Song recv_song(); + [CCode (cname = "mpd_send_status")] + public bool send_status(); + [CCode (cname = "mpd_recv_status")] + public Status recv_status(); + [CCode (cname = "mpd_run_status")] + public Status run_status(); + [CCode (cname = "mpd_send_allowed_commands")] + public bool send_allowed_commands(); + [CCode (cname = "mpd_send_disallowed_commands")] + public bool send_disallowed_commands(); + [CCode (cname = "mpd_recv_command_pair")] + public Pair? recv_command_pair(); + [CCode (cname = "mpd_send_list_url_schemes")] + public bool send_list_url_schemas(); + [CCode (cname = "mpd_recv_url_scheme_pair")] + public Pair? recv_url_scheme_pair(); + [CCode (cname = "mpd_send_list_tag_types")] + public bool send_list_tag_types(); + [CCode (cname = "mpd_recv_tag_type_pair")] + public Pair? recv_tag_type_pair(); + [CCode (cname = "mpd_send_list_all")] + public bool send_list_all(string path); + [CCode (cname = "mpd_send_list_all_meta")] + public bool send_list_all_meta(string path); + [CCode (cname = "mpd_send_list_meta")] + public bool send_list_meta(string path); + [CCode (cname = "mpd_send_update")] + public bool send_update(string? path = null); + [CCode (cname = "mpd_send_rescan")] + public bool send_rescan(string? path = null); + [CCode (cname = "mpd_recv_update_id")] + public uint recv_update_id(); + [CCode (cname = "mpd_run_update")] + public uint run_update(string? path = null); + [CCode (cname = "mpd_run_rescan")] + public uint run_rescan(string? path = null); + [CCode (cname = "mpd_send_idle")] + public bool send_idle(); + [CCode (cname = "mpd_send_idle_mask")] + public bool send_idle_mask(Idle mask); + [CCode (cname = "mpd_send_noidle")] + public bool send_noidle(); + [CCode (cname = "mpd_recv_idle")] + public Idle recv_idle(bool disable_timeout); + [CCode (cname = "mpd_run_idle")] + public Idle run_idle(); + [CCode (cname = "mpd_run_idle_mask")] + public Idle run_idle_mask(Idle mask); + [CCode (cname = "mpd_run_noidle")] + public Idle run_noidle(); + [CCode (cname = "mpd_send_stats")] + public bool send_stats(); + [CCode (cname = "mpd_recv_stats")] + public Stats recv_stats(); + [CCode (cname = "mpd_run_stats")] + public Stats run_stats(); + [CCode (cname = "mpd_send_sticker_set")] + public bool send_sticker_set(string type, string uri, string name, string value); + [CCode (cname = "mpd_run_sticker_set")] + public bool run_sticker_set(string type, string uri, string name, string value); + [CCode (cname = "mpd_send_sticker_delete")] + public bool send_sticker_delete(string type, string uri, string name); + [CCode (cname = "mpd_run_sticker_delete")] + public bool run_sticker_delete(string type, string uri, string name); + [CCode (cname = "mpd_send_sticker_get")] + public bool send_sticker_get(string type, string uri, string name); + [CCode (cname = "mpd_send_sticker_list")] + public bool send_sticker_list(string type, string uri); + [CCode (cname = "mpd_send_sticker_find")] + public bool send_sticker_find(string type, string base_uri, string name); + [CCode (cname = "mpd_recv_sticker")] + public Pair recv_sticker(); + [CCode (cname = "mpd_return_sticker")] + public void return_sticker(Pair pair); + [CCode (cname = "mpd_send_list_queue_meta")] + public bool send_list_queue_meta(); + [CCode (cname = "mpd_send_list_queue_range_meta")] + public bool send_list_queue_range_meta(uint start, uint end); + [CCode (cname = "mpd_send_get_queue_song_pos")] + public bool send_get_queue_song_pos(uint pos); + [CCode (cname = "mpd_run_get_queue_song_pos")] + public Song run_get_queue_song_pos(uint pos); + [CCode (cname = "mpd_send_get_queue_song_id")] + public bool send_get_queue_song_id(uint id); + [CCode (cname = "mpd_run_get_queue_song_id")] + public Song run_get_queue_song_id(uint id); + [CCode (cname = "mpd_send_queue_changes_meta")] + public bool send_queue_changes_meta(uint version); + [CCode (cname = "mpd_send_queue_changes_brief")] + public bool send_queue_changes_brief(uint version); + [CCode (cname = "mpd_recv_queue_change_brief")] + public bool recv_queue_change_brief(out uint position_r, out uint id_r); + [CCode (cname = "mpd_send_add")] + public bool send_add(string file); + [CCode (cname = "mpd_run_add")] + public bool run_add(string uri); + [CCode (cname = "mpd_send_add_id")] + public bool send_add_id(string file); + [CCode (cname = "mpd_send_add_id_to")] + public bool send_add_id_to(string uri, uint to); + [CCode (cname = "mpd_recv_song_id")] + public int recv_song_id(); + [CCode (cname = "mpd_run_add_id")] + public int run_add_id(string file); + [CCode (cname = "mpd_run_add_id_to")] + public int run_add_id_to(string uri, uint to); + [CCode (cname = "mpd_send_delete")] + public bool send_delete(uint pos); + [CCode (cname = "mpd_run_delete")] + public bool run_delete(uint pos); + [CCode (cname = "mpd_send_delete_range")] + public bool send_delete_range(uint start, uint end); + [CCode (cname = "mpd_run_delete_range")] + public bool run_delete_range(uint start, uint end); + [CCode (cname = "mpd_send_delete_id")] + public bool send_delete_id(uint id); + [CCode (cname = "mpd_run_delete_id")] + public bool run_delete_id(uint id); + [CCode (cname = "mpd_send_shuffle")] + public bool send_shuffle(); + [CCode (cname = "mpd_run_shuffle")] + public bool run_shuffle(); + [CCode (cname = "mpd_send_shuffle_range")] + public bool send_shuffle_range(uint start, uint end); + [CCode (cname = "mpd_run_shuffle_range")] + public bool run_shuffle_range(uint start, uint end); + [CCode (cname = "mpd_send_clear")] + public bool send_clear(); + [CCode (cname = "mpd_run_clear")] + public bool run_clear(); + [CCode (cname = "mpd_send_move")] + public bool send_move(uint from, uint to); + [CCode (cname = "mpd_run_move")] + public bool run_move(uint from, uint to); + [CCode (cname = "mpd_send_move_id")] + public bool send_move_id(uint from, uint to); + [CCode (cname = "mpd_run_move_id")] + public bool run_move_id(uint from, uint to); + [CCode (cname = "mpd_send_move_range")] + public bool send_move_range(uint start, uint end, uint to); + [CCode (cname = "mpd_run_move_range")] + public bool run_move_range(uint start, uint end, uint to); + [CCode (cname = "mpd_send_swap")] + public bool send_swap(uint pos1, uint pos2); + [CCode (cname = "mpd_run_swap")] + public bool run_swap(uint pos1, uint pos2); + [CCode (cname = "mpd_send_swap_id")] + public bool send_swap_id(uint id1, uint id2); + [CCode (cname = "mpd_run_swap_id")] + public bool run_swap_id(uint id1, uint id2); + [CCode (cname = "mpd_send_prio")] + public bool send_prio(int priority, uint position); + [CCode (cname = "mpd_run_prio")] + public bool run_prio(int priority, uint position); + [CCode (cname = "mpd_send_prio_range")] + public bool send_prio_range(int priority, uint start, uint end); + [CCode (cname = "mpd_run_prio_range")] + public bool run_prio_range(int priority, uint start, uint end); + [CCode (cname = "mpd_send_prio_id")] + public bool send_prio_id(int priority, uint id); + [CCode (cname = "mpd_run_prio_id")] + public bool run_prio_id(int priority, uint id); + [CCode (cname = "mpd_send_current_song")] + public bool send_current_song(); + [CCode (cname = "mpd_run_current_song")] + public Song run_current_song(); + [CCode (cname = "mpd_send_play")] + public bool send_play(); + [CCode (cname = "mpd_run_play")] + public bool run_play(); + [CCode (cname = "mpd_send_play_pos")] + public bool send_play_pos(uint song_pos); + [CCode (cname = "mpd_run_play_pos")] + public bool run_play_pos(uint song_pos); + [CCode (cname = "mpd_send_play_id")] + public bool send_play_id(uint id); + [CCode (cname = "mpd_run_play_id")] + public bool run_play_id(uint song_id); + [CCode (cname = "mpd_send_stop")] + public bool send_stop(); + [CCode (cname = "mpd_run_stop")] + public bool run_stop(); + [CCode (cname = "mpd_send_toggle_pause")] + public bool send_toggle_pause(); + [CCode (cname = "mpd_run_toggle_pause")] + public bool run_toggle_pause(); + [CCode (cname = "mpd_send_pause")] + public bool send_pause(bool mode); + [CCode (cname = "mpd_run_pause")] + public bool run_pause(bool mode); + [CCode (cname = "mpd_send_next")] + public bool send_next(); + [CCode (cname = "mpd_run_next")] + public bool run_next(); + [CCode (cname = "mpd_send_previous")] + public bool send_previous(); + [CCode (cname = "mpd_run_previous")] + public bool run_previous(); + [CCode (cname = "mpd_send_seek_pos")] + public bool send_seek_pos(uint song_pos, uint t); + [CCode (cname = "mpd_run_seek_pos")] + public bool run_seek_pos(uint song_pos, uint t); + [CCode (cname = "mpd_send_seek_id")] + public bool send_seek_id(uint id, uint t); + [CCode (cname = "mpd_run_seek_id")] + public bool run_seek_id(uint song_id, uint t); + [CCode (cname = "mpd_send_repeat")] + public bool send_repeat(bool mode); + [CCode (cname = "mpd_run_repeat")] + public bool run_repeat(bool mode); + [CCode (cname = "mpd_send_random")] + public bool send_random(bool mode); + [CCode (cname = "mpd_run_random")] + public bool run_random(bool mode); + [CCode (cname = "mpd_send_single")] + public bool send_single(bool mode); + [CCode (cname = "mpd_run_single")] + public bool run_single(bool mode); + [CCode (cname = "mpd_send_consume")] + public bool send_consume(bool mode); + [CCode (cname = "mpd_run_consume")] + public bool run_consume(bool mode); + [CCode (cname = "mpd_send_crossfade")] + public bool send_crossfade(uint seconds); + [CCode (cname = "mpd_run_crossfade")] + public bool run_crossfade(uint seconds); + [CCode (cname = "mpd_send_mixrampdb")] + public bool send_mixrampdb(float db); + [CCode (cname = "mpd_run_mixrampdb")] + public bool run_mixrampdb(float db); + [CCode (cname = "mpd_send_mixrampdelay")] + public bool send_mixrampdelay(float seconds); + [CCode (cname = "mpd_run_mixrampdelay")] + public bool run_mixrampdelay(float seconds); + [CCode (cname = "mpd_send_clearerror")] + public bool send_clearerror(); + [CCode (cname = "mpd_run_clearerror")] + public bool run_clearerror(); + [CCode (cname = "mpd_send_list_playlists")] + public bool send_list_playlists(); + [CCode (cname = "mpd_send_subscribe")] + public bool send_subscribe(string channel); + [CCode (cname = "mpd_run_subscribe")] + public bool run_subscribe(string channel); + [CCode (cname = "mpd_send_unsubscribe")] + public bool send_unsubscribe(string channel); + [CCode (cname = "mpd_run_unsubscribe")] + public bool run_unsubscribe(string channel); + [CCode (cname = "mpd_send_send_message")] + public bool send_send_message(string channel, string text); + [CCode (cname = "mpd_run_send_message")] + public bool run_send_message(string channel, string text); + [CCode (cname = "mpd_send_read_messages")] + public bool send_read_messages(); + [CCode (cname = "mpd_recv_message")] + public Message recv_message(); + [CCode (cname = "mpd_send_channels")] + public bool send_channels(); + [CCode (cname = "mpd_recv_channel_pair")] + public Pair recv_channel_pair(); + } + + [CCode (cname = "struct mpd_directory", + copy_function = "mpd_directory_dup", + free_function = "mpd_directory_free")] + [Compact] + public class Directory { + public string path { get; } + + public unowned string get_path(); + public bool feed(Mpd.Pair pair); + public Entity? entity_begin(); + } + + [CCode (cname = "struct mpd_entity", + free_function = "mpd_entity_free")] + [Compact] + public class Entity { + public EntityType type { get; } + public Directory directory { get; } + public Song song { get; } + public Playlist playlist { get; } + + public EntityType get_type(); + public Directory get_directory(); + public Song get_song(); + public Playlist get_playlist(); + public bool feed(Pair pair); + } + + [CCode (cname = "struct mpd_output", + free_function = "mpd_output_free")] + [Compact] + public class Output { + public uint id { get; } + public string name { get; } + public bool enabled { get; } + + public bool feed(Pair pair); + public uint get_id(); + public unowned string get_name(); + public bool get_enabled(); + } + + [CCode (cname = "struct mpd_pair", + free_function = "")] + [Compact] + public class Pair { + public unowned string name; + public unowned string value; + [CCode (cname = "mpd_directory_begin")] + public Directory? directory_begin(); + [CCode (cname = "mpd_output_begin")] + public Output output_begin(); + [CCode (cname = "mpd_playlist_begin")] + public Playlist playlist_begin(); + [CCode (cname = "mpd_song_begin")] + public Song song_begin(); + [CCode (cname = "mpd_idle_parse_pair")] + public Idle idle_parse_pair(); + } + + [CCode (cname = "struct mpd_parser", + free_function = "mpd_parser_free")] + [Compact] + public class Parser { + public ServerError server_error { get; } + public uint at { get; } + public string message { get; } + public string name { get; } + public string value { get; } + + public ParserResult feed(string line); + public bool is_discrete(); + public ServerError get_server_error(); + public uint get_at(); + public unowned string get_message(); + public unowned string get_name(); + public unowned string get_value(); + } + + [CCode (cname = "struct mpd_playlist", + copy_function = "mpd_playlist_dup", + free_function = "mpd_playlist_free")] + [Compact] + public class Playlist { + public string path { get; } + public int64 last_modified { get; } + + public string get_path(); + public int64 get_last_modified(); + public bool feed(Pair pair); + } + + [CCode (cname = "struct mpd_song", + copy_function = "mpd_song_dup", + free_function = "mpd_song_free")] + [Compact] + public class Song { + public string uri { get; } + public uint duration { get; } + public int64 last_modified { get; } + public uint pos { get; set; } + public uint id { get; } + + public unowned string get_uri(); + public unowned string get_tag(TagType type, uint idx = 0); + public uint get_duration(); + public int64 get_last_modified(); + public void set_pos(uint pos); + public uint get_pos(); + public uint get_id(); + public bool feed(Pair pair); + } + + [CCode (cname = "struct mpd_stats", + free_function = "mpd_stats_free")] + [Compact] + public class Stats { + public uint number_of_artist { get; } + public uint number_of_albums { get; } + public uint number_of_songs { get; } + public ulong uptime { get; } + public ulong db_update_time { get; } + public ulong play_time { get; } + public ulong db_play_time { get; } + + public void feed(Pair pair); + public uint get_number_of_artists(); + public uint get_number_of_albums(); + public uint get_number_of_songs(); + public ulong get_uptime(); + public ulong get_db_update_time(); + public ulong get_play_time(); + public ulong get_db_play_time(); + } + + [CCode (cname = "struct mpd_status", + free_function = "mpd_status_free")] + [Compact] + public class Status { + public int volume { get; } + public bool repeat { get; } + public bool random { get; } + public bool single { get; } + public bool consume { get; } + public uint queue_length { get; } + public uint queue_version { get; } + public State state { get; } + public uint crossfade { get; } + public float mixrampdb { get; } + public float mixrampdelay { get; } + public int song_pos { get; } + public int song_id { get; } + public uint elapsed_time { get; } + public uint elapsed_ms { get; } + public uint total_time { get; } + public uint kbit_rate { get; } + public AudioFormat audio_format { get; } + public uint update_id { get; } + public string error { get; } + + public int get_volume(); + public bool get_repeat(); + public bool get_random(); + public bool get_single(); + public bool get_consume(); + public uint get_queue_length(); + public uint get_queue_version(); + public State get_state(); + public uint get_crossfade(); + public float get_mixrampdb(); + public float get_mixrampdelay(); + public int get_song_pos(); + public int get_song_id(); + public int get_next_song_pos(); + public int get_next_song_id(); + public uint get_elapsed_time(); + public uint get_elapsed_ms(); + public uint get_total_time(); + public uint get_kbit_rate(); + public AudioFormat get_audio_format(); + public uint get_update_id(); + public unowned string get_error(); + } + + [CCode (cname = "struct mpd_settings", + free_function = "mpd_settings_free")] + [Compact] + public class Settings { + public string? host { get; } + public uint port { get; } + public uint timeout_ms { get; } + public string? password { get; } + + public Settings(string? host = null, uint port = 0, uint timeout_ms = 0, string? reserved = null, string? password = null); + public string? get_host(); + public uint get_port(); + public uint get_timeout_ms(); + public string? get_password(); + } + + [CCode (cname = "struct mpd_message", + free_function = "mpd_message_free")] + [Compact] + public class Message { + public string channel { get; } + public string text { get; } + + public bool feed(Pair pair); + public unowned string get_channel(); + public unowned string get_text(); + } + + public Status status_begin(); + public unowned string tag_name(TagType type); + public TagType tag_name_parse(string name); + public TagType tag_name_iparse(string name); + public unowned string? idle_name(Idle idle); + public Idle idle_name_parse(string name); + public Stats stats_begin(); + public unowned string parse_sticker(string input, out int64 name_length_r); + + public const string LIBMPDCLIENT_MAJOR_VERSION; + public const string LIBMPDCLIENT_MINOR_VERSION; + public const string LIBMPDCLIENT_PATCH_VERSION; +}