tools

various tools I have been using throughout the years
Log | Files | Refs | README | LICENSE

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 }