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/>.
25 #include <sys/param.h>
27 #include <sys/param.h>
35 #include "upnpglobalvars.h"
39 #include "image_utils.h"
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 )
48 strcpy(strchr(*cache_file
, '\0')-4, ".jpg");
50 return (!access(*cache_file
, F_OK
));
54 save_resized_album_art(image_s
*imsrc
, const char *path
)
59 char cache_dir
[MAXPATHLEN
];
64 if( art_cache_exists(path
, &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
)
73 dsth
= (imsrc
->height
<<8) / ((imsrc
->width
<<8)/160);
77 dstw
= (imsrc
->width
<<8) / ((imsrc
->height
<<8)/160);
80 imdst
= image_resize(imsrc
, dstw
, dsth
);
87 cache_file
= image_save_to_jpeg_file(imdst
, cache_file
);
93 /* And our main album art functions */
95 update_if_album_art(const char *path
)
99 char file
[MAXPATHLEN
];
100 char fpath
[MAXPATHLEN
];
101 char dpath
[MAXPATHLEN
];
106 enum file_types type
= TYPE_UNKNOWN
;
107 media_types dir_type
;
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;
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
)))
129 dir
= dirname(dpath
);
133 while ((dp
= readdir(dh
)) != NULL
)
137 else if (is_dir(dp
) == 1)
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] == '.')
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
);
158 DPRINTF(E_WARN
, L_METADATA
, "Error setting %s as cover art for %s\n", match
, dp
->d_name
);
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
;
172 static char last_path
[PATH_MAX
];
173 static unsigned int last_hash
= 0;
174 static int last_success
= 0;
177 if( !image_data
|| !image_size
|| !path
)
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
)
188 art_cache_exists(path
, &art_path
);
189 if( link(last_path
, art_path
) == 0 )
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
);
200 if( link(last_path
, art_path
) == 0 )
203 DPRINTF(E_WARN
, L_METADATA
, "Linking %s to %s failed [%s]\n", art_path
, last_path
, strerror(errno
));
210 imsrc
= image_new_from_jpeg(NULL
, 0, image_data
, image_size
, 1, ROTATE_NONE
);
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 )
226 if( art_cache_exists(path
, &art_path
) )
228 cache_dir
= strdup(art_path
);
229 make_dir(dirname(cache_dir
), S_IRWXU
|S_IRGRP
|S_IXGRP
|S_IROTH
|S_IXOTH
);
231 dstfile
= fopen(art_path
, "w");
238 nwritten
= fwrite((void *)image_data
, 1, image_size
, 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
);
254 DPRINTF(E_WARN
, L_METADATA
, "Invalid embedded album art in %s\n", basename((char *)path
));
258 DPRINTF(E_DEBUG
, L_METADATA
, "Found new embedded album art in %s\n", basename((char *)path
));
260 strcpy(last_path
, art_path
);
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;
278 if( stat(path
, &st
) != 0 )
281 if( S_ISDIR(st
.st_mode
) )
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
);
294 strncpyt(file
, path
, sizeof(file
));
295 p
= strrchr(file
, '.');
299 ret
= access(file
, R_OK
);
303 p
= strrchr(file
, '/');
306 memmove(p
+2, p
+1, file
+MAXPATHLEN
-p
-2);
308 ret
= access(file
, R_OK
);
314 if( art_cache_exists(file
, &art_file
) )
317 imsrc
= image_new_from_jpeg(file
, 1, NULL
, 0, 1, ROTATE_NONE
);
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
) )
334 imsrc
= image_new_from_jpeg(file
, 1, NULL
, 0, 1, ROTATE_NONE
);
338 width
= imsrc
->width
;
339 height
= imsrc
->height
;
340 if( width
> 160 || height
> 160 )
341 art_file
= save_resized_album_art(imsrc
, file
);
343 art_file
= strdup(file
);
352 find_album_art(const char *path
, uint8_t *image_data
, int image_size
)
354 char *album_art
= NULL
;
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
);
363 if( sql_exec(db
, "INSERT into ALBUM_ART (PATH) VALUES ('%q')", album_art
) == SQLITE_OK
)
364 ret
= sqlite3_last_insert_rowid(db
);