/* playlist_basic.c * - Simple built-in unscripted playlist * * $Id: playlist_basic.c,v 1.7 2002/08/10 04:26:52 msmith Exp $ * * Copyright (c) 2001-2 Michael Smith * Copyright (c) 2003 Karl Heyes * * This program is distributed under the terms of the GNU General * Public License, version 2. You may use, modify, and redistribute * it under the terms of this license. A copy should be included * with this source. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include "cfgparse.h" #include "inputmodule.h" #include "im_playlist.h" #include "playlist_basic.h" #define MODULE "playlist-basic/" #include "logging.h" static void shuffle(char **buf, int len) { int n,d; char *temp; n = len; while(n > 1) { d = (int) ((double)n * rand()/(RAND_MAX+1.0)); temp = buf[d]; buf[d] = buf[n-1]; buf[n-1] = temp; --n; } LOG_DEBUG0("Playlist has been shuffled"); } static int load_playlist(basic_playlist *data) { FILE *file; char buf[1024]; int buflen; file = fopen(data->file, "r"); if (file == NULL) { LOG_ERROR2("Playlist file %s could not be opened: %s", data->file, strerror(errno)); return -1; } if(data->pl) { int i; for(i = 0; i < data->len; i++) free(data->pl[i]); free(data->pl); } data->pl = NULL; data->len = 0; buflen = 0; while (1) { if(fgets(buf,1024, file) == NULL) break; if(buf[0]==0) break; if(buf[0]=='\n' || (buf[0]=='\r' && buf[1]=='\n')) continue; if(buf[0] == '#') /* Commented out entry */ continue; buf[strlen(buf)-1] = 0; /* De-fuck windows files. */ if(strlen(buf) > 0 && buf[strlen(buf)-1] == '\r') buf[strlen(buf)-1] = 0; if(buflen < data->len+1) { char **tmp; buflen += 100; tmp = realloc(data->pl, buflen*sizeof(char *)); if (tmp == NULL) break; data->pl = tmp; } data->pl[data->len++] = strdup(buf); } if(data->random) shuffle(data->pl, data->len); fclose (file); return 0; } static void playlist_basic_clear(void *data) { basic_playlist *pl = data; if(pl) { if(pl->pl) { int i; for(i=0; i < pl->len; i++) free(pl->pl[i]); free(pl->pl); } free(pl); } } static char *playlist_basic_get_next_filename(void *data) { basic_playlist *pl = (basic_playlist *)data; char *ptr = NULL, *dest = NULL; int reload_playlist = 0; struct stat st; if (stat(pl->file, &st)) { LOG_ERROR2("Couldn't stat file \"%s\": %s", pl->file, strerror(errno)); return NULL; } if (pl->pl) { if (st.st_mtime != pl->mtime) { reload_playlist = 1; LOG_INFO1("Reloading playlist after file \"%s\" changed", pl->file); pl->mtime = st.st_mtime; } } else { LOG_INFO1("Loading playlist from file \"%s\"", pl->file); reload_playlist = 1; pl->mtime = st.st_mtime; } if (reload_playlist) { if (load_playlist(pl) < 0) return NULL; if (pl->restartafterreread) pl->pos = 0; } if (pl->pos >= pl->len) /* reached the end of the potentially updated list */ { if (pl->once) return NULL; pl->pos = 0; if (pl->random) shuffle(pl->pl, pl->len); } ptr = pl->pl [pl->pos++]; if ((dest = malloc (strlen (ptr)+1)) == NULL) return NULL; strcpy (dest, ptr); return dest; } static void playlist_basic_free_filename(void *data __attribute__((unused)), char *fn) { if (fn) free (fn); } int playlist_basic_initialise(module_param_t *params, struct playlist_state *pl) { basic_playlist *data; pl->get_filename = playlist_basic_get_next_filename; pl->clear = playlist_basic_clear; pl->free_filename = playlist_basic_free_filename; pl->sleep = 1; pl->data = calloc(1, sizeof(basic_playlist)); data = (basic_playlist *)pl->data; while (params != NULL) { if (!strcmp(params->name, "file")) { if (data->file) free(data->file); data->file = params->value; } else if (!strcmp(params->name, "random")) data->random = atoi(params->value); else if(!strcmp(params->name, "once")) data->once = atoi(params->value); else if(!strcmp(params->name, "restart-after-reread")) data->restartafterreread = atoi(params->value); else if(!strcmp(params->name, "sleep")) pl->sleep = atoi(params->value); else if(!strcmp(params->name, "type")) ; /* We recognise this, but don't want to do anything with it */ else { LOG_WARN1("Unknown parameter to playlist input module: %s", params->name); } params = params->next; } if (!data->file) { LOG_ERROR0("No filename specified for playlist module"); free(data); return -1; } return 0; }