Improved use of album name when locating the album art file: replace chars that are...
[kugel-rb.git] / apps / recorder / albumart.c
blobd99280ce85db660d3a902f01276d3f320a38d03a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Nicolas Pennequin
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <string.h>
21 #include "sprintf.h"
22 #include "system.h"
23 #include "albumart.h"
24 #include "id3.h"
25 #include "gwps.h"
26 #include "buffering.h"
27 #include "dircache.h"
28 #include "debug.h"
31 /* Strip filename from a full path
33 * buf - buffer to extract directory to.
34 * buf_size - size of buffer.
35 * fullpath - fullpath to extract from.
37 * Split the directory part of the given fullpath and store it in buf
38 * (including last '/').
39 * The function return parameter is a pointer to the filename
40 * inside the given fullpath.
42 static char* strip_filename(char* buf, int buf_size, const char* fullpath)
44 char* sep;
45 int len;
47 if (!buf || buf_size <= 0 || !fullpath)
48 return NULL;
50 /* if 'fullpath' is only a filename return immediately */
51 sep = strrchr(fullpath, '/');
52 if (sep == NULL)
54 buf[0] = 0;
55 return (char*)fullpath;
58 len = MIN(sep - fullpath + 1, buf_size - 1);
59 strncpy(buf, fullpath, len);
60 buf[len] = 0;
61 return (sep + 1);
64 /* Strip extension from a filename.
66 * buf - buffer to output the result to.
67 * buf_size - size of the output buffer buffer.
68 * file - filename to strip extension from.
70 * Return value is a pointer to buf, which contains the result.
72 static char* strip_extension(char* buf, int buf_size, const char* file)
74 char* sep;
75 int len;
77 if (!buf || buf_size <= 0 || !file)
78 return NULL;
80 buf[0] = 0;
82 sep = strrchr(file,'.');
83 if (sep == NULL)
84 return NULL;
86 len = MIN(sep - file, buf_size - 1);
87 strncpy(buf, file, len);
88 buf[len] = 0;
89 return buf;
92 /* Test file existence, using dircache of possible */
93 static bool file_exists(const char *file)
95 int fd;
97 if (!file || strlen(file) <= 0)
98 return false;
100 #ifdef HAVE_DIRCACHE
101 if (dircache_is_enabled())
102 return (dircache_get_entry_ptr(file) != NULL);
103 #endif
105 fd = open(file, O_RDONLY);
106 if (fd < 0)
107 return false;
108 close(fd);
109 return true;
112 /* Make sure part of path only contain chars valid for a FAT32 long name.
113 * Double quotes are replaced with single quotes, other unsupported chars
114 * are replaced with an underscore.
116 * path - path to modify.
117 * offset - where in path to start checking.
118 * count - number of chars to check.
120 static void fix_path_part(char* path, int offset, int count)
122 static const char invalid_chars[] = "*/:<>?\\|";
123 int i;
125 path += offset;
127 for (i = 0; i <= count; i++, path++)
129 if (*path == '"')
130 *path = '\'';
131 else if (strchr(invalid_chars, *path))
132 *path = '_';
136 /* Look for the first matching album art bitmap in the following list:
137 * ./<trackname><size>.bmp
138 * ./<albumname><size>.bmp
139 * ./cover<size>.bmp
140 * ../<albumname><size>.bmp
141 * ../cover<size>.bmp
142 * <size> is the value of the size_string parameter, <trackname> and
143 * <albumname> are read from the ID3 metadata.
144 * If a matching bitmap is found, its filename is stored in buf.
145 * Return value is true if a bitmap was found, false otherwise.
147 static bool search_files(const struct mp3entry *id3, const char *size_string,
148 char *buf, int buflen)
150 char path[MAX_PATH + 1];
151 char dir[MAX_PATH + 1];
152 bool found = false;
153 const char *trackname;
154 int dirlen;
155 int albumlen;
157 if (!id3 || !buf)
158 return false;
160 trackname = id3->path;
161 strip_filename(dir, sizeof(dir), trackname);
162 dirlen = strlen(dir);
163 albumlen = id3->album ? strlen(id3->album) : 0;
165 /* the first file we look for is one specific to the track playing */
166 strip_extension(path, sizeof(path) - strlen(size_string) - 4, trackname);
167 strcat(path, size_string);
168 strcat(path, ".bmp");
169 found = file_exists(path);
170 if (!found && albumlen > 0)
172 /* if it doesn't exist,
173 * we look for a file specific to the track's album name */
174 snprintf(path, sizeof(path),
175 "%s%s%s.bmp", dir, id3->album, size_string);
176 fix_path_part(path, dirlen, albumlen);
177 found = file_exists(path);
180 if (!found)
182 /* if it still doesn't exist, we look for a generic file */
183 snprintf(path, sizeof(path),
184 "%scover%s.bmp", dir, size_string);
185 found = file_exists(path);
188 if (!found)
190 /* if it still doesn't exist,
191 * we continue to search in the parent directory */
192 strcpy(path, dir);
193 path[dirlen - 1] = 0;
194 strip_filename(dir, sizeof(dir), path);
195 dirlen = strlen(dir);
198 /* only try parent if there is one */
199 if (dirlen > 0)
201 if (!found && albumlen > 0)
203 /* we look in the parent directory
204 * for a file specific to the track's album name */
205 snprintf(path, sizeof(path),
206 "%s%s%s.bmp", dir, id3->album, size_string);
207 fix_path_part(path, dirlen, albumlen);
208 found = file_exists(path);
211 if (!found)
213 /* if it still doesn't exist, we look in the parent directory
214 * for a generic file */
215 snprintf(path, sizeof(path),
216 "%scover%s.bmp", dir, size_string);
217 found = file_exists(path);
221 if (!found)
222 return false;
224 strncpy(buf, path, buflen);
225 DEBUGF("Album art found: %s\n", path);
226 return true;
229 /* Look for albumart bitmap in the same dir as the track and in its parent dir.
230 * Stores the found filename in the buf parameter.
231 * Returns true if a bitmap was found, false otherwise */
232 bool find_albumart(const struct mp3entry *id3, char *buf, int buflen)
234 if (!id3 || !buf)
235 return false;
237 char size_string[9];
238 struct wps_data *data = gui_wps[0].data;
240 if (!data)
241 return false;
243 DEBUGF("Looking for album art for %s\n", id3->path);
245 /* Write the size string, e.g. ".100x100". */
246 snprintf(size_string, sizeof(size_string), ".%dx%d",
247 data->albumart_max_width, data->albumart_max_height);
249 /* First we look for a bitmap of the right size */
250 if (search_files(id3, size_string, buf, buflen))
251 return true;
253 /* Then we look for generic bitmaps */
254 *size_string = 0;
255 return search_files(id3, size_string, buf, buflen);
258 /* Draw the album art bitmap from the given handle ID onto the given WPS.
259 Call with clear = true to clear the bitmap instead of drawing it. */
260 void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
262 if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
263 return;
265 struct wps_data *data = gwps->data;
267 #ifdef HAVE_REMOTE_LCD
268 /* No album art on RWPS */
269 if (data->remote_wps)
270 return;
271 #endif
273 struct bitmap *bmp;
274 if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
275 return;
277 short x = data->albumart_x;
278 short y = data->albumart_y;
279 short width = bmp->width;
280 short height = bmp->height;
282 if (data->albumart_max_width > 0)
284 /* Crop if the bitmap is too wide */
285 width = MIN(bmp->width, data->albumart_max_width);
287 /* Align */
288 if (data->albumart_xalign & WPS_ALBUMART_ALIGN_RIGHT)
289 x += data->albumart_max_width - width;
290 else if (data->albumart_xalign & WPS_ALBUMART_ALIGN_CENTER)
291 x += (data->albumart_max_width - width) / 2;
294 if (data->albumart_max_height > 0)
296 /* Crop if the bitmap is too high */
297 height = MIN(bmp->height, data->albumart_max_height);
299 /* Align */
300 if (data->albumart_yalign & WPS_ALBUMART_ALIGN_BOTTOM)
301 y += data->albumart_max_height - height;
302 else if (data->albumart_yalign & WPS_ALBUMART_ALIGN_CENTER)
303 y += (data->albumart_max_height - height) / 2;
306 if (!clear)
308 /* Draw the bitmap */
309 gwps->display->set_drawmode(DRMODE_FG);
310 gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0, bmp->width,
311 x, y, width, height);
312 gwps->display->set_drawmode(DRMODE_SOLID);
314 else
316 /* Clear the bitmap */
317 gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
318 gwps->display->fillrect(x, y, width, height);
319 gwps->display->set_drawmode(DRMODE_SOLID);