1 /* -*- linux-c -*-
2 Copyright (C) 2007 Tom Szilagyi
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: metadata_api.c 1237 2012-02-04 10:30:17Z assworth $
19 */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "i18n.h"
28 #include "options.h"
29 #include "decoder/file_decoder.h"
30 #include "utils.h"
31 #include "metadata.h"
32 #include "volume.h"
33 #include "metadata_api.h"
34
35
36 extern options_t options;
37
38 /* get frame of given type, with preference between different tags.
39 preference order: MPEGSTREAM > GEN_STREAM > OXC > APE > ID3v2 > ID3v1 */
40 meta_frame_t *
metadata_pref_frame_by_type(metadata_t * meta,int type,meta_frame_t * root)41 metadata_pref_frame_by_type(metadata_t * meta, int type, meta_frame_t * root) {
42
43 meta_frame_t * frame;
44 static int tag;
45
46 if (root == NULL) {
47 tag = META_TAG_MAX;
48 }
49
50 while (tag > 0) {
51 frame = metadata_get_frame_by_tag_and_type(meta, tag, type, root);
52 if (frame) {
53 return frame;
54 }
55 tag >>= 1;
56 }
57
58 return NULL;
59 }
60
61
62 int
metadata_get_string_field(metadata_t * meta,int type,char ** str)63 metadata_get_string_field(metadata_t * meta, int type, char ** str) {
64
65 meta_frame_t * frame;
66
67 if (meta == NULL)
68 return 0;
69 frame = metadata_pref_frame_by_type(meta, type, NULL);
70 if (frame != NULL) {
71 *str = frame->field_val;
72 return 1;
73 } else {
74 return 0;
75 }
76
77 }
78
79 int
metadata_get_title(metadata_t * meta,char ** str)80 metadata_get_title(metadata_t * meta, char ** str) {
81
82 #ifdef HAVE_MOD
83 meta_frame_t * frame;
84 #endif /* HAVE_MOD */
85
86 if (meta == NULL)
87 return 0;
88
89 #ifdef HAVE_MOD
90 frame = metadata_get_frame_by_tag_and_type(meta, META_TAG_MODINFO, META_FIELD_MODINFO, NULL);
91 if (frame != NULL) {
92 mod_info * mi = (mod_info *)frame->data;
93 *str = mi->title;
94 return 1;
95 }
96 #endif /* HAVE_MOD */
97
98 return metadata_get_string_field(meta, META_FIELD_TITLE, str);
99 }
100
101
102 int
metadata_get_artist(metadata_t * meta,char ** str)103 metadata_get_artist(metadata_t * meta, char ** str) {
104 return metadata_get_string_field(meta, META_FIELD_ARTIST, str);
105 }
106
107
108 int
metadata_get_album(metadata_t * meta,char ** str)109 metadata_get_album(metadata_t * meta, char ** str) {
110 return metadata_get_string_field(meta, META_FIELD_ALBUM, str);
111 }
112
113
114 int
metadata_get_date(metadata_t * meta,char ** str)115 metadata_get_date(metadata_t * meta, char ** str) {
116 return metadata_get_string_field(meta, META_FIELD_DATE, str);
117 }
118
119
120 int
metadata_get_genre(metadata_t * meta,char ** str)121 metadata_get_genre(metadata_t * meta, char ** str) {
122 return metadata_get_string_field(meta, META_FIELD_GENRE, str);
123 }
124
125
126 int
metadata_get_comment(metadata_t * meta,char ** str)127 metadata_get_comment(metadata_t * meta, char ** str) {
128 return metadata_get_string_field(meta, META_FIELD_COMMENT, str);
129 }
130
131
132 int
metadata_get_icy_name(metadata_t * meta,char ** str)133 metadata_get_icy_name(metadata_t * meta, char ** str) {
134 return metadata_get_string_field(meta, META_FIELD_ICY_NAME, str);
135 }
136
137
138 int
metadata_get_icy_descr(metadata_t * meta,char ** str)139 metadata_get_icy_descr(metadata_t * meta, char ** str) {
140 return metadata_get_string_field(meta, META_FIELD_ICY_DESCR, str);
141 }
142
143
144 int
metadata_get_tracknum(metadata_t * meta,int * val)145 metadata_get_tracknum(metadata_t * meta, int * val) {
146
147 meta_frame_t * frame;
148
149 if (meta == NULL)
150 return 0;
151 frame = metadata_pref_frame_by_type(meta, META_FIELD_TRACKNO, NULL);
152 if (frame != NULL) {
153 *val = frame->int_val;
154 return 1;
155 } else {
156 return 0;
157 }
158 }
159
160
161 int
metadata_get_rva(metadata_t * meta,float * fval)162 metadata_get_rva(metadata_t * meta, float * fval) {
163
164 int rva_type;
165 meta_frame_t * frame;
166
167 if (meta == NULL)
168 return 0;
169
170 switch (options.replaygain_tag_to_use) {
171 case 0: rva_type = META_FIELD_RG_TRACK_GAIN;
172 break;
173 default: rva_type = META_FIELD_RG_ALBUM_GAIN;
174 break;
175 }
176
177 frame = metadata_pref_frame_by_type(meta, rva_type, NULL);
178 if (frame != NULL) {
179 *fval = rva_from_replaygain(frame->float_val);
180 return 1;
181 } else {
182 /* fallback on the other ReplayGain frame */
183 if (rva_type == META_FIELD_RG_TRACK_GAIN) {
184 rva_type = META_FIELD_RG_ALBUM_GAIN;
185 } else {
186 rva_type = META_FIELD_RG_TRACK_GAIN;
187 }
188 frame = metadata_pref_frame_by_type(meta, rva_type, NULL);
189 if (frame != NULL) {
190 *fval = rva_from_replaygain(frame->float_val);
191 return 1;
192 } else {
193 /* fallback on RVA frame */
194 frame = metadata_pref_frame_by_type(meta, META_FIELD_RVA2, NULL);
195 if (frame != NULL) {
196 *fval = frame->float_val;
197 return 1;
198 }
199 }
200 }
201 return 0;
202 }
203
204
205 void
meta_update_frame_data(meta_frame_t * frame,char * str,int val,float fval)206 meta_update_frame_data(meta_frame_t * frame, char * str, int val, float fval) {
207
208 if (META_FIELD_TEXT(frame->type)) {
209 if (frame->field_val != NULL) {
210 free(frame->field_val);
211 }
212 frame->field_val = strdup(str);
213 } else if (META_FIELD_INT(frame->type)) {
214 frame->int_val = val;
215 } else if (META_FIELD_FLOAT(frame->type)) {
216 frame->float_val = fval;
217 } else { /* no binary frames in update_basic mode */
218 fprintf(stderr, "meta_update_frame_data: programmer error\n");
219 }
220 }
221
222
223 void
meta_update_frame(metadata_t * meta,int add_tags,int type,char * str,int val,float fval)224 meta_update_frame(metadata_t * meta, int add_tags, int type,
225 char * str, int val, float fval) {
226
227 int tag = 1;
228 while (tag) {
229 meta_frame_t * frame;
230
231 if ((meta->valid_tags & tag) == 0) {
232 tag <<= 1;
233 continue;
234 }
235
236 frame = metadata_get_frame_by_tag_and_type(meta, tag, type, NULL);
237 if ((frame == NULL) && ((add_tags & tag) != 0)) {
238
239 char * s;
240 /* make sure frame type is available in this tag */
241 if (!meta_get_fieldname_embedded(tag, type, &s)) {
242 tag <<= 1;
243 continue;
244 }
245
246 /* add new frame */
247 frame = meta_frame_new();
248 if (frame == NULL) {
249 fprintf(stderr, "meta_update_frame: calloc error\n");
250 return;
251 }
252 frame->tag = tag;
253 frame->type = type;
254 frame->flags = meta_get_default_flags(tag, type);
255 meta_update_frame_data(frame, str, val, fval);
256 metadata_add_frame(meta, frame);
257 } else if (frame != NULL) {
258 meta_update_frame_data(frame, str, val, fval);
259 }
260 tag <<= 1;
261 }
262 }
263
264
265 int
meta_update_basic(char * filename,char * title,char * artist,char * album,char * comment,char * genre,char * date,int trackno)266 meta_update_basic(char * filename,
267 char * title, char * artist, char * album,
268 char * comment, char * genre, char * date, int trackno) {
269
270 file_decoder_t * fdec = file_decoder_new();
271 int add_tags;
272 int ret;
273
274 if (fdec == NULL) {
275 return META_ERROR_NOMEM;
276 }
277
278 if (file_decoder_open(fdec, filename) != 0) {
279 file_decoder_delete(fdec);
280 return META_ERROR_OPEN;
281 }
282
283 if (fdec->meta == NULL) {
284 file_decoder_close(fdec);
285 file_decoder_delete(fdec);
286 return META_ERROR_NO_METASUPPORT;
287 }
288
289 if (!fdec->meta->writable) {
290 file_decoder_close(fdec);
291 file_decoder_delete(fdec);
292 return META_ERROR_NOT_WRITABLE;
293 }
294
295 if (fdec->file_lib == MAD_LIB) {
296 add_tags = 0;
297 if (options.batch_mpeg_add_id3v1) {
298 add_tags |= META_TAG_ID3v1;
299 }
300 if (options.batch_mpeg_add_id3v2) {
301 add_tags |= META_TAG_ID3v2;
302 }
303 if (options.batch_mpeg_add_ape) {
304 add_tags |= META_TAG_APE;
305 }
306 } else {
307 add_tags = fdec->meta->valid_tags;
308 }
309
310 if (fdec->meta_write == NULL) {
311 file_decoder_close(fdec);
312 file_decoder_delete(fdec);
313 return META_ERROR_INTERNAL;
314 }
315
316 if (title != NULL && !is_all_wspace(title)) {
317 cut_trailing_whitespace(title);
318 meta_update_frame(fdec->meta, add_tags, META_FIELD_TITLE, title, 0, 0.0f);
319 }
320 if (artist != NULL && !is_all_wspace(artist)) {
321 cut_trailing_whitespace(artist);
322 meta_update_frame(fdec->meta, add_tags, META_FIELD_ARTIST, artist, 0, 0.0f);
323 }
324 if (album != NULL && !is_all_wspace(album)) {
325 cut_trailing_whitespace(album);
326 meta_update_frame(fdec->meta, add_tags, META_FIELD_ALBUM, album, 0, 0.0f);
327 }
328 if (trackno != -1) {
329 meta_update_frame(fdec->meta, add_tags, META_FIELD_TRACKNO, NULL, trackno, 0.0f);
330 }
331 if (date != NULL && !is_all_wspace(date)) {
332 cut_trailing_whitespace(date);
333 meta_update_frame(fdec->meta, add_tags, META_FIELD_DATE, date, 0, 0.0f);
334 }
335 if (genre != NULL && !is_all_wspace(genre)) {
336 cut_trailing_whitespace(genre);
337 meta_update_frame(fdec->meta, add_tags, META_FIELD_GENRE, genre, 0, 0.0f);
338 }
339 if (comment != NULL && !is_all_wspace(comment)) {
340 cut_trailing_whitespace(comment);
341 meta_update_frame(fdec->meta, add_tags, META_FIELD_COMMENT, comment, 0, 0.0f);
342 }
343
344 ret = fdec->meta_write(fdec, fdec->meta);
345 file_decoder_close(fdec);
346 file_decoder_delete(fdec);
347
348 return ret;
349 }
350
351 const char *
metadata_strerror(int error)352 metadata_strerror(int error) {
353
354 switch (error) {
355 case META_ERROR_NONE: return _("Success");
356 case META_ERROR_NOMEM: return _("Memory allocation error");
357 case META_ERROR_OPEN: return _("Unable to open file");
358 case META_ERROR_NO_METASUPPORT: return _("No metadata support for this format");
359 case META_ERROR_NOT_WRITABLE: return _("File is not writable");
360 case META_ERROR_INVALID_TRACKNO: return _("Invalid 'Track no.' field value");
361 case META_ERROR_INVALID_GENRE: return _("Invalid 'Genre' field value");
362 case META_ERROR_INVALID_CODING: return _("Conversion to target charset failed");
363 case META_ERROR_INTERNAL: return _("Internal error");
364 default: return _("Unknown error");
365 }
366 }
367