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/>.
30 #include "upnpglobalvars.h"
34 #include "image_utils.h"
38 art_cache_exists(const char * orig_path
, char ** cache_file
)
40 asprintf(cache_file
, "%s/art_cache%s", db_path
, orig_path
);
41 strcpy(strchr(*cache_file
, '\0')-4, ".jpg");
43 return (!access(*cache_file
, F_OK
));
47 save_resized_album_art(image_s
* imsrc
, const char * path
)
57 if( art_cache_exists(path
, &cache_file
) )
60 cache_dir
= strdup(cache_file
);
61 make_dir(dirname(cache_dir
), S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);
64 if( imsrc
->width
> imsrc
->height
)
67 dsth
= (imsrc
->height
<<8) / ((imsrc
->width
<<8)/160);
71 dstw
= (imsrc
->width
<<8) / ((imsrc
->height
<<8)/160);
74 imdst
= image_resize(imsrc
, dstw
, dsth
);
78 if( image_save_to_jpeg_file(imdst
, cache_file
) == 0 )
88 /* Simple, efficient hash function from Daniel J. Bernstein */
89 unsigned int DJBHash(const char * str
, int len
)
91 unsigned int hash
= 5381;
94 for(i
= 0; i
< len
; str
++, i
++)
96 hash
= ((hash
<< 5) + hash
) + (*str
);
102 /* And our main album art functions */
104 update_if_album_art(const char * path
)
113 enum file_types type
= TYPE_UNKNOWN
;
114 sqlite_int64 art_id
= 0;
116 match
= strdup(basename((char *)path
));
117 /* Check if this file name matches a specific audio or video file */
118 if( ends_with(match
, ".cover.jpg") )
120 ncmp
= strlen(match
)-10;
124 ncmp
= strrchr(match
, '.') - match
;
126 /* Check if this file name matches one of the default album art names */
127 album_art
= is_album_art(match
);
129 dir
= dirname(strdup(path
));
133 while ((dp
= readdir(dh
)) != NULL
)
142 asprintf(&file
, "%s/%s", dir
, dp
->d_name
);
143 type
= resolve_unknown_type(file
, ALL_MEDIA
);
150 if( type
!= TYPE_FILE
)
152 if( (*(dp
->d_name
) != '.') &&
153 (is_video(dp
->d_name
) || is_audio(dp
->d_name
)) &&
154 (album_art
|| strncmp(dp
->d_name
, match
, ncmp
) == 0) )
156 DPRINTF(E_DEBUG
, L_METADATA
, "New file %s looks like cover art for %s\n", path
, dp
->d_name
);
157 asprintf(&file
, "%s/%s", dir
, dp
->d_name
);
158 art_id
= find_album_art(file
, NULL
, 0);
159 if( sql_exec(db
, "UPDATE DETAILS set ALBUM_ART = %lld where PATH = '%q'", art_id
, file
) != SQLITE_OK
)
160 DPRINTF(E_WARN
, L_METADATA
, "Error setting %s as cover art for %s\n", match
, dp
->d_name
);
171 check_embedded_art(const char * path
, const char * image_data
, int image_size
)
173 int width
= 0, height
= 0;
174 char * art_path
= NULL
;
178 static char last_path
[PATH_MAX
];
179 static unsigned int last_hash
= 0;
180 static int last_success
= 0;
183 if( !image_data
|| !image_size
|| !path
)
187 /* If the embedded image matches the embedded image from the last file we
188 * checked, just make a hard link. Better than storing it on the disk twice. */
189 hash
= DJBHash(image_data
, image_size
);
190 if( hash
== last_hash
)
194 art_cache_exists(path
, &art_path
);
195 if( link(last_path
, art_path
) == 0 )
201 if( errno
== ENOENT
)
203 cache_dir
= strdup(art_path
);
204 make_dir(dirname(cache_dir
), S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);
206 if( link(last_path
, art_path
) == 0 )
209 DPRINTF(E_WARN
, L_METADATA
, "Linking %s to %s failed [%s]\n", art_path
, last_path
, strerror(errno
));
216 imsrc
= image_new_from_jpeg(NULL
, 0, image_data
, image_size
, 1);
222 width
= imsrc
->width
;
223 height
= imsrc
->height
;
225 if( width
> 160 || height
> 160 )
227 art_path
= save_resized_album_art(imsrc
, path
);
229 else if( width
> 0 && height
> 0 )
232 if( art_cache_exists(path
, &art_path
) )
234 cache_dir
= strdup(art_path
);
235 make_dir(dirname(cache_dir
), S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);
237 dstfile
= fopen(art_path
, "w");
244 nwritten
= fwrite((void *)image_data
, 1, image_size
, dstfile
);
246 if( nwritten
!= image_size
)
248 DPRINTF(E_WARN
, L_METADATA
, "Embedded art error: wrote %d/%d bytes\n", nwritten
, image_size
);
259 DPRINTF(E_WARN
, L_METADATA
, "Invalid embedded album art in %s\n", basename((char *)path
));
263 DPRINTF(E_DEBUG
, L_METADATA
, "Found new embedded album art in %s\n", basename((char *)path
));
265 strcpy(last_path
, art_path
);
271 check_for_album_file(char * dir
, const char * path
)
273 char * file
= malloc(PATH_MAX
);
274 struct album_art_name_s
* album_art_name
;
275 image_s
* imsrc
= NULL
;
276 int width
=0, height
=0;
279 /* First look for file-specific cover art */
280 sprintf(file
, "%s.cover.jpg", path
);
281 if( access(file
, R_OK
) == 0 )
283 if( art_cache_exists(file
, &art_file
) )
286 imsrc
= image_new_from_jpeg(file
, 1, NULL
, 0, 1);
290 sprintf(file
, "%s", path
);
292 strcat(file
, ".jpg");
293 if( access(file
, R_OK
) == 0 )
295 if( art_cache_exists(file
, &art_file
) )
298 imsrc
= image_new_from_jpeg(file
, 1, NULL
, 0, 1);
303 /* Then fall back to possible generic cover art file names */
304 for( album_art_name
= album_art_names
; album_art_name
; album_art_name
= album_art_name
->next
)
306 sprintf(file
, "%s/%s", dir
, album_art_name
->name
);
307 if( access(file
, R_OK
) == 0 )
309 if( art_cache_exists(file
, &art_file
) )
316 imsrc
= image_new_from_jpeg(file
, 1, NULL
, 0, 1);
320 width
= imsrc
->width
;
321 height
= imsrc
->height
;
322 if( width
> 160 || height
> 160 )
325 file
= save_resized_album_art(imsrc
, art_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;
344 char * mypath
= strdup(path
);
346 if( (image_size
&& (album_art
= check_embedded_art(path
, image_data
, image_size
))) ||
347 (album_art
= check_for_album_file(dirname(mypath
), path
)) )
349 sql
= sqlite3_mprintf("SELECT ID from ALBUM_ART where PATH = '%q'", album_art
? album_art
: path
);
350 if( (sql_get_table(db
, sql
, &result
, &rows
, &cols
) == SQLITE_OK
) && rows
)
352 ret
= strtoll(result
[1], NULL
, 10);
356 if( sql_exec(db
, "INSERT into ALBUM_ART (PATH) VALUES ('%q')", album_art
) == SQLITE_OK
)
357 ret
= sqlite3_last_insert_rowid(db
);
359 sqlite3_free_table(result
);