meta.c 8.86 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*****************************************************************************
 * meta.c : Metadata handling
 *****************************************************************************
 * Copyright (C) 1998-2004 the VideoLAN team
 * $Id$
 *
 * Authors: Antoine Cellerier <dionoea@videolan.org>
 *          Clément Stenac <zorglub@videolan.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

25
26
27
28
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

29
#include <vlc_common.h>
zorglub's avatar
zorglub committed
30
#include <vlc_playlist.h>
31
#include <vlc_url.h>
32
#include <vlc_arrays.h>
33

34
#include "input_internal.h"
35
#include "../playlist/art.h"
36

37
38
39
40
41
42
43
44
45
struct vlc_meta_t
{
    char * ppsz_meta[VLC_META_TYPE_COUNT];
    
    vlc_dictionary_t extra_tags;
    
    int i_status;
};

46
/* FIXME bad name convention */
47
const char * vlc_meta_TypeToLocalizedString( vlc_meta_type_t meta_type )
48
{
Rafaël Carré's avatar
Rafaël Carré committed
49
    switch( meta_type )
50
    {
Rafaël Carré's avatar
Rafaël Carré committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    case vlc_meta_Title:        return _("Title");
    case vlc_meta_Artist:       return _("Artist");
    case vlc_meta_Genre:        return _("Genre");
    case vlc_meta_Copyright:    return _("Copyright");
    case vlc_meta_Album:        return _("Album");
    case vlc_meta_TrackNumber:  return _("Track number");
    case vlc_meta_Description:  return _("Description");
    case vlc_meta_Rating:       return _("Rating");
    case vlc_meta_Date:         return _("Date");
    case vlc_meta_Setting:      return _("Setting");
    case vlc_meta_URL:          return _("URL");
    case vlc_meta_Language:     return _("Language");
    case vlc_meta_NowPlaying:   return _("Now Playing");
    case vlc_meta_Publisher:    return _("Publisher");
    case vlc_meta_EncodedBy:    return _("Encoded by");
    case vlc_meta_ArtworkURL:   return _("Artwork URL");
    case vlc_meta_TrackID:      return _("Track ID");

    default: abort();
70
    }
Rafaël Carré's avatar
Rafaël Carré committed
71
};
72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

/**
 * vlc_meta contructor.
 * vlc_meta_Delete() will free the returned pointer.
 */ 
vlc_meta_t *vlc_meta_New( void )
{
    vlc_meta_t *m = (vlc_meta_t*)malloc( sizeof(*m) );
    if( !m )
        return NULL;
    memset( m->ppsz_meta, 0, sizeof(m->ppsz_meta) );
    m->i_status = 0;
    vlc_dictionary_init( &m->extra_tags, 0 );
    return m;
}

/* Free a dictonary key allocated by strdup() in vlc_meta_AddExtra() */
static void vlc_meta_FreeExtraKey( void *p_data, void *p_obj )
{
    VLC_UNUSED( p_obj );
    free( p_data );
}

void vlc_meta_Delete( vlc_meta_t *m )
{
    int i;
    for( i = 0; i < VLC_META_TYPE_COUNT ; i++ )
        free( m->ppsz_meta[i] );
    vlc_dictionary_clear( &m->extra_tags, vlc_meta_FreeExtraKey, NULL );
    free( m );
}

/**
 * vlc_meta has two kinds of meta, the one in a table, and the one in a
 * dictionary.
 * FIXME - Why don't we merge those two?
 */ 

void vlc_meta_Set( vlc_meta_t *p_meta, vlc_meta_type_t meta_type, const char *psz_val )
{
    free( p_meta->ppsz_meta[meta_type] );
    p_meta->ppsz_meta[meta_type] = psz_val ? strdup( psz_val ) : NULL;
}

const char *vlc_meta_Get( const vlc_meta_t *p_meta, vlc_meta_type_t meta_type )
{
    return p_meta->ppsz_meta[meta_type];
}

void vlc_meta_AddExtra( vlc_meta_t *m, const char *psz_name, const char *psz_value )
{
    char *psz_oldvalue = (char *)vlc_dictionary_value_for_key( &m->extra_tags, psz_name );
    if( psz_oldvalue != kVLCDictionaryNotFound )
        vlc_dictionary_remove_value_for_key( &m->extra_tags, psz_name,
                                            vlc_meta_FreeExtraKey, NULL );
    vlc_dictionary_insert( &m->extra_tags, psz_name, strdup(psz_value) );
}

const char * vlc_meta_GetExtra( const vlc_meta_t *m, const char *psz_name )
{
    return (char *)vlc_dictionary_value_for_key(&m->extra_tags, psz_name);
}

unsigned vlc_meta_GetExtraCount( const vlc_meta_t *m )
{
    return vlc_dictionary_keys_count(&m->extra_tags);
}

char** vlc_meta_CopyExtraNames( const vlc_meta_t *m )
{
    return vlc_dictionary_all_keys(&m->extra_tags);
}

/**
 * vlc_meta status (see vlc_meta_status_e)
 */
149
int vlc_meta_GetStatus( vlc_meta_t *m )
150
151
152
153
{
    return m->i_status;
}

154
void vlc_meta_SetStatus( vlc_meta_t *m, int status )
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
{
    m->i_status = status;
}


/**
 * Merging meta
 */
void vlc_meta_Merge( vlc_meta_t *dst, const vlc_meta_t *src )
{
    char **ppsz_all_keys;
    int i;
    
    if( !dst || !src )
        return;
    
    for( i = 0; i < VLC_META_TYPE_COUNT; i++ )
    {
        if( src->ppsz_meta[i] )
        {
            free( dst->ppsz_meta[i] );
            dst->ppsz_meta[i] = strdup( src->ppsz_meta[i] );
        }
    }
    
    /* XXX: If speed up are needed, it is possible */
    ppsz_all_keys = vlc_dictionary_all_keys( &src->extra_tags );
    for( i = 0; ppsz_all_keys && ppsz_all_keys[i]; i++ )
    {
        /* Always try to remove the previous value */
        vlc_dictionary_remove_value_for_key( &dst->extra_tags, ppsz_all_keys[i], vlc_meta_FreeExtraKey, NULL );
        
        void *p_value = vlc_dictionary_value_for_key( &src->extra_tags, ppsz_all_keys[i] );
        vlc_dictionary_insert( &dst->extra_tags, ppsz_all_keys[i], strdup( (const char*)p_value ) );
        free( ppsz_all_keys[i] );
    }
    free( ppsz_all_keys );
}


195
196
void input_ExtractAttachmentAndCacheArt( input_thread_t *p_input )
{
197
    input_item_t *p_item = p_input->p->p_item;
198

199
    /* */
200
    char *psz_arturl = input_item_GetArtURL( p_item );
201
202
203
    if( !psz_arturl || strncmp( psz_arturl, "attachment://", strlen("attachment://") ) )
    {
        msg_Err( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
204
        free( psz_arturl );
205
206
207
        return;
    }

208
209
    playlist_t *p_playlist = pl_Hold( p_input );
    if( !p_playlist )
210
211
    {
        free( psz_arturl );
212
        return;
213
    }
214
215


216
    if( input_item_IsArtFetched( p_item ) )
217
218
219
220
    {
        /* XXX Weird, we should not have end up with attachment:// art url unless there is a race
         * condition */
        msg_Warn( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
221
        playlist_FindArtInCache( p_item );
222
        goto exit;
223
224
225
    }

    /* */
226
    input_attachment_t *p_attachment = NULL;
227
228

    vlc_mutex_lock( &p_item->lock );
229
    for( int i_idx = 0; i_idx < p_input->p->i_attachment; i_idx++ )
230
231
232
233
    {
        if( !strcmp( p_input->p->attachment[i_idx]->psz_name,
                     &psz_arturl[strlen("attachment://")] ) )
        {
234
            p_attachment = vlc_input_attachment_Duplicate( p_input->p->attachment[i_idx] );
235
236
237
            break;
        }
    }
238
239
    vlc_mutex_unlock( &p_item->lock );

240
241
    if( !p_attachment || p_attachment->i_data <= 0 )
    {
242
243
        if( p_attachment )
            vlc_input_attachment_Delete( p_attachment );
244
        msg_Warn( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
245
        goto exit;
246
247
    }

248
249
    /* */
    const char *psz_type = NULL;
250
    if( !strcmp( p_attachment->psz_mime, "image/jpeg" ) )
251
        psz_type = ".jpg";
252
    else if( !strcmp( p_attachment->psz_mime, "image/png" ) )
253
        psz_type = ".png";
254

255
256
257
    /* */
    playlist_SaveArt( p_playlist, p_item,
                      p_attachment->p_data, p_attachment->i_data, psz_type );
258

259
260
261
262
263
    vlc_input_attachment_Delete( p_attachment );

exit:
    pl_Release( p_input );
    free( psz_arturl );
264
}
265

266
267
268
269
270
271
272
273
274
275
276
277
278
279
int input_item_WriteMeta( vlc_object_t *obj, input_item_t *p_item )
{
    meta_export_t *p_export =
        vlc_custom_create( obj, sizeof( *p_export ), VLC_OBJECT_GENERIC,
                           "meta writer" );
    if( p_export == NULL )
        return VLC_ENOMEM;
    vlc_object_attach( p_export, obj );
    p_export->p_item = p_item;

    int type;
    vlc_mutex_lock( &p_item->lock );
    type = p_item->i_type;
    vlc_mutex_unlock( &p_item->lock );
280
    if( type == ITEM_TYPE_FILE )
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
    {
        char *psz_uri = input_item_GetURI( p_item );

#warning FIXME: function for URI->path conversion!
        decode_URI( psz_uri );
        if( !strncmp( psz_uri, "file://", 7 ) )
        {
            p_export->psz_file = strdup( psz_uri + 7 );
            free( psz_uri );
        }
        else
#warning This should not happen!
            p_export->psz_file = psz_uri;
    }
    else
    {
        vlc_object_release( p_export );
        return VLC_EGENERIC;
    }

    module_t *p_mod = module_need( p_export, "meta writer", NULL, false );
    if( p_mod )
        module_unneed( p_export, p_mod );
    vlc_object_release( p_export );
    return VLC_SUCCESS;
}