A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Generate A-Z menus in the tagtree

this adds a new command %byfirstletter

%byfirstletter "custom_track" "Track A to Z" "title"
^ command ^menu name ^menu title ^subitem

need a better name for subitem btw..

this patch also allows us to tell when we are in the BFL menu
by checking customaction == ONPLAY_CUSTOMACTION_FIRSTLETTER
we then enable spelling of the letters in the menu
it spells Numeric too but that shouldn't matter with the upcoming voice patch

Change-Id: I59815f697a4ef84a8cb540783b620d15f6670e00

+93 -99
+1
apps/onplay.h
··· 28 28 enum { 29 29 ONPLAY_NO_CUSTOMACTION, 30 30 ONPLAY_CUSTOMACTION_SHUFFLE_SONGS, 31 + ONPLAY_CUSTOMACTION_FIRSTLETTER, 31 32 }; 32 33 33 34 int onplay(char* file, int attr, int from_context, bool hotkey, int customaction);
+5 -88
apps/tagnavi.config
··· 30 30 # 31 31 32 32 # Define the A to Z Artist sub menu 33 - %menu_start "custom_artist" "Artist A to Z" 34 - "Numeric" -> canonicalartist ? canonicalartist < "A" -> album -> title = "fmt_title" 35 - "A" -> canonicalartist ? canonicalartist ^ "A" -> album -> title = "fmt_title" 36 - "B" -> canonicalartist ? canonicalartist ^ "B" -> album -> title = "fmt_title" 37 - "C" -> canonicalartist ? canonicalartist ^ "C" -> album -> title = "fmt_title" 38 - "D" -> canonicalartist ? canonicalartist ^ "D" -> album -> title = "fmt_title" 39 - "E" -> canonicalartist ? canonicalartist ^ "E" -> album -> title = "fmt_title" 40 - "F" -> canonicalartist ? canonicalartist ^ "F" -> album -> title = "fmt_title" 41 - "G" -> canonicalartist ? canonicalartist ^ "G" -> album -> title = "fmt_title" 42 - "H" -> canonicalartist ? canonicalartist ^ "H" -> album -> title = "fmt_title" 43 - "I" -> canonicalartist ? canonicalartist ^ "I" -> album -> title = "fmt_title" 44 - "J" -> canonicalartist ? canonicalartist ^ "J" -> album -> title = "fmt_title" 45 - "K" -> canonicalartist ? canonicalartist ^ "K" -> album -> title = "fmt_title" 46 - "L" -> canonicalartist ? canonicalartist ^ "L" -> album -> title = "fmt_title" 47 - "M" -> canonicalartist ? canonicalartist ^ "M" -> album -> title = "fmt_title" 48 - "N" -> canonicalartist ? canonicalartist ^ "N" -> album -> title = "fmt_title" 49 - "O" -> canonicalartist ? canonicalartist ^ "O" -> album -> title = "fmt_title" 50 - "P" -> canonicalartist ? canonicalartist ^ "P" -> album -> title = "fmt_title" 51 - "Q" -> canonicalartist ? canonicalartist ^ "Q" -> album -> title = "fmt_title" 52 - "R" -> canonicalartist ? canonicalartist ^ "R" -> album -> title = "fmt_title" 53 - "S" -> canonicalartist ? canonicalartist ^ "S" -> album -> title = "fmt_title" 54 - "T" -> canonicalartist ? canonicalartist ^ "T" -> album -> title = "fmt_title" 55 - "U" -> canonicalartist ? canonicalartist ^ "U" -> album -> title = "fmt_title" 56 - "V" -> canonicalartist ? canonicalartist ^ "V" -> album -> title = "fmt_title" 57 - "W" -> canonicalartist ? canonicalartist ^ "W" -> album -> title = "fmt_title" 58 - "X" -> canonicalartist ? canonicalartist ^ "X" -> album -> title = "fmt_title" 59 - "Y" -> canonicalartist ? canonicalartist ^ "Y" -> album -> title = "fmt_title" 60 - "Z" -> canonicalartist ? canonicalartist ^ "Z" -> album -> title = "fmt_title" 33 + %byfirstletter "custom_artist" "Artist A to Z" "canonicalartist" 34 + # Define the A to Z album sub menu 35 + %byfirstletter "custom_album" "Album A to Z" "album" 36 + # Define the A to Z track sub menu 37 + %byfirstletter "custom_track" "Track A to Z" "title" 61 38 62 39 # ^ An empy line ends the menu 63 - 64 - # Define the A to Z album sub menu 65 - %menu_start "custom_album" "Album A to Z" 66 - "Numeric" -> album ? album < "A" -> title = "fmt_title" 67 - "A" -> album ? album ^ "A" -> title = "fmt_title" 68 - "B" -> album ? album ^ "B" -> title = "fmt_title" 69 - "C" -> album ? album ^ "C" -> title = "fmt_title" 70 - "D" -> album ? album ^ "D" -> title = "fmt_title" 71 - "E" -> album ? album ^ "E" -> title = "fmt_title" 72 - "F" -> album ? album ^ "F" -> title = "fmt_title" 73 - "G" -> album ? album ^ "G" -> title = "fmt_title" 74 - "H" -> album ? album ^ "H" -> title = "fmt_title" 75 - "I" -> album ? album ^ "I" -> title = "fmt_title" 76 - "J" -> album ? album ^ "J" -> title = "fmt_title" 77 - "K" -> album ? album ^ "K" -> title = "fmt_title" 78 - "L" -> album ? album ^ "L" -> title = "fmt_title" 79 - "M" -> album ? album ^ "M" -> title = "fmt_title" 80 - "N" -> album ? album ^ "N" -> title = "fmt_title" 81 - "O" -> album ? album ^ "O" -> title = "fmt_title" 82 - "P" -> album ? album ^ "P" -> title = "fmt_title" 83 - "Q" -> album ? album ^ "Q" -> title = "fmt_title" 84 - "R" -> album ? album ^ "R" -> title = "fmt_title" 85 - "S" -> album ? album ^ "S" -> title = "fmt_title" 86 - "T" -> album ? album ^ "T" -> title = "fmt_title" 87 - "U" -> album ? album ^ "U" -> title = "fmt_title" 88 - "V" -> album ? album ^ "V" -> title = "fmt_title" 89 - "W" -> album ? album ^ "W" -> title = "fmt_title" 90 - "X" -> album ? album ^ "X" -> title = "fmt_title" 91 - "Y" -> album ? album ^ "Y" -> title = "fmt_title" 92 - "Z" -> album ? album ^ "Z" -> title = "fmt_title" 93 - 94 - # Define the A to Z track sub menu 95 - %menu_start "custom_track" "Track A to Z" 96 - "Numeric" -> title ? title < "A" -> title = "fmt_title" 97 - "A" -> title ? title ^ "A" -> title = "fmt_title" 98 - "B" -> title ? title ^ "B" -> title = "fmt_title" 99 - "C" -> title ? title ^ "C" -> title = "fmt_title" 100 - "D" -> title ? title ^ "D" -> title = "fmt_title" 101 - "E" -> title ? title ^ "E" -> title = "fmt_title" 102 - "F" -> title ? title ^ "F" -> title = "fmt_title" 103 - "G" -> title ? title ^ "G" -> title = "fmt_title" 104 - "H" -> title ? title ^ "H" -> title = "fmt_title" 105 - "I" -> title ? title ^ "I" -> title = "fmt_title" 106 - "J" -> title ? title ^ "J" -> title = "fmt_title" 107 - "K" -> title ? title ^ "K" -> title = "fmt_title" 108 - "L" -> title ? title ^ "L" -> title = "fmt_title" 109 - "M" -> title ? title ^ "M" -> title = "fmt_title" 110 - "N" -> title ? title ^ "N" -> title = "fmt_title" 111 - "O" -> title ? title ^ "O" -> title = "fmt_title" 112 - "P" -> title ? title ^ "P" -> title = "fmt_title" 113 - "Q" -> title ? title ^ "Q" -> title = "fmt_title" 114 - "R" -> title ? title ^ "R" -> title = "fmt_title" 115 - "S" -> title ? title ^ "S" -> title = "fmt_title" 116 - "T" -> title ? title ^ "T" -> title = "fmt_title" 117 - "U" -> title ? title ^ "U" -> title = "fmt_title" 118 - "V" -> title ? title ^ "V" -> title = "fmt_title" 119 - "W" -> title ? title ^ "W" -> title = "fmt_title" 120 - "X" -> title ? title ^ "X" -> title = "fmt_title" 121 - "Y" -> title ? title ^ "Y" -> title = "fmt_title" 122 - "Z" -> title ? title ^ "Z" -> title = "fmt_title" 123 40 124 41 # Define the A to Z sub menu 125 42 %menu_start "a2z" "A to Z..."
+84 -10
apps/tagtree.c
··· 112 112 var_include, 113 113 var_rootmenu, 114 114 var_format, 115 + menu_byfirstletter, 115 116 menu_next, 116 117 menu_load, 117 118 menu_reload, ··· 173 174 static struct display_format *formats[TAGMENU_MAX_FMTS]; 174 175 static int format_count; 175 176 177 + #define MENUENTRY_MAX_NAME 64 176 178 struct menu_entry { 177 - char name[64]; 179 + char name[MENUENTRY_MAX_NAME]; 178 180 int type; 179 181 struct search_instruction { 180 - char name[64]; 182 + char name[MENUENTRY_MAX_NAME]; 181 183 int tagorder[MAX_TAGS]; 182 184 int tagorder_count; 183 185 struct tagcache_search_clause *clause[MAX_TAGS][TAGCACHE_MAX_CLAUSES]; ··· 381 383 TAG_MATCH("comment", tag_comment), 382 384 TAG_MATCH("discnum", tag_discnumber), 383 385 TAG_MATCH("%format", var_format), 386 + TAG_MATCH("%byfirstletter", menu_byfirstletter), 384 387 TAG_MATCH("%reload", menu_reload), 385 388 386 389 TAG_MATCH("filename", tag_filename), ··· 1058 1061 1059 1062 static bool parse_menu(const char *filename); 1060 1063 1064 + static bool alloc_menu_item(void) 1065 + { 1066 + /* Allocate */ 1067 + if (menu->items[menu->itemcount] == NULL) 1068 + menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry)); 1069 + if (!menu->items[menu->itemcount]) 1070 + { 1071 + logf("tagtree failed to allocate %s", "menu items"); 1072 + return false; 1073 + } 1074 + return true; 1075 + } 1076 + 1077 + static void firstletter_parse_buf(char *buf) 1078 + { 1079 + core_pin(tagtree_handle); 1080 + if (parse_search(menu->items[menu->itemcount], buf)) 1081 + { 1082 + menu->items[menu->itemcount]->type = menu_byfirstletter; 1083 + menu->itemcount++; 1084 + } 1085 + core_unpin(tagtree_handle);; 1086 + } 1087 + 1088 + static void build_firstletter_menu(char *buf, size_t bufsz) 1089 + { 1090 + const char *subitem = buf; 1091 + size_t l = strlen(buf) + 1; 1092 + buf+=l; 1093 + bufsz-=l; 1094 + 1095 + const char *showalbum = ""; 1096 + const char * const fmt ="\"%s\" -> %s ? %s %c \"%c\" -> %s title = \"fmt_title\""; 1097 + if (!alloc_menu_item()) 1098 + return; 1099 + 1100 + if (strcasestr(subitem, "artist") != NULL) 1101 + showalbum = "album ->"; /* album subitem for canonicalartist */ 1102 + 1103 + /* Numeric ex: "Numeric" -> album ? album < "A" -> title = "fmt_title" */ 1104 + snprintf(buf, bufsz, fmt, 1105 + str(LANG_DISPLAY_NUMERIC), subitem, subitem,'<', 'A', showalbum); 1106 + 1107 + firstletter_parse_buf(buf); 1108 + 1109 + for (int i = 0; i < 26; i++) 1110 + { 1111 + if (!alloc_menu_item()) 1112 + return; 1113 + 1114 + snprintf(buf, bufsz, fmt, "#", subitem, subitem,'^', 'A' + i, showalbum); 1115 + buf[1] = 'A' + i; /* overwrite the placeholder # with the current letter */ 1116 + /* ex: "A" -> title ? title ^ "A" -> title = "fmt_title" */ 1117 + firstletter_parse_buf(buf); 1118 + } 1119 + } 1120 + 1061 1121 static int parse_line(int n, char *buf, void *parameters) 1062 1122 { 1063 1123 char data[256]; ··· 1127 1187 logf("Load menu fail: %s", data); 1128 1188 } 1129 1189 break; 1130 - 1190 + case menu_byfirstletter: /* Fallthrough */ 1131 1191 case var_menu_start: 1132 1192 if (menu_count >= TAGMENU_MAX_MENUS) 1133 1193 { ··· 1169 1229 return 0; 1170 1230 } 1171 1231 logf("menu: %s", menu->title); 1232 + 1233 + if (variable == menu_byfirstletter) 1234 + { 1235 + if (get_token_str(data, sizeof(data)) < 0) 1236 + { 1237 + logf("%%firstletter_menu has no subitem"); /*artist,album*/ 1238 + return 0; 1239 + } 1240 + logf("A-Z Menu subitem: %s", data); 1241 + read_menu = false; 1242 + build_firstletter_menu(data, sizeof(data)); 1243 + break; 1244 + } 1172 1245 read_menu = true; 1173 1246 break; 1174 1247 ··· 1202 1275 return 0; 1203 1276 } 1204 1277 1205 - /* Allocate */ 1206 - if (menu->items[menu->itemcount] == NULL) 1207 - menu->items[menu->itemcount] = tagtree_alloc0(sizeof(struct menu_entry)); 1208 - if (!menu->items[menu->itemcount]) 1209 - { 1210 - logf("tagtree failed to allocate %s", "menu items"); 1278 + if (!alloc_menu_item()) 1211 1279 return -2; 1212 - } 1213 1280 core_pin(tagtree_handle); 1214 1281 if (parse_search(menu->items[menu->itemcount], buf)) 1215 1282 menu->itemcount++; ··· 1449 1516 1450 1517 static int retrieve_entries(struct tree_context *c, int offset, bool init) 1451 1518 { 1519 + logf( "%s", __func__); 1452 1520 char tcs_buf[TAGCACHE_BUFSZ]; 1453 1521 const long tcs_bufsz = sizeof(tcs_buf); 1454 1522 struct tagcache_search tcs; ··· 1817 1885 dptr->newtable = TABLE_NAVIBROWSE; 1818 1886 dptr->extraseek = i; 1819 1887 dptr->customaction = ONPLAY_CUSTOMACTION_SHUFFLE_SONGS; 1888 + break; 1889 + 1890 + case menu_byfirstletter: 1891 + dptr->newtable = TABLE_NAVIBROWSE; 1892 + dptr->extraseek = i; 1893 + dptr->customaction = ONPLAY_CUSTOMACTION_FIRSTLETTER; 1820 1894 break; 1821 1895 } 1822 1896
+3 -1
apps/tree.c
··· 205 205 struct tree_context * local_tc=(struct tree_context *)data; 206 206 char *name; 207 207 int attr=0; 208 + int customaction = ONPLAY_NO_CUSTOMACTION; 208 209 #ifdef HAVE_TAGCACHE 209 210 bool id3db = *(local_tc->dirfilter) == SHOW_ID3DB; 210 211 char buf[AVERAGE_FILENAME_LENGTH*2]; ··· 213 214 { 214 215 attr = tagtree_get_attr(local_tc); 215 216 name = tagtree_get_entry_name(local_tc, selected_item, buf, sizeof(buf)); 217 + customaction = tagtree_get_custom_action(local_tc); 216 218 } 217 219 else 218 220 #endif ··· 245 247 did_clip = false; 246 248 } 247 249 } 248 - bool spell_name = false; 250 + bool spell_name = (customaction == ONPLAY_CUSTOMACTION_FIRSTLETTER); 249 251 if(!did_clip) 250 252 { 251 253 /* say the number or spell if required or as a fallback */