Meta::FieldHash APETagHelper::tags() const { Meta::FieldHash data = TagHelper::tags(); TagLib::APE::ItemListMap map = m_tag->itemListMap(); for( TagLib::APE::ItemListMap::ConstIterator it = map.begin(); it != map.end(); ++it ) { qint64 field; QString value = TStringToQString( it->second.toString() ); if( ( field = fieldName( it->first ) ) ) { if( field == Meta::valRating ) data.insert( field, qRound( value.toFloat() * 10.0 ) ); else if( field == Meta::valScore ) data.insert( field, value.toFloat() * 100.0 ); else data.insert( field, value ); } else if( it->first == uidFieldName( UIDAFT ) && isValidUID( value, UIDAFT ) ) data.insert( Meta::valUniqueId, value ); else if( it->first == uidFieldName( UIDMusicBrainz ) && isValidUID( value, UIDMusicBrainz ) ) { if( !data.contains( Meta::valUniqueId ) ) // we prefere AFT uids data.insert( Meta::valUniqueId, value.prepend( "mb-" ) ); } } return data; }
Meta::FieldHash ASFTagHelper::tags() const { Meta::FieldHash data = TagHelper::tags(); TagLib::ASF::AttributeListMap map = m_tag->attributeListMap(); for( TagLib::ASF::AttributeListMap::ConstIterator it = map.begin(); it != map.end(); ++it ) { if( !it->second.size() ) continue; qint64 field; TagLib::ASF::Attribute value = it->second[0]; QString strValue = TStringToQString( value.toString() ); if( ( field = fieldName( it->first ) ) ) { if( field == Meta::valBpm || field == Meta::valPlaycount ) data.insert( field, value.toUInt() ); else if( field == Meta::valRating ) data.insert( field, qRound( strValue.toFloat() * 10.0 ) ); else if( field == Meta::valScore ) data.insert( field, strValue.toFloat() * 100.0 ); else if( field == Meta::valDiscNr ) data.insert( field, value.toUInt() ); else if( field == Meta::valCompilation ) data.insert( field, value.toBool() ); else if( field == Meta::valHasCover ) { for( TagLib::ASF::AttributeList::ConstIterator cover = it->second.begin(); cover != it->second.end(); ++cover ) { if( cover->type() != TagLib::ASF::Attribute::BytesType ) continue; TagLib::ASF::Picture pict = cover->toPicture(); if( ( pict.type() == TagLib::ASF::Picture::FrontCover || pict.type() == TagLib::ASF::Picture::Other ) && pict.dataSize() > MIN_COVER_SIZE ) { data.insert( field, true ); break; } } } else data.insert( field, strValue ); } else if( it->first == uidFieldName( UIDAFT ) && isValidUID( strValue, UIDAFT ) ) data.insert( Meta::valUniqueId, strValue ); else if( it->first == uidFieldName( UIDMusicBrainz ) && isValidUID( strValue, UIDMusicBrainz ) ) { if( !data.contains( Meta::valUniqueId ) ) // we prefere AFT uids data.insert( Meta::valUniqueId, strValue.prepend( "mb-" ) ); } } return data; }
TrackList ClementineProvider::artistTracks( const QString &artistName ) { const QString query = "SELECT filename, title, artist, album, composer, year, track, " "disc, rating, lastplayed, playcount FROM songs WHERE artist = :artist"; QVariantMap bindValues; bindValues.insert( ":artist", artistName ); const QList<qint64> fields = QList<qint64>() << Meta::valTitle << Meta::valArtist << Meta::valAlbum << Meta::valComposer << Meta::valYear << Meta::valTrackNr << Meta::valDiscNr << Meta::valRating << Meta::valLastPlayed << Meta::valPlaycount; TrackList result; foreach( const QVariantList &row, m_connection->query( query, bindValues ) ) { const QVariant &filename = row[0]; Meta::FieldHash metadata; for( int i = 0; i < fields.size(); ++i ) metadata.insert( fields[i], row[i + 1] ); result << TrackPtr( new ClementineTrack( filename, m_connection, metadata ) ); } return result; }
TrackList BansheeProvider::artistTracks( const QString &artistName ) { // Due to Banshee's peculiar track info storage, to avoid massive amount of confusion // we only take tracks from PrimarySource: MusicLibrarySource-Library (always ID 1) const QString query = "SELECT TrackID, TRIM(t.Title), ar.Name, al.Title, " "TRIM(t.Composer), t.Year, t.TrackNumber, t.Disc, t.Rating, " "t.LastPlayedStamp, t.PlayCount " "FROM coretracks t " "INNER JOIN coreartists ar USING(ArtistID) " "LEFT JOIN corealbums al USING(AlbumID) " "WHERE ar.Name = :artist AND t.PrimarySourceID = 1"; QVariantMap bindValues; bindValues.insert( ":artist", artistName ); const QList<qint64> fields = QList<qint64>() << Meta::valTitle << Meta::valArtist << Meta::valAlbum << Meta::valComposer << Meta::valYear << Meta::valTrackNr << Meta::valDiscNr << Meta::valRating << Meta::valLastPlayed << Meta::valPlaycount; TrackList result; foreach( const QVariantList &row, m_connection->query( query, bindValues ) ) { const qint64 trackId = row[0].toLongLong(); Meta::FieldHash metadata; for( int i = 0; i < fields.size(); ++i ) metadata.insert( fields[i], row[i + 1] ); result << TrackPtr( new BansheeTrack( trackId, m_connection, metadata ) ); } return result; }
Meta::FieldHash MP4TagHelper::tags() const { Meta::FieldHash data = TagHelper::tags(); TagLib::MP4::ItemListMap map = m_tag->itemListMap(); for( TagLib::MP4::ItemListMap::ConstIterator it = map.begin(); it != map.end(); ++it ) { qint64 field; QString value = TStringToQString( it->second.toStringList().toString( '\n' ) ); if( ( field = fieldName( it->first ) ) ) { if( field == Meta::valHasCover ) { TagLib::MP4::CoverArtList coverList = it->second.toCoverArtList(); for( TagLib::MP4::CoverArtList::ConstIterator it = coverList.begin(); it != coverList.end(); ++it ) if( it->data().size() > MIN_COVER_SIZE ) { data.insert( field, true ); break; } } // http://gitorious.org/~jefferai/xdg-specs/jefferais-xdg-specs/blobs/mediaspecs/specifications/FMPSpecs/specification.txt sais that mp4 tags should be saved as strings else if( field == Meta::valPlaycount ) data.insert( field, value.toInt() ); else if( field == Meta::valRating ) data.insert( field, qRound( value.toFloat() * 10.0 ) ); else if( field == Meta::valScore ) data.insert( field, value.toFloat() * 100.0 ); else if( field == Meta::valBpm ) data.insert( field, it->second.toInt() ); else if( field == Meta::valDiscNr ) data.insert( field, it->second.toIntPair().first ); else if( field == Meta::valCompilation ) data.insert( field, it->second.toBool() ); else data.insert( field, value ); } else if( it->first == uidFieldName( UIDAFT ) && isValidUID( value, UIDAFT ) ) data.insert( Meta::valUniqueId, value ); } return data; }
Meta::FieldHash TagHelper::tags() const { Meta::FieldHash data; data.insert( Meta::valTitle, TStringToQString( m_tag->title() ) ); data.insert( Meta::valArtist, TStringToQString( m_tag->artist() ) ); data.insert( Meta::valAlbum, TStringToQString( m_tag->album() ) ); data.insert( Meta::valTrackNr, m_tag->track() ); data.insert( Meta::valYear, m_tag->year() ); data.insert( Meta::valGenre, TStringToQString( m_tag->genre() ) ); data.insert( Meta::valComment, TStringToQString( m_tag->comment() ) ); return data; }
Meta::FieldHash ID3v2TagHelper::tags() const { Meta::FieldHash data = TagHelper::tags(); TagLib::ID3v2::FrameList list = m_tag->frameList(); for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it ) { qint64 field; TagLib::String frameName = TagLib::String( ( *it )->frameID() ); if( ( field = fieldName( frameName ) ) ) { if( field == Meta::valUniqueId ) { TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast< TagLib::ID3v2::UniqueFileIdentifierFrame * >( *it ); if( !frame ) continue; QString identifier = TStringToQString( TagLib::String( frame->identifier() ) ); if( identifier.isEmpty() ) continue; if( frame->owner() == uidFieldName( UIDAFT ) && isValidUID( identifier, UIDAFT ) ) data.insert( Meta::valUniqueId, identifier ); continue; } else if( field == Meta::valHasCover ) { TagLib::ID3v2::AttachedPictureFrame *frame = dynamic_cast< TagLib::ID3v2::AttachedPictureFrame * >( *it ); if( !frame ) continue; if( ( frame->type() == TagLib::ID3v2::AttachedPictureFrame::FrontCover || frame->type() == TagLib::ID3v2::AttachedPictureFrame::Other ) && frame->picture().size() > MIN_COVER_SIZE ) // must be at least 1kb { data.insert( Meta::valHasCover, true ); } continue; } TagLib::ID3v2::TextIdentificationFrame *frame = dynamic_cast< TagLib::ID3v2::TextIdentificationFrame * >( *it ); if( !frame ) continue; QString value = TStringToQString( frame->fieldList().toString( '\n' ) ); if( field == Meta::valDiscNr ) { int disc; if( ( disc = splitDiscNr( value ).first ) ) data.insert( field, disc ); } else if( field == Meta::valBpm ) data.insert( field, value.toFloat() ); else data.insert( field, value ); } else if( frameName == POPM_Frame ) { TagLib::ID3v2::PopularimeterFrame *frame = dynamic_cast< TagLib::ID3v2::PopularimeterFrame * >( *it ); if( !frame ) continue; if( TStringToQString( frame->email() ).isEmpty() ) // only read anonymous ratings { // FMPS tags have precedence if( !data.contains( Meta::valRating ) && frame->rating() != 0 ) data.insert( Meta::valRating, qRound( frame->rating() / 256.0 * 10.0 ) ); if( !data.contains( Meta::valPlaycount ) && frame->counter() < 10000 ) data.insert( Meta::valPlaycount, frame->counter() ); } } else if( frameName == TXXX_Frame ) { TagLib::ID3v2::UserTextIdentificationFrame *frame = dynamic_cast< TagLib::ID3v2::UserTextIdentificationFrame * >( *it ); if( !frame ) continue; // the value of the user text frame is stored in the // second and following fields. TagLib::StringList fields = frame->fieldList(); if( fields.size() >= 2 ) { QString value = TStringToQString( fields[1] ); if( fields[0] == fmpsFieldName( FMPSRating ) ) data.insert( Meta::valRating, qRound( value.toFloat() * 10.0 ) ); else if( fields[0] == fmpsFieldName( FMPSScore ) ) data.insert( Meta::valScore, value.toFloat() * 100.0 ); else if( fields[0] == fmpsFieldName( FMPSPlayCount ) ) data.insert( Meta::valPlaycount, value.toFloat() ); } } } return data; }