diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 08a6a54e3b..e329056add 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -16849,6 +16849,20 @@ *: "View Album Art" + + id: LANG_TAGNAVI_ALL_TRACKS_SORTED_BY_ALBUM + desc: "[By album]" entry in tag browser + user: core + + *: "[By album]" + + + *: "[By album]" + + + *: "All tracks sorted by album" + + id: LANG_HP_LO_SELECT desc: Output Select diff --git a/apps/lang/francais.lang b/apps/lang/francais.lang index abfb2a6a37..f7419d8d7a 100644 --- a/apps/lang/francais.lang +++ b/apps/lang/francais.lang @@ -2194,6 +2194,20 @@ *: "Toutes les pistes" + + id: LANG_TAGNAVI_ALL_TRACKS_SORTED_BY_ALBUM + desc: "[By album]" entry in tag browser + user: core + + *: "[By album]" + + + *: "[Par album]" + + + *: "Toutes les pistes triƩes par album" + + id: LANG_DISPLAY desc: in settings_menu() diff --git a/apps/tagtree.c b/apps/tagtree.c index 48176251a0..75752e20a9 100644 --- a/apps/tagtree.c +++ b/apps/tagtree.c @@ -80,6 +80,7 @@ struct tagentry { int newtable; int extraseek; int customaction; + char* album_name; }; static struct tagentry* tagtree_get_entry(struct tree_context *c, int id); @@ -90,6 +91,7 @@ enum table { TABLE_ROOT = 1, TABLE_NAVIBROWSE, TABLE_ALLSUBENTRIES, + TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS, TABLE_PLAYTRACK, }; @@ -913,6 +915,21 @@ static int compare(const void *p1, const void *p2) return qsort_fn(e1->name, e2->name, MAX_PATH); } +static int compare_with_albums(const void *p1, const void *p2) +{ + struct tagentry *e1 = (struct tagentry *)p1; + struct tagentry *e2 = (struct tagentry *)p2; + int sort_album_res = qsort_fn( + e1->album_name == NULL ? "" : e1->album_name, + e2->album_name == NULL ? "" : e2->album_name, MAX_PATH); + if (sort_album_res != 0) + { + /* If album name is different */ + return sort_album_res; + } + return qsort_fn(e1->name, e2->name, MAX_PATH); +} + static void tagtree_buffer_event(unsigned short id, void *ev_data) { (void)id; @@ -1597,7 +1614,7 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) #endif , 0, 0, 0); - if (c->currtable == TABLE_ALLSUBENTRIES) + if (c->currtable == TABLE_ALLSUBENTRIES || c->currtable == TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS) { tag = tag_title; level--; @@ -1661,8 +1678,17 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) fmt = NULL; for (i = 0; i < format_count; i++) { - if (formats[i]->group_id == csi->format_id[level]) - fmt = formats[i]; + if (c->currtable == TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS) + { + /* If it is sorted by albums, we need to use the proper view + that includes the disc number etc so sorting will be correct for each albums. + Otherwise, tracks will be sorted by title names */ + if (formats[i]->group_id != csi->format_id[level + 1]) + continue; + } + else if (formats[i]->group_id != csi->format_id[level]) + continue; + fmt = formats[i]; } if (fmt) @@ -1685,16 +1711,29 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) if (tag != tag_title && tag != tag_filename) { - if (offset == 0) + bool show_album_sorted = (tag == tag_album); + int show_album_sorted_offset = (show_album_sorted ? 1 : 0); + if (offset == 0 && show_album_sorted) { - dptr->newtable = TABLE_ALLSUBENTRIES; - dptr->name = ID2P(LANG_TAGNAVI_ALL_TRACKS); + dptr->newtable = TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS; + dptr->name = ID2P(LANG_TAGNAVI_ALL_TRACKS_SORTED_BY_ALBUM); + dptr->extraseek = 0; dptr->customaction = ONPLAY_NO_CUSTOMACTION; dptr++; current_entry_count++; c->special_entry_count++; } - if (offset <= 1) + if (offset <= (show_album_sorted_offset)) + { + dptr->newtable = TABLE_ALLSUBENTRIES; + dptr->name = ID2P(LANG_TAGNAVI_ALL_TRACKS); + dptr->extraseek = 0; + dptr->customaction = ONPLAY_NO_CUSTOMACTION; + dptr++; + current_entry_count++; + c->special_entry_count++; + } + if (offset <= (1 + show_album_sorted_offset)) { dptr->newtable = TABLE_NAVIBROWSE; dptr->name = ID2P(LANG_TAGNAVI_RANDOM); @@ -1706,6 +1745,8 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) } total_count += 2; + if (show_album_sorted) + total_count++; } while (tagcache_get_next(&tcs, tcs_buf, tcs_bufsz)) @@ -1727,7 +1768,15 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) /* Check the format */ for (i = 0; i < format_count; i++) { - if (formats[i]->group_id != csi->format_id[level]) + if (c->currtable == TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS) + { + /* If it is sorted by albums, we need to use the proper view + that includes the disc number etc so sorting will be correct for each albums. + Otherwise, tracks will be sorted by title names */ + if (formats[i]->group_id != csi->format_id[level + 1]) + continue; + } + else if (formats[i]->group_id != csi->format_id[level]) continue; if (tagcache_check_clauses(&tcs, formats[i]->clause, @@ -1744,13 +1793,22 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) { /* Fallback to basename */ char *lastname = dptr->name; dptr->name = core_get_data(c->cache.name_buffer_handle)+namebufused; - if (tagcache_retrieve(&tcs, tcs.idx_id, tag_virt_basename, dptr->name, + if ((c->cache.name_buffer_size - namebufused) > 0 && + tagcache_retrieve(&tcs, tcs.idx_id, tag_virt_basename, dptr->name, c->cache.name_buffer_size - namebufused)) { namebufused += strlen(dptr->name)+1; + dptr->album_name = core_get_data(c->cache.name_buffer_handle)+namebufused; + if ((c->cache.name_buffer_size - namebufused) > 0 && + tagcache_retrieve(&tcs, tcs.idx_id, tag_album, dptr->album_name, + c->cache.name_buffer_size - namebufused)) + namebufused += strlen(dptr->album_name)+1; + else + dptr->album_name = NULL; goto entry_skip_formatter; } dptr->name = lastname; /* restore last entry if filename failed */ + dptr->album_name = NULL; } tcs.result = str(LANG_TAGNAVI_UNTAGGED); @@ -1760,25 +1818,33 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) if (!tcs.ramresult || fmt) { + dptr->name = core_get_data(c->cache.name_buffer_handle)+namebufused; if (fmt) { int ret = format_str(&tcs, fmt, dptr->name, c->cache.name_buffer_size - namebufused); - if (ret >= 0) + bool error_on_str_format = ret < 0; + if (!error_on_str_format) { namebufused += strlen(dptr->name)+1; /* include NULL */ + dptr->album_name = core_get_data(c->cache.name_buffer_handle)+namebufused; + if ((c->cache.name_buffer_size - namebufused) > 0 && + tagcache_retrieve(&tcs, tcs.idx_id, tag_album, dptr->album_name, + c->cache.name_buffer_size - namebufused)) + namebufused += strlen(dptr->album_name)+1; + else + dptr->album_name = NULL; } else { - dptr->name[0] = '\0'; if (ret == -4) /* buffer full */ { logf("chunk mode #2: %d", current_entry_count); c->dirfull = true; sort = false; - break ; + break; } logf("format_str() failed"); @@ -1792,8 +1858,17 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) { tcs_get_basename(&tcs, is_basename); namebufused += tcs.result_len; - if (namebufused < c->cache.name_buffer_size) + bool buffer_full = (namebufused >= c->cache.name_buffer_size); + if (!buffer_full) + { + dptr->album_name = core_get_data(c->cache.name_buffer_handle)+namebufused; + if (tagcache_retrieve(&tcs, tcs.idx_id, tag_album, dptr->album_name, + c->cache.name_buffer_size - namebufused)) + namebufused += strlen(dptr->album_name)+1; + else + dptr->album_name = NULL; strcpy(dptr->name, tcs.result); + } else { logf("chunk mode #2a: %d", current_entry_count); @@ -1807,6 +1882,7 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init) { tcs_get_basename(&tcs, is_basename); dptr->name = tcs.result; + dptr->album_name = NULL; } entry_skip_formatter: dptr++; @@ -1843,7 +1919,8 @@ entry_skip_formatter: qsort(&entries[c->special_entry_count], current_entry_count - c->special_entry_count, sizeof(struct tagentry), - compare); + c->currtable == TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS ? compare_with_albums : compare + ); } if (!init) @@ -1985,6 +2062,7 @@ int tagtree_load(struct tree_context* c) break; case TABLE_ALLSUBENTRIES: + case TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS: case TABLE_NAVIBROWSE: logf("navibrowse..."); @@ -2060,10 +2138,10 @@ int tagtree_enter(struct tree_context* c, bool is_visible) if (seek == -1) /* menu item was selected */ { is_random_item = true; - if(c->filesindir<=2) /* Menu contains only and menu items */ + if(c->filesindir<=c->special_entry_count) /* Menu contains only special entries */ return 0; srand(current_tick); - dptr = (tagtree_get_entry(c, 2+(rand() % (c->filesindir-2)))); + dptr = (tagtree_get_entry(c, c->special_entry_count+(rand() % (c->filesindir-c->special_entry_count)))); seek = dptr->extraseek; } newextra = dptr->newtable; @@ -2195,6 +2273,7 @@ int tagtree_enter(struct tree_context* c, bool is_visible) case TABLE_NAVIBROWSE: case TABLE_ALLSUBENTRIES: + case TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS: if (newextra == TABLE_PLAYTRACK) { adjust_selection = false; @@ -2504,7 +2583,8 @@ static bool insert_all_playlist(struct tree_context *c, static bool goto_allsubentries(int newtable) { int i = 0; - while (i < 2 && (newtable == TABLE_NAVIBROWSE || newtable == TABLE_ALLSUBENTRIES)) + while (i < 2 && (newtable == TABLE_NAVIBROWSE || newtable == TABLE_ALLSUBENTRIES + || newtable == TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS)) { tagtree_enter(tc, false); tagtree_load(tc); @@ -2746,6 +2826,7 @@ char *tagtree_get_title(struct tree_context* c) case TABLE_NAVIBROWSE: case TABLE_ALLSUBENTRIES: + case TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS: logf("%s (NAVI/ALLSUB) idx: %d %s", __func__, c->currextra, current_title[c->currextra]); return current_title[c->currextra]; @@ -2768,6 +2849,7 @@ int tagtree_get_attr(struct tree_context* c) break; case TABLE_ALLSUBENTRIES: + case TABLE_ALLSUBENTRIES_SORTED_BY_ALBUMS: attr = FILE_ATTR_AUDIO; break; diff --git a/apps/tree.h b/apps/tree.h index e111cf5a1e..70d013e945 100644 --- a/apps/tree.h +++ b/apps/tree.h @@ -35,6 +35,7 @@ struct entry { unsigned time_write; /* Last write time */ #ifdef HAVE_TAGCACHE int customaction; /* db use */ + char* album_name; /* db use */ #endif };