tools

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

mpd_update_library.c (4241B)


      1 #include <ctype.h>
      2 #include <mpd/client.h>
      3 #include <stdbool.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <unistd.h>
      8 
      9 #define DEFAULT_HOST "localhost"
     10 #define DEFAULT_PORT 6600
     11 #define DEFAULT_BACKOFF 5
     12 
     13 struct mpd_connection *conn() {
     14   const char *host = getenv("MPD_HOST");
     15   if (host == NULL || strlen(host) == 0)
     16     host = DEFAULT_HOST;
     17 
     18   unsigned port = DEFAULT_PORT;
     19   const char *port_str = getenv("MPD_PORT");
     20   if (port_str != NULL && strlen(port_str) > 0)
     21     port = (unsigned)atoi(port_str);
     22 
     23   struct mpd_connection *c = mpd_connection_new(host, port, 0);
     24   if (c == NULL) {
     25     fprintf(stderr, "Failed to create MPD connection object\n");
     26     return NULL;
     27   }
     28 
     29   if (mpd_connection_get_error(c) != MPD_ERROR_SUCCESS) {
     30     fprintf(stderr, "Error connecting to MPD (%s:%u): %s\n", host, port,
     31             mpd_connection_get_error_message(c));
     32     mpd_connection_free(c);
     33     return NULL;
     34   }
     35   return c;
     36 }
     37 
     38 char *trim_whitespace(char *str) {
     39   char *end;
     40   while (isspace((unsigned char)*str))
     41     str++;
     42   if (*str == 0)
     43     return str;
     44   end = str + strlen(str) - 1;
     45   while (end > str && isspace((unsigned char)*end))
     46     end--;
     47   end[1] = '\0';
     48   return str;
     49 }
     50 
     51 int main(int argc, char *argv[]) {
     52   if (argc > 1 &&
     53       (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
     54     printf("Usage: %s [input_file]\n", argv[0]);
     55     return 0;
     56   }
     57 
     58   FILE *input = stdin;
     59   if (argc > 1) {
     60     input = fopen(argv[1], "r");
     61     if (input == NULL) {
     62       perror("Error opening file");
     63       return 1;
     64     }
     65   } else if (isatty(STDIN_FILENO)) {
     66     fprintf(stderr, "Reading from stdin... (Press Ctrl+D to finish)\n");
     67   }
     68 
     69   char **top_dirs = NULL;
     70   int dir_count = 0;
     71   char *line = NULL;
     72   size_t len = 0;
     73   ssize_t read_bytes;
     74 
     75   while ((read_bytes = getline(&line, &len, input)) != -1) {
     76     char *trimmed = trim_whitespace(line);
     77     if (strlen(trimmed) == 0 || trimmed[0] == '#')
     78       continue;
     79 
     80     char *slash = strchr(trimmed, '/');
     81     if (slash != NULL)
     82       *slash = '\0';
     83 
     84     bool found = false;
     85     for (int i = 0; i < dir_count; i++) {
     86       if (strcmp(top_dirs[i], trimmed) == 0) {
     87         found = true;
     88         break;
     89       }
     90     }
     91 
     92     if (!found) {
     93       char **temp_dirs = realloc(top_dirs, sizeof(char *) * (dir_count + 1));
     94       if (temp_dirs == NULL) {
     95         perror("realloc");
     96         break;
     97       }
     98       top_dirs = temp_dirs;
     99       top_dirs[dir_count] = strdup(trimmed);
    100       if (top_dirs[dir_count] == NULL) {
    101         perror("strdup");
    102         break;
    103       }
    104       dir_count++;
    105     }
    106   }
    107   free(line);
    108   if (input != stdin)
    109     fclose(input);
    110 
    111   if (dir_count == 0) {
    112     printf("No directories found in input.\n");
    113     for (int i = 0; i < dir_count; i++)
    114       free(top_dirs[i]);
    115     free(top_dirs);
    116     return 0;
    117   }
    118 
    119   printf("Found %d unique top-level directories to update.\n", dir_count);
    120 
    121   struct mpd_connection *c = conn();
    122   if (c == NULL) {
    123     for (int i = 0; i < dir_count; i++)
    124       free(top_dirs[i]);
    125     free(top_dirs);
    126     return 1;
    127   }
    128 
    129   int backoff = DEFAULT_BACKOFF;
    130   const char *backoff_str = getenv("MPD_UPDATE_BACKOFF");
    131   if (backoff_str != NULL && strlen(backoff_str) > 0)
    132     backoff = atoi(backoff_str);
    133 
    134   int updated_count = 0;
    135   int error_count = 0;
    136 
    137   for (int i = 0; i < dir_count; i++) {
    138     printf("Updating: '%s'\n", top_dirs[i]);
    139     unsigned job_id = mpd_run_update(c, top_dirs[i]);
    140     if (job_id == 0) {
    141       fprintf(stderr, "  ✗ Failed: %s\n", mpd_connection_get_error_message(c));
    142       error_count++;
    143       mpd_connection_clear_error(c);
    144     } else {
    145       printf("  ✓ Success (Job ID: %u)\n", job_id);
    146       updated_count++;
    147     }
    148     if (i < dir_count - 1 && backoff > 0)
    149       sleep(backoff);
    150   }
    151 
    152   printf("Update completed!\n");
    153   printf("Total directories processed: %d\n", dir_count);
    154   printf("Successfully updated: %d\n", updated_count);
    155   printf("Errors: %d\n", error_count);
    156 
    157   struct mpd_status *status = mpd_run_status(c);
    158   if (status != NULL) {
    159     if (mpd_status_get_update_id(status) > 0)
    160       printf("MPD is currently updating...\n");
    161     mpd_status_free(status);
    162   }
    163 
    164   for (int i = 0; i < dir_count; i++)
    165     free(top_dirs[i]);
    166   free(top_dirs);
    167   mpd_connection_free(c);
    168   return 0;
    169 }