~ubuntu-branches/ubuntu/maverick/vlc/maverick

« back to all changes in this revision

Viewing changes to src/input/meta.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2008-09-17 21:56:14 UTC
  • mfrom: (1.1.17 upstream)
  • Revision ID: james.westby@ubuntu.com-20080917215614-tj0vx8xzd57e52t8
Tags: 0.9.2-1ubuntu1
* New Upstream Release, exception granted by
    - dktrkranz, norsetto, Hobbsee (via irc). LP: #270404

Changes done in ubuntu:

* add libxul-dev to build-depends
* make sure that vlc is build against libxul in configure. This doesn't
  change anything in the package, but makes it more robust if building
  in an 'unclean' chroot or when modifying the package.
* debian/control: make Vcs-* fields point to the motumedia branch
* add libx264-dev and libass-dev to build-depends
  LP: #210354, #199870
* actually enable libass support by passing --enable-libass to configure
* enable libdca: add libdca-dev to build depends and --enable-libdca
* install the x264 plugin.

Changes already in the pkg-multimedia branch in debian:

* don't install usr/share/vlc/mozilla in debian/mozilla-plugin-vlc.install  
* new upstream .desktop file now registers flash video mimetype LP: #261567
* add Xb-Npp-Applications to mozilla-plugin-vlc
* remove duplicate entries in debian/vlc-nox.install

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * meta.c : Metadata handling
 
3
 *****************************************************************************
 
4
 * Copyright (C) 1998-2004 the VideoLAN team
 
5
 * $Id: 402c9919ea47577b26d663e6678db48be32524d6 $
 
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 <vlc_common.h>
 
30
#include <vlc_input.h>
 
31
#include <vlc_stream.h>
 
32
#include <vlc_meta.h>
 
33
#include <vlc_playlist.h>
 
34
#include <vlc_charset.h>
 
35
#include <vlc_strings.h>
 
36
#include "../playlist/playlist_internal.h"
 
37
#include <errno.h>
 
38
#include <limits.h>                                             /* PATH_MAX */
 
39
#include <assert.h>
 
40
 
 
41
#ifdef HAVE_SYS_STAT_H
 
42
#   include <sys/stat.h>
 
43
#endif
 
44
 
 
45
#include "../libvlc.h"
 
46
 
 
47
const char *
 
48
input_MetaTypeToLocalizedString( vlc_meta_type_t meta_type )
 
49
{
 
50
    switch( meta_type )
 
51
    {
 
52
    case vlc_meta_Title:        return _("Title");
 
53
    case vlc_meta_Artist:       return _("Artist");
 
54
    case vlc_meta_Genre:        return _("Genre");
 
55
    case vlc_meta_Copyright:    return _("Copyright");
 
56
    case vlc_meta_Album:        return _("Album");
 
57
    case vlc_meta_TrackNumber:  return _("Track number");
 
58
    case vlc_meta_Description:  return _("Description");
 
59
    case vlc_meta_Rating:       return _("Rating");
 
60
    case vlc_meta_Date:         return _("Date");
 
61
    case vlc_meta_Setting:      return _("Setting");
 
62
    case vlc_meta_URL:          return _("URL");
 
63
    case vlc_meta_Language:     return _("Language");
 
64
    case vlc_meta_NowPlaying:   return _("Now Playing");
 
65
    case vlc_meta_Publisher:    return _("Publisher");
 
66
    case vlc_meta_EncodedBy:    return _("Encoded by");
 
67
    case vlc_meta_ArtworkURL:   return _("Artwork URL");
 
68
    case vlc_meta_TrackID:      return _("Track ID");
 
69
 
 
70
    default: abort();
 
71
    }
 
72
};
 
73
 
 
74
#define input_FindArtInCache(a,b) __input_FindArtInCache(VLC_OBJECT(a),b)
 
75
static int __input_FindArtInCache( vlc_object_t *, input_item_t *p_item );
 
76
 
 
77
/* Return codes:
 
78
 *   0 : Art is in cache or is a local file
 
79
 *   1 : Art found, need to download
 
80
 *  -X : Error/not found
 
81
 */
 
82
int input_ArtFind( playlist_t *p_playlist, input_item_t *p_item )
 
83
{
 
84
    int i_ret = VLC_EGENERIC;
 
85
    module_t *p_module;
 
86
    char *psz_title, *psz_artist, *psz_album;
 
87
 
 
88
    psz_artist = input_item_GetArtist( p_item );
 
89
    psz_album = input_item_GetAlbum( p_item );
 
90
    psz_title = input_item_GetTitle( p_item );
 
91
    if(!psz_title)
 
92
        psz_title = input_item_GetName( p_item );
 
93
 
 
94
    if( !psz_title && !psz_artist && !psz_album )
 
95
        return VLC_EGENERIC;
 
96
 
 
97
    free( psz_title );
 
98
 
 
99
    /* If we already checked this album in this session, skip */
 
100
    if( psz_artist && psz_album )
 
101
    {
 
102
        FOREACH_ARRAY( playlist_album_t album, p_playlist->p_fetcher->albums )
 
103
            if( !strcmp( album.psz_artist, psz_artist ) &&
 
104
                !strcmp( album.psz_album, psz_album ) )
 
105
            {
 
106
                msg_Dbg( p_playlist, " %s - %s has already been searched",
 
107
                         psz_artist, psz_album );
 
108
        /* TODO-fenrir if we cache art filename too, we can go faster */
 
109
                free( psz_artist );
 
110
                free( psz_album );
 
111
                if( album.b_found )
 
112
                {
 
113
                    if( !strncmp( album.psz_arturl, "file://", 7 ) )
 
114
                        input_item_SetArtURL( p_item, album.psz_arturl );
 
115
                    else /* Actually get URL from cache */
 
116
                        input_FindArtInCache( p_playlist, p_item );
 
117
                    return 0;
 
118
                }
 
119
                else
 
120
                {
 
121
                    return VLC_EGENERIC;
 
122
                }
 
123
            }
 
124
        FOREACH_END();
 
125
    }
 
126
    free( psz_artist );
 
127
    free( psz_album );
 
128
 
 
129
    input_FindArtInCache( p_playlist, p_item );
 
130
 
 
131
    char *psz_arturl = input_item_GetArtURL( p_item );
 
132
    if( psz_arturl )
 
133
    {
 
134
        /* We already have an URL */
 
135
        if( !strncmp( psz_arturl, "file://", strlen( "file://" ) ) )
 
136
        {
 
137
            free( psz_arturl );
 
138
            return 0; /* Art is in cache, no need to go further */
 
139
        }
 
140
 
 
141
        free( psz_arturl );
 
142
        
 
143
        /* Art need to be put in cache */
 
144
        return 1;
 
145
    }
 
146
 
 
147
    PL_LOCK;
 
148
    p_playlist->p_private = p_item;
 
149
    psz_album = input_item_GetAlbum( p_item );
 
150
    psz_artist = input_item_GetArtist( p_item );
 
151
    psz_title = input_item_GetTitle( p_item );
 
152
    if( !psz_title )
 
153
        psz_title = input_item_GetName( p_item );
 
154
 
 
155
    if( psz_album && psz_artist )
 
156
    {
 
157
        msg_Dbg( p_playlist, "searching art for %s - %s",
 
158
             psz_artist, psz_album );
 
159
    }
 
160
    else
 
161
    {
 
162
        msg_Dbg( p_playlist, "searching art for %s",
 
163
             psz_title );
 
164
    }
 
165
    free( psz_title );
 
166
 
 
167
    p_module = module_Need( p_playlist, "art finder", 0, false );
 
168
 
 
169
    if( p_module )
 
170
        i_ret = 1;
 
171
    else
 
172
        msg_Dbg( p_playlist, "unable to find art" );
 
173
 
 
174
    /* Record this album */
 
175
    if( psz_artist && psz_album )
 
176
    {
 
177
        playlist_album_t a;
 
178
        a.psz_artist = psz_artist;
 
179
        a.psz_album = psz_album;
 
180
        a.psz_arturl = input_item_GetArtURL( p_item );
 
181
        a.b_found = (i_ret == VLC_EGENERIC ? false : true );
 
182
        ARRAY_APPEND( p_playlist->p_fetcher->albums, a );
 
183
    }
 
184
    else
 
185
    {
 
186
        free( psz_artist );
 
187
        free( psz_album );
 
188
    }
 
189
 
 
190
    if( p_module )
 
191
        module_Unneed( p_playlist, p_module );
 
192
    p_playlist->p_private = NULL;
 
193
    PL_UNLOCK;
 
194
 
 
195
    return i_ret;
 
196
}
 
197
 
 
198
static void ArtCacheCreateDir( const char *psz_dir )
 
199
{
 
200
    char newdir[strlen( psz_dir ) + 1];
 
201
    strcpy( newdir, psz_dir );
 
202
    char * psz_newdir = newdir;
 
203
    char * psz = psz_newdir;
 
204
 
 
205
    while( *psz )
 
206
    {
 
207
        while( *psz && *psz != DIR_SEP_CHAR) psz++;
 
208
        if( !*psz ) break;
 
209
        *psz = 0;
 
210
        if( !EMPTY_STR( psz_newdir ) )
 
211
            utf8_mkdir( psz_newdir, 0700 );
 
212
        *psz = DIR_SEP_CHAR;
 
213
        psz++;
 
214
    }
 
215
    utf8_mkdir( psz_dir, 0700 );
 
216
}
 
217
 
 
218
static char * ArtCacheGetSanitizedFileName( const char *psz )
 
219
{
 
220
    char *dup = strdup(psz);
 
221
    int i;
 
222
 
 
223
    filename_sanitize( dup );
 
224
 
 
225
    /* Doesn't create a filename with invalid characters
 
226
     * TODO: several filesystems forbid several characters: list them all
 
227
     */
 
228
    for( i = 0; dup[i] != '\0'; i++ )
 
229
    {
 
230
        if( dup[i] == DIR_SEP_CHAR )
 
231
            dup[i] = ' ';
 
232
    }
 
233
    return dup;
 
234
}
 
235
 
 
236
#define ArtCacheGetDirPath(a,b,c,d,e) __ArtCacheGetDirPath(VLC_OBJECT(a),b,c,d,e)
 
237
static void __ArtCacheGetDirPath( vlc_object_t *p_obj,
 
238
                                  char *psz_dir,
 
239
                                  const char *psz_title,
 
240
                                  const char *psz_artist, const char *psz_album )
 
241
{
 
242
    (void)p_obj;
 
243
    char *psz_cachedir = config_GetCacheDir();
 
244
 
 
245
    if( !EMPTY_STR(psz_artist) && !EMPTY_STR(psz_album) )
 
246
    {
 
247
        char * psz_album_sanitized = ArtCacheGetSanitizedFileName( psz_album );
 
248
        char * psz_artist_sanitized = ArtCacheGetSanitizedFileName( psz_artist );
 
249
        snprintf( psz_dir, PATH_MAX, "%s" DIR_SEP
 
250
                  "art" DIR_SEP "artistalbum" DIR_SEP "%s" DIR_SEP "%s",
 
251
                  psz_cachedir, psz_artist_sanitized, psz_album_sanitized );
 
252
        free( psz_album_sanitized );
 
253
        free( psz_artist_sanitized );
 
254
    }
 
255
    else
 
256
    {
 
257
        char * psz_title_sanitized = ArtCacheGetSanitizedFileName( psz_title );
 
258
        snprintf( psz_dir, PATH_MAX, "%s" DIR_SEP
 
259
                  "art" DIR_SEP "title" DIR_SEP "%s",
 
260
                  psz_cachedir, psz_title_sanitized );
 
261
        free( psz_title_sanitized );
 
262
    }
 
263
    free( psz_cachedir );
 
264
}
 
265
 
 
266
 
 
267
 
 
268
#define ArtCacheGetFilePath(a,b,c,d,e,f) __ArtCacheGetFilePath(VLC_OBJECT(a),b,c,d,e,f)
 
269
static void __ArtCacheGetFilePath( vlc_object_t *p_obj,
 
270
                                   char * psz_filename,
 
271
                                   const char *psz_title,
 
272
                                   const char *psz_artist, const char *psz_album,
 
273
                                   const char *psz_extension )
 
274
{
 
275
    char psz_dir[PATH_MAX+1];
 
276
    char * psz_ext;
 
277
    ArtCacheGetDirPath( p_obj, psz_dir, psz_title, psz_artist, psz_album );
 
278
 
 
279
    if( psz_extension )
 
280
    {
 
281
        psz_ext = strndup( psz_extension, 6 );
 
282
        filename_sanitize( psz_ext );
 
283
    }
 
284
    else psz_ext = strdup( "" );
 
285
 
 
286
    snprintf( psz_filename, PATH_MAX, "file://%s" DIR_SEP "art%s",
 
287
              psz_dir, psz_ext );
 
288
 
 
289
    free( psz_ext );
 
290
}
 
291
 
 
292
static int __input_FindArtInCache( vlc_object_t *p_obj, input_item_t *p_item )
 
293
{
 
294
    char *psz_artist;
 
295
    char *psz_album;
 
296
    char *psz_title;
 
297
    char psz_dirpath[PATH_MAX+1];
 
298
    char psz_filepath[PATH_MAX+1];
 
299
    char * psz_filename;
 
300
    DIR * p_dir;
 
301
 
 
302
    psz_artist = input_item_GetArtist( p_item );
 
303
    psz_album = input_item_GetAlbum( p_item );
 
304
    psz_title = input_item_GetTitle( p_item );
 
305
    if( !psz_title ) psz_title = input_item_GetName( p_item );
 
306
 
 
307
    if( !psz_title && ( !psz_album || !psz_artist ) )
 
308
    {
 
309
        free( psz_artist );
 
310
        free( psz_album );
 
311
        free( psz_title );
 
312
        return VLC_EGENERIC;
 
313
    }
 
314
 
 
315
    ArtCacheGetDirPath( p_obj, psz_dirpath, psz_title,
 
316
                           psz_artist, psz_album );
 
317
 
 
318
    free( psz_artist );
 
319
    free( psz_album );
 
320
    free( psz_title );
 
321
 
 
322
    /* Check if file exists */
 
323
    p_dir = utf8_opendir( psz_dirpath );
 
324
    if( !p_dir )
 
325
        return VLC_EGENERIC;
 
326
 
 
327
    while( (psz_filename = utf8_readdir( p_dir )) )
 
328
    {
 
329
        if( !strncmp( psz_filename, "art", 3 ) )
 
330
        {
 
331
            snprintf( psz_filepath, PATH_MAX, "file://%s" DIR_SEP "%s",
 
332
                      psz_dirpath, psz_filename );
 
333
            input_item_SetArtURL( p_item, psz_filepath );
 
334
            free( psz_filename );
 
335
            closedir( p_dir );
 
336
            return VLC_SUCCESS;
 
337
        }
 
338
        free( psz_filename );
 
339
    }
 
340
 
 
341
    /* Not found */
 
342
    closedir( p_dir );
 
343
    return VLC_EGENERIC;
 
344
}
 
345
 
 
346
/**
 
347
 * Download the art using the URL or an art downloaded
 
348
 * This function should be called only if data is not already in cache
 
349
 */
 
350
int input_DownloadAndCacheArt( playlist_t *p_playlist, input_item_t *p_item )
 
351
{
 
352
    int i_status = VLC_EGENERIC;
 
353
    stream_t *p_stream;
 
354
    char psz_filename[PATH_MAX+1];
 
355
    char *psz_artist = NULL;
 
356
    char *psz_album = NULL;
 
357
    char *psz_title = NULL;
 
358
    char *psz_arturl;
 
359
    char *psz_type;
 
360
 
 
361
    psz_artist = input_item_GetArtist( p_item );
 
362
    psz_album = input_item_GetAlbum( p_item );
 
363
    psz_title = input_item_GetTitle( p_item );
 
364
    if( !psz_title )
 
365
        psz_title = input_item_GetName( p_item );
 
366
 
 
367
    if( !psz_title && (!psz_artist || !psz_album) )
 
368
    {
 
369
        free( psz_title );
 
370
        free( psz_album );
 
371
        free( psz_artist );
 
372
        return VLC_EGENERIC;
 
373
    }
 
374
 
 
375
    psz_arturl = input_item_GetArtURL( p_item );
 
376
    assert( !EMPTY_STR( psz_arturl ) );
 
377
 
 
378
    if( !strncmp( psz_arturl , "file://", 7 ) )
 
379
    {
 
380
        msg_Dbg( p_playlist, "Album art is local file, no need to cache" );
 
381
        free( psz_arturl );
 
382
        return VLC_SUCCESS;
 
383
    }
 
384
    else if( !strncmp( psz_arturl , "APIC", 4 ) )
 
385
    {
 
386
        msg_Warn( p_playlist, "APIC fetch not supported yet" );
 
387
        free( psz_arturl );
 
388
        return VLC_EGENERIC;
 
389
    }
 
390
 
 
391
    psz_type = strrchr( psz_arturl, '.' );
 
392
    if( psz_type && strlen( psz_type ) > 5 )
 
393
        psz_type = NULL; /* remove extension if it's > to 4 characters */
 
394
 
 
395
    /* Warning: psz_title, psz_artist, psz_album may change in ArtCache*() */
 
396
 
 
397
    ArtCacheGetDirPath( p_playlist, psz_filename, psz_title, psz_artist,
 
398
                        psz_album );
 
399
    ArtCacheCreateDir( psz_filename );
 
400
    ArtCacheGetFilePath( p_playlist, psz_filename, psz_title, psz_artist,
 
401
                         psz_album, psz_type );
 
402
 
 
403
    free( psz_artist );
 
404
    free( psz_album );
 
405
    free( psz_title );
 
406
 
 
407
    p_stream = stream_UrlNew( p_playlist, psz_arturl );
 
408
    if( p_stream )
 
409
    {
 
410
        uint8_t p_buffer[65536];
 
411
        long int l_read;
 
412
        FILE *p_file = utf8_fopen( psz_filename+7, "w" );
 
413
        if( p_file == NULL ) {
 
414
            msg_Err( p_playlist, "Unable write album art in %s",
 
415
                     psz_filename + 7 );
 
416
            free( psz_arturl );
 
417
            return VLC_EGENERIC;
 
418
        }
 
419
        int err = 0;
 
420
        while( ( l_read = stream_Read( p_stream, p_buffer, sizeof (p_buffer) ) ) )
 
421
        {
 
422
            if( fwrite( p_buffer, l_read, 1, p_file ) != 1 )
 
423
            {
 
424
                err = errno;
 
425
                break;
 
426
            }
 
427
        }
 
428
        if( fclose( p_file ) && !err )
 
429
            err = errno;
 
430
        stream_Delete( p_stream );
 
431
 
 
432
        if( err )
 
433
        {
 
434
            errno = err;
 
435
            msg_Err( p_playlist, "%s: %m", psz_filename );
 
436
        }
 
437
        else
 
438
            msg_Dbg( p_playlist, "album art saved to %s\n", psz_filename );
 
439
 
 
440
        input_item_SetArtURL( p_item, psz_filename );
 
441
        i_status = VLC_SUCCESS;
 
442
    }
 
443
    free( psz_arturl );
 
444
    return i_status;
 
445
}
 
446
 
 
447
void input_ExtractAttachmentAndCacheArt( input_thread_t *p_input )
 
448
{
 
449
    input_item_t *p_item = p_input->p->input.p_item;
 
450
    const char *psz_arturl;
 
451
    const char *psz_artist = NULL;
 
452
    const char *psz_album = NULL;
 
453
    const char *psz_title = NULL;
 
454
    char *psz_type = NULL;
 
455
    char psz_filename[PATH_MAX+1];
 
456
    FILE *f;
 
457
    input_attachment_t *p_attachment;
 
458
    struct stat s;
 
459
    int i_idx;
 
460
 
 
461
    /* TODO-fenrir merge input_ArtFind with download and make it set the flags FETCH
 
462
     * and then set it here to to be faster */
 
463
 
 
464
    psz_arturl = vlc_meta_Get( p_item->p_meta, vlc_meta_ArtworkURL );
 
465
 
 
466
    if( !psz_arturl || strncmp( psz_arturl, "attachment://", strlen("attachment://") ) )
 
467
    {
 
468
        msg_Err( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
 
469
        return;
 
470
    }
 
471
 
 
472
    if( input_item_IsArtFetched( p_item ) )
 
473
    {
 
474
        /* XXX Weird, we should not have end up with attachment:// art url unless there is a race
 
475
         * condition */
 
476
        msg_Warn( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
 
477
        input_FindArtInCache( p_input, p_item );
 
478
        return;
 
479
    }
 
480
 
 
481
    /* */
 
482
    for( i_idx = 0, p_attachment = NULL; i_idx < p_input->p->i_attachment; i_idx++ )
 
483
    {
 
484
        if( !strcmp( p_input->p->attachment[i_idx]->psz_name,
 
485
                     &psz_arturl[strlen("attachment://")] ) )
 
486
        {
 
487
            p_attachment = p_input->p->attachment[i_idx];
 
488
            break;
 
489
        }
 
490
    }
 
491
    if( !p_attachment || p_attachment->i_data <= 0 )
 
492
    {
 
493
        msg_Warn( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
 
494
        return;
 
495
    }
 
496
 
 
497
    psz_artist = vlc_meta_Get( p_item->p_meta, vlc_meta_Artist );
 
498
    psz_album = vlc_meta_Get( p_item->p_meta, vlc_meta_Album );
 
499
    psz_title = vlc_meta_Get( p_item->p_meta, vlc_meta_Title );
 
500
    if( !strcmp( p_attachment->psz_mime, "image/jpeg" ) )
 
501
        psz_type = strdup( ".jpg" );
 
502
    else if( !strcmp( p_attachment->psz_mime, "image/png" ) )
 
503
        psz_type = strdup( ".png" );
 
504
 
 
505
    if( !psz_title )
 
506
        psz_title = p_item->psz_name;
 
507
 
 
508
    if( (!psz_artist || !psz_album ) && !psz_title )
 
509
        return;
 
510
 
 
511
    ArtCacheGetDirPath( p_input, psz_filename, psz_title, psz_artist, psz_album );
 
512
    ArtCacheCreateDir( psz_filename );
 
513
    ArtCacheGetFilePath( p_input, psz_filename, psz_title, psz_artist, psz_album, psz_type );
 
514
    free( psz_type );
 
515
 
 
516
    /* Check if we already dumped it */
 
517
    if( !utf8_stat( psz_filename+7, &s ) )
 
518
    {
 
519
        vlc_meta_Set( p_item->p_meta, vlc_meta_ArtworkURL, psz_filename );
 
520
        return;
 
521
    }
 
522
 
 
523
    f = utf8_fopen( psz_filename+7, "w" );
 
524
    if( f )
 
525
    {
 
526
        if( fwrite( p_attachment->p_data, p_attachment->i_data, 1, f ) != 1 )
 
527
            msg_Err( p_input, "%s: %m", psz_filename );
 
528
        else
 
529
        {
 
530
            msg_Dbg( p_input, "album art saved to %s\n", psz_filename );
 
531
            vlc_meta_Set( p_item->p_meta, vlc_meta_ArtworkURL, psz_filename );
 
532
        }
 
533
        fclose( f );
 
534
    }
 
535
}