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:
parent
781f955aa2
commit
7ccbd705f4
8 changed files with 101 additions and 50 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -358,6 +358,7 @@ static int add_to_playlist(void* arg)
|
|||
onplay_result = ONPLAY_START_PLAY;
|
||||
}
|
||||
|
||||
playlist_set_modified(NULL, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
123
apps/playlist.c
123
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 == ¤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; 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 = ¤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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue