00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00032
00033 #ifdef HAVE_CONFIG_H
00034 #include "autoconfig.h"
00035 #endif
00036
00037 #ifdef HAVE_TAGLIB
00038
00039 #include <taglib.h>
00040 #include <fileref.h>
00041 #include <tag.h>
00042 #include <id3v2tag.h>
00043 #include <mpegfile.h>
00044 #include <audioproperties.h>
00045 #include <attachedpictureframe.h>
00046 #include <textidentificationframe.h>
00047 #include <tstring.h>
00048
00049 #include "taglib_handler.h"
00050 #include "string_converter.h"
00051 #include "config_manager.h"
00052 #include "common.h"
00053 #include "tools.h"
00054 #include "mem_io_handler.h"
00055
00056 #include "content_manager.h"
00057
00058 using namespace zmm;
00059
00060 TagHandler::TagHandler() : MetadataHandler()
00061 {
00062 }
00063
00064 static void addField(metadata_fields_t field, TagLib::Tag *tag, Ref<CdsItem> item)
00065 {
00066 TagLib::String val;
00067 String value;
00068 unsigned int i;
00069
00070 if (tag == NULL)
00071 return;
00072
00073 if (tag->isEmpty())
00074 return;
00075
00076 Ref<StringConverter> sc = StringConverter::i2i();
00077
00078 switch (field)
00079 {
00080 case M_TITLE:
00081 val = tag->title();
00082 break;
00083 case M_ARTIST:
00084 val = tag->artist();
00085 break;
00086 case M_ALBUM:
00087 val = tag->album();
00088 break;
00089 case M_DATE:
00090 i = tag->year();
00091 if (i > 0)
00092 {
00093 value = String::from(i);
00094
00095 if (string_ok(value))
00096 value = value + _("-01-01");
00097 }
00098 else
00099 return;
00100 break;
00101 case M_GENRE:
00102 val = tag->genre();
00103 break;
00104 case M_DESCRIPTION:
00105 val = tag->comment();
00106 break;
00107 case M_TRACKNUMBER:
00108 i = tag->track();
00109 if (i > 0)
00110 {
00111 value = String::from(i);
00112 item->setTrackNumber((int)i);
00113 }
00114 else
00115 return;
00116 break;
00117 default:
00118 return;
00119 }
00120
00121 if ((field != M_DATE) && (field != M_TRACKNUMBER))
00122 value = val.toCString(true);
00123
00124 value = trim_string(value);
00125
00126 if (string_ok(value))
00127 {
00128 item->setMetadata(MT_KEYS[field].upnp, sc->convert(value));
00129
00130 }
00131 }
00132
00133 void TagHandler::fillMetadata(Ref<CdsItem> item)
00134 {
00135 Ref<Array<StringBase> > aux;
00136 Ref<StringConverter> sc = StringConverter::i2i();
00137
00138 TagLib::FileRef f(item->getLocation().c_str());
00139
00140 if (f.isNull() || (!f.tag()))
00141 return;
00142
00143
00144 TagLib::Tag *tag = f.tag();
00145
00146 for (int i = 0; i < M_MAX; i++)
00147 addField((metadata_fields_t) i, tag, item);
00148
00149 int temp;
00150
00151 TagLib::AudioProperties *audioProps = f.audioProperties();
00152
00153 if (audioProps == NULL)
00154 return;
00155
00156
00157 temp = audioProps->bitrate() * 1024 / 8;
00158
00159 if (temp > 0)
00160 {
00161 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_BITRATE),
00162 String::from(temp));
00163 }
00164
00165 temp = audioProps->length();
00166 if (temp > 0)
00167 {
00168 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_DURATION),
00169 secondsToHMS(temp));
00170 }
00171
00172 temp = audioProps->sampleRate();
00173 if (temp > 0)
00174 {
00175 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_SAMPLEFREQUENCY),
00176 String::from(temp));
00177 }
00178
00179 temp = audioProps->channels();
00180
00181 if (temp > 0)
00182 {
00183 item->getResource(0)->addAttribute(MetadataHandler::getResAttrName(R_NRAUDIOCHANNELS),
00184 String::from(temp));
00185 }
00186
00187 Ref<Dictionary> mappings = ConfigManager::getInstance()->getDictionaryOption(CFG_IMPORT_MAPPINGS_MIMETYPE_TO_CONTENTTYPE_LIST);
00188 String content_type = mappings->get(item->getMimeType());
00189
00190 if (content_type != CONTENT_TYPE_MP3)
00191 return;
00192
00193
00194
00195 TagLib::MPEG::File mp(item->getLocation().c_str());
00196
00197 if (!mp.isValid() || !mp.ID3v2Tag())
00198 return;
00199
00200
00201 Ref<ConfigManager> cm = ConfigManager::getInstance();
00202 aux = cm->getStringArrayOption(CFG_IMPORT_LIBOPTS_ID3_AUXDATA_TAGS_LIST);
00203 if (aux != nil)
00204 {
00205 for (int j = 0; j < aux->size(); j++)
00206 {
00207 String desiredFrame = aux->get(j);
00208 if (string_ok(desiredFrame))
00209 {
00210 const TagLib::ID3v2::FrameList& allFrames = mp.ID3v2Tag()->frameList();
00211 if (!allFrames.isEmpty())
00212 {
00213 TagLib::ID3v2::FrameList::ConstIterator it = allFrames.begin();
00214 for (; it != allFrames.end(); it++)
00215 {
00216 TagLib::String frameID((*it)->frameID(), TagLib::String::Latin1);
00217
00218
00219 TagLib::ID3v2::TextIdentificationFrame *textFrame =
00220 dynamic_cast<TagLib::ID3v2::TextIdentificationFrame *>(*it);
00221
00222 if (textFrame)
00223 {
00224
00225
00226 if (frameID == desiredFrame.c_str())
00227 {
00228 TagLib::String frameContents = textFrame->toString();
00229
00230 String value(frameContents.toCString(true), frameContents.size());
00231 value = sc->convert(value);
00232 log_debug("Adding frame: %s with value %s\n", desiredFrame.c_str(), value.c_str());
00233 item->setAuxData(desiredFrame, value);
00234 }
00235 }
00236 }
00237 }
00238 }
00239 }
00240 }
00241
00242 TagLib::ID3v2::FrameList list = mp.ID3v2Tag()->frameList("APIC");
00243 if (!list.isEmpty())
00244 {
00245 TagLib::ID3v2::AttachedPictureFrame *art =
00246 static_cast<TagLib::ID3v2::AttachedPictureFrame *>(list.front());
00247
00248 if (art->picture().size() < 1)
00249 return;
00250
00251 String art_mimetype = sc->convert(art->mimeType().toCString(true));
00252
00253
00254 if (!string_ok(art_mimetype) || (art_mimetype.index('/') == -1))
00255 {
00256 #ifdef HAVE_MAGIC
00257 art_mimetype = ContentManager::getInstance()->getMimeTypeFromBuffer((void *)art->picture().data(), art->picture().size());
00258 if (!string_ok(art_mimetype))
00259 #endif
00260 art_mimetype = _(MIMETYPE_DEFAULT);
00261 }
00262
00263
00264
00265 if (art_mimetype != _(MIMETYPE_DEFAULT))
00266 {
00267 Ref<CdsResource> resource(new CdsResource(CH_ID3));
00268 resource->addAttribute(MetadataHandler::getResAttrName(R_PROTOCOLINFO), renderProtocolInfo(art_mimetype));
00269 resource->addParameter(_(RESOURCE_CONTENT_TYPE), _(ID3_ALBUM_ART));
00270 item->addResource(resource);
00271 }
00272 }
00273 }
00274
00275 Ref<IOHandler> TagHandler::serveContent(Ref<CdsItem> item, int resNum, off_t *data_size)
00276 {
00277
00278 TagLib::MPEG::File f(item->getLocation().c_str());
00279
00280 if (!f.isValid())
00281 throw _Exception(_("TagHandler: could not open file: ") +
00282 item->getLocation());
00283
00284
00285 if (!f.ID3v2Tag())
00286 throw _Exception(_("TagHandler: resource has no album information"));
00287
00288 TagLib::ID3v2::FrameList list = f.ID3v2Tag()->frameList("APIC");
00289 if (list.isEmpty())
00290 throw _Exception(_("TagHandler: resource has no album information"));
00291
00292 TagLib::ID3v2::AttachedPictureFrame *art =
00293 static_cast<TagLib::ID3v2::AttachedPictureFrame *>(list.front());
00294
00295 Ref<IOHandler> h(new MemIOHandler((void *)art->picture().data(),
00296 art->picture().size()));
00297
00298 *data_size = art->picture().size();
00299 return h;
00300 }
00301
00302 #endif // HAVE_TAGLIB