summaryrefslogtreecommitdiffstats
path: root/apps/playlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playlist.c')
-rw-r--r--apps/playlist.c109
1 files changed, 88 insertions, 21 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index ccceb4db7b..b6e307065e 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -123,7 +123,16 @@
/* default load buffer size (should be at least 1 KiB) */
#define PLAYLIST_LOAD_BUFLEN (32*1024)
-#define PLAYLIST_CONTROL_FILE_VERSION 2
+/*
+ * Minimum supported version and current version of the control file.
+ * Any versions outside of this range will be rejected by the loader.
+ *
+ * v1 was the initial version when dynamic playlists were first implemented.
+ * v2 was added shortly thereafter and has been used since 2003.
+ * v3 added the (C)lear command and is otherwise identical to v2.
+ */
+#define PLAYLIST_CONTROL_FILE_MIN_VERSION 2
+#define PLAYLIST_CONTROL_FILE_VERSION 3
#define PLAYLIST_COMMAND_SIZE (MAX_PATH+12)
@@ -432,6 +441,9 @@ static int flush_cached_control_unlocked(struct playlist_info* playlist)
case PLAYLIST_COMMAND_RESET:
result = fdprintf(playlist->control_fd, "%s\n", "R");
break;
+ case PLAYLIST_COMMAND_CLEAR:
+ result = fdprintf(playlist->control_fd, "%s\n", "C");
+ break;
default:
break;
}
@@ -1344,6 +1356,53 @@ static int create_and_play_dir(int direction, bool play_last)
}
/*
+ * remove all tracks, leaving the current track queued
+ */
+static int remove_all_tracks_unlocked(struct playlist_info *playlist, bool write)
+{
+ if (playlist->amount <= 0)
+ return 0;
+
+ /* Move current track down to position 0 */
+ playlist->indices[0] = playlist->indices[playlist->index];
+#ifdef HAVE_DIRCACHE
+ if (playlist->dcfrefs_handle)
+ {
+ struct dircache_fileref *dcfrefs =
+ core_get_data(playlist->dcfrefs_handle);
+ dcfrefs[0] = dcfrefs[playlist->index];
+ }
+#endif
+
+ /* Update playlist state as if by remove_track_unlocked() */
+ bool inserted = playlist->indices[0] & PLAYLIST_INSERT_TYPE_MASK;
+
+ playlist->index = 0;
+ playlist->amount = 1;
+ playlist->indices[0] |= PLAYLIST_QUEUED;
+
+ if (inserted)
+ playlist->num_inserted_tracks = 1;
+ else
+ playlist->deleted = true;
+
+ playlist->first_index = 0;
+
+ if (playlist->last_insert_pos == 0)
+ playlist->last_insert_pos = -1;
+ else
+ playlist->last_insert_pos = 0;
+
+ if (write && playlist->control_fd >= 0)
+ {
+ update_control(playlist, PLAYLIST_COMMAND_CLEAR, -1, -1, NULL, NULL, NULL);
+ sync_control(playlist, false);
+ }
+
+ return 0;
+}
+
+/*
* Add track to playlist at specified position. There are seven special
* positions that can be specified:
* PLAYLIST_PREPEND - Add track at beginning of playlist
@@ -1444,7 +1503,7 @@ static int add_track_to_playlist_unlocked(struct playlist_info* playlist,
break;
}
case PLAYLIST_REPLACE:
- if (playlist_remove_all_tracks(playlist) < 0)
+ if (remove_all_tracks_unlocked(playlist, true) < 0)
return -1;
int newpos = playlist->index + 1;
playlist->last_insert_pos = position = insert_position = newpos;
@@ -2635,7 +2694,7 @@ int playlist_insert_directory(struct playlist_info* playlist,
if (position == PLAYLIST_REPLACE)
{
- if (playlist_remove_all_tracks(playlist) == 0)
+ if (remove_all_tracks_unlocked(playlist, true) == 0)
position = PLAYLIST_INSERT_LAST;
else
{
@@ -2727,7 +2786,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
if (position == PLAYLIST_REPLACE)
{
- if (playlist_remove_all_tracks(playlist) == 0)
+ if (remove_all_tracks_unlocked(playlist, true) == 0)
position = PLAYLIST_INSERT_LAST;
else
{
@@ -3221,8 +3280,6 @@ int playlist_randomise(struct playlist_info* playlist, unsigned int seed,
/*
* Removes all tracks, from the playlist, leaving the presently playing
* track queued.
- *
- * TODO: This is insanely slow for huge playlists. Must fix.
*/
int playlist_remove_all_tracks(struct playlist_info *playlist)
{
@@ -3234,23 +3291,11 @@ int playlist_remove_all_tracks(struct playlist_info *playlist)
dc_thread_stop(playlist);
playlist_mutex_lock(&playlist->mutex);
- while (playlist->index > 0)
- if ((result = remove_track_unlocked(playlist, 0, true)) < 0)
- goto out;
-
- while (playlist->amount > 1)
- if ((result = remove_track_unlocked(playlist, 1, true)) < 0)
- goto out;
-
- if (playlist->amount == 1) {
- playlist->indices[0] |= PLAYLIST_QUEUED;
- }
+ result = remove_all_tracks_unlocked(playlist, true);
-out:
playlist_mutex_unlock(&playlist->mutex);
dc_thread_start(playlist, false);
-
- return 0;
+ return result;
}
/*
@@ -3384,7 +3429,17 @@ int playlist_resume(void)
version = atoi(str1);
- if (version != PLAYLIST_CONTROL_FILE_VERSION)
+ /*
+ * TODO: Playlist control file version upgrades
+ *
+ * If an older version control file is loaded then
+ * the header should be updated to the latest version
+ * in case any incompatible commands are written out.
+ * (It's not a big deal since the error message will
+ * be practically the same either way...)
+ */
+ if (version < PLAYLIST_CONTROL_FILE_MIN_VERSION ||
+ version > PLAYLIST_CONTROL_FILE_VERSION)
{
result = -3;
goto out;
@@ -3523,6 +3578,15 @@ int playlist_resume(void)
playlist->last_insert_pos = -1;
break;
}
+ case PLAYLIST_COMMAND_CLEAR:
+ {
+ if (remove_all_tracks_unlocked(playlist, false) < 0)
+ {
+ result = -16;
+ goto out;
+ }
+ break;
+ }
case PLAYLIST_COMMAND_COMMENT:
default:
break;
@@ -3570,6 +3634,9 @@ int playlist_resume(void)
case 'R':
current_command = PLAYLIST_COMMAND_RESET;
break;
+ case 'C':
+ current_command = PLAYLIST_COMMAND_CLEAR;
+ break;
case '#':
current_command = PLAYLIST_COMMAND_COMMENT;
break;