]> git.sesse.net Git - vlc/blob - src/playlist/art.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / src / playlist / art.c
1 /*****************************************************************************
2  * art.c : Art metadata handling
3  *****************************************************************************
4  * Copyright (C) 1998-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea@videolan.org>
8  *          ClĂ©ment Stenac <zorglub@videolan.org
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <assert.h>
30 #include <vlc_common.h>
31 #include <vlc_playlist.h>
32 #include <vlc_fs.h>
33 #include <vlc_strings.h>
34 #include <vlc_stream.h>
35 #include <vlc_url.h>
36 #include <vlc_md5.h>
37
38 #include <limits.h>                                             /* PATH_MAX */
39
40 #ifdef HAVE_SYS_STAT_H
41 #   include <sys/stat.h>
42 #endif
43
44 #include "../libvlc.h"
45 #include "playlist_internal.h"
46
47 static void ArtCacheCreateDir( const char *psz_dir )
48 {
49     char newdir[strlen( psz_dir ) + 1];
50     strcpy( newdir, psz_dir );
51     char * psz_newdir = newdir;
52     char * psz = psz_newdir;
53
54     while( *psz )
55     {
56         while( *psz && *psz != DIR_SEP_CHAR) psz++;
57         if( !*psz ) break;
58         *psz = 0;
59         if( !EMPTY_STR( psz_newdir ) )
60             vlc_mkdir( psz_newdir, 0700 );
61         *psz = DIR_SEP_CHAR;
62         psz++;
63     }
64     vlc_mkdir( psz_dir, 0700 );
65 }
66
67 static char* ArtCacheGetDirPath( const char *psz_arturl, const char *psz_artist,
68                                  const char *psz_album )
69 {
70     char *psz_dir;
71     char *psz_cachedir = config_GetUserDir(VLC_CACHE_DIR);
72
73     if( !EMPTY_STR(psz_artist) && !EMPTY_STR(psz_album) )
74     {
75         char *psz_album_sanitized = strdup( psz_album );
76         filename_sanitize( psz_album_sanitized );
77         char *psz_artist_sanitized = strdup( psz_artist );
78         filename_sanitize( psz_artist_sanitized );
79         if( asprintf( &psz_dir, "%s" DIR_SEP "art" DIR_SEP "artistalbum"
80                       DIR_SEP "%s" DIR_SEP "%s", psz_cachedir,
81                       psz_artist_sanitized, psz_album_sanitized ) == -1 )
82             psz_dir = NULL;
83         free( psz_album_sanitized );
84         free( psz_artist_sanitized );
85     }
86     else
87     {
88         /* If artist or album missing cache by art download URL. The download
89            URL will be md5 hashed to form a valid cache filename. We assume that
90            psz_arturl is always the download URL and not the already hashed filename.
91            (We should never need to call this function if art has already been
92            downloaded anyway). */
93         struct md5_s md5;
94         InitMD5( &md5 );
95         AddMD5( &md5, psz_arturl, strlen( psz_arturl ) );
96         EndMD5( &md5 );
97         char * psz_arturl_sanitized = psz_md5_hash( &md5 );
98         if( asprintf( &psz_dir, "%s" DIR_SEP "art" DIR_SEP "arturl" DIR_SEP
99                       "%s", psz_cachedir, psz_arturl_sanitized ) == -1 )
100             psz_dir = NULL;
101         free( psz_arturl_sanitized );
102     }
103     free( psz_cachedir );
104     return psz_dir;
105 }
106
107 static char *ArtCachePath( input_item_t *p_item )
108 {
109     char* psz_path = NULL;
110     const char *psz_artist;
111     const char *psz_album;
112     const char *psz_arturl;
113
114     vlc_mutex_lock( &p_item->lock );
115
116     if( !p_item->p_meta )
117         p_item->p_meta = vlc_meta_New();
118     if( !p_item->p_meta )
119         goto end;
120
121     psz_artist = vlc_meta_Get( p_item->p_meta, vlc_meta_Artist );
122     psz_album = vlc_meta_Get( p_item->p_meta, vlc_meta_Album );
123     psz_arturl = vlc_meta_Get( p_item->p_meta, vlc_meta_ArtworkURL );
124
125     if( (EMPTY_STR(psz_artist) || EMPTY_STR(psz_album) ) && !psz_arturl )
126         goto end;
127
128     psz_path = ArtCacheGetDirPath( psz_arturl, psz_artist, psz_album );
129
130 end:
131     vlc_mutex_unlock( &p_item->lock );
132     return psz_path;
133 }
134
135 static char *ArtCacheName( input_item_t *p_item, const char *psz_type )
136 {
137     char *psz_path = ArtCachePath( p_item );
138     if( !psz_path )
139         return NULL;
140
141     ArtCacheCreateDir( psz_path );
142
143     char *psz_ext = strdup( psz_type ? psz_type : "" );
144     filename_sanitize( psz_ext );
145     char *psz_filename;
146     if( asprintf( &psz_filename, "%s" DIR_SEP "art%s", psz_path, psz_ext ) < 0 )
147         psz_filename = NULL;
148
149     free( psz_ext );
150     free( psz_path );
151
152     return psz_filename;
153 }
154
155 /* */
156 int playlist_FindArtInCache( input_item_t *p_item )
157 {
158     char *psz_path = ArtCachePath( p_item );
159
160     if( !psz_path )
161         return VLC_EGENERIC;
162
163     /* Check if file exists */
164     DIR *p_dir = vlc_opendir( psz_path );
165     if( !p_dir )
166     {
167         free( psz_path );
168         return VLC_EGENERIC;
169     }
170
171     bool b_found = false;
172     char *psz_filename;
173     while( !b_found && (psz_filename = vlc_readdir( p_dir )) )
174     {
175         if( !strncmp( psz_filename, "art", 3 ) )
176         {
177             char *psz_file;
178             if( asprintf( &psz_file, "%s" DIR_SEP "%s",
179                           psz_path, psz_filename ) != -1 )
180             {
181                 char *psz_uri = make_URI( psz_file, "file" );
182                 if( psz_uri )
183                 {
184                     input_item_SetArtURL( p_item, psz_uri );
185                     free( psz_uri );
186                 }
187                 free( psz_file );
188             }
189
190             b_found = true;
191         }
192         free( psz_filename );
193     }
194
195     /* */
196     closedir( p_dir );
197     free( psz_path );
198     return b_found ? VLC_SUCCESS : VLC_EGENERIC;
199 }
200
201
202 /* */
203 int playlist_SaveArt( playlist_t *p_playlist, input_item_t *p_item,
204                       const uint8_t *p_buffer, int i_buffer, const char *psz_type )
205 {
206     char *psz_filename = ArtCacheName( p_item, psz_type );
207
208     if( !psz_filename )
209         return VLC_EGENERIC;
210
211     char *psz_uri = make_URI( psz_filename, "file" );
212     if( !psz_uri )
213     {
214         free( psz_filename );
215         return VLC_EGENERIC;
216     }
217
218     /* Check if we already dumped it */
219     struct stat s;
220     if( !vlc_stat( psz_filename, &s ) )
221     {
222         input_item_SetArtURL( p_item, psz_uri );
223         free( psz_filename );
224         free( psz_uri );
225         return VLC_SUCCESS;
226     }
227
228     /* Dump it otherwise */
229     FILE *f = vlc_fopen( psz_filename, "wb" );
230     if( f )
231     {
232         if( fwrite( p_buffer, i_buffer, 1, f ) != 1 )
233         {
234             msg_Err( p_playlist, "%s: %m", psz_filename );
235         }
236         else
237         {
238             msg_Dbg( p_playlist, "album art saved to %s", psz_filename );
239             input_item_SetArtURL( p_item, psz_uri );
240         }
241         fclose( f );
242     }
243     free( psz_filename );
244     free( psz_uri );
245     return VLC_SUCCESS;
246 }
247