MiniDLNA: update from 1.1.2 to 1.1.4
[tomato.git] / release / src-rt-6.x.4708 / router / minidlna / albumart.c
blob20ed14ebaf0e81c68325b234dd03a88a866730d0
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 int64_t art_id = 0;
108 int ret;
110 strncpyt(fpath, path, sizeof(fpath));
111 match = basename(fpath);
112 /* Check if this file name matches a specific audio or video file */
113 if( ends_with(match, ".cover.jpg") )
115 ncmp = strlen(match)-10;
117 else
119 ncmp = strrchr(match, '.') - match;
121 /* Check if this file name matches one of the default album art names */
122 album_art = is_album_art(match);
124 strncpyt(dpath, path, sizeof(dpath));
125 dir = dirname(dpath);
126 dh = opendir(dir);
127 if( !dh )
128 return;
129 while ((dp = readdir(dh)) != NULL)
131 if (is_reg(dp) == 1)
133 type = TYPE_FILE;
135 else if (is_dir(dp) == 1)
137 type = TYPE_DIR;
139 else
141 snprintf(file, sizeof(file), "%s/%s", dir, dp->d_name);
142 type = resolve_unknown_type(file, ALL_MEDIA);
144 if( type != TYPE_FILE )
145 continue;
146 if( (dp->d_name[0] != '.') &&
147 (is_video(dp->d_name) || is_audio(dp->d_name)) &&
148 (album_art || strncmp(dp->d_name, match, ncmp) == 0) )
150 DPRINTF(E_DEBUG, L_METADATA, "New file %s looks like cover art for %s\n", path, dp->d_name);
151 snprintf(file, sizeof(file), "%s/%s", dir, dp->d_name);
152 art_id = find_album_art(file, NULL, 0);
153 ret = sql_exec(db, "UPDATE DETAILS set ALBUM_ART = %lld where PATH = '%q'", (long long)art_id, file);
154 if( ret != SQLITE_OK )
155 DPRINTF(E_WARN, L_METADATA, "Error setting %s as cover art for %s\n", match, dp->d_name);
158 closedir(dh);
161 char *
162 check_embedded_art(const char *path, uint8_t *image_data, int image_size)
164 int width = 0, height = 0;
165 char *art_path = NULL;
166 char *cache_dir;
167 FILE *dstfile;
168 image_s *imsrc;
169 static char last_path[PATH_MAX];
170 static unsigned int last_hash = 0;
171 static int last_success = 0;
172 unsigned int hash;
174 if( !image_data || !image_size || !path )
176 return NULL;
178 /* If the embedded image matches the embedded image from the last file we
179 * checked, just make a hard link. Better than storing it on the disk twice. */
180 hash = DJBHash(image_data, image_size);
181 if( hash == last_hash )
183 if( !last_success )
184 return NULL;
185 art_cache_exists(path, &art_path);
186 if( link(last_path, art_path) == 0 )
188 return(art_path);
190 else
192 if( errno == ENOENT )
194 cache_dir = strdup(art_path);
195 make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
196 free(cache_dir);
197 if( link(last_path, art_path) == 0 )
198 return(art_path);
200 DPRINTF(E_WARN, L_METADATA, "Linking %s to %s failed [%s]\n", art_path, last_path, strerror(errno));
201 free(art_path);
202 art_path = NULL;
205 last_hash = hash;
207 imsrc = image_new_from_jpeg(NULL, 0, image_data, image_size, 1, ROTATE_NONE);
208 if( !imsrc )
210 last_success = 0;
211 return NULL;
213 width = imsrc->width;
214 height = imsrc->height;
216 if( width > 160 || height > 160 )
218 art_path = save_resized_album_art(imsrc, path);
220 else if( width > 0 && height > 0 )
222 size_t nwritten;
223 if( art_cache_exists(path, &art_path) )
224 goto end_art;
225 cache_dir = strdup(art_path);
226 make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
227 free(cache_dir);
228 dstfile = fopen(art_path, "w");
229 if( !dstfile )
231 free(art_path);
232 art_path = NULL;
233 goto end_art;
235 nwritten = fwrite((void *)image_data, 1, image_size, dstfile);
236 fclose(dstfile);
237 if( nwritten != image_size )
239 DPRINTF(E_WARN, L_METADATA, "Embedded art error: wrote %lu/%d bytes\n",
240 (unsigned long)nwritten, image_size);
241 remove(art_path);
242 free(art_path);
243 art_path = NULL;
244 goto end_art;
247 end_art:
248 image_free(imsrc);
249 if( !art_path )
251 DPRINTF(E_WARN, L_METADATA, "Invalid embedded album art in %s\n", basename((char *)path));
252 last_success = 0;
253 return NULL;
255 DPRINTF(E_DEBUG, L_METADATA, "Found new embedded album art in %s\n", basename((char *)path));
256 last_success = 1;
257 strcpy(last_path, art_path);
259 return(art_path);
262 static char *
263 check_for_album_file(const char *path)
265 char file[MAXPATHLEN];
266 char mypath[MAXPATHLEN];
267 struct album_art_name_s *album_art_name;
268 image_s *imsrc = NULL;
269 int width=0, height=0;
270 char *art_file, *p;
271 const char *dir;
272 struct stat st;
273 int ret;
275 if( stat(path, &st) != 0 )
276 return NULL;
278 if( S_ISDIR(st.st_mode) )
280 dir = path;
281 goto check_dir;
283 strncpyt(mypath, path, sizeof(mypath));
284 dir = dirname(mypath);
286 /* First look for file-specific cover art */
287 snprintf(file, sizeof(file), "%s.cover.jpg", path);
288 ret = access(file, R_OK);
289 if( ret != 0 )
291 strncpyt(file, path, sizeof(file));
292 p = strrchr(file, '.');
293 if( p )
295 strcpy(p, ".jpg");
296 ret = access(file, R_OK);
298 if( ret != 0 )
300 p = strrchr(file, '/');
301 if( p )
303 memmove(p+2, p+1, file+MAXPATHLEN-p-2);
304 p[1] = '.';
305 ret = access(file, R_OK);
309 if( ret == 0 )
311 if( art_cache_exists(file, &art_file) )
312 goto existing_file;
313 free(art_file);
314 imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE);
315 if( imsrc )
316 goto found_file;
318 check_dir:
319 /* Then fall back to possible generic cover art file names */
320 for( album_art_name = album_art_names; album_art_name; album_art_name = album_art_name->next )
322 snprintf(file, sizeof(file), "%s/%s", dir, album_art_name->name);
323 if( access(file, R_OK) == 0 )
325 if( art_cache_exists(file, &art_file) )
327 existing_file:
328 return art_file;
330 free(art_file);
331 imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE);
332 if( !imsrc )
333 continue;
334 found_file:
335 width = imsrc->width;
336 height = imsrc->height;
337 if( width > 160 || height > 160 )
338 art_file = save_resized_album_art(imsrc, file);
339 else
340 art_file = strdup(file);
341 image_free(imsrc);
342 return(art_file);
345 return NULL;
348 int64_t
349 find_album_art(const char *path, uint8_t *image_data, int image_size)
351 char *album_art = NULL;
352 int64_t ret = 0;
354 if( (image_size && (album_art = check_embedded_art(path, image_data, image_size))) ||
355 (album_art = check_for_album_file(path)) )
357 ret = sql_get_int_field(db, "SELECT ID from ALBUM_ART where PATH = '%q'", album_art);
358 if( !ret )
360 if( sql_exec(db, "INSERT into ALBUM_ART (PATH) VALUES ('%q')", album_art) == SQLITE_OK )
361 ret = sqlite3_last_insert_rowid(db);
364 free(album_art);
366 return ret;