2 Copyright (C) 2006-2010 by Jonas Kramer.
3 Published under the terms of the GNU General Public License (GPL).
13 #include <sys/types.h>
21 #include "completion.h"
34 extern char ** popular
;
35 static int radiocomplete(char *, const unsigned, int);
37 static char ** users
= NULL
, ** artists
= NULL
, ** overall
= NULL
;
40 Prompt for a Last.FM radio station URI, providing kind of smart tab
41 completion and a history. No return value, playback of the URI is started
44 void radioprompt(const char * prompt
) {
45 char * url
, * decoded
= NULL
;
47 struct prompt setup
= {
50 .history
= uniq(slurp(rcpath("radio-history"))),
51 .callback
= radiocomplete
,
54 /* Get overall top tags. */
55 overall
= overalltags();
57 /* Get user, friends and neighbors. */
58 users
= neighbors(value(& rc
, "username"));
59 users
= merge(users
, friends(value(& rc
, "username")), 0);
60 users
= append(users
, value(& rc
, "username"));
62 /* Get top artists. */
63 artists
= topartists(value(& rc
, "username"));
66 url
= readline(& setup
);
68 /* Free everything. */
73 overall
= users
= artists
= NULL
;
78 decode(url
, & decoded
);
86 /* Callback for the radio prompt for smart completion of radio URIs. */
87 int radiocomplete(char * line
, const unsigned max
, int changed
) {
88 unsigned length
= strlen(line
), nsplt
= 0, slash
= 0, nres
= 0;
90 char ** splt
, * types
[] = {
99 /* Remove leading "lastfm://", if found. */
100 if(!strncasecmp(line
, "lastfm://", 9)) {
101 memmove(line
, line
+ 9, 9);
102 memset(line
+ 9, 0, max
- (length
-= 9));
105 if(length
> 0 && line
[length
- 1] == '/') {
110 splt
= split(line
, "/", & nsplt
);
117 switch(nsplt
+ (slash
? 1 : 0)) {
119 /* First level completions (user, usertags, artists, ...) */
122 /* Get next match from first level chunks and fill it in. */
123 if((match
= nextmatch(types
, changed
? splt
[0] : NULL
, & nres
)) != NULL
) {
124 snprintf(line
, max
, "%s%s", match
, nres
== 1 ? "/" : "");
129 /* Second level completions (user/$USER, globaltags/$TAG, ...) */
131 /* For URIs like "{user,usertags}/...". */
132 if(!strcmp(splt
[0], "user") || !strcmp(splt
[0], "usertags")) {
134 /* Get next match for 2nd level user chunk (user) and fill it in. */
135 match
= nextmatch(users
, changed
? (slash
? "" : splt
[1]) : NULL
, & nres
);
138 snprintf(line
, max
, "%s/%s%s", splt
[0], match
, nres
== 1 ? "/" : "");
141 /* For URIs like "artist/...". */
142 else if(!strcmp(splt
[0], "artist")) {
144 /* Get next artist match for 2nd level. */
145 match
= nextmatch(artists
, changed
? (slash
? "" : splt
[1]) : NULL
, & nres
);
148 snprintf(line
, max
, "%s/%s%s", splt
[0], match
, nres
== 1 ? "/" : "");
152 For URIs like "globaltags/...". Simply tag completion applied
155 else if(!strcmp(splt
[0], "globaltags")) {
156 char * lastchunk
= strrchr(line
, '/') + 1;
157 popular
= overalltags();
158 tagcomplete(lastchunk
, max
- (lastchunk
- line
), changed
);
163 /* Third level completions (artist/$ARTIST/fans, ...) */
165 /* "user/$USER/{personal,neighbors,loved,recommended,playlist}" */
166 if(!strcmp(splt
[0], "user")) {
176 /* Get next match for 3rd level chunk and fill it in. */
177 match
= nextmatch(radios
, changed
? (slash
? "" : splt
[2]) : NULL
, NULL
);
178 snprintf(line
, max
, "%s/%s/%s", splt
[0], splt
[1], match
? match
: splt
[2]);
181 /* "artist/$ARTIST/{fans,similarartists}" */
182 else if(!strcmp(splt
[0], "artist")) {
189 /* Get next match for 3rd level chunk. */
190 match
= nextmatch(radios
, changed
? (slash
? "" : splt
[2]) : NULL
, NULL
);
191 snprintf(line
, max
, "%s/%s/%s", splt
[0], splt
[1], match
? match
: splt
[2]);
194 /* Simple tag completion for "usertags" stations. */
195 else if(!strcmp(splt
[0], "usertags")) {
196 char * lastchunk
= strrchr(line
, '/') + 1;
198 popular
= overalltags();
199 tagcomplete(lastchunk
, max
- (lastchunk
- line
), changed
);