Describe the magic of search_albumart_files (still not complete)
[kugel-rb/myfork.git] / apps / recorder / albumart.c
blobe33fcb8d08131dec4d7ef25736cfe09519aff6de
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Nicolas Pennequin
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <string.h>
23 #include "sprintf.h"
24 #include "system.h"
25 #include "albumart.h"
26 #include "metadata.h"
27 #include "gwps.h"
28 #include "buffering.h"
29 #include "dircache.h"
30 #include "debug.h"
31 #include "misc.h"
32 #include "settings.h"
34 #if defined(HAVE_JPEG) || defined(PLUGIN)
35 #define USE_JPEG_COVER
36 #endif
38 /* Strip filename from a full path
40 * buf - buffer to extract directory to.
41 * buf_size - size of buffer.
42 * fullpath - fullpath to extract from.
44 * Split the directory part of the given fullpath and store it in buf
45 * (including last '/').
46 * The function return parameter is a pointer to the filename
47 * inside the given fullpath.
49 static char* strip_filename(char* buf, int buf_size, const char* fullpath)
51 char* sep;
52 int len;
54 if (!buf || buf_size <= 0 || !fullpath)
55 return NULL;
57 /* if 'fullpath' is only a filename return immediately */
58 sep = strrchr(fullpath, '/');
59 if (sep == NULL)
61 buf[0] = 0;
62 return (char*)fullpath;
65 len = MIN(sep - fullpath + 1, buf_size - 1);
66 strncpy(buf, fullpath, len);
67 buf[len] = 0;
68 return (sep + 1);
71 /* Make sure part of path only contain chars valid for a FAT32 long name.
72 * Double quotes are replaced with single quotes, other unsupported chars
73 * are replaced with an underscore.
75 * path - path to modify.
76 * offset - where in path to start checking.
77 * count - number of chars to check.
79 static void fix_path_part(char* path, int offset, int count)
81 static const char invalid_chars[] = "*/:<>?\\|";
82 int i;
84 path += offset;
86 for (i = 0; i <= count; i++, path++)
88 if (*path == 0)
89 return;
90 if (*path == '"')
91 *path = '\'';
92 else if (strchr(invalid_chars, *path))
93 *path = '_';
97 #ifdef USE_JPEG_COVER
98 static const char * extensions[] = { "jpeg", "jpg", "bmp" };
99 static int extension_lens[] = { 4, 3, 3 };
100 /* Try checking for several file extensions, return true if a file is found and
101 * leaving the path modified to include the matching extension.
103 static bool try_exts(char *path, int len)
105 int i;
106 for (i = 0; i < 3; i++)
108 if (extension_lens[i] + len > MAX_PATH)
109 continue;
110 strcpy(path + len, extensions[i]);
111 if (file_exists(path))
112 return true;
114 return false;
116 #define EXT
117 #else
118 #define EXT "bmp"
119 #define try_exts(path, len) file_exists(path)
120 #endif
122 /* Look for the first matching album art bitmap in the following list:
123 * ./<trackname><size>.{jpeg,jpg,bmp}
124 * ./<albumname><size>.{jpeg,jpg,bmp}
125 * ./cover<size>.bmp
126 * ../<albumname><size>.{jpeg,jpg,bmp}
127 * ../cover<size>.{jpeg,jpg,bmp}
128 * ROCKBOX_DIR/albumart/<artist>-<albumname><size>.{jpeg,jpg,bmp}
129 * <size> is the value of the size_string parameter, <trackname> and
130 * <albumname> are read from the ID3 metadata.
131 * If a matching bitmap is found, its filename is stored in buf.
132 * Return value is true if a bitmap was found, false otherwise.
134 * If the first symbol in size_string is a colon (e.g. ":100x100")
135 * then the colon is skipped ("100x100" will be used) and the track
136 * specific image (./<trackname><size>.bmp) is not tried.
138 bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
139 char *buf, int buflen)
141 char path[MAX_PATH + 1];
142 char dir[MAX_PATH + 1];
143 bool found = false;
144 const char *trackname;
145 const char *artist;
146 int dirlen;
147 int albumlen;
148 int pathlen;
150 if (!id3 || !buf)
151 return false;
153 trackname = id3->path;
155 if (strcmp(trackname, "No file!") == 0)
156 return false;
158 strip_filename(dir, sizeof(dir), trackname);
159 dirlen = strlen(dir);
160 albumlen = id3->album ? strlen(id3->album) : 0;
162 /* the first file we look for is one specific to the track playing */
163 if (*size_string == ':')
164 size_string++;
165 else {
166 strip_extension(path, sizeof(path) - strlen(size_string) - 4, trackname);
167 strcat(path, size_string);
168 strcat(path, "." EXT);
169 #ifdef USE_JPEG_COVER
170 pathlen = strlen(path);
171 #endif
172 found = try_exts(path, pathlen);
174 if (!found && albumlen > 0)
176 /* if it doesn't exist,
177 * we look for a file specific to the track's album name */
178 pathlen = snprintf(path, sizeof(path),
179 "%s%s%s." EXT, dir, id3->album, size_string);
180 fix_path_part(path, dirlen, albumlen);
181 found = try_exts(path, pathlen);
184 if (!found)
186 /* if it still doesn't exist, we look for a generic file */
187 pathlen = snprintf(path, sizeof(path),
188 "%scover%s." EXT, dir, size_string);
189 found = try_exts(path, pathlen);
192 #ifdef USE_JPEG_COVER
193 if (!found && !*size_string)
195 snprintf (path, sizeof(path), "%sfolder.jpg", dir);
196 found = file_exists(path);
198 #endif
200 artist = id3->albumartist != NULL ? id3->albumartist : id3->artist;
202 if (!found && artist && id3->album)
204 /* look in the albumart subdir of .rockbox */
205 pathlen = snprintf(path, sizeof(path),
206 ROCKBOX_DIR "/albumart/%s-%s%s." EXT,
207 artist,
208 id3->album,
209 size_string);
210 fix_path_part(path, strlen(ROCKBOX_DIR "/albumart/"), MAX_PATH);
211 found = try_exts(path, pathlen);
214 if (!found)
216 /* if it still doesn't exist,
217 * we continue to search in the parent directory */
218 strcpy(path, dir);
219 path[dirlen - 1] = 0;
220 strip_filename(dir, sizeof(dir), path);
221 dirlen = strlen(dir);
224 /* only try parent if there is one */
225 if (dirlen > 0)
227 if (!found && albumlen > 0)
229 /* we look in the parent directory
230 * for a file specific to the track's album name */
231 pathlen = snprintf(path, sizeof(path),
232 "%s%s%s." EXT, dir, id3->album, size_string);
233 fix_path_part(path, dirlen, albumlen);
234 found = try_exts(path, pathlen);
237 if (!found)
239 /* if it still doesn't exist, we look in the parent directory
240 * for a generic file */
241 pathlen = snprintf(path, sizeof(path),
242 "%scover%s." EXT, dir, size_string);
243 found = try_exts(path, pathlen);
247 if (!found)
248 return false;
250 strncpy(buf, path, buflen);
251 DEBUGF("Album art found: %s\n", path);
252 return true;
255 #ifndef PLUGIN
256 /* Look for albumart bitmap in the same dir as the track and in its parent dir.
257 * Stores the found filename in the buf parameter.
258 * Returns true if a bitmap was found, false otherwise */
259 bool find_albumart(const struct mp3entry *id3, char *buf, int buflen)
261 if (!id3 || !buf)
262 return false;
264 char size_string[9];
265 struct wps_data *data = gui_wps[0].data;
267 if (!data)
268 return false;
270 DEBUGF("Looking for album art for %s\n", id3->path);
272 /* Write the size string, e.g. ".100x100". */
273 snprintf(size_string, sizeof(size_string), ".%dx%d",
274 data->albumart_max_width, data->albumart_max_height);
276 /* First we look for a bitmap of the right size */
277 if (search_albumart_files(id3, size_string, buf, buflen))
278 return true;
280 /* Then we look for generic bitmaps */
281 *size_string = 0;
282 return search_albumart_files(id3, size_string, buf, buflen);
285 /* Draw the album art bitmap from the given handle ID onto the given WPS.
286 Call with clear = true to clear the bitmap instead of drawing it. */
287 void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
289 if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
290 return;
292 struct wps_data *data = gwps->data;
294 #ifdef HAVE_REMOTE_LCD
295 /* No album art on RWPS */
296 if (data->remote_wps)
297 return;
298 #endif
300 struct bitmap *bmp;
301 if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
302 return;
304 short x = data->albumart_x;
305 short y = data->albumart_y;
306 short width = bmp->width;
307 short height = bmp->height;
309 if (data->albumart_max_width > 0)
311 /* Crop if the bitmap is too wide */
312 width = MIN(bmp->width, data->albumart_max_width);
314 /* Align */
315 if (data->albumart_xalign & WPS_ALBUMART_ALIGN_RIGHT)
316 x += data->albumart_max_width - width;
317 else if (data->albumart_xalign & WPS_ALBUMART_ALIGN_CENTER)
318 x += (data->albumart_max_width - width) / 2;
321 if (data->albumart_max_height > 0)
323 /* Crop if the bitmap is too high */
324 height = MIN(bmp->height, data->albumart_max_height);
326 /* Align */
327 if (data->albumart_yalign & WPS_ALBUMART_ALIGN_BOTTOM)
328 y += data->albumart_max_height - height;
329 else if (data->albumart_yalign & WPS_ALBUMART_ALIGN_CENTER)
330 y += (data->albumart_max_height - height) / 2;
333 if (!clear)
335 /* Draw the bitmap */
336 gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0, bmp->width,
337 x, y, width, height);
338 #ifdef HAVE_LCD_INVERT
339 if (global_settings.invert) {
340 gwps->display->set_drawmode(DRMODE_COMPLEMENT);
341 gwps->display->fillrect(x, y, width, height);
342 gwps->display->set_drawmode(DRMODE_SOLID);
344 #endif
346 else
348 /* Clear the bitmap */
349 gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
350 gwps->display->fillrect(x, y, width, height);
351 gwps->display->set_drawmode(DRMODE_SOLID);
355 void get_albumart_size(struct bitmap *bmp)
357 /* FIXME: What should we do with albumart on remote? */
358 struct wps_data *data = gui_wps[0].data;
360 bmp->width = data->albumart_max_width;
361 bmp->height = data->albumart_max_height;
363 #endif /* PLUGIN */