Qt4 - Remove the enqueue button and regroup it under the play button, since it is...
[vlc.git] / modules / meta_engine / taglib.cpp
1 /*****************************************************************************
2  * taglib.cpp: Taglib tag parser/writer
3  *****************************************************************************
4  * Copyright (C) 2003-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 #include <vlc/vlc.h>
24 #include <vlc_playlist.h>
25 #include <vlc_meta.h>
26 #include <vlc_demux.h>
27
28 #include <fileref.h>
29 #include <tag.h>
30 #include <id3v2tag.h>
31 #include <mpegfile.h>
32 #include <flacfile.h>
33 #include <uniquefileidentifierframe.h>
34 #if 0 //for artist and album id
35 #include <textidentificationframe.h>
36 #endif
37
38 static int  ReadMeta    ( vlc_object_t * );
39 static int  DownloadArt ( vlc_object_t * );
40 static int  WriteMeta   ( vlc_object_t * );
41
42 vlc_module_begin();
43     set_capability( "meta reader", 1000 );
44     set_callbacks( ReadMeta, NULL );
45     add_submodule();
46         set_capability( "art downloader", 50 );
47         set_callbacks( DownloadArt, NULL );
48     add_submodule();
49         set_capability( "meta writer", 50 );
50         set_callbacks( WriteMeta, NULL );
51 vlc_module_end();
52
53 static bool checkID3Image( const TagLib::ID3v2::Tag *tag )
54 {
55     TagLib::ID3v2::FrameList l = tag->frameListMap()[ "APIC" ];
56     return !l.isEmpty();
57 }
58
59 /* Try detecting embedded art */
60 static void DetectImage( TagLib::FileRef f, vlc_meta_t *p_meta )
61 {
62     if( TagLib::MPEG::File *mpeg =
63                dynamic_cast<TagLib::MPEG::File *>(f.file() ) )
64     {
65         if( mpeg->ID3v2Tag() && checkID3Image( mpeg->ID3v2Tag() ) )
66             vlc_meta_SetArtURL( p_meta, "APIC" );
67     }
68     else if( TagLib::FLAC::File *flac =
69              dynamic_cast<TagLib::FLAC::File *>(f.file() ) )
70     {
71         if( flac->ID3v2Tag() && checkID3Image( flac->ID3v2Tag() ) )
72             vlc_meta_SetArtURL( p_meta, "APIC" );
73     }
74 #if 0
75 /* This needs special additions to taglib */
76  * else if( TagLib::MP4::File *mp4 =
77                dynamic_cast<TagLib::MP4::File *>( f.file() ) )
78     {
79         TagLib::MP4::Tag *mp4tag =
80                 dynamic_cast<TagLib::MP4::Tag *>( mp4->tag() );
81         if( mp4tag && mp4tag->cover().size() )
82             vlc_meta_SetArtURL( p_meta, "MP4C" );
83     }
84 #endif
85 }
86
87 static int ReadMeta( vlc_object_t *p_this )
88 {
89     demux_t *p_demux = (demux_t *)p_this;
90
91     if( !strncmp( p_demux->psz_access, "file", 4 ) )
92     {
93         if( !p_demux->p_private )
94             p_demux->p_private = (void*)vlc_meta_New();
95         TagLib::FileRef f( p_demux->psz_path );
96         if( !f.isNull() && f.tag() && !f.tag()->isEmpty() )
97         {
98             TagLib::Tag *tag = f.tag();
99             vlc_meta_t *p_meta = (vlc_meta_t *)(p_demux->p_private );
100
101 #define SET( foo, bar ) vlc_meta_Set##foo( p_meta, tag->bar ().toCString(true))
102             SET( Title, title );
103             SET( Artist, artist );
104             SET( Album, album );
105 //            SET( Comment, comment );
106             SET( Genre, genre );
107 //            SET( Year, year ); Gra, this is an int, need to convert
108 //            SET( Tracknum , track ); Same
109 #undef SET
110
111             if( TagLib::MPEG::File *p_mpeg =
112                 dynamic_cast<TagLib::MPEG::File *>(f.file() ) )
113             {
114                 if( p_mpeg->ID3v2Tag() )
115                 {
116                     TagLib::ID3v2::Tag *tag = p_mpeg->ID3v2Tag();
117                     TagLib::ID3v2::FrameList list = tag->frameListMap()["UFID"];
118                     TagLib::ID3v2::UniqueFileIdentifierFrame* p_ufid;
119                     for( TagLib::ID3v2::FrameList::Iterator iter = list.begin();
120                             iter != list.end(); iter++ )
121                     {
122                         p_ufid = dynamic_cast<TagLib::ID3v2::UniqueFileIdentifierFrame*>(*iter);
123                         const char *owner = p_ufid->owner().toCString();
124                         if (!strcmp( owner, "http://musicbrainz.org" ))
125                         {
126                             /* ID3v2 UFID contains up to 64 bytes binary data
127                              * but in our case it will be a '\0' 
128                              * terminated string */
129                             char *psz_ufid = (char*) malloc( 64 );
130                             int j = 0;
131                             while( ( j < 63 ) &&
132                                     ( j < p_ufid->identifier().size() ) )
133                                 psz_ufid[j] = p_ufid->identifier()[j++];
134                             psz_ufid[j] = '\0';
135                             vlc_meta_SetTrackID( p_meta, psz_ufid );
136                             free( psz_ufid );
137                         }
138                     }
139                     /* musicbrainz artist and album id: not useful yet */
140 #if 0
141                     list = tag->frameListMap()["TXXX"];
142                     TagLib::ID3v2::UserTextIdentificationFrame* p_txxx;
143                     for( TagLib::ID3v2::FrameList::Iterator iter = list.begin();
144                             iter != list.end(); iter++ )
145                     {
146                         p_txxx = dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>(*iter);
147                         const char *psz_desc= p_txxx->description().toCString();
148                         if( !strncmp( psz_desc, "MusicBrainz Artist Id", 21 ) )
149                             vlc_meta_SetArtistID( p_meta,
150                                     p_txxx->fieldList().toString().toCString());
151                         if( !strncmp( psz_desc, "MusicBrainz Album Id", 20 ) )
152                             vlc_meta_SetAlbumID( p_meta,
153                                     p_txxx->fieldList().toString().toCString());
154                     }
155 #endif
156                 }
157             }
158
159             DetectImage( f, p_meta );
160
161             return VLC_SUCCESS;
162         }
163     }
164     return VLC_EGENERIC;
165 }
166
167 static int WriteMeta( vlc_object_t *p_this )
168 {
169     playlist_t *p_playlist = (playlist_t *)p_this;
170     meta_export_t *p_export = (meta_export_t *)p_playlist->p_private;
171     input_item_t *p_item = p_export->p_item;
172
173     TagLib::FileRef f( p_export->psz_file );
174     if( !f.isNull() && f.tag() )
175     {
176         TagLib::Tag *tag = f.tag();
177         tag->setArtist( p_item->p_meta->psz_artist );
178         f.save();
179         return VLC_SUCCESS;
180     }
181     return VLC_EGENERIC;
182 }
183
184 static int DownloadArt( vlc_object_t *p_this )
185 {
186     /* We need to be passed the file name
187      * Fetch the thing from the file, save it to the cache folder
188      */
189     return VLC_EGENERIC;
190 }