Volume breaks output format, removed for now.
[shell-fm.git] / source / tag.c
blobd4d21654d36234d628da948c8e7f4856596366e2
1 /*
2 Copyright (C) 2006 by Jonas Kramer
3 Copyright (C) 2006 by Bart Trojanowski <bart@jukie.net>
5 Published under the terms of the GNU General Public License (GPLv2).
6 */
8 #define _GNU_SOURCE
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <assert.h>
17 #include "settings.h"
18 #include "http.h"
19 #include "split.h"
20 #include "interface.h"
21 #include "completion.h"
22 #include "md5.h"
23 #include "feeds.h"
25 #include "readline.h"
26 #include "tag.h"
27 #include "xmlrpc.h"
28 #include "util.h"
29 #include "globals.h"
31 char ** popular = NULL;
33 void tag(struct hash data) {
34 char key, * tagstring;
35 struct prompt setup = {
36 .prompt = "Tags (comma separated): ",
37 .line = NULL,
38 .history = NULL,
39 .callback = tagcomplete,
42 if(!data.content)
43 return;
45 fputs("Tag (a)rtist, a(l)bum, (t)rack or (c)ancel?\n", stderr);
47 while(!strchr("altc", (key = fetchkey(2))));
49 if(key == 'c')
50 return;
52 popular = merge(toptags(key, data), usertags(value(& rc, "username")), 0);
54 setup.line = oldtags(key, data);
56 assert((tagstring = strdup(readline(& setup))) != NULL);
58 if(setup.line) {
59 free(setup.line);
60 setup.line = NULL;
63 purge(popular);
64 popular = NULL;
66 sendtag(key, tagstring, data);
67 free(tagstring);
71 char * oldtags(char key, struct hash track) {
72 unsigned length, x;
73 char * tags = NULL, * url = calloc(512, sizeof(char)),
74 * user = NULL, * artist = NULL, * arg = NULL,
75 * file = NULL, ** resp;
77 assert(url != NULL);
79 switch(key) {
80 case 'a':
81 file = "artisttags.xml";
82 break;
83 case 'l':
84 file = "albumtags.xml";
85 break;
86 case 't':
87 default:
88 file = "tracktags.xml";
91 encode(value(& track, "creator"), & artist);
92 stripslashes(artist);
94 encode(value(& rc, "username"), & user);
96 length = snprintf(
97 url, 512, "http://ws.audioscrobbler.com/1.0/user/%s/%s?artist=%s",
98 user, file, artist);
100 free(user);
101 free(artist);
103 if(key == 'l') {
104 encode(value(& track, "album"), & arg);
105 /* don't request tags for a not-existing album */
106 if(!strlen(arg)) {
107 free(arg);
108 return NULL;
110 stripslashes(arg);
111 length += snprintf(url + length, 512 - length, "&album=%s", arg);
112 } else if(key == 't') {
113 encode(value(& track, "title"), & arg);
114 stripslashes(arg);
115 length += snprintf(url + length, 512 - length, "&track=%s", arg);
118 if(arg)
119 free(arg);
121 resp = fetch(url, NULL, NULL, NULL);
122 free(url);
124 if(!resp)
125 return NULL;
127 for(x = 0, length = 0; resp[x]; ++x) {
128 char * pbeg = strstr(resp[x], "<name>"), * pend;
129 if(pbeg) {
130 pbeg += 6;
131 pend = strstr(pbeg, "</name>");
132 if(pend) {
133 char * thistag = strndup(pbeg, pend - pbeg);
134 unsigned nlength = strlen(thistag) + length;
136 assert(thistag != NULL);
138 if(length)
139 ++nlength;
141 tags = realloc(tags, nlength + 1);
143 assert(tags != NULL);
145 sprintf(tags + length, "%s%s", length ? "," : "", thistag);
147 free(thistag);
148 length = nlength;
153 purge(resp);
155 return tags;
159 void stripslashes(char * string) {
160 unsigned x = 0;
161 while(x < strlen(string)) {
162 if(string[x] == 0x2F)
163 strncpy(string + x, string + x + 1, strlen(string + x + 1));
164 else
165 ++x;
170 int tagcomplete(char * line, const unsigned max, int changed) {
171 unsigned length, nres = 0;
172 int retval = 0;
173 char * ptr = NULL;
174 const char * match = NULL;
176 assert(line != NULL);
178 length = strlen(line);
180 /* Remove spaces at the beginning of the string. */
181 while(isspace(line[0])) {
182 retval = !0;
183 memmove(line, line + 1, strlen(line + 1));
184 line[--length] = 0;
187 /* Remove spaces at the end of the string. */
188 while((length = strlen(line)) > 0 && isspace(line[length - 1])) {
189 retval = !0;
190 line[--length] = 0;
193 /* No need for tab completion if there are no popular tags. */
194 if(!popular || !popular[0])
195 return retval;
197 /* Get pointer to the beginning of the last tag in tag string. */
198 if((ptr = strrchr(line, ',')) == NULL)
199 ptr = line;
200 else
201 ++ptr;
203 length = strlen(ptr);
204 if(!length)
205 changed = !0;
207 /* Get next match in list of popular tags. */
208 if((match = nextmatch(popular, changed ? ptr : NULL, & nres)) != NULL) {
209 snprintf(ptr, max - (ptr - line) - 1, "%s%s", match, nres < 2 ? "," : "");
210 retval = !0;
213 return retval;
217 void sendtag(char key, char * tagstring, struct hash data) {
218 unsigned nsplt = 0;
219 int result = 0;
220 char ** splt = NULL;
222 if(tagstring) {
223 unsigned length = strlen(tagstring);
224 /* remove trailing commas */
225 while(tagstring[length-1] == ',')
226 tagstring[--length] = 0;
228 splt = split(tagstring, ",\n", & nsplt);
231 switch(key) {
232 case 'a':
233 result =
234 xmlrpc("tagArtist", "sas", value(& data, "creator"), splt, "set");
235 break;
237 case 'l':
238 result = xmlrpc(
239 "tagAlbum", "ssas",
240 value(& data, "creator"),
241 value(& data, "album"),
242 splt, "set"
244 break;
246 case 't':
247 result = xmlrpc(
248 "tagTrack", "ssas",
249 value(& data, "creator"),
250 value(& data, "title"),
251 splt, "set"
253 break;
256 if(!enabled(QUIET))
257 puts(result ? "Tagged." : "Sorry, failed.");
259 purge(splt);
260 splt = NULL;