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/>.
24 #include <sys/param.h>
31 #include "upnpglobalvars.h"
35 #include "image_utils.h"
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 )
46 strcpy(strchr(*cache_file
, '\0')-4, ".jpg");
48 return (!access(*cache_file
, F_OK
));
52 save_resized_album_art(image_s
*imsrc
, const char *path
)
57 char cache_dir
[MAXPATHLEN
];
62 if( art_cache_exists(path
, &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
)
71 dsth
= (imsrc
->height
<<8) / ((imsrc
->width
<<8)/160);
75 dstw
= (imsrc
->width
<<8) / ((imsrc
->height
<<8)/160);
78 imdst
= image_resize(imsrc
, dstw
, dsth
);
82 if( image_save_to_jpeg_file(imdst
, cache_file
) == 0 )
92 /* And our main album art functions */
94 update_if_album_art(const char *path
)
98 char file
[MAXPATHLEN
];
99 char fpath
[MAXPATHLEN
];
100 char dpath
[MAXPATHLEN
];
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;
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
);
127 while ((dp
= readdir(dh
)) != NULL
)
136 snprintf(file
, sizeof(file
), "%s/%s", dir
, dp
->d_name
);
137 type
= resolve_unknown_type(file
, ALL_MEDIA
);
143 if( type
!= TYPE_FILE
)
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
);
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
;
167 static char last_path
[PATH_MAX
];
168 static unsigned int last_hash
= 0;
169 static int last_success
= 0;
172 if( !image_data
|| !image_size
|| !path
)
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
)
183 art_cache_exists(path
, &art_path
);
184 if( link(last_path
, art_path
) == 0 || (errno
== EEXIST
) )
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
);
195 if( link(last_path
, art_path
) == 0 )
198 DPRINTF(E_WARN
, L_METADATA
, "Linking %s to %s failed [%s]\n", art_path
, last_path
, strerror(errno
));
205 imsrc
= image_new_from_jpeg(NULL
, 0, image_data
, image_size
, 1, ROTATE_NONE
);
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 )
221 if( art_cache_exists(path
, &art_path
) )
223 cache_dir
= strdup(art_path
);
224 make_dir(dirname(cache_dir
), S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);
226 dstfile
= fopen(art_path
, "w");
233 nwritten
= fwrite((void *)image_data
, 1, image_size
, dstfile
);
235 if( nwritten
!= image_size
)
237 DPRINTF(E_WARN
, L_METADATA
, "Embedded art error: wrote %d/%d bytes\n", nwritten
, image_size
);
248 DPRINTF(E_WARN
, L_METADATA
, "Invalid embedded album art in %s\n", basename((char *)path
));
252 DPRINTF(E_DEBUG
, L_METADATA
, "Found new embedded album art in %s\n", basename((char *)path
));
254 strcpy(last_path
, art_path
);
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;
271 if( stat(path
, &st
) != 0 )
274 if( S_ISDIR(st
.st_mode
) )
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
) )
289 imsrc
= image_new_from_jpeg(file
, 1, NULL
, 0, 1, ROTATE_NONE
);
293 snprintf(file
, sizeof(file
), "%s", path
);
294 art_file
= strrchr(file
, '.');
296 strcpy(art_file
, ".jpg");
297 if( access(file
, R_OK
) == 0 )
299 if( art_cache_exists(file
, &art_file
) )
302 imsrc
= image_new_from_jpeg(file
, 1, NULL
, 0, 1, ROTATE_NONE
);
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
) )
319 imsrc
= image_new_from_jpeg(file
, 1, NULL
, 0, 1, ROTATE_NONE
);
323 width
= imsrc
->width
;
324 height
= imsrc
->height
;
325 if( width
> 160 || height
> 160 )
326 art_file
= save_resized_album_art(imsrc
, file
);
328 art_file
= strdup(file
);
337 find_album_art(const char *path
, const char *image_data
, int image_size
)
339 char *album_art
= NULL
;
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);
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
);