mpd_update_queue.c (4380B)
1 #include <mpd/client.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <stdbool.h> 6 #include <unistd.h> 7 8 #define DEFAULT_HOST "localhost" 9 #define DEFAULT_PORT 6600 10 11 struct mpd_connection *conn() { 12 const char *host = getenv("MPD_HOST"); 13 if (host == NULL || strlen(host) == 0) host = DEFAULT_HOST; 14 15 unsigned port = DEFAULT_PORT; 16 const char *port_str = getenv("MPD_PORT"); 17 if (port_str != NULL && strlen(port_str) > 0) port = (unsigned)atoi(port_str); 18 19 struct mpd_connection *c = mpd_connection_new(host, port, 0); 20 if (c == NULL) { 21 fprintf(stderr, "Failed to create MPD connection object\n"); 22 return NULL; 23 } 24 25 if (mpd_connection_get_error(c) != MPD_ERROR_SUCCESS) { 26 fprintf(stderr, "Error connecting to MPD (%s:%u): %s\n", host, port, mpd_connection_get_error_message(c)); 27 mpd_connection_free(c); 28 return NULL; 29 } 30 return c; 31 } 32 33 int main(int argc, char *argv[]) { 34 if (argc < 2) { 35 fprintf(stderr, "Usage: %s <new_queue_file>\n", argv[0]); 36 return 1; 37 } 38 39 FILE *input = fopen(argv[1], "r"); 40 if (input == NULL) { 41 perror("Error opening file"); 42 return 1; 43 } 44 45 struct mpd_connection *c = conn(); 46 if (c == NULL) { 47 fclose(input); 48 return 1; 49 } 50 51 char **new_tracks = NULL; 52 int track_count = 0; 53 char *line = NULL; 54 size_t len = 0; 55 ssize_t read_bytes; 56 char *current_file = NULL; 57 58 /* Read input file first, before querying MPD state */ 59 while ((read_bytes = getline(&line, &len, input)) != -1) { 60 if (read_bytes > 0 && line[read_bytes - 1] == '\n') line[read_bytes - 1] = '\0'; 61 if (read_bytes > 1 && line[read_bytes - 2] == '\r') line[read_bytes - 2] = '\0'; 62 if (strlen(line) == 0 || line[0] == '#') continue; 63 64 char **temp_tracks = realloc(new_tracks, sizeof(char *) * (track_count + 1)); 65 if (temp_tracks == NULL) { 66 perror("realloc"); 67 goto cleanup; 68 } 69 new_tracks = temp_tracks; 70 71 new_tracks[track_count] = strdup(line); 72 if (new_tracks[track_count] == NULL) { 73 perror("strdup"); 74 goto cleanup; 75 } 76 track_count++; 77 } 78 79 /* Re-query MPD state before building command list */ 80 struct mpd_status *status = mpd_run_status(c); 81 if (status == NULL) { 82 fprintf(stderr, "Error getting status: %s\n", mpd_connection_get_error_message(c)); 83 goto cleanup; 84 } 85 enum mpd_state state = mpd_status_get_state(status); 86 int current_pos = mpd_status_get_song_pos(status); 87 int total_queue_len = mpd_status_get_queue_length(status); 88 mpd_status_free(status); 89 90 if (state == MPD_STATE_PLAY || state == MPD_STATE_PAUSE) { 91 struct mpd_song *song = mpd_run_current_song(c); 92 if (song != NULL) { 93 current_file = strdup(mpd_song_get_uri(song)); 94 mpd_song_free(song); 95 } 96 } 97 98 /* Compute new_pos from fresh current_file */ 99 int new_pos = -1; 100 for (int i = 0; i < track_count; i++) { 101 if (current_file && strcmp(new_tracks[i], current_file) == 0 && new_pos == -1) { 102 new_pos = i; 103 } 104 } 105 106 if (!mpd_command_list_begin(c, false)) { 107 fprintf(stderr, "Failed to start command list: %s\n", mpd_connection_get_error_message(c)); 108 goto cleanup; 109 } 110 111 if (state == MPD_STATE_STOP || current_file == NULL || new_pos == -1) { 112 mpd_send_clear(c); 113 for (int i = 0; i < track_count; i++) mpd_send_add(c, new_tracks[i]); 114 if (state != MPD_STATE_STOP) mpd_send_play(c); 115 } else { 116 for (int i = total_queue_len - 1; i >= 0; i--) { 117 if (i != current_pos) mpd_send_delete(c, i); 118 } 119 for (int i = 0; i < track_count; i++) { 120 if (i != new_pos) mpd_send_add(c, new_tracks[i]); 121 } 122 if (new_pos > 0) mpd_send_move(c, 0, new_pos); 123 } 124 125 if (!mpd_command_list_end(c) || !mpd_response_finish(c)) { 126 fprintf(stderr, "Failed to execute command list: %s\n", mpd_connection_get_error_message(c)); 127 } else { 128 printf("Queue updated successfully.\n"); 129 } 130 131 cleanup: 132 free(line); 133 fclose(input); 134 if (current_file) free(current_file); 135 for (int i = 0; i < track_count; i++) free(new_tracks[i]); 136 free(new_tracks); 137 mpd_connection_free(c); 138 return 0; 139 }