Updates to Tomato RAF including NGINX && PHP
[tomato.git] / release / src / router / minidlna / albumart.c
blob9369e6beea0ffa21f7d0a6621b781740007bc964
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 <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <dirent.h>
23 #include <sys/stat.h>
24 #include <sys/param.h>
25 #include <libgen.h>
26 #include <setjmp.h>
27 #include <errno.h>
29 #include <jpeglib.h>
31 #include "upnpglobalvars.h"
32 #include "albumart.h"
33 #include "sql.h"
34 #include "utils.h"
35 #include "image_utils.h"
36 #include "log.h"
38 static int
39 art_cache_exists(const char *orig_path, char **cache_file)
41 if( asprintf(cache_file, "%s/art_cache%s", db_path, orig_path) < 0 )
43 *cache_file = NULL;
44 return 0;
46 strcpy(strchr(*cache_file, '\0')-4, ".jpg");
48 return (!access(*cache_file, F_OK));
51 static char *
52 save_resized_album_art(image_s *imsrc, const char *path)
54 int dstw, dsth;
55 image_s *imdst;
56 char *cache_file;
57 char cache_dir[MAXPATHLEN];
59 if( !imsrc )
60 return NULL;
62 if( art_cache_exists(path, &cache_file) )
63 return cache_file;
65 strncpyt(cache_dir, cache_file, sizeof(cache_dir));
66 make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
68 if( imsrc->width > imsrc->height )
70 dstw = 160;
71 dsth = (imsrc->height<<8) / ((imsrc->width<<8)/160);
73 else
75 dstw = (imsrc->width<<8) / ((imsrc->height<<8)/160);
76 dsth = 160;
78 imdst = image_resize(imsrc, dstw, dsth);
79 if( !imdst )
80 goto error;
82 if( image_save_to_jpeg_file(imdst, cache_file) == 0 )
84 image_free(imdst);
85 return cache_file;
87 error:
88 free(cache_file);
89 return NULL;
92 /* And our main album art functions */
93 void
94 update_if_album_art(const char *path)
96 char *dir;
97 char *match;
98 char file[MAXPATHLEN];
99 char fpath[MAXPATHLEN];
100 char dpath[MAXPATHLEN];
101 int ncmp = 0;
102 int album_art;
103 DIR *dh;
104 struct dirent *dp;
105 enum file_types type = TYPE_UNKNOWN;
106 sqlite_int64 art_id = 0;
108 strncpyt(fpath, path, sizeof(fpath));
109 match = basename(fpath);
110 /* Check if this file name matches a specific audio or video file */
111 if( ends_with(match, ".cover.jpg") )
113 ncmp = strlen(match)-10;
115 else
117 ncmp = strrchr(match, '.') - match;
119 /* Check if this file name matches one of the default album art names */
120 album_art = is_album_art(match);
122 strncpyt(dpath, path, sizeof(dpath));
123 dir = dirname(dpath);
124 dh = opendir(dir);
125 if( !dh )
126 return;
127 while ((dp = readdir(dh)) != NULL)
129 switch( dp->d_type )
131 case DT_REG:
132 type = TYPE_FILE;
133 break;
134 case DT_LNK:
135 case DT_UNKNOWN:
136 snprintf(file, sizeof(file), "%s/%s", dir, dp->d_name);
137 type = resolve_unknown_type(file, ALL_MEDIA);
138 break;
139 default:
140 type = TYPE_UNKNOWN;
141 break;
143 if( type != TYPE_FILE )
144 continue;
145 if( (*(dp->d_name) != '.') &&
146 (is_video(dp->d_name) || is_audio(dp->d_name)) &&
147 (album_art || strncmp(dp->d_name, match, ncmp) == 0) )
149 DPRINTF(E_DEBUG, L_METADATA, "New file %s looks like cover art for %s\n", path, dp->d_name);
150 snprintf(file, sizeof(file), "%s/%s", dir, dp->d_name);
151 art_id = find_album_art(file, NULL, 0);
152 if( sql_exec(db, "UPDATE DETAILS set ALBUM_ART = %lld where PATH = '%q'", art_id, file) != SQLITE_OK )
153 DPRINTF(E_WARN, L_METADATA, "Error setting %s as cover art for %s\n", match, dp->d_name);
156 closedir(dh);
159 char *
160 check_embedded_art(const char *path, const char *image_data, int image_size)
162 int width = 0, height = 0;
163 char *art_path = NULL;
164 char *cache_dir;
165 FILE *dstfile;
166 image_s *imsrc;
167 static char last_path[PATH_MAX];
168 static unsigned int last_hash = 0;
169 static int last_success = 0;
170 unsigned int hash;
172 if( !image_data || !image_size || !path )
174 return NULL;
176 /* If the embedded image matches the embedded image from the last file we
177 * checked, just make a hard link. Better than storing it on the disk twice. */
178 hash = DJBHash(image_data, image_size);
179 if( hash == last_hash )
181 if( !last_success )
182 return NULL;
183 art_cache_exists(path, &art_path);
184 if( link(last_path, art_path) == 0 || (errno == EEXIST) )
186 return(art_path);
188 else
190 if( errno == ENOENT )
192 cache_dir = strdup(art_path);
193 make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
194 free(cache_dir);
195 if( link(last_path, art_path) == 0 )
196 return(art_path);
198 DPRINTF(E_WARN, L_METADATA, "Linking %s to %s failed [%s]\n", art_path, last_path, strerror(errno));
199 free(art_path);
200 art_path = NULL;
203 last_hash = hash;
205 imsrc = image_new_from_jpeg(NULL, 0, image_data, image_size, 1, ROTATE_NONE);
206 if( !imsrc )
208 last_success = 0;
209 return NULL;
211 width = imsrc->width;
212 height = imsrc->height;
214 if( width > 160 || height > 160 )
216 art_path = save_resized_album_art(imsrc, path);
218 else if( width > 0 && height > 0 )
220 size_t nwritten;
221 if( art_cache_exists(path, &art_path) )
222 goto end_art;
223 cache_dir = strdup(art_path);
224 make_dir(dirname(cache_dir), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
225 free(cache_dir);
226 dstfile = fopen(art_path, "w");
227 if( !dstfile )
229 free(art_path);
230 art_path = NULL;
231 goto end_art;
233 nwritten = fwrite((void *)image_data, 1, image_size, dstfile);
234 fclose(dstfile);
235 if( nwritten != image_size )
237 DPRINTF(E_WARN, L_METADATA, "Embedded art error: wrote %d/%d bytes\n", nwritten, image_size);
238 remove(art_path);
239 free(art_path);
240 art_path = NULL;
241 goto end_art;
244 end_art:
245 image_free(imsrc);
246 if( !art_path )
248 DPRINTF(E_WARN, L_METADATA, "Invalid embedded album art in %s\n", basename((char *)path));
249 last_success = 0;
250 return NULL;
252 DPRINTF(E_DEBUG, L_METADATA, "Found new embedded album art in %s\n", basename((char *)path));
253 last_success = 1;
254 strcpy(last_path, art_path);
256 return(art_path);
259 static char *
260 check_for_album_file(const char *path)
262 char file[MAXPATHLEN];
263 char mypath[MAXPATHLEN];
264 struct album_art_name_s *album_art_name;
265 image_s *imsrc = NULL;
266 int width=0, height=0;
267 char *art_file;
268 const char *dir;
269 struct stat st;
271 if( stat(path, &st) != 0 )
272 return NULL;
274 if( S_ISDIR(st.st_mode) )
276 dir = path;
277 goto check_dir;
279 strncpyt(mypath, path, sizeof(mypath));
280 dir = dirname(mypath);
282 /* First look for file-specific cover art */
283 snprintf(file, sizeof(file), "%s.cover.jpg", path);
284 if( access(file, R_OK) == 0 )
286 if( art_cache_exists(file, &art_file) )
287 goto existing_file;
288 free(art_file);
289 imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE);
290 if( imsrc )
291 goto found_file;
293 snprintf(file, sizeof(file), "%s", path);
294 art_file = strrchr(file, '.');
295 if( art_file )
296 strcpy(art_file, ".jpg");
297 if( access(file, R_OK) == 0 )
299 if( art_cache_exists(file, &art_file) )
300 goto existing_file;
301 free(art_file);
302 imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE);
303 if( imsrc )
304 goto found_file;
306 check_dir:
307 /* Then fall back to possible generic cover art file names */
308 for( album_art_name = album_art_names; album_art_name; album_art_name = album_art_name->next )
310 snprintf(file, sizeof(file), "%s/%s", dir, album_art_name->name);
311 if( access(file, R_OK) == 0 )
313 if( art_cache_exists(file, &art_file) )
315 existing_file:
316 return art_file;
318 free(art_file);
319 imsrc = image_new_from_jpeg(file, 1, NULL, 0, 1, ROTATE_NONE);
320 if( !imsrc )
321 continue;
322 found_file:
323 width = imsrc->width;
324 height = imsrc->height;
325 if( width > 160 || height > 160 )
326 art_file = save_resized_album_art(imsrc, file);
327 else
328 art_file = strdup(file);
329 image_free(imsrc);
330 return(art_file);
333 return NULL;
336 sqlite_int64
337 find_album_art(const char *path, const char *image_data, int image_size)
339 char *album_art = NULL;
340 char *sql;
341 char **result;
342 int cols, rows;
343 sqlite_int64 ret = 0;
345 if( (image_size && (album_art = check_embedded_art(path, image_data, image_size))) ||
346 (album_art = check_for_album_file(path)) )
348 sql = sqlite3_mprintf("SELECT ID from ALBUM_ART where PATH = '%q'", album_art ? album_art : path);
349 if( (sql_get_table(db, sql, &result, &rows, &cols) == SQLITE_OK) && rows )
351 ret = strtoll(result[1], NULL, 10);
353 else
355 if( sql_exec(db, "INSERT into ALBUM_ART (PATH) VALUES ('%q')", album_art) == SQLITE_OK )
356 ret = sqlite3_last_insert_rowid(db);
358 sqlite3_free_table(result);
359 sqlite3_free(sql);
361 free(album_art);
363 return ret;