commit 0c2d45d9df8938ca790371b719cde8fd4c6c6e92
parent 029901cd0fb66bc83afe39d31e687114ced3f429
Author: mtmn <miro@haravara.org>
Date: Wed, 6 May 2026 22:20:55 +0200
feat: add mpd scripts
Diffstat:
| A | mpd/BUILD | | | 63 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | mpd/mpd_add_to_playlist.c | | | 93 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | mpd/mpd_add_to_queue.c | | | 114 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | mpd/mpd_edit_queue.c | | | 210 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | mpd/mpd_update_library.c | | | 153 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | mpd/mpd_update_queue.c | | | 137 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
6 files changed, 770 insertions(+), 0 deletions(-)
diff --git a/mpd/BUILD b/mpd/BUILD
@@ -0,0 +1,63 @@
+load("@rules_cc//cc:defs.bzl", "cc_binary")
+load("//bazel:local-deploy.bzl", "local_deploy")
+
+package(default_visibility = ["//visibility:public"])
+
+COMMON_COPTS = [
+ "-Wall",
+ "-Wextra",
+ "-O2",
+ "-fanalyzer",
+ "-Wshadow",
+]
+
+cc_binary(
+ name = "mpd_add_to_playlist",
+ srcs = ["mpd_add_to_playlist.c"],
+ copts = COMMON_COPTS,
+ linkopts = ["-lmpdclient"],
+ visibility = ["//visibility:public"],
+)
+
+cc_binary(
+ name = "mpd_add_to_queue",
+ srcs = ["mpd_add_to_queue.c"],
+ copts = COMMON_COPTS,
+ linkopts = ["-lmpdclient"],
+ visibility = ["//visibility:public"],
+)
+
+cc_binary(
+ name = "mpd_update_queue",
+ srcs = ["mpd_update_queue.c"],
+ copts = COMMON_COPTS,
+ linkopts = ["-lmpdclient"],
+ visibility = ["//visibility:public"],
+)
+
+cc_binary(
+ name = "mpd_edit_queue",
+ srcs = ["mpd_edit_queue.c"],
+ copts = COMMON_COPTS,
+ linkopts = ["-lmpdclient"],
+ visibility = ["//visibility:public"],
+)
+
+cc_binary(
+ name = "mpd_update_library",
+ srcs = ["mpd_update_library.c"],
+ copts = COMMON_COPTS,
+ linkopts = ["-lmpdclient"],
+ visibility = ["//visibility:public"],
+)
+
+local_deploy(
+ name = "deploy",
+ srcs = [
+ ":mpd_add_to_playlist",
+ ":mpd_add_to_queue",
+ ":mpd_update_queue",
+ ":mpd_edit_queue",
+ ":mpd_update_library",
+ ],
+)
diff --git a/mpd/mpd_add_to_playlist.c b/mpd/mpd_add_to_playlist.c
@@ -0,0 +1,93 @@
+#include <mpd/client.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+// #define DEBUG
+#ifdef DEBUG
+#define D(x) \
+ do { \
+ x; \
+ } while (0)
+#else
+#define D(x) \
+ do { \
+ } while (0)
+#endif
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_PORT 6600
+struct mpd_connection *conn() {
+ // Read host from environment variable, use default if not set
+ const char *host = getenv("MPD_HOST");
+ if (host == NULL || strlen(host) == 0) {
+ host = DEFAULT_HOST;
+ }
+ D(printf("Using host: %s\n", host));
+
+ // Read port from environment variable, use default if not set
+ unsigned port = DEFAULT_PORT;
+ const char *port_str = getenv("MPD_PORT");
+ if (port_str != NULL && strlen(port_str) > 0) {
+ port = (unsigned)atoi(port_str);
+ }
+ D(printf("Using port: %u\n", port));
+
+ D(printf("%s %s:%u\n", "Connecting to", host, port));
+
+ struct mpd_connection *c = mpd_connection_new(host, port, 0);
+ enum mpd_error err = mpd_connection_get_error(c);
+ if (err != 0) {
+ printf("Error code: %u. View error codes here: "
+ "https://www.musicpd.org/doc/libmpdclient/error_8h.html\n",
+ err);
+ mpd_connection_free(c);
+ return 0;
+ }
+#ifdef PASS
+ const char *pass = PASS;
+ if (mpd_run_password(c, pass) == false) {
+ printf("%s\n", "Bad password");
+ mpd_connection_free(c);
+ return 0;
+ }
+#endif
+ D(printf("%s %s:%u\n", "Connected to", host, port));
+ return c;
+}
+int main(int argc, char *argv[]) {
+ // Check for playlist name argument
+ if (argc < 2) {
+ printf("Usage: %s PLAYLIST_NAME\n", argv[0]);
+ return 1;
+ }
+
+ const char *playlist = argv[1];
+ D(printf("Using playlist: %s\n", playlist));
+
+ struct mpd_connection *c = conn();
+ if (c == 0)
+ return -1;
+
+ struct mpd_song *curr = mpd_run_current_song(c);
+ if (curr == NULL) {
+ printf("No song is currently playing\n");
+ mpd_connection_free(c);
+ return -1;
+ }
+
+ const char *curr_uri = mpd_song_get_uri(curr);
+ D(printf("Currently playing: %s\n", curr_uri));
+
+ if (mpd_run_playlist_add(c, playlist, curr_uri)) {
+ printf("%s %s %s %s\n", "Added", curr_uri, "to playlist", playlist);
+ } else {
+ printf("%s\n", "Some error");
+ mpd_song_free(curr);
+ mpd_connection_free(c);
+ return -1;
+ }
+ // Free resources
+ mpd_song_free(curr);
+ mpd_connection_free(c);
+
+ return 0;
+}
diff --git a/mpd/mpd_add_to_queue.c b/mpd/mpd_add_to_queue.c
@@ -0,0 +1,114 @@
+#include <mpd/client.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+// #define DEBUG
+#ifdef DEBUG
+#define D(x) \
+ do { \
+ x; \
+ } while (0)
+#else
+#define D(x) \
+ do { \
+ } while (0)
+#endif
+
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_PORT 6600
+
+struct mpd_connection *conn() {
+ const char *host = getenv("MPD_HOST");
+ if (host == NULL || strlen(host) == 0) {
+ host = DEFAULT_HOST;
+ }
+
+ unsigned port = DEFAULT_PORT;
+ const char *port_str = getenv("MPD_PORT");
+ if (port_str != NULL && strlen(port_str) > 0) {
+ port = (unsigned)atoi(port_str);
+ }
+
+ struct mpd_connection *c = mpd_connection_new(host, port, 0);
+ if (c == NULL) {
+ fprintf(stderr, "Failed to create MPD connection object\n");
+ return NULL;
+ }
+
+ enum mpd_error err = mpd_connection_get_error(c);
+ if (err != 0) {
+ fprintf(stderr, "Error connecting to MPD (%s:%u): %s (code: %u)\n",
+ host, port, mpd_connection_get_error_message(c), err);
+ mpd_connection_free(c);
+ return NULL;
+ }
+#ifdef PASS
+ const char *pass = PASS;
+ if (mpd_run_password(c, pass) == false) {
+ fprintf(stderr, "MPD authentication failed: %s\n", mpd_connection_get_error_message(c));
+ mpd_connection_free(c);
+ return NULL;
+ }
+#endif
+ return c;
+}
+
+int main(int argc, char *argv[]) {
+ FILE *input = stdin;
+
+ if (argc > 1) {
+ input = fopen(argv[1], "r");
+ if (input == NULL) {
+ perror("Error opening file");
+ return 1;
+ }
+ } else if (isatty(STDIN_FILENO)) {
+ fprintf(stderr, "Reading from stdin... (Press Ctrl+D to finish, or provide a filename as argument)\n");
+ }
+
+ struct mpd_connection *c = conn();
+ if (c == NULL) {
+ if (input != stdin) fclose(input);
+ return -1;
+ }
+
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read_bytes;
+ int added_count = 0;
+ int failed_count = 0;
+
+ while ((read_bytes = getline(&line, &len, input)) != -1) {
+ if (read_bytes > 0 && line[read_bytes - 1] == '\n') {
+ line[read_bytes - 1] = '\0';
+ read_bytes--;
+ }
+ if (read_bytes > 0 && line[read_bytes - 1] == '\r') {
+ line[read_bytes - 1] = '\0';
+ read_bytes--;
+ }
+
+ if (read_bytes == 0) continue;
+ if (line[0] == '#') continue;
+
+ if (!mpd_run_add(c, line)) {
+ fprintf(stderr, "Failed to add track: %s (Error: %s)\n", line, mpd_connection_get_error_message(c));
+ failed_count++;
+ if (!mpd_connection_clear_error(c)) break;
+ } else {
+ printf("Added: %s\n", line);
+ added_count++;
+ }
+ }
+
+ printf("\nSummary: Added %d tracks, failed to add %d tracks.\n", added_count, failed_count);
+
+ free(line);
+ if (input != stdin) fclose(input);
+ mpd_connection_free(c);
+
+ return 0;
+}
diff --git a/mpd/mpd_edit_queue.c b/mpd/mpd_edit_queue.c
@@ -0,0 +1,210 @@
+#include <mpd/client.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <ctype.h>
+
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_PORT 6600
+
+struct mpd_connection *conn() {
+ const char *host = getenv("MPD_HOST");
+ if (host == NULL || strlen(host) == 0) host = DEFAULT_HOST;
+
+ unsigned port = DEFAULT_PORT;
+ const char *port_str = getenv("MPD_PORT");
+ if (port_str != NULL && strlen(port_str) > 0) port = (unsigned)atoi(port_str);
+
+ struct mpd_connection *c = mpd_connection_new(host, port, 0);
+ if (c == NULL) {
+ fprintf(stderr, "Failed to create MPD connection object\n");
+ return NULL;
+ }
+
+ if (mpd_connection_get_error(c) != MPD_ERROR_SUCCESS) {
+ fprintf(stderr, "Error connecting to MPD (%s:%u): %s\n", host, port, mpd_connection_get_error_message(c));
+ mpd_connection_free(c);
+ return NULL;
+ }
+ return c;
+}
+
+char* trim_whitespace(char* str) {
+ char *end;
+ while(isspace((unsigned char)*str)) str++;
+ if(*str == 0) return str;
+ end = str + strlen(str) - 1;
+ while(end > str && isspace((unsigned char)*end)) end--;
+ end[1] = '\0';
+ return str;
+}
+
+int main() {
+ struct mpd_connection *c = conn();
+ if (c == NULL) return 1;
+
+ struct mpd_status *status = mpd_run_status(c);
+ if (status == NULL) {
+ fprintf(stderr, "Error getting status: %s\n", mpd_connection_get_error_message(c));
+ mpd_connection_free(c);
+ return 1;
+ }
+ enum mpd_state state = mpd_status_get_state(status);
+ int current_pos = mpd_status_get_song_pos(status);
+ int total_queue_len = mpd_status_get_queue_length(status);
+ mpd_status_free(status);
+
+ char *current_file = NULL;
+ if (state == MPD_STATE_PLAY || state == MPD_STATE_PAUSE) {
+ struct mpd_song *song = mpd_run_current_song(c);
+ if (song != NULL) {
+ current_file = strdup(mpd_song_get_uri(song));
+ mpd_song_free(song);
+ }
+ }
+
+ char tmp_template[] = "/tmp/mpd_queue_XXXXXX";
+ int fd = mkstemp(tmp_template);
+ if (fd == -1) {
+ perror("mkstemp");
+ if (current_file) free(current_file);
+ mpd_connection_free(c);
+ return 1;
+ }
+
+ FILE *f = fdopen(fd, "w");
+ if (f == NULL) {
+ perror("fdopen");
+ close(fd);
+ unlink(tmp_template);
+ if (current_file) free(current_file);
+ mpd_connection_free(c);
+ return 1;
+ }
+
+ if (!mpd_send_list_queue_meta(c)) {
+ fprintf(stderr, "Error sending queue request\n");
+ fclose(f);
+ unlink(tmp_template);
+ if (current_file) free(current_file);
+ mpd_connection_free(c);
+ return 1;
+ }
+
+ struct mpd_entity *entity;
+ while ((entity = mpd_recv_entity(c)) != NULL) {
+ if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
+ const struct mpd_song *song = mpd_entity_get_song(entity);
+ fprintf(f, "%s\n", mpd_song_get_uri(song));
+ }
+ mpd_entity_free(entity);
+ }
+ fclose(f);
+
+ if (mpd_connection_get_error(c) != MPD_ERROR_SUCCESS) {
+ fprintf(stderr, "Error reading queue: %s\n", mpd_connection_get_error_message(c));
+ unlink(tmp_template);
+ if (current_file) free(current_file);
+ mpd_connection_free(c);
+ return 1;
+ }
+ mpd_response_finish(c);
+
+ const char *editor = getenv("EDITOR");
+ if (editor == NULL || strlen(editor) == 0) editor = "vi";
+
+ pid_t pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ unlink(tmp_template);
+ if (current_file) free(current_file);
+ mpd_connection_free(c);
+ return 1;
+ } else if (pid == 0) {
+ execlp(editor, editor, tmp_template, NULL);
+ perror("execlp");
+ exit(1);
+ }
+
+ int wstatus;
+ waitpid(pid, &wstatus, 0);
+
+ f = fopen(tmp_template, "r");
+ if (f == NULL) {
+ perror("fopen");
+ unlink(tmp_template);
+ if (current_file) free(current_file);
+ mpd_connection_free(c);
+ return 1;
+ }
+
+ char **new_tracks = NULL;
+ int track_count = 0;
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read_bytes;
+ int new_pos = -1;
+
+ while ((read_bytes = getline(&line, &len, f)) != -1) {
+ char *trimmed = trim_whitespace(line);
+ if (strlen(trimmed) == 0 || trimmed[0] == '#') continue;
+
+ char **temp_tracks = realloc(new_tracks, sizeof(char *) * (track_count + 1));
+ if (temp_tracks == NULL) {
+ perror("realloc");
+ goto cleanup;
+ }
+ new_tracks = temp_tracks;
+
+ new_tracks[track_count] = strdup(trimmed);
+ if (new_tracks[track_count] == NULL) {
+ perror("strdup");
+ goto cleanup;
+ }
+
+ if (current_file && strcmp(new_tracks[track_count], current_file) == 0 && new_pos == -1) {
+ new_pos = track_count;
+ }
+ track_count++;
+ }
+
+ if (!mpd_command_list_begin(c, false)) {
+ fprintf(stderr, "Failed to start command list: %s\n", mpd_connection_get_error_message(c));
+ goto cleanup;
+ }
+
+ if (state == MPD_STATE_STOP || current_file == NULL || new_pos == -1) {
+ mpd_send_clear(c);
+ for (int i = 0; i < track_count; i++) {
+ mpd_send_add(c, new_tracks[i]);
+ }
+ if (state != MPD_STATE_STOP) mpd_send_play(c);
+ } else {
+ for (int i = total_queue_len - 1; i >= 0; i--) {
+ if (i != current_pos) mpd_send_delete(c, i);
+ }
+ for (int i = 0; i < track_count; i++) {
+ if (i != new_pos) mpd_send_add(c, new_tracks[i]);
+ }
+ if (new_pos > 0) mpd_send_move(c, 0, new_pos);
+ }
+
+ if (!mpd_command_list_end(c) || !mpd_response_finish(c)) {
+ fprintf(stderr, "Failed to execute command list: %s\n", mpd_connection_get_error_message(c));
+ } else {
+ printf("Queue updated successfully.\n");
+ }
+
+cleanup:
+ free(line);
+ if (f) fclose(f);
+ unlink(tmp_template);
+ if (current_file) free(current_file);
+ for (int i = 0; i < track_count; i++) free(new_tracks[i]);
+ free(new_tracks);
+ mpd_connection_free(c);
+ return 0;
+}
diff --git a/mpd/mpd_update_library.c b/mpd/mpd_update_library.c
@@ -0,0 +1,153 @@
+#include <mpd/client.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_PORT 6600
+#define DEFAULT_BACKOFF 5
+
+struct mpd_connection *conn() {
+ const char *host = getenv("MPD_HOST");
+ if (host == NULL || strlen(host) == 0) host = DEFAULT_HOST;
+
+ unsigned port = DEFAULT_PORT;
+ const char *port_str = getenv("MPD_PORT");
+ if (port_str != NULL && strlen(port_str) > 0) port = (unsigned)atoi(port_str);
+
+ struct mpd_connection *c = mpd_connection_new(host, port, 0);
+ if (c == NULL) {
+ fprintf(stderr, "Failed to create MPD connection object\n");
+ return NULL;
+ }
+
+ if (mpd_connection_get_error(c) != MPD_ERROR_SUCCESS) {
+ fprintf(stderr, "Error connecting to MPD (%s:%u): %s\n", host, port, mpd_connection_get_error_message(c));
+ mpd_connection_free(c);
+ return NULL;
+ }
+ return c;
+}
+
+char* trim_whitespace(char* str) {
+ char *end;
+ while(isspace((unsigned char)*str)) str++;
+ if(*str == 0) return str;
+ end = str + strlen(str) - 1;
+ while(end > str && isspace((unsigned char)*end)) end--;
+ end[1] = '\0';
+ return str;
+}
+
+int main(int argc, char *argv[]) {
+ if (argc > 1 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
+ printf("Usage: %s [input_file]\n", argv[0]);
+ return 0;
+ }
+
+ FILE *input = stdin;
+ if (argc > 1) {
+ input = fopen(argv[1], "r");
+ if (input == NULL) {
+ perror("Error opening file");
+ return 1;
+ }
+ } else if (isatty(STDIN_FILENO)) {
+ fprintf(stderr, "Reading from stdin... (Press Ctrl+D to finish)\n");
+ }
+
+ char **top_dirs = NULL;
+ int dir_count = 0;
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read_bytes;
+
+ while ((read_bytes = getline(&line, &len, input)) != -1) {
+ char *trimmed = trim_whitespace(line);
+ if (strlen(trimmed) == 0 || trimmed[0] == '#') continue;
+
+ char *slash = strchr(trimmed, '/');
+ if (slash != NULL) *slash = '\0';
+
+ bool found = false;
+ for (int i = 0; i < dir_count; i++) {
+ if (strcmp(top_dirs[i], trimmed) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ char **temp_dirs = realloc(top_dirs, sizeof(char *) * (dir_count + 1));
+ if (temp_dirs == NULL) {
+ perror("realloc");
+ break;
+ }
+ top_dirs = temp_dirs;
+ top_dirs[dir_count] = strdup(trimmed);
+ if (top_dirs[dir_count] == NULL) {
+ perror("strdup");
+ break;
+ }
+ dir_count++;
+ }
+ }
+ free(line);
+ if (input != stdin) fclose(input);
+
+ if (dir_count == 0) {
+ printf("No directories found in input.\n");
+ for (int i = 0; i < dir_count; i++) free(top_dirs[i]);
+ free(top_dirs);
+ return 0;
+ }
+
+ printf("Found %d unique top-level directories to update.\n", dir_count);
+
+ struct mpd_connection *c = conn();
+ if (c == NULL) {
+ for (int i = 0; i < dir_count; i++) free(top_dirs[i]);
+ free(top_dirs);
+ return 1;
+ }
+
+ int backoff = DEFAULT_BACKOFF;
+ const char *backoff_str = getenv("MPD_UPDATE_BACKOFF");
+ if (backoff_str != NULL && strlen(backoff_str) > 0) backoff = atoi(backoff_str);
+
+ int updated_count = 0;
+ int error_count = 0;
+
+ for (int i = 0; i < dir_count; i++) {
+ printf("Updating: '%s'\n", top_dirs[i]);
+ unsigned job_id = mpd_run_update(c, top_dirs[i]);
+ if (job_id == 0) {
+ fprintf(stderr, " ✗ Failed: %s\n", mpd_connection_get_error_message(c));
+ error_count++;
+ mpd_connection_clear_error(c);
+ } else {
+ printf(" ✓ Success (Job ID: %u)\n", job_id);
+ updated_count++;
+ }
+ if (i < dir_count - 1 && backoff > 0) sleep(backoff);
+ }
+
+ printf("Update completed!\n");
+ printf("Total directories processed: %d\n", dir_count);
+ printf("Successfully updated: %d\n", updated_count);
+ printf("Errors: %d\n", error_count);
+
+ struct mpd_status *status = mpd_run_status(c);
+ if (status != NULL) {
+ if (mpd_status_get_update_id(status) > 0) printf("MPD is currently updating...\n");
+ mpd_status_free(status);
+ }
+
+ for (int i = 0; i < dir_count; i++) free(top_dirs[i]);
+ free(top_dirs);
+ mpd_connection_free(c);
+ return 0;
+}
diff --git a/mpd/mpd_update_queue.c b/mpd/mpd_update_queue.c
@@ -0,0 +1,137 @@
+#include <mpd/client.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_PORT 6600
+
+struct mpd_connection *conn() {
+ const char *host = getenv("MPD_HOST");
+ if (host == NULL || strlen(host) == 0) host = DEFAULT_HOST;
+
+ unsigned port = DEFAULT_PORT;
+ const char *port_str = getenv("MPD_PORT");
+ if (port_str != NULL && strlen(port_str) > 0) port = (unsigned)atoi(port_str);
+
+ struct mpd_connection *c = mpd_connection_new(host, port, 0);
+ if (c == NULL) {
+ fprintf(stderr, "Failed to create MPD connection object\n");
+ return NULL;
+ }
+
+ if (mpd_connection_get_error(c) != MPD_ERROR_SUCCESS) {
+ fprintf(stderr, "Error connecting to MPD (%s:%u): %s\n", host, port, mpd_connection_get_error_message(c));
+ mpd_connection_free(c);
+ return NULL;
+ }
+ return c;
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <new_queue_file>\n", argv[0]);
+ return 1;
+ }
+
+ FILE *input = fopen(argv[1], "r");
+ if (input == NULL) {
+ perror("Error opening file");
+ return 1;
+ }
+
+ struct mpd_connection *c = conn();
+ if (c == NULL) {
+ fclose(input);
+ return 1;
+ }
+
+ struct mpd_status *status = mpd_run_status(c);
+ if (status == NULL) {
+ fprintf(stderr, "Error getting status: %s\n", mpd_connection_get_error_message(c));
+ fclose(input);
+ mpd_connection_free(c);
+ return 1;
+ }
+
+ enum mpd_state state = mpd_status_get_state(status);
+ int current_pos = mpd_status_get_song_pos(status);
+ int total_queue_len = mpd_status_get_queue_length(status);
+ mpd_status_free(status);
+
+ char *current_file = NULL;
+ if (state == MPD_STATE_PLAY || state == MPD_STATE_PAUSE) {
+ struct mpd_song *song = mpd_run_current_song(c);
+ if (song != NULL) {
+ current_file = strdup(mpd_song_get_uri(song));
+ mpd_song_free(song);
+ }
+ }
+
+ char **new_tracks = NULL;
+ int track_count = 0;
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read_bytes;
+ int new_pos = -1;
+
+ while ((read_bytes = getline(&line, &len, input)) != -1) {
+ if (read_bytes > 0 && line[read_bytes - 1] == '\n') line[read_bytes - 1] = '\0';
+ if (read_bytes > 1 && line[read_bytes - 2] == '\r') line[read_bytes - 2] = '\0';
+ if (strlen(line) == 0 || line[0] == '#') continue;
+
+ char **temp_tracks = realloc(new_tracks, sizeof(char *) * (track_count + 1));
+ if (temp_tracks == NULL) {
+ perror("realloc");
+ goto cleanup;
+ }
+ new_tracks = temp_tracks;
+
+ new_tracks[track_count] = strdup(line);
+ if (new_tracks[track_count] == NULL) {
+ perror("strdup");
+ goto cleanup;
+ }
+
+ if (current_file && strcmp(new_tracks[track_count], current_file) == 0 && new_pos == -1) {
+ new_pos = track_count;
+ }
+ track_count++;
+ }
+
+ if (!mpd_command_list_begin(c, false)) {
+ fprintf(stderr, "Failed to start command list: %s\n", mpd_connection_get_error_message(c));
+ goto cleanup;
+ }
+
+ if (state == MPD_STATE_STOP || current_file == NULL || new_pos == -1) {
+ mpd_send_clear(c);
+ for (int i = 0; i < track_count; i++) mpd_send_add(c, new_tracks[i]);
+ if (state != MPD_STATE_STOP) mpd_send_play(c);
+ } else {
+ for (int i = total_queue_len - 1; i >= 0; i--) {
+ if (i != current_pos) mpd_send_delete(c, i);
+ }
+ for (int i = 0; i < track_count; i++) {
+ if (i != new_pos) mpd_send_add(c, new_tracks[i]);
+ }
+ if (new_pos > 0) mpd_send_move(c, 0, new_pos);
+ }
+
+ if (!mpd_command_list_end(c) || !mpd_response_finish(c)) {
+ fprintf(stderr, "Failed to execute command list: %s\n", mpd_connection_get_error_message(c));
+ } else {
+ printf("Queue updated successfully.\n");
+ }
+
+cleanup:
+ free(line);
+ fclose(input);
+ if (current_file) free(current_file);
+ for (int i = 0; i < track_count; i++) free(new_tracks[i]);
+ free(new_tracks);
+ mpd_connection_free(c);
+ return 0;
+}