Wrap up version 1.3.3.
[minidlna.git] / albumart.c
blobde026ecd124e26d59115a98b4ccadc493a4407f5
1 /* MiniDLNA media server
2 * Copyright (C) 2008 Justin Maggard
4 * This file is part of MiniDLNA.
6 * MiniDLNA is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * MiniDLNA is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
18 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <dirent.h>
25 #include <sys/param.h>
26 #include <sys/stat.h>
27 #include <sys/param.h>
28 #include <limits.h>
29 #include <libgen.h>
30 #include <setjmp.h>
31 #include <errno.h>
33 #include <jpeglib.h>
35 #include "upnpglobalvars.h"
36 #include "albumart.h"
37 #include "sql.h"
38 #include "utils.h"
39 #include "image_utils.h"
40 #include "log.h"
42 static int
43 art_cache_exists(const char *orig_path, char **cache_file)
45 if( xasprintf(cache_file, "%s/art_cache%s", db_path, orig_path) < 0 )
46 return 0;
48 strcpy(strchr(*cache_file, '\0')-4, ".jpg");
50 return (!access(*cache_file, F_OK));
53 static char *
54 save_resized_album_art(image_s *imsrc, const char *path)
56 int dstw, dsth;
57 image_s *imdst;
58 char *cache_file;
59 char cache_dir[MAXPATHLEN];
61 if( !imsrc )
62 return NULL;
64 if( art_cache_exists(path, &cache_file) )
65 return cache_file;
67 strncpyt(cache_dir, cache_file, sizeof(cache_dir));
68 make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
70 if( imsrc->width > imsrc->height )
72 dstw = 160;
73 dsth = (imsrc->height<<8) / ((imsrc->width<<8)/160);
75 else
77 dstw = (imsrc->width<<8) / ((imsrc->height<<8)/160);
78 dsth = 160;
80 imdst = image_resize(imsrc, dstw, dsth);
81 if( !imdst )
83 free(cache_file);
84 return NULL;
87 cache_file = image_save_to_jpeg_file(imdst, cache_file);
88 image_free(imdst);
90 return cache_file;
93 /* And our main album art functions */
94 void
95 update_if_album_art(const char *path)
97 char *dir;
98 char *match;
99 char file[MAXPATHLEN];
100 char fpath[MAXPATHLEN];
101 char dpath[MAXPATHLEN];
102 int ncmp = 0;
103 int album_art;
104 DIR *dh;
105 struct dirent *dp;
106 enum file_types type = TYPE_UNKNOWN;
107 media_types dir_type;
108 int64_t art_id = 0;
109 int ret;
111 strncpyt(fpath, path, sizeof(fpath));
112 match = basename(fpath);
113 /* Check if this file name matches a specific audio or video file */
114 if( ends_with(match, ".cover.jpg") )
116 ncmp = strlen(match)-10;
118 else
120 ncmp = strrchr(match, '.') - match;
122 /* Check if this file name matches one of the default album art names */
123 album_art = is_album_art(match);
125 strncpyt(dpath, path, sizeof(dpath));
126 dir_type = valid_media_types(dpath);
127 if (!(dir_type & (TYPE_VIDEO|TYPE_AUDIO)))
128 return;
129 dir = dirname(dpath);
130 dh = opendir(dir);
131 if( !dh )
132 return;
133 while ((dp = readdir(dh)) != NULL)
135 if (is_reg(dp) == 1)
136 type = TYPE_FILE;
137 else if (is_dir(dp) == 1)
138 type = TYPE_DIR;
139 else
141 snprintf(file, sizeof(file), "%s/%s", dir, dp->d_name);
142 type = resolve_unknown_type(file, dir_type);
145 if (type != TYPE_FILE || dp->d_name[0] == '.')
146 continue;
148 if(((is_video(dp->d_name) && (dir_type & TYPE_VIDEO)) ||
149 (is_audio(dp->d_name) && (dir_type & TYPE_AUDIO))) &&
150 (album_art || strncmp(dp->d_name, match, ncmp) == 0) )
152 snprintf(file, sizeof(file), "%s/%s", dir, dp->d_name);
153 art_id = find_album_art(file, NULL, 0);
154 ret = sql_exec(db, "UPDATE DETAILS set ALBUM_ART = %lld where PATH = '%q' and ALBUM_ART != %lld", (long long)art_id, file, (long long)art_id);
155 if( ret == SQLITE_OK )
156 DPRINTF(E_DEBUG, L_METADATA, "Updated cover art for %s to %s\n", dp->d_name, path);
157 else
158 DPRINTF(E_WARN, L_METADATA, "Error setting %s as cover art for %s\n", match, dp->d_name);
161 closedir(dh);
164 char *
165 check_embedded_art(const char *path, uint8_t *image_data, int image_size)
167 int width = 0, height = 0;
168 char *art_path = NULL;
169 char *cache_dir;
170 FILE *dstfile;
171 image_s *imsrc;
172 static char last_path[PATH_MAX];
173 static unsigned int last_hash = 0;
174 static int last_success = 0;
175 unsigned int hash;
177 if( !image_data || !image_size || !path )
179 return NULL;
181 /* If the embedded image matches the embedded image from the last file we
182 * checked, just make a hard link. Better than storing it on the disk twice. */
183 hash = DJBHash(image_data, image_size);
184 if( hash == last_hash )
186 if( !last_success )
187 return NULL;
188 art_cache_exists(path, &art_path);
189 if( link(last_path, art_path) == 0 )
191 return(art_path);
193 else
195 if( errno == ENOENT )
197 cache_dir = strdup(art_path);
198 make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
199 free(cache_dir);
200 if( link(last_path, art_path) == 0 )
201 return(art_path);
203 DPRINTF(E_WARN, L_METADATA, "Linking %s to %s failed [%s]\n", art_path, last_path, strerror(errno));
204 free(art_path);
205 art_path = NULL;
208 last_hash = hash;
210 imsrc = image_new_from_jpeg(NULL, 0, image_data, image_size, 1, ROTATE_NONE);
211 if( !imsrc )
213 last_success = 0;
214 return NULL;
216 width = imsrc->width;
217 height = imsrc->height;
219 if( width > 160 || height > 160 )
221 art_path = save_resized_album_art(imsrc, path);
223 else if( width > 0 && height > 0 )
225 size_t nwritten;
226 if( art_cache_exists(path, &art_path) )
227 goto end_art;
228 cache_dir = strdup(art_path);
229 make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
230 free(cache_dir);
231 dstfile = fopen(art_path, "w");
232 if( !dstfile )
234 free(art_path);
235 art_path = NULL;
236 goto end_art;
238 nwritten = fwrite((void *)image_data, 1, image_size, dstfile);
239 fclose(dstfile);
240 if( nwritten != image_size )
242 DPRINTF(E_WARN, L_METADATA, "Embedded art error: wrote %lu/%d bytes\n",
243 (unsigned long)nwritten, image_size);
244 remove(art_path);
245 free(art_path);
246 art_path = NULL;
247 goto end_art;
250 end_art:
251 image_free(imsrc);
252 if( !art_path )
254 DPRINTF(E_WARN, L_METADATA, "Invalid embedded album art in %s\n", basename((char *)path));
255 last_success = 0;
256 return NULL;
258 DPRINTF(E_DEBUG, L_METADATA, "Found new embedded album art in %s\n", basename((char *)path));
259 last_success = 1;
260 strcpy(last_path, art_path);
262 return(art_path);
265 static char *
266 check_for_album_file(const char *path)
268 char file[MAXPATHLEN];
269 char mypath[MAXPATHLEN];
270 struct album_art_name_s *album_art_name;
271 image_s *imsrc = NULL;
272 int width=0, height=0;
273 char *art_file, *p;
274 const char *dir;
275 struct stat st;
276 int ret;
278 if( stat(path, &st) != 0 )
279 return NULL;
281 if( S_ISDIR(st.st_mode) )
283 dir = path;
284 goto check_dir;
286 strncpyt(mypath, path, sizeof(mypath));
287 dir = dirname(mypath);
289 /* First look for file-specific cover art */
290 snprintf(file, sizeof(file), "%s.cover.jpg", path);
291 ret = access(file, R_OK);
292 if( ret != 0 )
294 strncpyt(file, path, sizeof(file));
295 p = strrchr(file, '.');
296 if( p )
298 strcpy(p, ".jpg");
299 ret = access(file, R_OK);
301 if( ret != 0 )
303 p = strrchr(file, '/');
304 if( p )
306 memmove(p+2, p+1, file+MAXPATHLEN-p-2);
307 p[1] = '.';
308 ret = access(file, R_OK);
312 if( ret == 0 )
314 if( art_cache_exists(file, &art_file) )
315 goto existing_file;
316 free(art_file);
317 imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE);
318 if( imsrc )
319 goto found_file;
321 check_dir:
322 /* Then fall back to possible generic cover art file names */
323 for( album_art_name = album_art_names; album_art_name; album_art_name = album_art_name->next )
325 snprintf(file, sizeof(file), "%s/%s", dir, album_art_name->name);
326 if( access(file, R_OK) == 0 )
328 if( art_cache_exists(file, &art_file) )
330 existing_file:
331 return art_file;
333 free(art_file);
334 imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE);
335 if( !imsrc )
336 continue;
337 found_file:
338 width = imsrc->width;
339 height = imsrc->height;
340 if( width > 160 || height > 160 )
341 art_file = save_resized_album_art(imsrc, file);
342 else
343 art_file = strdup(file);
344 image_free(imsrc);
345 return(art_file);
348 return NULL;
351 int64_t
352 find_album_art(const char *path, uint8_t *image_data, int image_size)
354 char *album_art = NULL;
355 int64_t ret = 0;
357 if( (image_size && (album_art = check_embedded_art(path, image_data, image_size))) ||
358 (album_art = check_for_album_file(path)) )
360 ret = sql_get_int_field(db, "SELECT ID from ALBUM_ART where PATH = '%q'", album_art);
361 if( !ret )
363 if( sql_exec(db, "INSERT into ALBUM_ART (PATH) VALUES ('%q')", album_art) == SQLITE_OK )
364 ret = sqlite3_last_insert_rowid(db);
367 free(album_art);
369 return ret;