From 7ccbd705f43553ff358d6713c8d6ac7cc9e3c343 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Wed, 29 Mar 2023 10:58:30 +0100 Subject: 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 --- apps/filetree.c | 2 - apps/onplay.c | 1 + apps/playlist.c | 123 ++++++++++++++++++++++----------- apps/playlist.h | 8 ++- apps/playlist_viewer.c | 13 +++- apps/plugins/pictureflow/pictureflow.c | 1 - apps/tagtree.c | 1 - apps/tree.c | 2 - 8 files changed, 101 insertions(+), 50 deletions(-) (limited to 'apps') 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:::) @@ -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 == ¤t_playlist) + playlist->flags |= PLAYLIST_FLAG_DIRPLAY; - /* only the current playlist can use dirplay */ - if (dirused && playlist == ¤t_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; iamount; 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 = ¤t_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 = ¤t_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 = ¤t_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 = ¤t_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(¤t_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; } -- cgit v1.2.3