/* Sort the playlist by file names. */ void plist_sort_fname (struct plist *plist) { struct plist_item *sorted; struct rb_node *x; int n; if (plist_count(plist) == 0) return; sorted = (struct plist_item *)xmalloc (plist_count(plist) * sizeof(struct plist_item)); x = rb_min (plist->search_tree); assert (!rb_is_null(x)); while (plist_deleted(plist, (intptr_t)rb_get_data (x))) x = rb_next (x); sorted[0] = plist->items[(intptr_t)rb_get_data (x)]; rb_set_data (x, NULL); n = 1; while (!rb_is_null(x = rb_next(x))) { if (!plist_deleted(plist, (intptr_t)rb_get_data (x))) { sorted[n] = plist->items[(intptr_t)rb_get_data (x)]; rb_set_data (x, (void *)(intptr_t)n++); } } plist->num = n; plist->not_deleted = n; memcpy (plist->items, sorted, sizeof(struct plist_item) * n); free (sorted); }
/* Make a title from the file name for the item. If hide extension != 0, strip * the file name from extension. */ void make_file_title (struct plist *plist, const int num, const int hide_extension) { assert (plist != NULL); assert (num >= 0 && num < plist->num); assert (!plist_deleted(plist, num)); if (file_type(plist->items[num].file) != F_URL) { char *file = xstrdup (plist->items[num].file); if (hide_extension) { char *dot = strrchr (file, '.'); if (dot) *dot = 0; } if (options_get_int ("FileNamesIconv")) { char *old_title = file; file = files_iconv_str (file); free (old_title); } plist_set_title_file (plist, num, file); free (file); } else plist_set_title_file (plist, num, plist->items[num].file); }
/* Return the index of the last non-deleted item from the playlist. * Return -1 if there are no items. */ int plist_last (const struct plist *plist) { int i; i = plist->num - 1; while (i > 0 && plist_deleted(plist, i)) i--; return i; }
/* Switch playlist titles to title_file */ void switch_titles_file (struct plist *plist) { int i; int hide_extension = options_get_int("HideFileExtension"); for (i = 0; i < plist->num; i++) if (!plist_deleted(plist, i)) { if (!plist->items[i].title_file) make_file_title (plist, i, hide_extension); assert (plist->items[i].title_file != NULL); plist->items[i].title = plist->items[i].title_file; } }
/* Find an item in the list. Return the index or -1 if not found. */ int plist_find_fname (struct plist *plist, const char *file) { struct rb_node *x; assert (plist != NULL); x = rb_search (plist->search_tree, file); if (rb_is_null(x)) return -1; return !plist_deleted(plist, (intptr_t)rb_get_data (x)) ? (intptr_t)rb_get_data (x) : -1; }
void plist_discard_tags (struct plist *plist) { int i; assert (plist != NULL); for (i = 0; i < plist->num; i++) if (!plist_deleted(plist, i) && plist->items[i].tags) { tags_free (plist->items[i].tags); plist->items[i].tags = NULL; } plist->items_with_time = 0; plist->total_time = 0; }
/* Add the content of playlist b to a by copying items. */ void plist_cat (struct plist *a, struct plist *b) { int i; assert (a != NULL); assert (b != NULL); for (i = 0; i < b->num; i++) { assert (b->items[i].file != NULL); if (!plist_deleted (b, i) && plist_find_fname (a, b->items[i].file) == -1) plist_add_from_item (a, &b->items[i]); } }
/* Find an item in the list; also find deleted items. If there is more than * one item for this file, return the non-deleted one or, if all are deleted, * return the last of them. Return the index or -1 if not found. */ int plist_find_del_fname (const struct plist *plist, const char *file) { int i; int item = -1; assert (plist != NULL); for (i = 0; i < plist->num; i++) { if (plist->items[i].file && !strcmp(plist->items[i].file, file)) { if (item == -1 || plist_deleted(plist, item)) item = i; } } return item; }
/* Switch playlist titles to title_tags */ void switch_titles_tags (struct plist *plist) { int i; for (i = 0; i < plist->num; i++) if (!plist_deleted(plist, i)) { if (plist->items[i].title_tags) plist->items[i].title = plist->items[i].title_tags; else { if (!plist->items[i].title_file) make_file_title (plist, i, options_get_int("HideFileExtension")); plist->items[i].title = plist->items[i].title_file; } } }
/* Returns the next filename that is a dead entry, or NULL if there are none * left. * * It will set the index on success. */ const char *plist_get_next_dead_entry (const struct plist *plist, int *last_index) { int i; assert (last_index != NULL); assert (plist != NULL); for (i = *last_index; i < plist->num; i++) { if (plist->items[i].file && ! plist_deleted(plist, i) && ! can_read_file(plist->items[i].file)) { *last_index = i + 1; return plist->items[i].file; } } return NULL; }
/* Client requested we send the queue so we get it from audio.c and * send it to the client. */ static int req_send_queue (struct client *cli) { int i; struct plist *queue; logit ("Client with fd %d wants queue... sending it", cli->socket); if (!send_int(cli->socket, EV_DATA)) { logit ("Error while sending response; disconnecting the client"); close (cli->socket); del_client (cli); return 0; } queue = audio_queue_get_contents (); for (i = 0; i < queue->num; i++) if (!plist_deleted(queue, i)) { if(!send_item(cli->socket, &queue->items[i])){ logit ("Error sending queue; disconnecting the client"); close (cli->socket); del_client (cli); free (queue); return 0; } } plist_free (queue); free (queue); if (!send_item (cli->socket, NULL)) { logit ("Error while sending end of playlist mark; " "disconnecting the client"); close (cli->socket); del_client (cli); return 0; } logit ("Queue sent"); return 1; }
/* Make a title from the tags for the item. */ void make_tags_title (struct plist *plist, const int num) { assert (plist != NULL); assert (num >= 0 && num < plist->num); assert (!plist_deleted(plist, num)); if (file_type(plist->items[num].file) == F_URL) make_file_title (plist, num, 0); else if (!plist->items[num].title_tags) { char *title; assert (plist->items[num].file != NULL); if (plist->items[num].tags->title) { title = build_title (plist->items[num].tags); plist_set_title_tags (plist, num, title); free (title); } else make_file_title (plist, num, options_get_int("HideFileExtension")); } }
/* Save plist in m3u format. Strip paths by strip_path bytes. * If save_serial is not 0, the playlist serial is saved in a * comment. */ static int plist_save_m3u (struct plist *plist, const char *fname, const int strip_path, const int save_serial) { FILE *file; int i; debug ("Saving playlist to '%s'", fname); if (!(file = fopen(fname, "w"))) { error ("Can't save playlist: %s", strerror(errno)); return 0; } if (flock(fileno(file), LOCK_EX) == -1) logit ("Can't flock() the playlist file: %s", strerror(errno)); if (fprintf(file, "#EXTM3U\r\n") < 0) { error ("Error writing playlist: %s", strerror(errno)); fclose (file); return 0; } if (save_serial && fprintf(file, "#MOCSERIAL: %d\r\n", plist_get_serial(plist)) < 0) { error ("Error writing playlist: %s", strerror(errno)); fclose (file); return 0; } for (i = 0; i < plist->num; i++) { if (!plist_deleted(plist, i)) { int ret; /* EXTM3U */ if (plist->items[i].tags) ret = fprintf (file, "#EXTINF:%d,%s\r\n", plist->items[i].tags->time, plist->items[i].title_tags ? plist->items[i].title_tags : plist->items[i].title_file); else ret = fprintf (file, "#EXTINF:%d,%s\r\n", 0, plist->items[i].title_file); if (ret < 0) { error ("Error writing playlist: %s", strerror(errno)); fclose (file); return 0; } /* file */ if (fprintf(file, "%s\r\n", plist->items[i].file + strip_path) < 0) { error ("Error writing playlist: %s", strerror(errno)); fclose (file); return 0; } } } if (flock(fileno(file), LOCK_UN) == -1) logit ("Can't flock() (unlock) the playlist file: %s", strerror(errno)); if (fclose(file)) { error ("Error writing playlist: %s", strerror(errno)); return 0; } return 1; }
/* Save plist in m3u format. Strip paths by strip_path bytes. * If save_serial is not 0, the playlist serial is saved in a * comment. */ static int plist_save_m3u (struct plist *plist, const char *fname, const int strip_path, const int save_serial) { FILE *file = NULL; int i, ret, result = 0; debug ("Saving playlist to '%s'", fname); file = fopen (fname, "w"); if (!file) { error_errno ("Can't save playlist", errno); return 0; } /* Lock gets released by fclose(). */ if (lockf (fileno (file), F_LOCK, 0) == -1) log_errno ("Can't lock the playlist file", errno); if (fprintf (file, "#EXTM3U\r\n") < 0) { error_errno ("Error writing playlist", errno); goto err; } if (save_serial && fprintf (file, "#MOCSERIAL: %d\r\n", plist_get_serial (plist)) < 0) { error_errno ("Error writing playlist", errno); goto err; } for (i = 0; i < plist->num; i++) { if (!plist_deleted (plist, i)) { /* EXTM3U */ if (plist->items[i].tags) ret = fprintf (file, "#EXTINF:%d,%s\r\n", plist->items[i].tags->time, plist->items[i].title_tags ? plist->items[i].title_tags : plist->items[i].title_file); else ret = fprintf (file, "#EXTINF:%d,%s\r\n", 0, plist->items[i].title_file); /* file */ if (ret >= 0) ret = fprintf (file, "%s\r\n", plist->items[i].file + strip_path); if (ret < 0) { error_errno ("Error writing playlist", errno); goto err; } } } ret = fclose (file); file = NULL; if (ret) error_errno ("Error writing playlist", errno); else result = 1; err: if (file) fclose (file); return result; }