forked from len0rd/rockbox
Option to constrain get_next_dir() to directories below global_settings.start_directory.
When enabled, if the user has set "Start File Browser Here" (config.cfg: start directory) to anything other than root and "Auto-Change Directory" is set to "Yes" or "Random", the directory returned when an auto change is required will be constrained to the value of "start directory" or below. Change-Id: Iaab773868c4cab5a54f6ae67bdb22e84642a9e4b Reviewed-on: http://gerrit.rockbox.org/182 Reviewed-by: Nick Peskett <rockbox@peskett.co.uk> Tested-by: Nick Peskett <rockbox@peskett.co.uk>
This commit is contained in:
parent
69978d7046
commit
be10817e1c
10 changed files with 159 additions and 71 deletions
|
@ -12993,3 +12993,17 @@
|
||||||
*: "Restart Sleep Timer On Keypress"
|
*: "Restart Sleep Timer On Keypress"
|
||||||
</voice>
|
</voice>
|
||||||
</phrase>
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_CONSTRAIN_NEXT_FOLDER
|
||||||
|
desc: in settings_menu. Whether LANG_NEXT_FOLDER should be constrained to directories within LANG_SET_AS_START_DIR
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: "Constrain Auto-Change"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: "Constrain Auto-Change"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: "Constrain Auto-Change"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
|
|
@ -135,6 +135,8 @@ MENUITEM_SETTING(beep, &global_settings.beep ,NULL);
|
||||||
MENUITEM_SETTING(spdif_enable, &global_settings.spdif_enable, NULL);
|
MENUITEM_SETTING(spdif_enable, &global_settings.spdif_enable, NULL);
|
||||||
#endif
|
#endif
|
||||||
MENUITEM_SETTING(next_folder, &global_settings.next_folder, NULL);
|
MENUITEM_SETTING(next_folder, &global_settings.next_folder, NULL);
|
||||||
|
MENUITEM_SETTING(constrain_next_folder,
|
||||||
|
&global_settings.constrain_next_folder, NULL);
|
||||||
static int audioscrobbler_callback(int action,const struct menu_item_ex *this_item)
|
static int audioscrobbler_callback(int action,const struct menu_item_ex *this_item)
|
||||||
{
|
{
|
||||||
(void)this_item;
|
(void)this_item;
|
||||||
|
@ -205,7 +207,7 @@ MAKE_MENU(playback_settings,ID2P(LANG_PLAYBACK),0,
|
||||||
#ifdef HAVE_SPDIF_POWER
|
#ifdef HAVE_SPDIF_POWER
|
||||||
&spdif_enable,
|
&spdif_enable,
|
||||||
#endif
|
#endif
|
||||||
&next_folder, &audioscrobbler, &cuesheet
|
&next_folder, &constrain_next_folder, &audioscrobbler, &cuesheet
|
||||||
#ifdef HAVE_HEADPHONE_DETECTION
|
#ifdef HAVE_HEADPHONE_DETECTION
|
||||||
,&unplug_menu
|
,&unplug_menu
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2644,8 +2644,17 @@ static void audio_on_skip(void)
|
||||||
skip_pending = TRACK_SKIP_NONE;
|
skip_pending = TRACK_SKIP_NONE;
|
||||||
|
|
||||||
/* Update the playlist current track now */
|
/* Update the playlist current track now */
|
||||||
while (playlist_next(playlist_delta) < 0)
|
int pl_retval;
|
||||||
|
while ((pl_retval = playlist_next(playlist_delta)) < 0)
|
||||||
{
|
{
|
||||||
|
if (pl_retval < -1)
|
||||||
|
{
|
||||||
|
/* Some variety of fatal error while updating playlist */
|
||||||
|
filling = STATE_ENDED;
|
||||||
|
audio_stop_playback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Manual skip out of range (because the playlist wasn't updated
|
/* Manual skip out of range (because the playlist wasn't updated
|
||||||
yet by us and so the check in audio_skip returned 'ok') - bring
|
yet by us and so the check in audio_skip returned 'ok') - bring
|
||||||
back into range */
|
back into range */
|
||||||
|
|
107
apps/playlist.c
107
apps/playlist.c
|
@ -175,7 +175,7 @@ static int compare(const void* p1, const void* p2);
|
||||||
static int get_filename(struct playlist_info* playlist, int index, int seek,
|
static int get_filename(struct playlist_info* playlist, int index, int seek,
|
||||||
bool control_file, char *buf, int buf_length);
|
bool control_file, char *buf, int buf_length);
|
||||||
static int get_next_directory(char *dir);
|
static int get_next_directory(char *dir);
|
||||||
static int get_next_dir(char *dir, bool is_forward, bool recursion);
|
static int get_next_dir(char *dir, bool is_forward);
|
||||||
static int get_previous_directory(char *dir);
|
static int get_previous_directory(char *dir);
|
||||||
static int check_subdir_for_music(char *dir, const char *subdir, bool recurse);
|
static int check_subdir_for_music(char *dir, const char *subdir, bool recurse);
|
||||||
static int format_track_path(char *dest, char *src, int buf_length, int max,
|
static int format_track_path(char *dest, char *src, int buf_length, int max,
|
||||||
|
@ -608,8 +608,10 @@ static int create_and_play_dir(int direction, bool play_last)
|
||||||
else
|
else
|
||||||
res = get_previous_directory(dir);
|
res = get_previous_directory(dir);
|
||||||
|
|
||||||
if (!res)
|
if (res < 0)
|
||||||
{
|
/* return the error encountered */
|
||||||
|
return res;
|
||||||
|
|
||||||
if (playlist_create(dir, NULL) != -1)
|
if (playlist_create(dir, NULL) != -1)
|
||||||
{
|
{
|
||||||
ft_build_playlist(tree_get_context(), 0);
|
ft_build_playlist(tree_get_context(), 0);
|
||||||
|
@ -632,7 +634,6 @@ static int create_and_play_dir(int direction, bool play_last)
|
||||||
/* we've overwritten the dircache when getting the next/previous dir,
|
/* we've overwritten the dircache when getting the next/previous dir,
|
||||||
so the tree browser context will need to be reloaded */
|
so the tree browser context will need to be reloaded */
|
||||||
reload_directory();
|
reload_directory();
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
@ -1435,18 +1436,18 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_next_directory(char *dir){
|
static int get_next_directory(char *dir){
|
||||||
return get_next_dir(dir,true,false);
|
return get_next_dir(dir, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_previous_directory(char *dir){
|
static int get_previous_directory(char *dir){
|
||||||
return get_next_dir(dir,false,false);
|
return get_next_dir(dir, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* search through all the directories (starting with the current) to find
|
* search through all the directories (starting with the current) to find
|
||||||
* one that has tracks to play
|
* one that has tracks to play
|
||||||
*/
|
*/
|
||||||
static int get_next_dir(char *dir, bool is_forward, bool recursion)
|
static int get_next_dir(char *dir, bool is_forward)
|
||||||
{
|
{
|
||||||
struct playlist_info* playlist = ¤t_playlist;
|
struct playlist_info* playlist = ¤t_playlist;
|
||||||
int result = -1;
|
int result = -1;
|
||||||
|
@ -1454,6 +1455,27 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
|
||||||
bool exit = false;
|
bool exit = false;
|
||||||
struct tree_context* tc = tree_get_context();
|
struct tree_context* tc = tree_get_context();
|
||||||
int saved_dirfilter = *(tc->dirfilter);
|
int saved_dirfilter = *(tc->dirfilter);
|
||||||
|
unsigned int base_len;
|
||||||
|
|
||||||
|
if (global_settings.constrain_next_folder)
|
||||||
|
{
|
||||||
|
/* constrain results to directories below user's start directory */
|
||||||
|
strcpy(dir, global_settings.start_directory);
|
||||||
|
base_len = strlen(dir);
|
||||||
|
|
||||||
|
/* strip any trailing slash from base directory */
|
||||||
|
if (base_len > 0 && dir[base_len - 1] == '/')
|
||||||
|
{
|
||||||
|
base_len--;
|
||||||
|
dir[base_len] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* start from root directory */
|
||||||
|
dir[0] = '\0';
|
||||||
|
base_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* process random folder advance */
|
/* process random folder advance */
|
||||||
if (global_settings.next_folder == FOLDER_ADVANCE_RANDOM)
|
if (global_settings.next_folder == FOLDER_ADVANCE_RANDOM)
|
||||||
|
@ -1461,43 +1483,46 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
|
||||||
int fd = open(ROCKBOX_DIR "/folder_advance_list.dat", O_RDONLY);
|
int fd = open(ROCKBOX_DIR "/folder_advance_list.dat", O_RDONLY);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
{
|
{
|
||||||
char buffer[MAX_PATH];
|
|
||||||
int folder_count = 0;
|
int folder_count = 0;
|
||||||
|
read(fd,&folder_count,sizeof(int));
|
||||||
|
if (folder_count)
|
||||||
|
{
|
||||||
|
char buffer[MAX_PATH];
|
||||||
|
/* give up looking for a directory after we've had four
|
||||||
|
times as many tries as there are directories. */
|
||||||
|
unsigned long allowed_tries = folder_count * 4;
|
||||||
|
int i;
|
||||||
srand(current_tick);
|
srand(current_tick);
|
||||||
*(tc->dirfilter) = SHOW_MUSIC;
|
*(tc->dirfilter) = SHOW_MUSIC;
|
||||||
tc->sort_dir = global_settings.sort_dir;
|
tc->sort_dir = global_settings.sort_dir;
|
||||||
read(fd,&folder_count,sizeof(int));
|
while (!exit && allowed_tries--)
|
||||||
if (!folder_count)
|
|
||||||
exit = true;
|
|
||||||
while (!exit)
|
|
||||||
{
|
{
|
||||||
int i = rand()%folder_count;
|
i = rand() % folder_count;
|
||||||
lseek(fd,sizeof(int) + (MAX_PATH*i),SEEK_SET);
|
lseek(fd, sizeof(int) + (MAX_PATH * i), SEEK_SET);
|
||||||
read(fd,buffer,MAX_PATH);
|
read(fd, buffer, MAX_PATH);
|
||||||
if (check_subdir_for_music(buffer, "", false) ==0)
|
/* is the current dir within our base dir and has music? */
|
||||||
|
if ((base_len == 0 || !strncmp(buffer, dir, base_len))
|
||||||
|
&& check_subdir_for_music(buffer, "", false) == 0)
|
||||||
exit = true;
|
exit = true;
|
||||||
}
|
}
|
||||||
if (folder_count)
|
|
||||||
strcpy(dir,buffer);
|
|
||||||
close(fd);
|
close(fd);
|
||||||
*(tc->dirfilter) = saved_dirfilter;
|
*(tc->dirfilter) = saved_dirfilter;
|
||||||
tc->sort_dir = global_settings.sort_dir;
|
tc->sort_dir = global_settings.sort_dir;
|
||||||
reload_directory();
|
reload_directory();
|
||||||
|
if (exit)
|
||||||
|
{
|
||||||
|
strcpy(dir,buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not random folder advance (or random folder advance unavailable) */
|
|
||||||
if (recursion)
|
|
||||||
{
|
|
||||||
/* start with root */
|
|
||||||
dir[0] = '\0';
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
close(fd);
|
||||||
/* start with current directory */
|
|
||||||
strlcpy(dir, playlist->filename, playlist->dirlen);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the current file is within our base dir, use its dir instead */
|
||||||
|
if (base_len == 0 || !strncmp(playlist->filename, dir, base_len))
|
||||||
|
strlcpy(dir, playlist->filename, playlist->dirlen);
|
||||||
|
|
||||||
/* use the tree browser dircache to load files */
|
/* use the tree browser dircache to load files */
|
||||||
*(tc->dirfilter) = SHOW_ALL;
|
*(tc->dirfilter) = SHOW_ALL;
|
||||||
|
@ -1565,6 +1590,19 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
|
||||||
tree_unlock_cache(tc);
|
tree_unlock_cache(tc);
|
||||||
|
|
||||||
if (!exit)
|
if (!exit)
|
||||||
|
{
|
||||||
|
/* we've already descended to the base dir with nothing found,
|
||||||
|
check whether that contains music */
|
||||||
|
if (strlen(dir) <= base_len)
|
||||||
|
{
|
||||||
|
result = check_subdir_for_music(dir, "", true);
|
||||||
|
if (result == -1)
|
||||||
|
/* there's no music files in the base directory,
|
||||||
|
treat as a fatal error */
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* move down to parent directory. current directory name is
|
/* move down to parent directory. current directory name is
|
||||||
stored as the starting point for the search in parent */
|
stored as the starting point for the search in parent */
|
||||||
|
@ -1578,16 +1616,12 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* restore dirfilter */
|
/* restore dirfilter */
|
||||||
*(tc->dirfilter) = saved_dirfilter;
|
*(tc->dirfilter) = saved_dirfilter;
|
||||||
tc->sort_dir = global_settings.sort_dir;
|
tc->sort_dir = global_settings.sort_dir;
|
||||||
|
|
||||||
/* special case if nothing found: try start searching again from root */
|
|
||||||
if (result == -1 && !recursion){
|
|
||||||
result = get_next_dir(dir, is_forward, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1606,7 +1640,12 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
|
||||||
bool has_subdir = false;
|
bool has_subdir = false;
|
||||||
struct tree_context* tc = tree_get_context();
|
struct tree_context* tc = tree_get_context();
|
||||||
|
|
||||||
snprintf(dir+dirlen, MAX_PATH-dirlen, "/%s", subdir);
|
snprintf(
|
||||||
|
dir + dirlen, MAX_PATH - dirlen,
|
||||||
|
/* only add a trailing slash if we need one */
|
||||||
|
dirlen && dir[dirlen - 1] == '/' ? "%s" : "/%s",
|
||||||
|
subdir
|
||||||
|
);
|
||||||
|
|
||||||
if (ft_load(tc, dir) < 0)
|
if (ft_load(tc, dir) < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,8 +65,15 @@ static void traversedir(char* location, char* name)
|
||||||
bool check = false;
|
bool check = false;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* behave differently if we're at root to avoid
|
||||||
|
duplication of the initial slash later on */
|
||||||
|
if (location[0] == '\0' && name[0] == '\0') {
|
||||||
|
rb->strcpy(fullpath, "");
|
||||||
|
dir = rb->opendir("/");
|
||||||
|
} else {
|
||||||
rb->snprintf(fullpath, sizeof(fullpath), "%s/%s", location, name);
|
rb->snprintf(fullpath, sizeof(fullpath), "%s/%s", location, name);
|
||||||
dir = rb->opendir(fullpath);
|
dir = rb->opendir(fullpath);
|
||||||
|
}
|
||||||
if (dir) {
|
if (dir) {
|
||||||
entry = rb->readdir(dir);
|
entry = rb->readdir(dir);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
|
|
|
@ -590,6 +590,8 @@ struct user_settings
|
||||||
/* playlist/playback settings */
|
/* playlist/playback settings */
|
||||||
int repeat_mode; /* 0=off 1=repeat all 2=repeat one 3=shuffle 4=ab */
|
int repeat_mode; /* 0=off 1=repeat all 2=repeat one 3=shuffle 4=ab */
|
||||||
int next_folder; /* move to next folder */
|
int next_folder; /* move to next folder */
|
||||||
|
bool constrain_next_folder; /* whether next_folder is constrained to
|
||||||
|
directories within start_directory */
|
||||||
int recursive_dir_insert; /* should directories be inserted recursively */
|
int recursive_dir_insert; /* should directories be inserted recursively */
|
||||||
bool fade_on_stop; /* fade on pause/unpause/stop */
|
bool fade_on_stop; /* fade on pause/unpause/stop */
|
||||||
bool playlist_shuffle;
|
bool playlist_shuffle;
|
||||||
|
|
|
@ -1328,6 +1328,9 @@ const struct settings_list settings[] = {
|
||||||
"folder navigation", "off,on,random",NULL ,3,
|
"folder navigation", "off,on,random",NULL ,3,
|
||||||
ID2P(LANG_SET_BOOL_NO), ID2P(LANG_SET_BOOL_YES),
|
ID2P(LANG_SET_BOOL_NO), ID2P(LANG_SET_BOOL_YES),
|
||||||
ID2P(LANG_RANDOM)),
|
ID2P(LANG_RANDOM)),
|
||||||
|
BOOL_SETTING(0, constrain_next_folder, LANG_CONSTRAIN_NEXT_FOLDER, false,
|
||||||
|
"constrain next folder", off_on,
|
||||||
|
LANG_SET_BOOL_YES, LANG_SET_BOOL_NO, NULL),
|
||||||
|
|
||||||
#ifdef HAVE_TAGCACHE
|
#ifdef HAVE_TAGCACHE
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
|
|
|
@ -145,6 +145,7 @@
|
||||||
cuesheet support
|
cuesheet support
|
||||||
& on, off & N/A\\
|
& on, off & N/A\\
|
||||||
folder navigation & off, on, random & N/A\\
|
folder navigation & off, on, random & N/A\\
|
||||||
|
constrain next folder & off, on & N/A\\
|
||||||
gather runtime data & off, on & N/A\\
|
gather runtime data & off, on & N/A\\
|
||||||
\opt{usb_charging_enable}{
|
\opt{usb_charging_enable}{
|
||||||
usb charging & on, off, force & N/A\\
|
usb charging & on, off, force & N/A\\
|
||||||
|
|
|
@ -221,8 +221,15 @@ you to configure settings related to audio playback.
|
||||||
|
|
||||||
\note{This feature only works when songs have been played from the file
|
\note{This feature only works when songs have been played from the file
|
||||||
browser. Using it with the database may cause unexpected behaviour.}
|
browser. Using it with the database may cause unexpected behaviour.}
|
||||||
|
|
||||||
%
|
%
|
||||||
|
|
||||||
|
\section{\label{ref:ConstrainAutoChange}Constrain Auto-Change}
|
||||||
|
If enabled and you have set \setting{Start File Browser Here} to a directory
|
||||||
|
other than root, \setting{Auto-Change Directory} will be constrained to the
|
||||||
|
directory you have chosen and those below it.
|
||||||
|
See \reference{ref:StartFileBrowserHere}.
|
||||||
|
%
|
||||||
|
|
||||||
\opt{headphone_detection}{
|
\opt{headphone_detection}{
|
||||||
\section{Pause on Headphone Unplug}
|
\section{Pause on Headphone Unplug}
|
||||||
Enables and disables automatic pausing of
|
Enables and disables automatic pausing of
|
||||||
|
|
|
@ -188,9 +188,13 @@ each option pertains both to files and directories):
|
||||||
\item [Set As Recording Directory.]
|
\item [Set As Recording Directory.]
|
||||||
Save recordings in the selected directory.
|
Save recordings in the selected directory.
|
||||||
}
|
}
|
||||||
\item [Start File Browser Here.]
|
\item [\label{ref:StartFileBrowserHere}Start File Browser Here.]
|
||||||
This option allows users to set the currently selected directory as the default
|
This option allows users to set the currently selected directory as the default
|
||||||
start directory for the file browser. This option is not available for files.
|
start directory for the file browser. This option is not available for files.
|
||||||
|
\note{If you have \setting{Auto-Change Directory} and
|
||||||
|
\setting{Constrain Auto-Change} enabled, the directories returned will
|
||||||
|
be constrained to the directory you have chosen here and those below it.
|
||||||
|
See \reference{ref:ConstrainAutoChange}}
|
||||||
\item [Add to Shortcuts.]
|
\item [Add to Shortcuts.]
|
||||||
Adds a link to the selected item in the \fname{shortcuts.link} file.
|
Adds a link to the selected item in the \fname{shortcuts.link} file.
|
||||||
If the file does not already exist it will be created in the root directory.
|
If the file does not already exist it will be created in the root directory.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue