示例#1
0
文件: playlist.c 项目: jonsafari/mocp
/* Remove items from playlist 'a' that are also present on playlist 'b'. */
void plist_remove_common_items (struct plist *a, struct plist *b)
{
	int i;

	assert (a != NULL);
	assert (b != NULL);

	for (i = 0; i < a->num; i += 1) {
		if (plist_find_fname(b, a->items[i].file) != -1)
			plist_delete (a, i);
	}
}
示例#2
0
文件: playlist.c 项目: jonsafari/mocp
/* 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]);
	}
}
示例#3
0
文件: playlist.c 项目: jonsafari/mocp
/* Swap the first item on the playlist with the item with file fname. */
void plist_swap_first_fname (struct plist *plist, const char *fname)
{
	int i;

	assert (plist != NULL);
	assert (fname != NULL);

	i = plist_find_fname (plist, fname);

	if (i != -1 && i != 0) {
		rb_delete (plist->search_tree, fname);
		rb_delete (plist->search_tree, plist->items[0].file);
		plist_swap (plist, 0, i);
		rb_insert (plist->search_tree, NULL);
		rb_insert (plist->search_tree, (void *)(intptr_t)i);
	}
}
示例#4
0
/* Move to the next file depending on the options set, the user
 * request and whether or not there are files in the queue. */
static void go_to_another_file ()
{
	int shuffle = options_get_int ("Shuffle");
	int go_next = (play_next || options_get_int("AutoNext"));
	int curr_playing_curr_pos;
	/* XXX: Shouldn't play_next be protected by mutex? */

	LOCK (curr_playing_mut);
	LOCK (plist_mut);

	/* If we move forward in the playlist and there are some songs in
	 * the queue, then play them. */
	if (plist_count(&queue) && go_next) {
		logit ("Playing file from queue");

		if (!before_queue_fname && curr_playing_fname)
			before_queue_fname = xstrdup (curr_playing_fname);

		curr_plist = &queue;
		curr_playing = plist_next (&queue, -1);

		server_queue_pop (queue.items[curr_playing].file);
		plist_delete (&queue, curr_playing);
	}
	else {
		/* If we just finished playing files from the queue and the
		 * appropriate option is set, continue with the file played
		 * before playing the queue. */
		if (before_queue_fname && options_get_int("QueueNextSongReturn")) {
			free (curr_playing_fname);
			curr_playing_fname = before_queue_fname;
			before_queue_fname = NULL;
		}

		if (shuffle) {
			curr_plist = &shuffled_plist;

			if (plist_count(&playlist)
					&& !plist_count(&shuffled_plist)) {
				plist_cat (&shuffled_plist, &playlist);
				plist_shuffle (&shuffled_plist);

				if (curr_playing_fname)
					plist_swap_first_fname (&shuffled_plist,
							curr_playing_fname);
			}
		}
		else
			curr_plist = &playlist;

		curr_playing_curr_pos = plist_find_fname (curr_plist,
				curr_playing_fname);

		/* If we came from the queue and the last file in
		 * queue wasn't in the playlist, we try to revert to
		 * the QueueNextSongReturn = 1 behaviour. */
		if (curr_playing_curr_pos == -1 && before_queue_fname) {
			curr_playing_curr_pos = plist_find_fname (curr_plist,
					before_queue_fname);
		}

		if (play_prev && plist_count(curr_plist)) {
			logit ("Playing previous...");

			if (curr_playing_curr_pos == -1
					|| started_playing_in_queue) {
				curr_playing = plist_prev (curr_plist, -1);
				started_playing_in_queue = 0;
			}
			else
				curr_playing = plist_prev (curr_plist,
						curr_playing_curr_pos);

			if (curr_playing == -1) {
				if (options_get_int("Repeat"))
					curr_playing = plist_last (curr_plist);
				logit ("Beginning of the list.");
			}
			else
				logit ("Previous item.");
		}
		else if (go_next && plist_count(curr_plist)) {
			logit ("Playing next...");

			if (curr_playing_curr_pos == -1
					|| started_playing_in_queue) {
				curr_playing = plist_next (curr_plist, -1);
				started_playing_in_queue = 0;
			}
			else
				curr_playing = plist_next (curr_plist,
						curr_playing_curr_pos);

			if (curr_playing == -1 && options_get_int("Repeat")) {
				if (shuffle) {
					plist_clear (&shuffled_plist);
					plist_cat (&shuffled_plist, &playlist);
					plist_shuffle (&shuffled_plist);
				}
				curr_playing = plist_next (curr_plist, -1);
				logit ("Going back to the first item.");
			}
			else if (curr_playing == -1)
				logit ("End of the list");
			else
				logit ("Next item");

		}
		else if (!options_get_int("Repeat")) {
			curr_playing = -1;
		}
		else
			debug ("Repeating file");

		if (before_queue_fname)
			free (before_queue_fname);
		before_queue_fname = NULL;
	}

	UNLOCK (plist_mut);
	UNLOCK (curr_playing_mut);
}
示例#5
0
/* Recursively add files from the directory to the playlist. 
 * Return 1 if OK (and even some errors), 0 if the user interrupted. */
static int read_directory_recurr_internal (const char *directory, struct plist *plist,
		ino_t **dir_stack, int *depth)
{
	DIR *dir;
	struct dirent *entry;
	struct stat st;

	if (stat(directory, &st)) {
		error ("Can't stat %s: %s", directory, strerror(errno));
		return 0;
	}

	assert (plist != NULL);
	assert (directory != NULL);

	if (*dir_stack && dir_symlink_loop(st.st_ino, *dir_stack, *depth)) {
		logit ("Detected symlink loop on %s", directory);
		return 1;
	}

	if (!(dir = opendir(directory))) {
		error ("Can't read directory: %s", strerror(errno));
		return 1;
	}

	(*depth)++;
	*dir_stack = (ino_t *)xrealloc (*dir_stack, sizeof(ino_t) * (*depth));
	(*dir_stack)[*depth - 1] = st.st_ino;

	
	while ((entry = readdir(dir))) {
		char file[PATH_MAX];
		enum file_type type;
		
		if (user_wants_interrupt()) {
			error ("Interrupted! Not all files read!");
			break;
		}
			
		if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
			continue;
		if (snprintf(file, sizeof(file), "%s/%s", directory,
					entry->d_name)
				>= (int)sizeof(file)) {
			error ("Path too long!");
			continue;
		}
		type = file_type (file);
		if (type == F_DIR)
			read_directory_recurr_internal(file, plist, dir_stack,
					depth);
		else if (type == F_SOUND && plist_find_fname(plist, file) == -1)
			plist_add (plist, file);
	}

	(*depth)--;
	*dir_stack = (ino_t *)xrealloc (*dir_stack, sizeof(ino_t) * (*depth));

	closedir (dir);
	return 1;
}
示例#6
0
/* Load M3U file into plist.  Return the number of items read. */
static int plist_load_m3u (struct plist *plist, const char *fname,
		const char *cwd, const int load_serial)
{
	FILE *file;
	char *line;
	int last_added = -1;
	int after_extinf = 0;
	int added = 0;

	if (!(file = fopen(fname, "r"))) {
		error ("Can't open playlist file: %s",
				strerror(errno));
		return 0;
	}

	if (flock(fileno(file), LOCK_SH) == -1)
		logit ("Can't flock() the playlist file: %s", strerror(errno));

	while ((line = read_line(file))) {
		if (!strncmp(line, "#EXTINF:", sizeof("#EXTINF:")-1)) {
			char *comma;
			char *num_err;
			char time_text[10] = "";
			int time_sec;

			if (after_extinf) {
				error ("Broken M3U file: double "
						"#EXTINF.");
				free (line);
				plist_delete (plist, last_added);
				return added;
			}

			/* Find the comma */
			comma = strchr (line + (sizeof("#EXTINF:") - 1), ',');
			if (!comma) {
				error ("Broken M3U file: no comma "
						"in #EXTINF.");
				free (line);
				return added;
			}

			/* Get the time string */
			time_text[sizeof(time_text)-1] = 0;
			strncpy (time_text, line + sizeof("#EXTINF:") - 1,
					MIN(comma - line - (sizeof("#EXTINF:")
						- 1), sizeof(time_text)));
			if (time_text[sizeof(time_text)-1]) {
				error ("Broken M3U file: "
						"wrong time.");
				free (line);
				return added;
			}

			/* Extract the time */
			time_sec = strtol (time_text, &num_err, 10);
			if (*num_err) {
				error ("Broken M3U file: "
						"time is not a number.");
				free (line);
				return added;
			}

			after_extinf = 1;
			last_added = plist_add (plist, NULL);
			plist_set_title_tags (plist, last_added, comma + 1);

			if (*time_text)
				plist_set_item_time (plist, last_added,
						time_sec);
		}
		else if (line[0] != '#') {
			char path[2*PATH_MAX];

			strip_string (line);
			if (strlen(line) <= PATH_MAX) {
				make_path (path, sizeof(path), cwd, line);

				if (plist_find_fname(plist, path) == -1) {
					if (after_extinf)
						plist_set_file (plist,
								last_added,
								path);
					else
						plist_add (plist, path);
					added++;
				}
				else if (after_extinf)
					plist_delete (plist, last_added);
			}
			else if (after_extinf)
				plist_delete (plist, last_added);

			after_extinf = 0;
		}
		else if (load_serial && !strncmp(line, "#MOCSERIAL: ",
					sizeof("#MOCSERIAL: ") - 1)) {
			char *serial_str = line + sizeof("#MOCSERIAL: ") - 1;

			if (serial_str[0]) {
				char *err;
				long serial;

				serial = strtol (serial_str, &err, 0);
				if (!*err) {
					plist_set_serial (plist, serial);
					logit ("Got MOCSERIAL tag with serial %d",
							(int)serial);
				}
			}
		}
		free (line);
	}

	if (flock(fileno(file), LOCK_UN) == -1)
		logit ("Can't flock() (unlock) the playlist file: %s",
				strerror(errno));
	fclose (file);

	return added;
}
示例#7
0
/* Load PLS file into plist. Return the number of items read. */
static int plist_load_pls (struct plist *plist, const char *fname,
		const char *cwd)
{
	FILE *file;
	char *line;
	long i, nitems, added = 0;
	char *e;

	if (!(file = fopen(fname, "r"))) {
		error ("Can't open playlist file: %s",
				strerror(errno));
		return 0;
	}

	line = read_ini_value (file, "playlist", "NumberOfEntries");
	if (!line) {

		/* Assume that it is a pls file version 1 - plist_load_m3u()
		 * should handle it like an m3u file without the m3u extensions. */
		fclose (file);
		return plist_load_m3u (plist, fname, cwd, 0);
	}

	nitems = strtol (line, &e, 10);
	if (*e) {
		error ("Broken PLS file");
		free (line);
		return 0;
	}
	free (line);

	for (i = 1; i <= nitems; i++) {
		char *pls_file, *pls_title, *pls_length;
		char key[16];
		int time;
		int last_added;
		char path[2*PATH_MAX];

		sprintf (key, "File%ld", i);
		if (!(pls_file = read_ini_value(file, "playlist", key))) {
			error ("Broken PLS file");
			break;
		}

		sprintf (key, "Title%ld", i);
		pls_title = read_ini_value(file, "playlist", key);

		sprintf (key, "Length%ld", i);
		pls_length = read_ini_value(file, "playlist", key);

		if (pls_length) {
			time = strtol (pls_length, &e, 10);
			if (*e)
				time = -1;
		}
		else
			time = -1;

		if (strlen(pls_file) <= PATH_MAX) {
			make_path (path, sizeof(path), cwd, pls_file);
			if (plist_find_fname(plist, path) == -1) {
				last_added = plist_add (plist, path);

				if (pls_title && pls_title[0])
					plist_set_title_tags (plist, last_added,
							pls_title);

				if (time > 0) {
					plist->items[last_added].tags
						= tags_new ();
					plist->items[last_added].tags->time
						= time;
					plist->items[last_added].tags->filled
						|= TAGS_TIME;
				}
			}
		}

		free (pls_file);
		if (pls_title)
			free (pls_title);
		if (pls_length)
			free (pls_length);
		added++;
	}

	fclose (file);

	return added;
}
示例#8
0
/* Load M3U file into plist.  Return the number of items read. */
static int plist_load_m3u (struct plist *plist, const char *fname,
		const char *cwd, const int load_serial)
{
	FILE *file;
	char *line = NULL;
	int last_added = -1;
	int after_extinf = 0;
	int added = 0;
	struct flock read_lock = {.l_type = F_RDLCK, .l_whence = SEEK_SET};

	file = fopen (fname, "r");
	if (!file) {
		error_errno ("Can't open playlist file", errno);
		return 0;
	}

	/* Lock gets released by fclose(). */
	if (fcntl (fileno (file), F_SETLKW, &read_lock) == -1)
		log_errno ("Can't lock the playlist file", errno);

	while ((line = read_line (file))) {
		if (!strncmp (line, "#EXTINF:", sizeof("#EXTINF:") - 1)) {
			char *comma, *num_err;
			char time_text[10] = "";
			int time_sec;

			if (after_extinf) {
				error ("Broken M3U file: double #EXTINF!");
				plist_delete (plist, last_added);
				goto err;
			}

			/* Find the comma */
			comma = strchr (line + (sizeof("#EXTINF:") - 1), ',');
			if (!comma) {
				error ("Broken M3U file: no comma in #EXTINF!");
				goto err;
			}

			/* Get the time string */
			time_text[sizeof(time_text) - 1] = 0;
			strncpy (time_text, line + sizeof("#EXTINF:") - 1,
			         MIN(comma - line - (sizeof("#EXTINF:") - 1),
			         sizeof(time_text)));
			if (time_text[sizeof(time_text) - 1]) {
				error ("Broken M3U file: wrong time!");
				goto err;
			}

			/* Extract the time. */
			time_sec = strtol (time_text, &num_err, 10);
			if (*num_err) {
				error ("Broken M3U file: time is not a number!");
				goto err;
			}

			after_extinf = 1;
			last_added = plist_add (plist, NULL);
			plist_set_title_tags (plist, last_added, comma + 1);

			if (*time_text)
				plist_set_item_time (plist, last_added, time_sec);
		}
		else if (line[0] != '#') {
			char path[2 * PATH_MAX];

			strip_string (line);
			if (strlen (line) <= PATH_MAX) {
				make_path (path, sizeof(path), cwd, line);

				if (plist_find_fname (plist, path) == -1) {
					if (after_extinf)
						plist_set_file (plist, last_added, path);
					else
						plist_add (plist, path);
					added += 1;
				}
				else if (after_extinf)
					plist_delete (plist, last_added);
			}
			else if (after_extinf)
				plist_delete (plist, last_added);

			after_extinf = 0;
		}
		else if (load_serial &&
		         !strncmp (line, "#MOCSERIAL: ", sizeof("#MOCSERIAL: ") - 1)) {
			char *serial_str = line + sizeof("#MOCSERIAL: ") - 1;

			if (serial_str[0]) {
				char *err;
				long serial;

				serial = strtol (serial_str, &err, 0);
				if (!*err) {
					plist_set_serial (plist, serial);
					logit ("Got MOCSERIAL tag with serial %ld", serial);
				}
			}
		}
		free (line);
	}

err:
	free (line);
	fclose (file);
	return added;
}