summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/lang/english.lang14
-rw-r--r--apps/menus/playback_menu.c4
-rw-r--r--apps/playback.c11
-rw-r--r--apps/playlist.c167
-rw-r--r--apps/plugins/random_folder_advance_config.c11
-rw-r--r--apps/settings.h2
-rw-r--r--apps/settings_list.c3
-rw-r--r--manual/appendix/config_file_options.tex1
-rw-r--r--manual/configure_rockbox/playback_options.tex7
-rw-r--r--manual/rockbox_interface/browsing_and_playing.tex6
10 files changed, 157 insertions, 69 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 627fda8b12..d428bee232 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -12993,3 +12993,17 @@
12993 *: "Restart Sleep Timer On Keypress" 12993 *: "Restart Sleep Timer On Keypress"
12994 </voice> 12994 </voice>
12995</phrase> 12995</phrase>
12996<phrase>
12997 id: LANG_CONSTRAIN_NEXT_FOLDER
12998 desc: in settings_menu. Whether LANG_NEXT_FOLDER should be constrained to directories within LANG_SET_AS_START_DIR
12999 user: core
13000 <source>
13001 *: "Constrain Auto-Change"
13002 </source>
13003 <dest>
13004 *: "Constrain Auto-Change"
13005 </dest>
13006 <voice>
13007 *: "Constrain Auto-Change"
13008 </voice>
13009</phrase>
diff --git a/apps/menus/playback_menu.c b/apps/menus/playback_menu.c
index d5b20d09f5..17b7e57d32 100644
--- a/apps/menus/playback_menu.c
+++ b/apps/menus/playback_menu.c
@@ -135,6 +135,8 @@ MENUITEM_SETTING(beep, &global_settings.beep ,NULL);
135MENUITEM_SETTING(spdif_enable, &global_settings.spdif_enable, NULL); 135MENUITEM_SETTING(spdif_enable, &global_settings.spdif_enable, NULL);
136#endif 136#endif
137MENUITEM_SETTING(next_folder, &global_settings.next_folder, NULL); 137MENUITEM_SETTING(next_folder, &global_settings.next_folder, NULL);
138MENUITEM_SETTING(constrain_next_folder,
139 &global_settings.constrain_next_folder, NULL);
138static int audioscrobbler_callback(int action,const struct menu_item_ex *this_item) 140static int audioscrobbler_callback(int action,const struct menu_item_ex *this_item)
139{ 141{
140 (void)this_item; 142 (void)this_item;
@@ -205,7 +207,7 @@ MAKE_MENU(playback_settings,ID2P(LANG_PLAYBACK),0,
205#ifdef HAVE_SPDIF_POWER 207#ifdef HAVE_SPDIF_POWER
206 &spdif_enable, 208 &spdif_enable,
207#endif 209#endif
208 &next_folder, &audioscrobbler, &cuesheet 210 &next_folder, &constrain_next_folder, &audioscrobbler, &cuesheet
209#ifdef HAVE_HEADPHONE_DETECTION 211#ifdef HAVE_HEADPHONE_DETECTION
210 ,&unplug_menu 212 ,&unplug_menu
211#endif 213#endif
diff --git a/apps/playback.c b/apps/playback.c
index 8fe43eb884..28f664357c 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -2644,8 +2644,17 @@ static void audio_on_skip(void)
2644 skip_pending = TRACK_SKIP_NONE; 2644 skip_pending = TRACK_SKIP_NONE;
2645 2645
2646 /* Update the playlist current track now */ 2646 /* Update the playlist current track now */
2647 while (playlist_next(playlist_delta) < 0) 2647 int pl_retval;
2648 while ((pl_retval = playlist_next(playlist_delta)) < 0)
2648 { 2649 {
2650 if (pl_retval < -1)
2651 {
2652 /* Some variety of fatal error while updating playlist */
2653 filling = STATE_ENDED;
2654 audio_stop_playback();
2655 return;
2656 }
2657
2649 /* Manual skip out of range (because the playlist wasn't updated 2658 /* Manual skip out of range (because the playlist wasn't updated
2650 yet by us and so the check in audio_skip returned 'ok') - bring 2659 yet by us and so the check in audio_skip returned 'ok') - bring
2651 back into range */ 2660 back into range */
diff --git a/apps/playlist.c b/apps/playlist.c
index bf55671bf1..5b5f489cde 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -175,7 +175,7 @@ static int compare(const void* p1, const void* p2);
175static int get_filename(struct playlist_info* playlist, int index, int seek, 175static int get_filename(struct playlist_info* playlist, int index, int seek,
176 bool control_file, char *buf, int buf_length); 176 bool control_file, char *buf, int buf_length);
177static int get_next_directory(char *dir); 177static int get_next_directory(char *dir);
178static int get_next_dir(char *dir, bool is_forward, bool recursion); 178static int get_next_dir(char *dir, bool is_forward);
179static int get_previous_directory(char *dir); 179static int get_previous_directory(char *dir);
180static int check_subdir_for_music(char *dir, const char *subdir, bool recurse); 180static int check_subdir_for_music(char *dir, const char *subdir, bool recurse);
181static int format_track_path(char *dest, char *src, int buf_length, int max, 181static int format_track_path(char *dest, char *src, int buf_length, int max,
@@ -608,32 +608,33 @@ static int create_and_play_dir(int direction, bool play_last)
608 else 608 else
609 res = get_previous_directory(dir); 609 res = get_previous_directory(dir);
610 610
611 if (!res) 611 if (res < 0)
612 /* return the error encountered */
613 return res;
614
615 if (playlist_create(dir, NULL) != -1)
612 { 616 {
613 if (playlist_create(dir, NULL) != -1) 617 ft_build_playlist(tree_get_context(), 0);
614 {
615 ft_build_playlist(tree_get_context(), 0);
616 618
617 if (global_settings.playlist_shuffle) 619 if (global_settings.playlist_shuffle)
618 playlist_shuffle(current_tick, -1); 620 playlist_shuffle(current_tick, -1);
619 621
620 if (play_last && direction <= 0) 622 if (play_last && direction <= 0)
621 index = current_playlist.amount - 1; 623 index = current_playlist.amount - 1;
622 else 624 else
623 index = 0; 625 index = 0;
624 626
625#if (CONFIG_CODEC == SWCODEC) 627#if (CONFIG_CODEC == SWCODEC)
626 current_playlist.started = true; 628 current_playlist.started = true;
627#else 629#else
628 playlist_start(index, 0); 630 playlist_start(index, 0);
629#endif 631#endif
630 }
631
632 /* we've overwritten the dircache when getting the next/previous dir,
633 so the tree browser context will need to be reloaded */
634 reload_directory();
635 } 632 }
636 633
634 /* we've overwritten the dircache when getting the next/previous dir,
635 so the tree browser context will need to be reloaded */
636 reload_directory();
637
637 return index; 638 return index;
638} 639}
639 640
@@ -1435,18 +1436,18 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
1435} 1436}
1436 1437
1437static int get_next_directory(char *dir){ 1438static int get_next_directory(char *dir){
1438 return get_next_dir(dir,true,false); 1439 return get_next_dir(dir, true);
1439} 1440}
1440 1441
1441static int get_previous_directory(char *dir){ 1442static int get_previous_directory(char *dir){
1442 return get_next_dir(dir,false,false); 1443 return get_next_dir(dir, false);
1443} 1444}
1444 1445
1445/* 1446/*
1446 * search through all the directories (starting with the current) to find 1447 * search through all the directories (starting with the current) to find
1447 * one that has tracks to play 1448 * one that has tracks to play
1448 */ 1449 */
1449static int get_next_dir(char *dir, bool is_forward, bool recursion) 1450static int get_next_dir(char *dir, bool is_forward)
1450{ 1451{
1451 struct playlist_info* playlist = &current_playlist; 1452 struct playlist_info* playlist = &current_playlist;
1452 int result = -1; 1453 int result = -1;
@@ -1454,6 +1455,27 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
1454 bool exit = false; 1455 bool exit = false;
1455 struct tree_context* tc = tree_get_context(); 1456 struct tree_context* tc = tree_get_context();
1456 int saved_dirfilter = *(tc->dirfilter); 1457 int saved_dirfilter = *(tc->dirfilter);
1458 unsigned int base_len;
1459
1460 if (global_settings.constrain_next_folder)
1461 {
1462 /* constrain results to directories below user's start directory */
1463 strcpy(dir, global_settings.start_directory);
1464 base_len = strlen(dir);
1465
1466 /* strip any trailing slash from base directory */
1467 if (base_len > 0 && dir[base_len - 1] == '/')
1468 {
1469 base_len--;
1470 dir[base_len] = '\0';
1471 }
1472 }
1473 else
1474 {
1475 /* start from root directory */
1476 dir[0] = '\0';
1477 base_len = 0;
1478 }
1457 1479
1458 /* process random folder advance */ 1480 /* process random folder advance */
1459 if (global_settings.next_folder == FOLDER_ADVANCE_RANDOM) 1481 if (global_settings.next_folder == FOLDER_ADVANCE_RANDOM)
@@ -1461,43 +1483,46 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
1461 int fd = open(ROCKBOX_DIR "/folder_advance_list.dat", O_RDONLY); 1483 int fd = open(ROCKBOX_DIR "/folder_advance_list.dat", O_RDONLY);
1462 if (fd >= 0) 1484 if (fd >= 0)
1463 { 1485 {
1464 char buffer[MAX_PATH];
1465 int folder_count = 0; 1486 int folder_count = 0;
1466 srand(current_tick);
1467 *(tc->dirfilter) = SHOW_MUSIC;
1468 tc->sort_dir = global_settings.sort_dir;
1469 read(fd,&folder_count,sizeof(int)); 1487 read(fd,&folder_count,sizeof(int));
1470 if (!folder_count) 1488 if (folder_count)
1471 exit = true;
1472 while (!exit)
1473 { 1489 {
1474 int i = rand()%folder_count; 1490 char buffer[MAX_PATH];
1475 lseek(fd,sizeof(int) + (MAX_PATH*i),SEEK_SET); 1491 /* give up looking for a directory after we've had four
1476 read(fd,buffer,MAX_PATH); 1492 times as many tries as there are directories. */
1477 if (check_subdir_for_music(buffer, "", false) ==0) 1493 unsigned long allowed_tries = folder_count * 4;
1478 exit = true; 1494 int i;
1495 srand(current_tick);
1496 *(tc->dirfilter) = SHOW_MUSIC;
1497 tc->sort_dir = global_settings.sort_dir;
1498 while (!exit && allowed_tries--)
1499 {
1500 i = rand() % folder_count;
1501 lseek(fd, sizeof(int) + (MAX_PATH * i), SEEK_SET);
1502 read(fd, buffer, MAX_PATH);
1503 /* is the current dir within our base dir and has music? */
1504 if ((base_len == 0 || !strncmp(buffer, dir, base_len))
1505 && check_subdir_for_music(buffer, "", false) == 0)
1506 exit = true;
1507 }
1508 close(fd);
1509 *(tc->dirfilter) = saved_dirfilter;
1510 tc->sort_dir = global_settings.sort_dir;
1511 reload_directory();
1512 if (exit)
1513 {
1514 strcpy(dir,buffer);
1515 return 0;
1516 }
1479 } 1517 }
1480 if (folder_count) 1518 else
1481 strcpy(dir,buffer); 1519 close(fd);
1482 close(fd);
1483 *(tc->dirfilter) = saved_dirfilter;
1484 tc->sort_dir = global_settings.sort_dir;
1485 reload_directory();
1486 return 0;
1487 } 1520 }
1488 } 1521 }
1489 1522
1490 /* not random folder advance (or random folder advance unavailable) */ 1523 /* if the current file is within our base dir, use its dir instead */
1491 if (recursion) 1524 if (base_len == 0 || !strncmp(playlist->filename, dir, base_len))
1492 {
1493 /* start with root */
1494 dir[0] = '\0';
1495 }
1496 else
1497 {
1498 /* start with current directory */
1499 strlcpy(dir, playlist->filename, playlist->dirlen); 1525 strlcpy(dir, playlist->filename, playlist->dirlen);
1500 }
1501 1526
1502 /* use the tree browser dircache to load files */ 1527 /* use the tree browser dircache to load files */
1503 *(tc->dirfilter) = SHOW_ALL; 1528 *(tc->dirfilter) = SHOW_ALL;
@@ -1546,7 +1571,7 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
1546 exit = true; 1571 exit = true;
1547 break; 1572 break;
1548 } 1573 }
1549 1574
1550 if (files[i].attr & ATTR_DIRECTORY) 1575 if (files[i].attr & ATTR_DIRECTORY)
1551 { 1576 {
1552 if (!start_dir) 1577 if (!start_dir)
@@ -1566,16 +1591,30 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
1566 1591
1567 if (!exit) 1592 if (!exit)
1568 { 1593 {
1569 /* move down to parent directory. current directory name is 1594 /* we've already descended to the base dir with nothing found,
1570 stored as the starting point for the search in parent */ 1595 check whether that contains music */
1571 start_dir = strrchr(dir, '/'); 1596 if (strlen(dir) <= base_len)
1572 if (start_dir)
1573 { 1597 {
1574 *start_dir = '\0'; 1598 result = check_subdir_for_music(dir, "", true);
1575 start_dir++; 1599 if (result == -1)
1600 /* there's no music files in the base directory,
1601 treat as a fatal error */
1602 result = -2;
1603 break;
1576 } 1604 }
1577 else 1605 else
1578 break; 1606 {
1607 /* move down to parent directory. current directory name is
1608 stored as the starting point for the search in parent */
1609 start_dir = strrchr(dir, '/');
1610 if (start_dir)
1611 {
1612 *start_dir = '\0';
1613 start_dir++;
1614 }
1615 else
1616 break;
1617 }
1579 } 1618 }
1580 } 1619 }
1581 1620
@@ -1583,11 +1622,6 @@ static int get_next_dir(char *dir, bool is_forward, bool recursion)
1583 *(tc->dirfilter) = saved_dirfilter; 1622 *(tc->dirfilter) = saved_dirfilter;
1584 tc->sort_dir = global_settings.sort_dir; 1623 tc->sort_dir = global_settings.sort_dir;
1585 1624
1586 /* special case if nothing found: try start searching again from root */
1587 if (result == -1 && !recursion){
1588 result = get_next_dir(dir, is_forward, true);
1589 }
1590
1591 return result; 1625 return result;
1592} 1626}
1593 1627
@@ -1606,7 +1640,12 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
1606 bool has_subdir = false; 1640 bool has_subdir = false;
1607 struct tree_context* tc = tree_get_context(); 1641 struct tree_context* tc = tree_get_context();
1608 1642
1609 snprintf(dir+dirlen, MAX_PATH-dirlen, "/%s", subdir); 1643 snprintf(
1644 dir + dirlen, MAX_PATH - dirlen,
1645 /* only add a trailing slash if we need one */
1646 dirlen && dir[dirlen - 1] == '/' ? "%s" : "/%s",
1647 subdir
1648 );
1610 1649
1611 if (ft_load(tc, dir) < 0) 1650 if (ft_load(tc, dir) < 0)
1612 { 1651 {
diff --git a/apps/plugins/random_folder_advance_config.c b/apps/plugins/random_folder_advance_config.c
index f459aa0776..7f6018df4e 100644
--- a/apps/plugins/random_folder_advance_config.c
+++ b/apps/plugins/random_folder_advance_config.c
@@ -65,8 +65,15 @@ static void traversedir(char* location, char* name)
65 bool check = false; 65 bool check = false;
66 int i; 66 int i;
67 67
68 rb->snprintf(fullpath, sizeof(fullpath), "%s/%s", location, name); 68 /* behave differently if we're at root to avoid
69 dir = rb->opendir(fullpath); 69 duplication of the initial slash later on */
70 if (location[0] == '\0' && name[0] == '\0') {
71 rb->strcpy(fullpath, "");
72 dir = rb->opendir("/");
73 } else {
74 rb->snprintf(fullpath, sizeof(fullpath), "%s/%s", location, name);
75 dir = rb->opendir(fullpath);
76 }
70 if (dir) { 77 if (dir) {
71 entry = rb->readdir(dir); 78 entry = rb->readdir(dir);
72 while (entry) { 79 while (entry) {
diff --git a/apps/settings.h b/apps/settings.h
index 012e289d0c..777c7dbefe 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -590,6 +590,8 @@ struct user_settings
590 /* playlist/playback settings */ 590 /* playlist/playback settings */
591 int repeat_mode; /* 0=off 1=repeat all 2=repeat one 3=shuffle 4=ab */ 591 int repeat_mode; /* 0=off 1=repeat all 2=repeat one 3=shuffle 4=ab */
592 int next_folder; /* move to next folder */ 592 int next_folder; /* move to next folder */
593 bool constrain_next_folder; /* whether next_folder is constrained to
594 directories within start_directory */
593 int recursive_dir_insert; /* should directories be inserted recursively */ 595 int recursive_dir_insert; /* should directories be inserted recursively */
594 bool fade_on_stop; /* fade on pause/unpause/stop */ 596 bool fade_on_stop; /* fade on pause/unpause/stop */
595 bool playlist_shuffle; 597 bool playlist_shuffle;
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 2258582a78..5acebef2a5 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -1328,6 +1328,9 @@ const struct settings_list settings[] = {
1328 "folder navigation", "off,on,random",NULL ,3, 1328 "folder navigation", "off,on,random",NULL ,3,
1329 ID2P(LANG_SET_BOOL_NO), ID2P(LANG_SET_BOOL_YES), 1329 ID2P(LANG_SET_BOOL_NO), ID2P(LANG_SET_BOOL_YES),
1330 ID2P(LANG_RANDOM)), 1330 ID2P(LANG_RANDOM)),
1331 BOOL_SETTING(0, constrain_next_folder, LANG_CONSTRAIN_NEXT_FOLDER, false,
1332 "constrain next folder", off_on,
1333 LANG_SET_BOOL_YES, LANG_SET_BOOL_NO, NULL),
1331 1334
1332#ifdef HAVE_TAGCACHE 1335#ifdef HAVE_TAGCACHE
1333#if CONFIG_CODEC == SWCODEC 1336#if CONFIG_CODEC == SWCODEC
diff --git a/manual/appendix/config_file_options.tex b/manual/appendix/config_file_options.tex
index 3db416ecfa..59148e15cc 100644
--- a/manual/appendix/config_file_options.tex
+++ b/manual/appendix/config_file_options.tex
@@ -145,6 +145,7 @@
145 cuesheet support 145 cuesheet support
146 & on, off & N/A\\ 146 & on, off & N/A\\
147 folder navigation & off, on, random & N/A\\ 147 folder navigation & off, on, random & N/A\\
148 constrain next folder & off, on & N/A\\
148 gather runtime data & off, on & N/A\\ 149 gather runtime data & off, on & N/A\\
149 \opt{usb_charging_enable}{ 150 \opt{usb_charging_enable}{
150 usb charging & on, off, force & N/A\\ 151 usb charging & on, off, force & N/A\\
diff --git a/manual/configure_rockbox/playback_options.tex b/manual/configure_rockbox/playback_options.tex
index b3a5c82ee6..bfc2f5c87a 100644
--- a/manual/configure_rockbox/playback_options.tex
+++ b/manual/configure_rockbox/playback_options.tex
@@ -221,8 +221,15 @@ you to configure settings related to audio playback.
221 221
222 \note{This feature only works when songs have been played from the file 222 \note{This feature only works when songs have been played from the file
223 browser. Using it with the database may cause unexpected behaviour.} 223 browser. Using it with the database may cause unexpected behaviour.}
224 %
224 225
226\section{\label{ref:ConstrainAutoChange}Constrain Auto-Change}
227 If enabled and you have set \setting{Start File Browser Here} to a directory
228 other than root, \setting{Auto-Change Directory} will be constrained to the
229 directory you have chosen and those below it.
230 See \reference{ref:StartFileBrowserHere}.
225 % 231 %
232
226\opt{headphone_detection}{ 233\opt{headphone_detection}{
227\section{Pause on Headphone Unplug} 234\section{Pause on Headphone Unplug}
228 Enables and disables automatic pausing of 235 Enables and disables automatic pausing of
diff --git a/manual/rockbox_interface/browsing_and_playing.tex b/manual/rockbox_interface/browsing_and_playing.tex
index d0144c261d..37d8cb01ca 100644
--- a/manual/rockbox_interface/browsing_and_playing.tex
+++ b/manual/rockbox_interface/browsing_and_playing.tex
@@ -188,9 +188,13 @@ each option pertains both to files and directories):
188 \item [Set As Recording Directory.] 188 \item [Set As Recording Directory.]
189 Save recordings in the selected directory. 189 Save recordings in the selected directory.
190} 190}
191\item [Start File Browser Here.] 191\item [\label{ref:StartFileBrowserHere}Start File Browser Here.]
192 This option allows users to set the currently selected directory as the default 192 This option allows users to set the currently selected directory as the default
193 start directory for the file browser. This option is not available for files. 193 start directory for the file browser. This option is not available for files.
194 \note{If you have \setting{Auto-Change Directory} and
195 \setting{Constrain Auto-Change} enabled, the directories returned will
196 be constrained to the directory you have chosen here and those below it.
197 See \reference{ref:ConstrainAutoChange}}
194\item [Add to Shortcuts.] 198\item [Add to Shortcuts.]
195 Adds a link to the selected item in the \fname{shortcuts.link} file. 199 Adds a link to the selected item in the \fname{shortcuts.link} file.
196 If the file does not already exist it will be created in the root directory. 200 If the file does not already exist it will be created in the root directory.