1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Aidan MacDonald 2023-03-29 10:58:30 +01:00
parent 781f955aa2
commit 7ccbd705f4
8 changed files with 101 additions and 50 deletions

View file

@ -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;
}

View file

@ -358,6 +358,7 @@ static int add_to_playlist(void* arg)
onplay_result = ONPLAY_START_PLAY;
}
playlist_set_modified(NULL, true);
return false;
}

View file

@ -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)
{
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,7 +2959,7 @@ out:
bool playlist_next_dir(int direction)
{
/* not to mess up real playlists */
if(!current_playlist.dirplay)
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;

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}