示例#1
0
文件: MP3.cpp 项目: 0x20h/mp3sort
bool MP3::readID3v2(const std::string& filename, Metadata& meta) {
	// After reading http://mail.kde.org/pipermail/taglib-devel/2008-March/000902.html
	// adding a big lock seems reasonable
	try {
		taglib_mutex.lock();	
		TagLib::MPEG::File f(filename.c_str());
		
		if (f.isValid() && f.tag()) {
			TagLib::Tag* pTag = f.tag();
			meta.interpret = pTag->artist().isNull() ? "" : pTag->artist().to8Bit(true);
			meta.album = pTag->album().isNull() ? "" : pTag->album().to8Bit(true);
			meta.title = pTag->title().isNull() ? "" : pTag->title().to8Bit(true);
			meta.genre = pTag->genre().isNull() ? "" : pTag->genre().to8Bit(true);
			meta.track_no = pTag->track();
			meta.year = pTag->year();
			taglib_mutex.unlock();
			return meta.complete();
		}
	} catch (const std::exception&) {
		taglib_mutex.unlock();
		// ...
	}
	
	return false;
}
示例#2
0
void Track::readTags()
{
    QByteArray fileName = QFile::encodeName( p->url.toLocalFile() );
    const char * encodedName = fileName.constData();
    TagLib::FileRef fileref = TagLib::FileRef( encodedName, true, TagLib::AudioProperties::Fast);

   if ( !fileref.isNull() )
   {
        if( fileref.tag() )
        {
            TagLib::Tag *tag = fileref.tag();

            p->title   = !tag->title().isNull() ? TStringToQString( tag->title() ).trimmed() : QObject::tr("Unknown");
            p->artist  = !tag->artist().isNull() ? TStringToQString( tag->artist() ).trimmed() : QObject::tr("Unknown");
            p->album   = !tag->album().isNull() ? TStringToQString( tag->album() ).trimmed() : QObject::tr("Unknown");
            p->comment = TStringToQString( tag->comment() ).trimmed();
            p->genre   = !tag->genre().isNull() ? TStringToQString( tag->genre() ).trimmed() : QObject::tr("Unknown");
            p->year    = tag->year() ? QString::number( tag->year() ) : QString::null;
            p->tracknumber   = tag->track() ? QString::number( tag->track() ) : QString::null;
            p->length     = fileref.audioProperties()->length();
            p->counter = 0;
            p->rate = 0;

            //polish up empty tags
            if( p->title == QObject::tr("Unknown") ) {
                QFileInfo fileInfo(p->url.toLocalFile());
                p->title = fileInfo.fileName().replace( '_', ' ' ).replace('.' + fileInfo.suffix(),"") ;
            }
        }
    }

}
示例#3
0
文件: analyzer.c 项目: suborb/reelvdr
bool MetaData(const char* filepath, cFields& fields, cRow& props)
{
#define ADD(x, t) do { if (t) { fields.push_back(x); props.push_back(t); } } while(0)
#define ADDSTRING(x, t) do { if (!t.empty()) { fields.push_back(x); props.push_back(t); } } while(0)
#define ADDINT(x, t) do { std::string c = *itoa(t); if (!c.empty()){ fields.push_back(x); props.push_back(c);} } while(0)
    
    TagLib::FileRef f(filepath);

    fields.clear();
    props.clear();

    //cTag t;
    //const char* tmp = NULL;
    std::string tmp;
    
    if (f.isNull()) 
    {
        std::cerr<< "Taglib failed on " << filepath << std::endl;
        ADD("metadata_needs_update", "2"); // failure
        return false;
    }
   
    TagLib::Tag *tag = f.tag();
    
    if (tag) 
    {
#if 0
      tmp   = toString(tag->title()).c_str();   ADD("title",   tmp);
      tmp   = toString(tag->artist()).c_str();  ADD("artist",  tmp);
      tmp   = toString(tag->album()).c_str();   ADD("album",   tmp);
      tmp   = toString(tag->comment()).c_str(); ADD("comment", tmp);
      tmp   = toString(tag->genre()).c_str();   ADD("genre",   tmp);
#else
        tmp   = toString(tag->title());   ADDSTRING("title",   tmp);
        tmp   = toString(tag->artist());  ADDSTRING("artist",  tmp);
        tmp   = toString(tag->album());   ADDSTRING("album",   tmp);
        tmp   = toString(tag->comment()); ADDSTRING("comment", tmp);
        tmp   = toString(tag->genre());   ADDSTRING("genre",   tmp);
#endif
      
      //ADDINT("track", tag->track());
      ADDINT("year",  tag->year());
    }
    
    TagLib::AudioProperties *prop = f.audioProperties();
    if (prop) 
    {
        ADDINT("bitrate",    prop->bitrate());
        ADDINT("samplerate", prop->sampleRate());
      //  ADDINT("channels",   prop->channels());
        ADDINT("length" ,    prop->length());
    }
 
    ADD("metadata_needs_update", "0");
    return true;
}
示例#4
0
文件: taghelpers.cpp 项目: qomp/qomp
Tune* tuneFromFile(const QString& file)
{
	Tune* tune = new Tune(false);
	tune->file = file;

	TagLib::FileRef ref = fileName2TaglibRef(file);
	if(!ref.isNull()) {
		if(ref.tag()) {
			TagLib::Tag* tag = ref.tag();
			tune->artist = safeTagLibString2QString( tag->artist() );
			tune->album = safeTagLibString2QString( tag->album() );
			tune->title = safeTagLibString2QString( tag->title() );
			tune->trackNumber = QString::number( tag->track() );
			tune->genre = safeTagLibString2QString( tag->genre() );
		}

		Qomp::loadCover(tune, ref.file());

		if(ref.audioProperties()) {
			TagLib::AudioProperties *prop = ref.audioProperties();
			tune->duration = Qomp::durationSecondsToString( prop->length() );
			tune->bitRate = QString::number( prop->bitrate() );
		}

		tune->setMetadataResolved(true);
	}

	return tune;
}
示例#5
0
int main(int argc, char *argv[])
{
  for(int i = 1; i < argc; i++) {

    cout << "path:" << argv[i] << endl;

    TagLib::FileRef f(argv[i]);

    if(!f.isNull() && f.tag()) {

      TagLib::Tag *tag = f.tag();

      cout << "title:" << (tag->title()).toCString(true)   << endl;
      cout << "artist:" << (tag->artist()).toCString(true) << endl;
      cout << "album:" << (tag->album()).toCString(true)   << endl;
      cout << "albumartist:" << (tag->albumArtist()).toCString(true) << endl;
      cout << "track:" << tag->track() << endl;
      cout << "disc:"  << tag->cdNr() << endl;
    }

    if(!f.isNull() && f.audioProperties()) {

      TagLib::AudioProperties *properties = f.audioProperties();

      cout << "bitrate:" << properties->bitrate() << endl;
      cout << "length:" << properties->length()  << endl;
    }
  if(i!=argc-1)
    cout << "---" << endl;
  }
  return 0;
}
示例#6
0
cFileInfoMenu::cFileInfoMenu(std::string mrl) : cOsdMenu( tr("File Info:"), 12)
{
	//set title
	//SetTitle(tr("mediaplayer - Id3 Info:"));
	mrl_ = mrl;
	fileInfoVec_ = GetFileInfo(mrl_);

	// Get title
	std::string title;
	TagLib::FileRef f( mrl.c_str() );
	if(!f.isNull() && f.tag())
	{
		TagLib::Tag *tag = f.tag();
								 // unicode = false
		title   = tag->title().stripWhiteSpace().toCString(false)  ;

		if (title.size())
		{
			char buffer[128];
			snprintf(buffer, 127, "File Info: %s", title.c_str());
			SetTitle(buffer);
			printf("setting title to : %s\n", buffer);
		}
	}

	ShowInfo();
}
示例#7
0
void getMp3Info(const WCHAR* fileName, MP3Info &info)
{
    TagLib::FileRef f(fileName);

    if (!f.isNull() && f.tag())
    {
        TagLib::Tag *tag = f.tag();

        info.tag[0] = tag->title().toWString();
        info.tag[1] = tag->artist().toWString();
        info.tag[2] = tag->album().toWString();
        info.tag[3] = tag->comment().toWString();
        info.tag[4] = tag->genre().toWString();
        info.year = tag->year();
        info.track = tag->track();

        TagLib::PropertyMap tags = f.file()->properties();

        if (!f.isNull() && f.audioProperties()) 
        {
            TagLib::AudioProperties *properties = f.audioProperties();

            int seconds = properties->length() % 60;
            int minutes = (properties->length() - seconds) / 60;

            info.bitrate = properties->bitrate();
            info.sample_rate = properties->sampleRate();
            info.channels = properties->channels();
            info.length_minutes = minutes;
            info.length_seconds = seconds;
        }
    }
}
示例#8
0
QList<QByteArray> MetaDetector::detectEncodings(const MetaPtr meta)
{
    if (meta->localPath.isEmpty()) {
        return QList<QByteArray>() << "UTF-8";
    }
    QByteArray                  detectByte;

    if (!meta->cuePath.isEmpty()) {
        QFile cueFile(meta->cuePath);
        if (cueFile.open(QIODevice::ReadOnly)) {
            detectByte =  cueFile.readAll();
            return detectEncodings(detectByte);
        }
    }

#ifdef _WIN32
    TagLib::FileRef f(meta->localPath.toStdWString().c_str());
#else
    TagLib::FileRef f(meta->localPath.toStdString().c_str());
#endif
    TagLib::Tag *tag = f.tag();

    if (tag) {
        detectByte += tag->title().toCString();
        detectByte += tag->artist().toCString();
        detectByte += tag->album().toCString();
    }

    return detectEncodings(detectByte);
}
示例#9
0
文件: tagsync.cpp 项目: ixxra/mymedia
bool parseAndWrite(const char* location, Json::Writer& writer)
{
  Json::Value metadata;
  metadata[LOCATION] = location;
  TagLib::FileRef f(location);

  if (f.isNull()){
    return false;
  }

  if (f.tag() && !f.tag()->isEmpty()){
    TagLib::Tag* tag = f.tag();
    TagLib::String artist = tag->artist();
    TagLib::String album = tag->artist();
    TagLib::String title = tag->title();

    uint track = tag->track();
    uint year = tag->year();

    metadata[TITLE] = title.toCString(true);
    metadata[ARTIST] = artist.toCString(true);
    metadata[ALBUM] = album.toCString(true);
    metadata[TRACK] = track;
    metadata[YEAR] = year;
  }

  std::cout << writer.write(metadata);
  return true;
}
示例#10
0
void
M3uLoader::getTags( const QFileInfo& info )
{
    QByteArray fileName = QFile::encodeName( info.canonicalFilePath() );
    const char *encodedName = fileName.constData();

    TagLib::FileRef f( encodedName );
    TagLib::Tag *tag = f.tag();

    QString artist = TStringToQString( tag->artist() ).trimmed();
    QString album  = TStringToQString( tag->album() ).trimmed();
    QString track  = TStringToQString( tag->title() ).trimmed();

    if ( artist.isEmpty() || track.isEmpty() )
    {
        qDebug() << "Error parsing" << info.fileName();
        return;
    }
    else
    {
        qDebug() << Q_FUNC_INFO << artist << track << album;
        Tomahawk::query_ptr q = Tomahawk::Query::get( artist, track, album, uuid(), !m_createNewPlaylist );
        if ( !q.isNull() )
            m_tracks << q;
    }
}
示例#11
0
AlbumTrack::AlbumTrack(Album* album, QString trackPath)
{
    this->path = trackPath;
    this->number = 0;
    this->artist = "Unknown Artist";
    this->album = album;
    this->genre = "Unknown Genre";

    TagLib::FileRef f(trackPath.toStdString().c_str());
    if(!f.isNull() && f.tag())
    {
        TagLib::Tag *tag = f.tag();
        title = QString(tag->title().toCString());
        number = tag->track();
        artist = QString(tag->artist().toCString());
        albumName = QString(tag->album().toCString());
        genre = QString(tag->genre().toCString());
    }
    if(!f.isNull() && f.audioProperties())
    {
        TagLib::AudioProperties *properties = f.audioProperties();
        duration = properties->length() * 1000;
        //Weil Fmod die gerne in Millisekunden hätte
    }
}
示例#12
0
int handle_file(const char* filepath, const char* filekey, AudioFileRecordStore& record_store)
{
    bool record_exists = record_store.find_record(filekey) != NULL;

    // Scanning a file for tags is expensive, so only do it if required.
    if(record_exists
            && !record_store.record_update_required(filekey))
    {
        // no update reqquired so has been handled.
        return 1;
    }

    TagLib::FileRef f(filepath);
    if (!f.isNull() && f.tag())
    {
        AudioFileRecord &record = record_store.get_record(filekey);
        record.update_start();

        if (verbose)
        {
            TagLib::Tag *tag = f.tag();
            std::cout << filepath << endl;
            std::cout << filekey << endl;
            std::cout << "-- TAG (basic) --" << endl;
            std::cout << "title   - \"" << tag->title()   << "\"" << endl;
            std::cout << "artist  - \"" << tag->artist()  << "\"" << endl;
            std::cout << "album   - \"" << tag->album()   << "\"" << endl;
            std::cout << "year    - \"" << tag->year()    << "\"" << endl;
            std::cout << "comment - \"" << tag->comment() << "\"" << endl;
            std::cout << "track   - \"" << tag->track()   << "\"" << endl;
            std::cout << "genre   - \"" << tag->genre()   << "\"" << endl;
        }

        TagLib::PropertyMap tags = f.file()->properties();

        for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i)
        {
            for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) 
            {
                record.update(i->first.toCString(true), j->toCString(true));
            }
        }

        if (f.audioProperties())
        {
            TagLib::AudioProperties *properties = f.audioProperties();
            record.update(audio_tags::BITRATE, properties->bitrate());
            record.update(audio_tags::LENGTH, properties->length());
            record.update(audio_tags::SAMPLERATE, properties->sampleRate());
            record.update(audio_tags::CHANNELS, properties->channels());
        }

        record.update_complete();
        return 1;
    }

    return 0;
}
TagLibTokenizer::TagLibTokenizer(const Document *pDocument) :
	Tokenizer(NULL),
	m_pTagDocument(NULL)
{
	if (pDocument != NULL)
	{
		Url urlObj(pDocument->getLocation());
		string pseudoContent;

		if ((urlObj.isLocal() == true) &&
			(urlObj.getFile().empty() == false))
		{
			string location(urlObj.getLocation());
			string trackTitle;

			location += "/";
			location += urlObj.getFile();

			TagLib::FileRef fileRef(location.c_str(), false);
			if (fileRef.isNull() == false)
			{
				TagLib::Tag *pTag = fileRef.tag();
				if ((pTag != NULL) &&
					(pTag->isEmpty() == false))
				{
					char yearStr[64];

					trackTitle = pTag->title().to8Bit(); 
					trackTitle += " ";
					trackTitle += pTag->artist().to8Bit();

					pseudoContent = trackTitle;
					pseudoContent += " ";
					pseudoContent += pTag->album().to8Bit();
					pseudoContent += " ";
					pseudoContent += pTag->comment().to8Bit();
					pseudoContent += " ";
					pseudoContent += pTag->genre().to8Bit();
					snprintf(yearStr, 64, " %u", pTag->year());
					pseudoContent += yearStr;
				}
			}
			else
			{
				trackTitle = pseudoContent = pDocument->getTitle();
			}

			m_pTagDocument = new Document(trackTitle, pDocument->getLocation(),
				pDocument->getType(), pDocument->getLanguage());
			m_pTagDocument->setData(pseudoContent.c_str(), pseudoContent.length());
			m_pTagDocument->setTimestamp(pDocument->getTimestamp());
			m_pTagDocument->setSize(pDocument->getSize());

			// Give the result to the parent class
			setDocument(m_pTagDocument);
		}
	}
}
示例#14
0
bool ReadTag(const musik::Core::String& fn, musik::Core::SongInfo& target)
{
    bool ret = true;

    musik::Core::Filename mfn(fn);

    target.SetFilename(fn);
    target.SetFormat("Ogg Vorbis");

    try
    {
#if defined (WIN32)
        TagLib::FileRef tag_file(fn.c_str());
#else    
        TagLib::FileRef tag_file(utf16to8(fn, true).c_str());
#endif
        if (!tag_file.isNull())
        {
            if (tag_file.tag())
            {
                TagLib::Tag *tag = tag_file.tag();        

                target.SetArtist(musik::Core::utf8to16(tag->artist().to8Bit(true)));
                target.SetAlbum(musik::Core::utf8to16(tag->album().to8Bit(true)));
                target.SetTitle(musik::Core::utf8to16(tag->title().to8Bit(true)));
                target.SetGenre(musik::Core::utf8to16(tag->genre().to8Bit(true)));
                target.SetNotes(musik::Core::utf8to16(tag->comment().to8Bit(true)));

                target.SetYear(musik::Core::IntToString(tag->year()));
                target.SetTrackNum(musik::Core::IntToString(tag->track()));
            }

            if (tag_file.audioProperties())
            {
                TagLib::AudioProperties *properties = tag_file.audioProperties();
                int duration = properties->length() * 1000;
                target.SetBitrate(musik::Core::IntToString(properties->bitrate()));
                target.SetDuration(musik::Core::IntToString(duration));
            }
        }

        // if the title is empty, then use the
        // filename...
        if (target.GetTitle().IsEmpty())
        {
            musik::Core::Filename MFN(fn);
            target.SetTitle(MFN.GetJustFilename());
        }
    }
    catch (...)
    {
        ret = false;
        cout << "taglib crashed reading: " << fn.c_str() << endl;
    }

    return ret;
}
示例#15
0
int main(int argc, char *argv[])
{
  for(int i = 1; i < argc; i++) {

    cout << "******************** \"" << argv[i] << "\" ********************" << endl;

    TagLib::FileRef f(argv[i]);

    if(!f.isNull() && f.tag()) {

      TagLib::Tag *tag = f.tag();

      cout << "-- TAG (basic) --" << endl;
      cout << "title   - \"" << tag->title()   << "\"" << endl;
      cout << "artist  - \"" << tag->artist()  << "\"" << endl;
      cout << "album   - \"" << tag->album()   << "\"" << endl;
      cout << "year    - \"" << tag->year()    << "\"" << endl;
      cout << "comment - \"" << tag->comment() << "\"" << endl;
      cout << "track   - \"" << tag->track()   << "\"" << endl;
      cout << "genre   - \"" << tag->genre()   << "\"" << endl;

      TagLib::PropertyMap tags = f.file()->properties();

      unsigned int longest = 0;
      for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
        if (i->first.size() > longest) {
          longest = i->first.size();
        }
      }

      cout << "-- TAG (properties) --" << endl;
      for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
        for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
          cout << left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << endl;
        }
      }

    }

    if(!f.isNull() && f.audioProperties()) {

      TagLib::AudioProperties *properties = f.audioProperties();

      int seconds = properties->length() % 60;
      int minutes = (properties->length() - seconds) / 60;

      cout << "-- AUDIO --" << endl;
      cout << "bitrate     - " << properties->bitrate() << endl;
      cout << "sample rate - " << properties->sampleRate() << endl;
      cout << "channels    - " << properties->channels() << endl;
      cout << "length      - " << minutes << ":" << setfill('0') << setw(2) << seconds << endl;
    }
  }
  return 0;
}
JNIEXPORT jstring JNICALL Java_TagLibReader_getTitle (JNIEnv *env, jobject thisObj, jstring path) {
	const jchar *pathCStr = env->GetStringChars(path, NULL);
	TagLib::FileRef f(reinterpret_cast<const wchar_t*>(pathCStr));
	if(!f.isNull() && f.tag()) {
      TagLib::Tag *tag = f.tag();
      return env->NewStringUTF(tag->title().toCString(true));
    }
    else {
    	return NULL;
    }
}
示例#17
0
void DataStore::addSongToLibrary(const Phonon::MediaSource& song, QSqlQuery &addQuery){
  QString fileName = song.fileName();
  QString songName;
  QString artistName;
  QString albumName;
  QString genre;
  int track;
  int duration;
  TagLib::FileRef f(fileName.toStdString().c_str());
  if(!f.isNull() && f.tag() && f.audioProperties()){
    TagLib::Tag *tag = f.tag();
    songName = TStringToQString(tag->title());
    artistName = TStringToQString(tag->artist());
    albumName = TStringToQString(tag->album());
    genre = TStringToQString(tag->genre());
    duration = f.audioProperties()->length();
    track = tag->track();
  }
  else{
    //TODO throw error
    return;
  }

  if(songName == ""){
    songName = unknownSongTitle();
  }
  if(artistName == ""){
    artistName = unknownSongArtist();
  }
  if(albumName == ""){
    albumName = unknownSongAlbum();
  }
  if(genre == ""){
    genre = unknownGenre();
  }

  Logger::instance()->log("adding song with title: " + songName + " to database");

  library_song_id_t hostId =-1;

  addQuery.bindValue(":song", songName);
  addQuery.bindValue(":artist", artistName);
  addQuery.bindValue(":album", albumName);
  addQuery.bindValue(":genre", genre);
  addQuery.bindValue(":track", track);
  addQuery.bindValue(":file", fileName);
  addQuery.bindValue(":duration", duration);
  EXEC_INSERT(
    "Failed to add song library" << songName.toStdString(), 
    addQuery,
    hostId,
    library_song_id_t)
}
示例#18
0
void
MetaBundle::readTags( TagLib::AudioProperties::ReadStyle readStyle )
{
    if( m_url.protocol() != "file" )
        return;

    const QString path = m_url.path();
    TagLib::FileRef fileref;
    TagLib::Tag *tag = 0;

    if( AmarokConfig::recodeID3v1Tags() && path.endsWith( ".mp3", false ) )
    {
        TagLib::MPEG::File *mpeg = new TagLib::MPEG::File( QFile::encodeName( path ), true, readStyle );
        fileref = TagLib::FileRef( mpeg );

        if( mpeg->isValid() )
            // we prefer ID3v1 over ID3v2 if recoding tags because
            // apparently this is what people who ignore ID3 standards want
            tag = mpeg->ID3v1Tag() ? (TagLib::Tag*)mpeg->ID3v1Tag() : (TagLib::Tag*)mpeg->ID3v2Tag();
    }

    else {
        fileref = TagLib::FileRef( QFile::encodeName( path ), true, readStyle );

        if( !fileref.isNull() )
            tag = fileref.tag();
    }

    if( !fileref.isNull() ) {
        if ( tag ) {
            #define strip( x ) TStringToQString( x ).stripWhiteSpace()
            m_title   = strip( tag->title() );
            m_artist  = strip( tag->artist() );
            m_album   = strip( tag->album() );
            m_comment = strip( tag->comment() );
            m_genre   = strip( tag->genre() );
            m_year    = tag->year() ? QString::number( tag->year() ) : QString();
            m_track   = tag->track() ? QString::number( tag->track() ) : QString();
            #undef strip

            m_isValidMedia = true;
        }

        init( fileref.audioProperties() );
    }

    //FIXME disabled for beta4 as it's simpler to not got 100 bug reports
    //else if( KMimeType::findByUrl( m_url )->is( "audio" ) )
    //    init( KFileMetaInfo( m_url, QString::null, KFileMetaInfo::Everything ) );
}
示例#19
0
    void MediaController::metaDataChanged()
    {
        QString extra_data;
        QByteArray encoded = QFile::encodeName(current_file.path());
        TagLib::FileRef ref(encoded.data(), true, TagLib::AudioProperties::Fast);
        if (ref.isNull())
        {
            info_label->setText(i18n("Playing: <b>%1</b>", current_file.name()));
            return;
        }

        TagLib::Tag* tag = ref.tag();
        if (!tag)
        {
            info_label->setText(i18n("Playing: <b>%1</b>", current_file.name()));
            return;
        }

        QString artist = t2q(tag->artist());
        QString title =  t2q(tag->title());
        QString album = t2q(tag->album());

        bool has_artist = !artist.isEmpty();
        bool has_title = !title.isEmpty();
        bool has_album = !album.isEmpty();

        if (has_artist && has_title && has_album)
        {
            extra_data = i18n("<b>%2</b> - <b>%1</b> (Album: <b>%3</b>)", title, artist, album);
            info_label->setText(extra_data);
        }
        else if (has_title && has_artist)
        {
            extra_data = i18n("<b>%2</b> - <b>%1</b>", title, artist);
            info_label->setText(extra_data);
        }
        else if (has_title)
        {
            extra_data = i18n("<b>%1</b>", title);
            info_label->setText(extra_data);
        }
        else
        {
            info_label->setText(i18n("<b>%1</b>", current_file.name()));
        }
    }
示例#20
0
string scan_file(const char* path)
{
    TagLib::FileRef f(path);
    if (!f.isNull() && f.tag()) {
        TagLib::Tag *tag = f.tag();
        int filesize = boost::filesystem::file_size(path);
        int bitrate = 0;
        int duration = 0;
        if (f.audioProperties()) {
            TagLib::AudioProperties *properties = f.audioProperties();
            duration = properties->length();
            bitrate = properties->bitrate();
        }
        string artist = tag->artist().toCString(true);
        string album  = tag->album().toCString(true);
        string track  = tag->title().toCString(true);
        boost::trim(artist);
        boost::trim(album);
        boost::trim(track);
        if (artist.length()==0 || track.length()==0) {
            return "{\"error\" : \"no tags\"}\n";
        }
        string ext(toUtf8(boost::filesystem::extension(path)));
        string mimetype = ext2mime(boost::to_lower_copy(ext));
        // turn it into a url by prepending file://
        // because we pass all urls to curl:
        string urlpath = urlify( toUtf8(path) );

        ostringstream os;
        os      <<  "{  \"url\" : \"" << urlpath << "\","
                    "   \"filesize\" : " << filesize << ","
                    "   \"mimetype\" : \"" << mimetype << "\","
                    "   \"artist\" : \"" << tidy(artist) << "\","
                    "   \"album\" : \"" << tidy(album) << "\","
                    "   \"track\" : \"" << tidy(track) << "\","
                    "   \"duration\" : " << duration << ","
                    "   \"bitrate\" : " << bitrate << ","
                    "   \"trackno\" : " << tag->track()

                <<  "}\n";
        return os.str();
    }
    return "{\"error\" : \"no tags\"}\n";
}
示例#21
0
int main(int argc, char *argv[])
{
    if (argc < 3) return 1;

    string what(argv[1]);

    TagLib::FileRef f(argv[2]);

    if(!f.isNull() && f.tag()) {

        TagLib::Tag *tag = f.tag();
       
        if (what == "title")  cout << tag->title()   << endl;
        if (what == "artist") cout << tag->artist()  << endl;
        if (what == "album")  cout << tag->album()   << endl;
        if (what == "year")   cout << tag->year()    << endl;
    }
    return 0;
}
示例#22
0
string scan_file(const char* path)
{
    TagLib::FileRef f(path);
    if (!f.isNull() && f.tag()) {
        TagLib::Tag *tag = f.tag();
        int bitrate = 0;
        int duration = 0;
        if (f.audioProperties()) {
            TagLib::AudioProperties *properties = f.audioProperties();
            duration = properties->length();
            bitrate = properties->bitrate();
        }
        string artist = tag->artist().toCString(true);
        string album  = tag->album().toCString(true);
        string track  = tag->title().toCString(true);
        trim(artist);
        trim(album);
        trim(track);
        if (artist.length()==0 || track.length()==0) {
            return "{\"error\" : \"no tags\"}";
        }
        string pathstr(path);
        string ext = pathstr.substr(pathstr.length()-4);
        std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
        string mimetype = ext2mime(ext);
        // turn it into a url by prepending file://
        // because we pass all urls to curl:
        string urlpath = urlify( path );

        ostringstream os;
        os      <<  "{  \"url\" : \"" << esc(urlpath) << "\","
                    "   \"mimetype\" : \"" << mimetype << "\","
                    "   \"artist\" : \"" << tidy(artist) << "\","
                    "   \"album\" : \"" << tidy(album) << "\","
                    "   \"track\" : \"" << tidy(track) << "\","
                    "   \"duration\" : " << duration << ","
                    "   \"bitrate\" : " << bitrate << ","
                    "   \"trackno\" : " << tag->track()
                <<  "}";
        return os.str();
    }
    return "{\"error\" : \"no tags\"}";
}
JNIEXPORT jobjectArray JNICALL Java_TagLibReader_getTags (JNIEnv *env, jobject thisObj, jstring path) {
	const jchar *pathCStr = env->GetStringChars(path, NULL);
	TagLib::FileRef f(reinterpret_cast<const wchar_t*>(pathCStr));
	jstring jartist;
	jstring jalbum;
	jstring jtitle;
	if(!f.isNull() && f.tag()) {
      TagLib::Tag *tag = f.tag();
      jartist = env->NewStringUTF(tag->artist().toCString(true));
      jalbum = env->NewStringUTF(tag->album().toCString(true));
      jtitle = env->NewStringUTF(tag->title().toCString(true));
    }
    else {
    	return NULL;
    }
	jclass classString = env->FindClass("java/lang/String");
   	jobjectArray outJNIArray = env->NewObjectArray(3, classString, NULL);
 	env->SetObjectArrayElement(outJNIArray, 0, jartist);
 	env->SetObjectArrayElement(outJNIArray, 1, jalbum);
 	env->SetObjectArrayElement(outJNIArray, 2, jtitle);
	return outJNIArray;
}
示例#24
0
int main(int argc, char *argv[])
{
    for(int i = 1; i < argc; i++) {

        cout << "******************** \"" << argv[i] << "\" ********************" << endl;

        TagLib::FileRef f(argv[i]);

        if(!f.isNull() && f.tag()) {

            TagLib::Tag *tag = f.tag();

            cout << "-- TAG --" << endl;
            cout << "title   - \"" << tag->title()   << "\"" << endl;
            cout << "artist  - \"" << tag->artist()  << "\"" << endl;
            cout << "album   - \"" << tag->album()   << "\"" << endl;
            cout << "year    - \"" << tag->year()    << "\"" << endl;
            cout << "comment - \"" << tag->comment() << "\"" << endl;
            cout << "track   - \"" << tag->track()   << "\"" << endl;
            cout << "genre   - \"" << tag->genre()   << "\"" << endl;
        }

        if(!f.isNull() && f.audioProperties()) {

            TagLib::AudioProperties *properties = f.audioProperties();

            int seconds = properties->length() % 60;
            int minutes = (properties->length() - seconds) / 60;

            cout << "-- AUDIO --" << endl;
            cout << "bitrate     - " << properties->bitrate() << endl;
            cout << "sample rate - " << properties->sampleRate() << endl;
            cout << "channels    - " << properties->channels() << endl;
            cout << "length      - " << minutes << ":" << formatSeconds(seconds) << endl;
        }
    }
    return 0;
}
示例#25
0
// Use Taglib to parse tags from file and add entried to wxListCtrl
void AddFromFile_Taglib(wxListCtrl *listctrl, const std::map< wxString, long > &mapping, const wxString &filename)
{
    TagLib::FileRef f = TagLib::FileRef(filename.c_str(), TagLib::String::UTF8 ); //TODO: is c_str() safe?

    if ( f.isNull() )
    {
        wxLogError(wxT("Error: TagLib could not read ") + filename + wxT("."));
        return;
    }

    if ( ! f.tag() )
    {
        wxLogError(wxT("Error: TagLib could not read the tags of file ") + filename + wxT("."));
        return;
    }

    TagLib::Tag *tag = f.tag();
    auto idx = listctrl->GetItemCount();
    auto row_idx = listctrl->InsertItem(idx, wxString::Format(wxT("%d"), idx) );

    // TODO: check return values
    listctrl->SetItem(row_idx, mapping.find("Artist")->second, wxString(tag->artist().to8Bit(true)) );
    listctrl->SetItem(row_idx, mapping.find("Trackname")->second, wxString(tag->title().to8Bit(true)));
    listctrl->SetItem(row_idx, mapping.find("Album")->second, wxString(tag->album().to8Bit(true)));

    if ( f.audioProperties() )
    {
      TagLib::AudioProperties *properties = f.audioProperties();
      int seconds = properties->length() % 60;
      int minutes = (properties->length() - seconds) / 60;

      wxString timestr = wxString::Format("%d:%02d", minutes, seconds);

      listctrl->SetItem(row_idx, mapping.find("Time")->second, timestr);
    }

}
示例#26
0
bool mediaTag(Artwork *art, TagLib::File *f)
{
    Q_ASSERT(f != NULL);
    Q_ASSERT(f->tag());

    TagLib::Tag *tag = f->tag();
    art->filetype = FILETYPE_UNKNOWN;

    // The basic stuff!!!
    art->artist = TStringToQString(tag->artist()).trimmed();
    art->album = TStringToQString(tag->album()).trimmed();
    art->track = TStringToQString(tag->title()).trimmed();
    art->genre = TStringToQString(tag->genre()).trimmed();
    art->year = tag->year();
    art->trackNo = tag->track();

    // we need something to search on!
    if (art->artist == "" && art->album == "" && art->track == "") {
        return false;
    }

    // Any audio properties???
    if (f->audioProperties()) {
        TagLib::AudioProperties *properties = f->audioProperties();

        int seconds = properties->length() % 60;
        int minutes = (properties->length() - seconds) / 60;
        art->duration = minutes * 60 + seconds;

        art->bitRate = properties->bitrate();
        art->sampleRate = properties->sampleRate();
        art->channels = properties->channels();
    }

    art->makeSearchable();
    return true;
}
示例#27
0
	void FileStore::scan(const string & a_path) {
		if (!fs::exists(a_path)) 
			return;
		if (fs::is_directory(a_path)) {
			fs::directory_iterator end; // default construction yields past-the-end
			for (fs::directory_iterator curr(a_path); curr != end; ++curr) {
				fs::path p = curr->path();
				string s = p.string();
				scan(s);
			}
		} else if (fs::is_regular_file(a_path)) {
			if (pathExists(a_path))
				return;
			TagLib::FileRef file_ref(a_path.c_str(), false);
			if (!file_ref.isNull() && file_ref.tag()) {
				cerr << "indexing " << a_path << endl;
				TagLib::Tag *t = file_ref.tag();
				string artist = t->artist().to8Bit(true);
				string album = t->album().to8Bit(true);
				string title = t->title().to8Bit(true);
				string genre = t->genre().to8Bit(true);
				string year = t->year() > 0 ? lexical_cast<string>(t->year()) : "";
				string track = t->track() > 0 ? lexical_cast<string>(t->track()) : "";
				string uri = "file://" + a_path;
				shared_ptr<UUID> fileID(generateID());
				addField(*fileID, ARTIST, artist);
				addField(*fileID, ARTIST, artist);
				addField(*fileID, ALBUM, album);
				addField(*fileID, YEAR, year);
				addField(*fileID, TITLE, title);
				addField(*fileID, GENRE, genre);
				addField(*fileID, TRACK, track);
				addField(*fileID, URI, uri);
			}
		}
	}
示例#28
0
void TagReader::ReadFile(const QString& filename,
                         pb::tagreader::SongMetadata* song) const {
  const QByteArray url(QUrl::fromLocalFile(filename).toEncoded());
  const QFileInfo info(filename);

  qLog(Debug) << "Reading tags from" << filename;

  song->set_basefilename(DataCommaSizeFromQString(info.fileName()));
  song->set_url(url.constData(), url.size());
  song->set_filesize(info.size());
  song->set_mtime(info.lastModified().toTime_t());
  song->set_ctime(info.created().toTime_t());

  std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename));
  if (fileref->isNull()) {
    qLog(Info) << "TagLib hasn't been able to read " << filename << " file";
    return;
  }

  TagLib::Tag* tag = fileref->tag();
  if (tag) {
    Decode(tag->title(), nullptr, song->mutable_title());
    Decode(tag->artist(), nullptr, song->mutable_artist());  // TPE1
    Decode(tag->album(), nullptr, song->mutable_album());
    Decode(tag->genre(), nullptr, song->mutable_genre());
    song->set_year(tag->year());
    song->set_track(tag->track());
    song->set_valid(true);
  }

  QString disc;
  QString compilation;

  // Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same
  // way;
  // apart, so we keep specific behavior for some formats by adding another
  // "else if" block below.
  if (TagLib::Ogg::XiphComment* tag =
          dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) {
    ParseOggTag(tag->fieldListMap(), nullptr, &disc, &compilation, song);
  }

  if (TagLib::MPEG::File* file =
          dynamic_cast<TagLib::MPEG::File*>(fileref->file())) {
    if (file->ID3v2Tag()) {
      const TagLib::ID3v2::FrameListMap& map = file->ID3v2Tag()->frameListMap();

      if (!map["TPOS"].isEmpty())
        disc = TStringToQString(map["TPOS"].front()->toString()).trimmed();

      if (!map["TBPM"].isEmpty())
        song->set_bpm(TStringToQString(map["TBPM"].front()->toString())
                          .trimmed()
                          .toFloat());

      if (!map["TCOM"].isEmpty())
        Decode(map["TCOM"].front()->toString(), nullptr,
               song->mutable_composer());

      if (!map["TIT1"].isEmpty())  // content group
        Decode(map["TIT1"].front()->toString(), nullptr,
               song->mutable_grouping());

      // Skip TPE1 (which is the artist) here because we already fetched it

      if (!map["TPE2"].isEmpty())  // non-standard: Apple, Microsoft
        Decode(map["TPE2"].front()->toString(), nullptr,
               song->mutable_albumartist());

      if (!map["TCMP"].isEmpty())
        compilation =
            TStringToQString(map["TCMP"].front()->toString()).trimmed();

      if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover);

      // Find a suitable comment tag.  For now we ignore iTunNORM comments.
      for (int i = 0; i < map["COMM"].size(); ++i) {
        const TagLib::ID3v2::CommentsFrame* frame =
            dynamic_cast<const TagLib::ID3v2::CommentsFrame*>(map["COMM"][i]);

        if (frame && TStringToQString(frame->description()) != "iTunNORM") {
          Decode(frame->text(), nullptr, song->mutable_comment());
          break;
        }
      }

      // Parse FMPS frames
      for (int i = 0; i < map["TXXX"].size(); ++i) {
        const TagLib::ID3v2::UserTextIdentificationFrame* frame =
            dynamic_cast<const TagLib::ID3v2::UserTextIdentificationFrame*>(
                map["TXXX"][i]);

        if (frame && frame->description().startsWith("FMPS_")) {
          ParseFMPSFrame(TStringToQString(frame->description()),
                         TStringToQString(frame->fieldList()[1]), song);
        }
      }

      // Check POPM tags
      // We do this after checking FMPS frames, so FMPS have precedence, as we
      // will consider POPM tags iff song has no rating/playcount already set.
      if (!map["POPM"].isEmpty()) {
        const TagLib::ID3v2::PopularimeterFrame* frame =
            dynamic_cast<const TagLib::ID3v2::PopularimeterFrame*>(
                map["POPM"].front());
        if (frame) {
          // Take a user rating only if there's no rating already set
          if (song->rating() <= 0 && frame->rating() > 0) {
            song->set_rating(ConvertPOPMRating(frame->rating()));
          }
          if (song->playcount() <= 0 && frame->counter() > 0) {
            song->set_playcount(frame->counter());
          }
        }
      }
    }
  } else if (TagLib::FLAC::File* file =
                 dynamic_cast<TagLib::FLAC::File*>(fileref->file())) {
    if (file->xiphComment()) {
      ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc,
                  &compilation, song);
#ifdef TAGLIB_HAS_FLAC_PICTURELIST
      if (!file->pictureList().isEmpty()) {
        song->set_art_automatic(kEmbeddedCover);
      }
#endif
    }
    Decode(tag->comment(), nullptr, song->mutable_comment());
  } else if (TagLib::MP4::File* file =
                 dynamic_cast<TagLib::MP4::File*>(fileref->file())) {
    if (file->tag()) {
      TagLib::MP4::Tag* mp4_tag = file->tag();
      const TagLib::MP4::ItemListMap& items = mp4_tag->itemListMap();

      // Find album artists
      TagLib::MP4::ItemListMap::ConstIterator it = items.find("aART");
      if (it != items.end()) {
        TagLib::StringList album_artists = it->second.toStringList();
        if (!album_artists.isEmpty()) {
          Decode(album_artists.front(), nullptr, song->mutable_albumartist());
        }
      }

      // Find album cover art
      if (items.find("covr") != items.end()) {
        song->set_art_automatic(kEmbeddedCover);
      }

      if (items.contains("disk")) {
        disc = TStringToQString(
            TagLib::String::number(items["disk"].toIntPair().first));
      }

      if (items.contains(kMP4_FMPS_Rating_ID)) {
        float rating =
            TStringToQString(items[kMP4_FMPS_Rating_ID].toStringList().toString(
                                 '\n')).toFloat();
        if (song->rating() <= 0 && rating > 0) {
          song->set_rating(rating);
        }
      }
      if (items.contains(kMP4_FMPS_Playcount_ID)) {
        int playcount =
            TStringToQString(
                items[kMP4_FMPS_Playcount_ID].toStringList().toString('\n'))
                .toFloat();
        if (song->playcount() <= 0 && playcount > 0) {
          song->set_playcount(playcount);
        }
      }
      if (items.contains(kMP4_FMPS_Playcount_ID)) {
        int score = TStringToQString(
                        items[kMP4_FMPS_Score_ID].toStringList().toString('\n'))
                        .toFloat() *
                    100;
        if (song->score() <= 0 && score > 0) {
          song->set_score(score);
        }
      }

      if (items.contains("\251wrt")) {
        Decode(items["\251wrt"].toStringList().toString(", "), nullptr,
               song->mutable_composer());
      }
      if (items.contains("\251grp")) {
        Decode(items["\251grp"].toStringList().toString(" "), nullptr,
               song->mutable_grouping());
      }
      Decode(mp4_tag->comment(), nullptr, song->mutable_comment());
    }
  }
#ifdef TAGLIB_WITH_ASF
  else if (TagLib::ASF::File* file =
               dynamic_cast<TagLib::ASF::File*>(fileref->file())) {
    const TagLib::ASF::AttributeListMap& attributes_map =
        file->tag()->attributeListMap();
    if (attributes_map.contains("FMPS/Rating")) {
      const TagLib::ASF::AttributeList& attributes =
          attributes_map["FMPS/Rating"];
      if (!attributes.isEmpty()) {
        float rating =
            TStringToQString(attributes.front().toString()).toFloat();
        if (song->rating() <= 0 && rating > 0) {
          song->set_rating(rating);
        }
      }
    }
    if (attributes_map.contains("FMPS/Playcount")) {
      const TagLib::ASF::AttributeList& attributes =
          attributes_map["FMPS/Playcount"];
      if (!attributes.isEmpty()) {
        int playcount = TStringToQString(attributes.front().toString()).toInt();
        if (song->playcount() <= 0 && playcount > 0) {
          song->set_playcount(playcount);
        }
      }
    }
    if (attributes_map.contains("FMPS/Rating_Amarok_Score")) {
      const TagLib::ASF::AttributeList& attributes =
          attributes_map["FMPS/Rating_Amarok_Score"];
      if (!attributes.isEmpty()) {
        int score =
            TStringToQString(attributes.front().toString()).toFloat() * 100;
        if (song->score() <= 0 && score > 0) {
          song->set_score(score);
        }
      }
    }
  }
#endif
  else if (tag) {
    Decode(tag->comment(), nullptr, song->mutable_comment());
  }

  if (!disc.isEmpty()) {
    const int i = disc.indexOf('/');
    if (i != -1) {
      // disc.right( i ).toInt() is total number of discs, we don't use this at
      // the moment
      song->set_disc(disc.left(i).toInt());
    } else {
      song->set_disc(disc.toInt());
    }
  }

  if (compilation.isEmpty()) {
    // well, it wasn't set, but if the artist is VA assume it's a compilation
    if (QStringFromStdString(song->artist()).toLower() == "various artists") {
      song->set_compilation(true);
    }
  } else {
    song->set_compilation(compilation.toInt() == 1);
  }

  if (fileref->audioProperties()) {
    song->set_bitrate(fileref->audioProperties()->bitrate());
    song->set_samplerate(fileref->audioProperties()->sampleRate());
    song->set_length_nanosec(fileref->audioProperties()->length() *
                             kNsecPerSec);
  }

  // Get the filetype if we can
  song->set_type(GuessFileType(fileref.get()));

// Set integer fields to -1 if they're not valid
#define SetDefault(field)   \
  if (song->field() <= 0) { \
    song->set_##field(-1);  \
  }
  SetDefault(track);
  SetDefault(disc);
  SetDefault(bpm);
  SetDefault(year);
  SetDefault(bitrate);
  SetDefault(samplerate);
  SetDefault(lastplayed);
#undef SetDefault
}
void CollectionScanner::popFromQueue() {
    if (stopped) return;

    if (fileQueue.isEmpty()) {
        complete();
        return;
    }

    QFileInfo fileInfo = fileQueue.first();
    // qDebug() << "Processing " << fileInfo.absoluteFilePath();

    // parse metadata with TagLib
    QString filename = fileInfo.absoluteFilePath();
#ifdef Q_OS_WIN
    const wchar_t * encodedName = reinterpret_cast<const wchar_t*>(filename.utf16());
    TagLib::FileRef fileref(encodedName);
#else
    // const char * encodedName = QFile::encodeName(filename).constData();
    TagLib::FileRef fileref((TagLib::FileName)filename.toUtf8());
#endif

    // if taglib cannot parse the file, drop it
    if (fileref.isNull()) {
        // qDebug() << "Taglib cannot parse" << fileInfo.absoluteFilePath();
        fileQueue.removeAll(fileInfo);

        // add to nontracks table
        QString path = fileInfo.absoluteFilePath();
        path.remove(this->rootDirectory.absolutePath() + "/");
        insertOrUpdateNonTrack(path, QDateTime::currentDateTime().toTime_t());

        QTimer::singleShot(0, this, SLOT(popFromQueue()));
        return;
    }

    // Ok this is an interesting file

    // This object will experience an incredible adventure,
    // facing countless perils and finally reaching its final destination
    FileInfo *file = new FileInfo();
    file->setFileInfo(fileInfo);

    // Copy TagLib::FileRef in our Tags class.
    // TagLib::FileRef keeps files open and we would quickly reach the max open files limit
    Tags *tags = new Tags();
    TagLib::Tag *tag = fileref.tag();
    if (tag) {
        tags->title = Tags::toQString(tag->title());
        tags->artist = Tags::toQString(tag->artist());
        tags->album = Tags::toQString(tag->album());
        tags->track = tag->track();
        tags->year = tag->year();
        TagLib::AudioProperties *audioProperties = fileref.audioProperties();
        if (audioProperties)
            tags->length = audioProperties->length();
    }
    file->setTags(tags);

    // get data from the internet
    giveThisFileAnArtist(file);
}
示例#30
0
QString NTagReaderTaglib::parse(const QString &format, bool *success, bool stopOnFail)
{
	if (format.isEmpty())
		return "";

	*success = true;

	if (!isValid())
		return "NTagReaderTaglib::InvalidFile";

	TagLib::Tag *tag = NTaglib::_tagRef->tag();
	TagLib::AudioProperties *ap = NTaglib::_tagRef->audioProperties();

	int seconds_total = ap->length();

	QString res;
	for (int i = 0; i < format.size(); ++i) {
		if (format.at(i) == '%') {
			++i;
			QChar ch = format.at(i);
			if (ch == 'a') {
				QString str = TStringToQString(tag->artist());
				if (!(*success = !str.isEmpty()))
					str = "<Unknown artist>";
				res += str;
			} else if (ch == 't') {
				QString str = TStringToQString(tag->title());
				if (!(*success = !str.isEmpty()))
					str = "<Unknown title>";
				res += str;
			} else if (ch == 'A') {
				QString str = TStringToQString(tag->album());
				if (!(*success = !str.isEmpty()))
					str = "<Unknown album>";
				res += str;
			} else if (ch == 'c') {
				QString str = TStringToQString(tag->comment());
				if (!(*success = !str.isEmpty()))
					str = "<Empty comment>";
				res += str;
			} else if (ch == 'g') {
				QString str = TStringToQString(tag->genre());
				if (!(*success = !str.isEmpty()))
					str = "<Unknown genre>";
				res += str;
			} else if (ch == 'y') {
				QString str = QString::number(tag->year());
				if (str == "0") {
					str = "<Unknown year>";
					*success = false;
				}
				res += str;
			} else if (ch == 'n') {
				QString str = QString::number(tag->track());
				if (str == "0") {
					str = "<Unknown track number>";
					*success = false;
				}
				res += str;
			} else if (ch == 'b') {
				if (auto *prop = dynamic_cast<TagLib::APE::Properties *>(ap)) {
					res += QString::number(prop->bitsPerSample());
				}
				else
				if (auto *prop = dynamic_cast<TagLib::FLAC::Properties *>(ap)) {
					res += QString::number(prop->sampleWidth());
				}
				else
				if (auto *prop = dynamic_cast<TagLib::MP4::Properties *>(ap)) {
					res += QString::number(prop->bitsPerSample());
				}
				else
				if (auto *prop = dynamic_cast<TagLib::RIFF::AIFF::Properties *>(ap)) {
					res += QString::number(prop->sampleWidth());
				}
				else
				if (auto *prop = dynamic_cast<TagLib::RIFF::WAV::Properties *>(ap)) {
					res += QString::number(prop->sampleWidth());
				}
				else
				if (auto *prop = dynamic_cast<TagLib::TrueAudio::Properties *>(ap)) {
					res += QString::number(prop->bitsPerSample());
				}
				else
				if (auto *prop = dynamic_cast<TagLib::WavPack::Properties *>(ap)) {
					res += QString::number(prop->bitsPerSample());
				}
				else {
					res += "<Unknown bit depth>";
					*success = false;
				}
			} else if (ch == 'd') {
				QString duration;
				if (seconds_total > 0) {
					int seconds = seconds_total % 60;
					int minutes = (seconds_total - seconds) / 60;
					int hours = minutes / 60;
					minutes = minutes % 60;
					if (hours > 0)
						duration.sprintf("%d:%02d:%02d", hours, minutes, seconds);
					else
						duration.sprintf("%d:%02d", minutes, seconds);
				} else {
					duration = "<Unknown duration>";
					*success = false;
				}
				res += duration;
			} else if (ch == 'D') {
				QString duration;
				if (seconds_total == 0) {
					duration = "<Unknown duration>";
					*success = false;
				} else {
					duration = QString::number(seconds_total);
				}
				res += duration;
			} else if (ch == 'B') {
				QString str = QString::number(ap->bitrate());
				if (str == "0") {
					str = "<Unknown bitrate>";
					*success = false;
				}
				res += str;
			} else if (ch == 's') {
				QString str = QString::number(ap->sampleRate() / (float)1000);
				if (str == "0") {
					str = "<Unknown sample rate>";
					*success = false;
				}
				res += str;
			} else if (ch == 'C') {
				QString str = QString::number(ap->channels());
				if (str == "0") {
					str = "<Unknown channels number>";
					*success = false;
				}
				res += str;
			} else if (ch == 'f') {
				res += QFileInfo(NTaglib::_filePath).baseName();
			} else if (ch == 'F') {
				res += QFileInfo(NTaglib::_filePath).fileName();
			} else if (ch == 'p') {
				res += QFileInfo(NTaglib::_filePath).absoluteFilePath();
			} else if (ch == 'e') {
				res += QFileInfo(NTaglib::_filePath).suffix();
			} else if (ch == 'E') {
				res += QFileInfo(NTaglib::_filePath).suffix().toUpper();
			} else if (ch == 'v') {
				res += QCoreApplication::applicationVersion();
			} else {
				res += ch;
			}
		} else if (format.at(i) == '{') {
			++i;
			int matchedAt = format.indexOf('}', i);
			if (matchedAt == -1) {
				res += "<condition error: unmatched '{'>";
				return res;
			}

			QString condition = format.mid(i, matchedAt - i);

			if (condition.indexOf('{') != -1) {
				res += "<condition error: extra '{'>";
				return res;
			}

			QStringList values = condition.split('|');
			if (values.count() < 2) {
				res += "<condition error: missing '|'>";
				return res;
			} else if (values.count() > 2) {
				res += "<condition error: extra '|'>";
				return res;
			}

			bool cond_res;
			QString cond_true = parse(values.at(0), &cond_res, true);
			if (cond_res) {
				res += cond_true;
			} else {
				res += parse(values.at(1), &cond_res);
			}
			i = matchedAt;
		} else {
			res += format.at(i);
		}
		if (!*success && stopOnFail)
			return "";
	}

	return res;
}