From f2356303d979e12c0c10ab589f42b0abbe0f2e10 Mon Sep 17 00:00:00 2001 From: Paul Sauro Date: Thu, 14 Nov 2024 20:12:39 +0100 Subject: [PATCH] [Tagtree] Add a new button to list automatically all tracks in all albums of the current view This feature allow easily to start playing all albums from an artist by following the albums tracks orders, just like the Stock OS does on the iPods when you try to listen to all songs from an artist. It is just a new opportunity, I did not touch the former "All tracks" button which sorts everything by title automatically since it is also very useful (and stock OS don't have this one, and sorting Alphabetically is very useful to listen to all versions of one track from an artist view). Change-Id: Icf2a29bffe49c4e72f9c81d9727310b84c1150e4 --- apps/lang/english.lang | 14 +++++ apps/lang/francais.lang | 14 +++++ apps/tagtree.c | 116 ++++++++++++++++++++++++++++++++++------ apps/tree.h | 1 + 4 files changed, 128 insertions(+), 17 deletions(-) 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 };