summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2023-03-29 10:58:30 +0100
committerAidan MacDonald <amachronic@protonmail.com>2023-10-01 11:05:29 -0400
commit7ccbd705f43553ff358d6713c8d6ac7cc9e3c343 (patch)
treecbd8b34688194715632f03e9248bb3a2e8a3dda7
parent781f955aa2fb813dd87986cbcc22c1676a2dd9a9 (diff)
downloadrockbox-7ccbd705f4.tar.gz
rockbox-7ccbd705f4.zip
playlist: Rework playlist modified detection and dirplay
The modified state is now an explicit flag that has to be set whenever a user-triggered modification occurs. This is recorded in the control file to ensure it doesn't get lost after resume. There may be some places I missed where the modified flag should be set/cleared, but it seems to work well enough right now. Change-Id: I3bdba358fc495b4ca84e389ac6e7bcbef820c219
-rw-r--r--apps/filetree.c2
-rw-r--r--apps/onplay.c1
-rw-r--r--apps/playlist.c123
-rw-r--r--apps/playlist.h8
-rw-r--r--apps/playlist_viewer.c13
-rw-r--r--apps/plugins/pictureflow/pictureflow.c1
-rw-r--r--apps/tagtree.c1
-rw-r--r--apps/tree.c2
8 files changed, 101 insertions, 50 deletions
diff --git a/apps/filetree.c b/apps/filetree.c
index 3e20c89924..42f13f39e7 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -148,7 +148,6 @@ bool ft_play_playlist(char* pathname, char* dirname,
if (global_settings.playlist_shuffle)
playlist_shuffle(current_tick, -1);
- playlist_set_modified(NULL, false);
playlist_start(0, 0, 0);
return true;
}
@@ -546,7 +545,6 @@ int ft_enter(struct tree_context* c)
start_index = 0;
}
- playlist_set_modified(NULL, false);
playlist_start(start_index, 0, 0);
play = true;
}
diff --git a/apps/onplay.c b/apps/onplay.c
index 5f8af77fca..4157544d28 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -358,6 +358,7 @@ static int add_to_playlist(void* arg)
onplay_result = ONPLAY_START_PLAY;
}
+ playlist_set_modified(NULL, true);
return false;
}
diff --git a/apps/playlist.c b/apps/playlist.c
index 67edc5fbe5..554e1afd7e 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -31,10 +31,13 @@
started and contains all the commands done to it.
The first non-comment line in a control file must begin with
- "P:VERSION:DIR:FILE" where VERSION is the playlist control file version,
+ "P:VERSION:DIR:FILE" where VERSION is the playlist control file version
DIR is the directory where the playlist is located and FILE is the
- playlist filename. For dirplay, FILE will be empty. An empty playlist
- will have both entries as null.
+ playlist filename (without the directory part).
+
+ When there is an on-disk playlist file, both DIR and FILE are nonempty.
+ Dynamically generated playlists (whether by the file browser, database,
+ or another means) have an empty FILE. For dirplay, DIR will be nonempty.
Control file commands:
a. Add track (A:<position>:<last position>:<path to track>)
@@ -130,9 +133,10 @@
* 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.
+ * v4 added the (F)lags command.
*/
#define PLAYLIST_CONTROL_FILE_MIN_VERSION 2
-#define PLAYLIST_CONTROL_FILE_VERSION 3
+#define PLAYLIST_CONTROL_FILE_VERSION 4
#define PLAYLIST_COMMAND_SIZE (MAX_PATH+12)
@@ -431,6 +435,9 @@ static int update_control_unlocked(struct playlist_info* playlist,
case PLAYLIST_COMMAND_CLEAR:
result = write(fd, "C\n", 2);
break;
+ case PLAYLIST_COMMAND_FLAGS:
+ result = fdprintf(fd, "F:%u:%u\n", i1, i2);
+ break;
default:
return -1;
}
@@ -481,8 +488,7 @@ static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume)
playlist->utf8 = true;
playlist->control_created = false;
- playlist->modified = false;
- playlist->dirplay = true;
+ playlist->flags = 0;
playlist->control_fd = -1;
@@ -501,6 +507,28 @@ static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume)
}
}
+int update_playlist_flags_unlocked(struct playlist_info *playlist,
+ unsigned int setf, unsigned int clearf)
+{
+ unsigned int newflags = (playlist->flags & ~clearf) | setf;
+ if (newflags == playlist->flags)
+ return 0;
+
+ playlist->flags = newflags;
+
+ if (playlist->control_fd >= 0)
+ {
+ int res = update_control_unlocked(playlist, PLAYLIST_COMMAND_FLAGS,
+ setf, clearf, NULL, NULL, NULL);
+ if (res < 0)
+ return res;
+
+ sync_control_unlocked(playlist);
+ }
+
+ return 0;
+}
+
/*
* Returns absolute path of track
*
@@ -567,28 +595,21 @@ static ssize_t format_track_path(char *dest, char *src, int buf_length,
static void new_playlist_unlocked(struct playlist_info* playlist,
const char *dir, const char *file)
{
- const char *fileused = file;
- const char *dirused = dir;
-
empty_playlist_unlocked(playlist, false);
- if (!fileused)
- {
- fileused = "";
+ /* enable dirplay for the current playlist if there's a DIR but no FILE */
+ if (!file && dir && playlist == &current_playlist)
+ playlist->flags |= PLAYLIST_FLAG_DIRPLAY;
- /* only the current playlist can use dirplay */
- if (dirused && playlist == &current_playlist)
- playlist->dirplay = true;
- else
- dirused = ""; /* empty playlist */
- }
+ dir = dir ?: "";
+ file = file ?: "";
- update_playlist_filename_unlocked(playlist, dirused, fileused);
+ update_playlist_filename_unlocked(playlist, dir, file);
if (playlist->control_fd >= 0)
{
update_control_unlocked(playlist, PLAYLIST_COMMAND_PLAYLIST,
- PLAYLIST_CONTROL_FILE_VERSION, -1, dirused, fileused, NULL);
+ PLAYLIST_CONTROL_FILE_VERSION, -1, dir, file, NULL);
sync_control_unlocked(playlist);
}
}
@@ -711,7 +732,6 @@ static int recreate_control_unlocked(struct playlist_info* playlist)
}
playlist->seed = 0;
- playlist->modified = true;
for (i=0; i<playlist->amount; i++)
{
@@ -1207,8 +1227,6 @@ static int create_and_play_dir(int direction, bool play_last)
if (global_settings.playlist_shuffle)
playlist_shuffle(current_tick, -1);
- playlist_set_modified(NULL, false);
-
if (play_last && direction <= 0)
index = current_playlist.amount - 1;
else
@@ -1248,7 +1266,6 @@ static int remove_all_tracks_unlocked(struct playlist_info *playlist, bool write
playlist->first_index = 0;
playlist->amount = 1;
playlist->indices[0] |= PLAYLIST_QUEUED;
- playlist->modified = true;
if (playlist->last_insert_pos == 0)
playlist->last_insert_pos = -1;
@@ -1423,7 +1440,6 @@ static int add_track_to_playlist_unlocked(struct playlist_info* playlist,
dc_init_filerefs(playlist, insert_position, 1);
playlist->amount++;
- playlist->modified = true;
return insert_position;
}
@@ -1466,7 +1482,6 @@ static int remove_track_unlocked(struct playlist_info* playlist,
}
playlist->amount--;
- playlist->modified = true;
/* update stored indices if needed */
if (position < playlist->index)
@@ -1559,7 +1574,6 @@ static int randomise_playlist_unlocked(struct playlist_info* playlist,
playlist->last_insert_pos = -1;
playlist->seed = seed;
- playlist->modified = true;
if (write)
{
@@ -1623,7 +1637,6 @@ static int sort_playlist_unlocked(struct playlist_info* playlist,
/* indices have been moved so last insert position is no longer valid */
playlist->last_insert_pos = -1;
- playlist->modified = true;
if (write && playlist->control_fd >= 0)
{
@@ -2106,7 +2119,7 @@ bool playlist_check(int steps)
struct playlist_info* playlist = &current_playlist;
/* always allow folder navigation */
- if (global_settings.next_folder && playlist->dirplay)
+ if (global_settings.next_folder && playlist_allow_dirplay(playlist))
return true;
int index = get_next_index(playlist, steps, -1);
@@ -2650,19 +2663,39 @@ bool playlist_modified(const struct playlist_info* playlist)
if (!playlist)
playlist = &current_playlist;
- return playlist->modified;
+ return !!(playlist->flags & PLAYLIST_FLAG_MODIFIED);
}
/*
- * Set the playlist modified status. Useful for clearing the modified status
- * after dynamically building a playlist.
+ * Set the playlist modified status. Should be called to set the flag after
+ * an explicit user action that modifies the playlist. You should not clear
+ * the modified flag without properly warning the user.
*/
-void playlist_set_modified(struct playlist_info *playlist, bool modified)
+void playlist_set_modified(struct playlist_info* playlist, bool modified)
{
if (!playlist)
playlist = &current_playlist;
- playlist->modified = modified;
+ playlist_write_lock(playlist);
+
+ if (modified)
+ update_playlist_flags_unlocked(playlist, PLAYLIST_FLAG_MODIFIED, 0);
+ else
+ update_playlist_flags_unlocked(playlist, 0, PLAYLIST_FLAG_MODIFIED);
+
+ playlist_write_unlock(playlist);
+}
+
+/* returns true if directory playback features should be enabled */
+bool playlist_allow_dirplay(const struct playlist_info *playlist)
+{
+ if (!playlist)
+ playlist = &current_playlist;
+
+ if (playlist_modified(playlist))
+ return false;
+
+ return !!(playlist->flags & PLAYLIST_FLAG_DIRPLAY);
}
/*
@@ -2875,7 +2908,7 @@ int playlist_next(int steps)
playlist->index = 0;
index = 0;
}
- else if (playlist->dirplay && global_settings.next_folder)
+ else if (global_settings.next_folder && playlist_allow_dirplay(playlist))
{
/* we switch playlists here */
index = create_and_play_dir(steps, true);
@@ -2926,8 +2959,8 @@ out:
bool playlist_next_dir(int direction)
{
/* not to mess up real playlists */
- if(!current_playlist.dirplay)
- return false;
+ if (!playlist_allow_dirplay(&current_playlist))
+ return false;
return create_and_play_dir(direction, false) >= 0;
}
@@ -3184,7 +3217,7 @@ int playlist_resume(void)
}
else if (str2[0] != '\0')
{
- playlist->dirplay = true;
+ playlist->flags |= PLAYLIST_FLAG_DIRPLAY;
}
/* load the rest of the data */
@@ -3314,6 +3347,14 @@ int playlist_resume(void)
}
break;
}
+ case PLAYLIST_COMMAND_FLAGS:
+ {
+ unsigned int setf = atoi(str1);
+ unsigned int clearf = atoi(str2);
+
+ playlist->flags = (playlist->flags & ~clearf) | setf;
+ break;
+ }
case PLAYLIST_COMMAND_COMMENT:
default:
break;
@@ -3364,6 +3405,9 @@ int playlist_resume(void)
case 'C':
current_command = PLAYLIST_COMMAND_CLEAR;
break;
+ case 'F':
+ current_command = PLAYLIST_COMMAND_FLAGS;
+ break;
case '#':
current_command = PLAYLIST_COMMAND_COMMENT;
break;
@@ -3462,7 +3506,6 @@ int playlist_resume(void)
}
out:
- playlist_set_modified(playlist, false);
playlist_write_unlock(playlist);
dc_thread_start(playlist, true);
@@ -3663,7 +3706,6 @@ int playlist_save(struct playlist_info* playlist, char *filename,
if (fd >= 0)
close(fd);
- playlist->modified = false;
cpu_boost(false);
return result;
@@ -3722,7 +3764,6 @@ int playlist_set_current(struct playlist_info* playlist)
current_playlist.amount = playlist->amount;
current_playlist.last_insert_pos = playlist->last_insert_pos;
current_playlist.seed = playlist->seed;
- current_playlist.modified = playlist->modified;
result = 0;
diff --git a/apps/playlist.h b/apps/playlist.h
index 6d86270bc4..4c8800e594 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -38,6 +38,9 @@
#define DEFAULT_DYNAMIC_PLAYLIST_NAME "/dynamic.m3u8"
+#define PLAYLIST_FLAG_MODIFIED (1u << 0) /* playlist was manually modified */
+#define PLAYLIST_FLAG_DIRPLAY (1u << 1) /* enable directory skipping */
+
enum playlist_command {
PLAYLIST_COMMAND_PLAYLIST,
PLAYLIST_COMMAND_ADD,
@@ -47,6 +50,7 @@ enum playlist_command {
PLAYLIST_COMMAND_UNSHUFFLE,
PLAYLIST_COMMAND_RESET,
PLAYLIST_COMMAND_CLEAR,
+ PLAYLIST_COMMAND_FLAGS,
PLAYLIST_COMMAND_COMMENT
};
@@ -64,8 +68,7 @@ struct playlist_info
{
bool utf8; /* playlist is in .m3u8 format */
bool control_created; /* has control file been created? */
- bool modified; /* has playlist been modified by the user? */
- bool dirplay; /* are we playing a directory directly? */
+ unsigned int flags; /* flags for misc. state */
int fd; /* descriptor of the open playlist file */
int control_fd; /* descriptor of the open control file */
int max_playlist_size; /* Max number of files in playlist. Mirror of
@@ -161,6 +164,7 @@ int playlist_randomise(struct playlist_info* playlist, unsigned int seed,
int playlist_sort(struct playlist_info* playlist, bool start_current);
bool playlist_modified(const struct playlist_info* playlist);
void playlist_set_modified(struct playlist_info* playlist, bool modified);
+bool playlist_allow_dirplay(const struct playlist_info* playlist);
int playlist_get_first_index(const struct playlist_info* playlist);
int playlist_get_seed(const struct playlist_info* playlist);
int playlist_amount_ex(const struct playlist_info* playlist);
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c
index 3d530e791a..d12aa26de4 100644
--- a/apps/playlist_viewer.c
+++ b/apps/playlist_viewer.c
@@ -802,15 +802,23 @@ static bool update_viewer_with_changes(struct gui_synclist *playlist_lists, enum
if (res == PV_ONPLAY_CHANGED ||
res == PV_ONPLAY_ITEM_REMOVED)
{
+ if (!viewer.playlist)
+ playlist_set_modified(NULL, true);
+
if (res == PV_ONPLAY_ITEM_REMOVED)
gui_synclist_del_item(playlist_lists);
+
update_playlist(true);
+
if (viewer.num_tracks <= 0)
exit = true;
+
if (viewer.selected_track >= viewer.num_tracks)
viewer.selected_track = viewer.num_tracks-1;
+
dirty = true;
}
+
/* the show_icons option in the playlist viewer settings
* menu might have changed */
update_lists(playlist_lists);
@@ -947,6 +955,10 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename,
splashf(HZ, (unsigned char *)"%s %s", str(LANG_MOVE),
str(LANG_FAILED));
}
+
+ if (!viewer.playlist)
+ playlist_set_modified(NULL, true);
+
update_playlist(true);
viewer.moving_track = -1;
viewer.moving_playlist_index = -1;
@@ -976,7 +988,6 @@ enum playlist_viewer_result playlist_viewer_ex(const char* filename,
if (global_settings.playlist_shuffle)
start_index = playlist_shuffle(current_tick, start_index);
playlist_start(start_index, 0, 0);
- playlist_set_modified(NULL, false);
if (viewer.initial_selection)
*(viewer.initial_selection) = viewer.selected_track;
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c
index c49d23dc49..1c380c7f28 100644
--- a/apps/plugins/pictureflow/pictureflow.c
+++ b/apps/plugins/pictureflow/pictureflow.c
@@ -4281,7 +4281,6 @@ static bool start_playback(bool return_to_WPS)
start_index = rb->playlist_shuffle(*rb->current_tick, pf_tracks.sel);
}
rb->playlist_start(start_index, 0, 0);
- rb->playlist_set_modified(NULL, false);
old_shuffle = shuffle;
#ifdef USEGSLIB
if (!return_to_WPS)
diff --git a/apps/tagtree.c b/apps/tagtree.c
index e715d4518b..78bf6bf255 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -2359,7 +2359,6 @@ static int tagtree_play_folder(struct tree_context* c)
}
playlist_start(start_index, 0, 0);
- playlist_set_modified(NULL, false);
return 0;
}
diff --git a/apps/tree.c b/apps/tree.c
index 2cbc8acf1d..8fa5f168fd 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -1106,7 +1106,6 @@ bool bookmark_play(char *resume_file, int index, unsigned long elapsed,
if (global_settings.playlist_shuffle)
playlist_shuffle(seed, -1);
- playlist_set_modified(NULL, false);
playlist_start(index, elapsed, offset);
started = true;
}
@@ -1159,7 +1158,6 @@ bool bookmark_play(char *resume_file, int index, unsigned long elapsed,
return false;
}
- playlist_set_modified(NULL, false);
playlist_start(index, elapsed, offset);
started = true;
}