bool APETagHelper::setTags( const Meta::FieldHash &changes ) { bool modified = TagHelper::setTags( changes ); foreach( const qint64 key, changes.keys() ) { QVariant value = changes.value( key ); TagLib::String field = fieldName( key ); if( !field.isNull() && !field.isEmpty() ) { if( key == Meta::valRating ) m_tag->addValue( field, Qt4QStringToTString( QString::number( value.toFloat() / 10.0 ) ) ); else if( key == Meta::valScore ) m_tag->addValue( field, Qt4QStringToTString( QString::number( value.toFloat() / 100.0 ) ) ); else m_tag->addValue( field, Qt4QStringToTString( value.toString() ) ); modified = true; } else if( key == Meta::valUniqueId ) { QPair < UIDType, QString > uidPair = splitUID( value.toString() ); if( uidPair.first == UIDInvalid ) continue; m_tag->addValue( uidFieldName( uidPair.first ), Qt4QStringToTString( uidPair.second ) ); modified = true; } } return modified; }
bool ASFTagHelper::setTags( const Meta::FieldHash &changes ) { bool modified = TagHelper::setTags( changes ); foreach( const qint64 key, changes.keys() ) { QVariant value = changes.value( key ); TagLib::String field = fieldName( key ); if( !field.isNull() && !field.isEmpty() ) { if( key == Meta::valHasCover ) continue; // http://gitorious.org/~jefferai/xdg-specs/jefferais-xdg-specs/blobs/mediaspecs/specifications/FMPSpecs/specification.txt sais that mp4 tags should be saved as strings if( key == Meta::valHasCover ) continue; else if( key == Meta::valRating ) m_tag->setAttribute( field, TagLib::ASF::Attribute( Qt4QStringToTString( QString::number( value.toFloat() / 10.0 ) ) ) ); else if( key == Meta::valScore ) m_tag->setAttribute( field, TagLib::ASF::Attribute( Qt4QStringToTString( QString::number( value.toFloat() / 100.0 ) ) ) ); else if( key == Meta::valBpm || key == Meta::valDiscNr ) m_tag->setAttribute( field, TagLib::ASF::Attribute( value.toUInt() ) ); else if( key == Meta::valCompilation ) m_tag->setAttribute( field, TagLib::ASF::Attribute( value.toBool() ) ); else m_tag->setAttribute( field, TagLib::ASF::Attribute( Qt4QStringToTString( value.toString() ) ) ); modified = true; } else if( key == Meta::valUniqueId ) { QPair < UIDType, QString > uidPair = splitUID( value.toString() ); if( uidPair.first == UIDInvalid ) continue; m_tag->setAttribute( uidFieldName( uidPair.first ), TagLib::ASF::Attribute( Qt4QStringToTString( uidPair.second ) ) ); modified = true; } } return modified; }
bool TagHelper::setTags( const Meta::FieldHash &changes ) { bool modified = false; if( changes.contains( Meta::valTitle ) ) { m_tag->setTitle( Qt4QStringToTString( changes.value( Meta::valTitle ).toString() ) ); modified = true; } if( changes.contains( Meta::valArtist ) ) { m_tag->setArtist( Qt4QStringToTString( changes.value( Meta::valArtist ).toString() ) ); modified = true; } if( changes.contains( Meta::valAlbum ) ) { m_tag->setAlbum( Qt4QStringToTString( changes.value( Meta::valAlbum ).toString() ) ); modified = true; } if( changes.contains( Meta::valTrackNr ) ) { m_tag->setTrack( changes.value( Meta::valTrackNr ).toUInt() ); modified = true; } if( changes.contains( Meta::valYear ) ) { m_tag->setYear( changes.value( Meta::valYear ).toUInt() ); modified = true; } if( changes.contains( Meta::valGenre ) ) { m_tag->setGenre( Qt4QStringToTString( changes.value( Meta::valGenre ).toString() ) ); modified = true; } if( changes.contains( Meta::valComment ) ) { m_tag->setComment( Qt4QStringToTString( changes.value( Meta::valComment ).toString() ) ); modified = true; } return modified; }
void IpodCopyTracksJob::run() { if( !m_coll ) return; // destructed behind our back float totalSafeCapacity = m_coll.data()->totalCapacity() - m_coll.data()->capacityMargin(); QByteArray mountPoint = QFile::encodeName( m_coll.data()->mountPoint() ); QString collectionPrettyName = m_coll.data()->prettyName(); int trackCount = m_sources.size(); QString operationText; if( m_transcodingConfig.isJustCopy() ) operationText = i18np( "Transferring one track to %2", "Transferring %1 tracks to %2", trackCount, collectionPrettyName ); else operationText = i18np( "Transcoding one track to %2", "Transcoding %1 tracks to %2", trackCount, collectionPrettyName ); Amarok::Components::logger()->newProgressOperation( this, operationText, trackCount, this, SLOT(abort()) ); itdb_start_sync( m_coll.data()->m_itdb ); QMapIterator<Meta::TrackPtr, KUrl> it( m_sources ); while( it.hasNext() ) { if( m_aborted || !m_coll ) break; it.next(); Meta::TrackPtr track = it.key(); KUrl sourceUrl = it.value(); emit startDuplicateTrackSearch( track ); // wait for searching to finish: m_searchingForDuplicates.acquire( 1 ); if( m_duplicateTrack ) { trackProcessed( Duplicate, track, m_duplicateTrack ); continue; } if( !m_coll ) break; // destructed behind our back if( m_transcodingConfig.isJustCopy() // if not copying, we catch big files later && track->filesize() > totalSafeCapacity - m_coll.data()->usedCapacity() ) { // this is a best effort check, we do one definite one after the file is copied debug() << "Refusing to copy" << track->prettyUrl() << "to iPod: there are only" << totalSafeCapacity - m_coll.data()->usedCapacity() << "free bytes (not" << "counting a safety margin) on iPod and track has" << track->filesize() << "bytes."; trackProcessed( ExceededingSafeCapacity, track ); continue; } QString fileExtension; if( m_transcodingConfig.isJustCopy() ) fileExtension = track->type(); else fileExtension = Amarok::Components::transcodingController()->format( m_transcodingConfig.encoder() )->fileExtension(); if( !m_coll.data()->supportedFormats().contains( fileExtension ) ) { m_notPlayableFormats.insert( fileExtension ); trackProcessed( NotPlayable, track ); continue; } QByteArray fakeSrcName( "filename." ); // only for file extension fakeSrcName.append( QFile::encodeName( fileExtension ) ); /* determine destination filename; we cannot use ipodTrack because as it has no itdb * (and thus mountpoint) set */ GError *error = 0; gchar *destFilename = itdb_cp_get_dest_filename( 0, mountPoint, fakeSrcName, &error ); if( error ) { warning() << "Cannot construct iPod track filename:" << error->message; g_error_free( error ); error = 0; } if( !destFilename ) { trackProcessed( InternalError, track ); continue; } // start the physical copying KUrl destUrl = KUrl( QFile::decodeName( destFilename ) ); emit startCopyOrTranscodeJob( sourceUrl, destUrl ); // wait for copying to finish: m_copying.acquire( 1 ); /* fsync so that progress bar gives correct info and user doesnt remove the iPod * prematurely */ QFile destFile( QFile::decodeName( destFilename ) ); if( !destFile.exists() ) { debug() << destFile.fileName() << "does not exist even though we thought we copied it to iPod"; trackProcessed( CopyingFailed, track ); continue; } if( !m_coll ) break; // destructed behind our back if( m_coll.data()->usedCapacity() > totalSafeCapacity ) { debug() << "We exceeded total safe-to-use capacity on iPod (safe-to-use:" << totalSafeCapacity << "B, used:" << m_coll.data()->usedCapacity() << "): removing copied track from iPod"; destFile.remove(); trackProcessed( ExceededingSafeCapacity, track ); continue; } // fsync needs a file opened for writing, and without Apped it truncates files (?) if( !destFile.open( QIODevice::WriteOnly | QIODevice::Append ) ) { warning() << "Cannot open file copied to ipod (for writing):" << destFile.fileName() << ": removing it"; destFile.remove(); trackProcessed( InternalError, track ); continue; } if( destFile.size() ) fsync( destFile.handle() ); // should flush all kernel buffers to disk destFile.close(); // create a new track object by copying meta-data from existing one: IpodMeta::Track *ipodTrack = new IpodMeta::Track( track ); // tell the track it has been copied: bool accepted = ipodTrack->finalizeCopying( mountPoint, destFilename ); g_free( destFilename ); destFilename = 0; if( !accepted ) { debug() << "ipodTrack->finalizeCopying( destFilename ) returned false!"; delete ipodTrack; trackProcessed( InternalError, track ); continue; } if( !m_transcodingConfig.isJustCopy() ) { // we need to reread some metadata in case the file was transcoded Meta::FieldHash fields = Meta::Tag::readTags( destFile.fileName() ); ipodTrack->setBitrate( fields.value( Meta::valBitrate, 0 ).toInt() ); ipodTrack->setLength( fields.value( Meta::valLength, 0 ).toLongLong() ); ipodTrack->setSampleRate( fields.value( Meta::valSamplerate, 0 ).toInt() ); Amarok::FileType type = Amarok::FileType( fields.value( Meta::valFormat, 0 ).toInt() ); ipodTrack->setType( Amarok::FileTypeSupport::toString( type ) ); // we retain ReplayGain, tags etc - these shouldn't change; size is read // in finalizeCopying() } // add the track to collection if( !m_coll ) { delete ipodTrack; break; // we were waiting for copying, m_coll may got destoryed } Meta::TrackPtr newTrack = m_coll.data()->addTrack( ipodTrack ); if( !newTrack ) { destFile.remove(); trackProcessed( InternalError, track ); continue; } trackProcessed( Success, track, newTrack ); } if( m_coll ) itdb_stop_sync( m_coll.data()->m_itdb ); emit endProgressOperation( this ); int sourceSize = m_sources.size(); int successCount = m_sourceTrackStatus.count( Success ); int duplicateCount = m_sourceTrackStatus.count( Duplicate ); QString transferredText; if ( m_transcodingConfig.isJustCopy() ) transferredText = i18ncp( "%2 is collection name", "Transferred one track to %2.", "Transferred %1 tracks to %2.", successCount, collectionPrettyName ); else transferredText = i18ncp( "%2 is collection name", "Transcoded one track to %2.", "Transcoded %1 tracks to %2.", successCount, collectionPrettyName ); if( successCount == sourceSize ) { Amarok::Components::logger()->shortMessage( transferredText ); } else if( m_aborted ) { QString text = i18np( "Transfer aborted. Managed to transfer one track.", "Transfer aborted. Managed to transfer %1 tracks.", successCount ); Amarok::Components::logger()->longMessage( text ); } else if( successCount + duplicateCount == sourceSize ) { QString text = i18ncp( "%2 is the 'Transferred 123 tracks to Some collection.' message", "%2 One track was already there.", "%2 %1 tracks were already there.", duplicateCount, transferredText ); Amarok::Components::logger()->longMessage( text ); } else { // somethig more severe failed, notify user using a dialog emit displaySorryDialog(); } }
bool ID3v2TagHelper::setTags( const Meta::FieldHash &changes ) { bool modified = TagHelper::setTags( changes ); foreach( const qint64 key, changes.keys() ) { QVariant value = changes.value( key ); TagLib::ByteVector field( fieldName( key ).toCString() ); if( !field.isNull() && !field.isEmpty() ) { if( key == Meta::valHasCover ) continue; else if( key == Meta::valUniqueId ) { QPair< UIDType, QString > uidPair = splitUID( value.toString() ); if( uidPair.first == UIDInvalid ) continue; TagLib::String owner = uidFieldName( uidPair.first ); TagLib::ByteVector uid( uidPair.second.toAscii().data() ); TagLib::ID3v2::FrameList list = m_tag->frameList(); for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if( ( *it )->frameID() == field ) { TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast< TagLib::ID3v2::UniqueFileIdentifierFrame * >( *it ); if( !frame ) continue; if( frame->owner() == owner ) { m_tag->removeFrame( frame ); modified = true; break; } } } if ( !uid.isEmpty() ) { m_tag->addFrame( new TagLib::ID3v2::UniqueFileIdentifierFrame( owner, uid ) ); modified = true; } continue; } TagLib::String tValue = Qt4QStringToTString( ( key == Meta::valCompilation ) ? QString::number( value.toInt() ) : value.toString() ); if( tValue.isEmpty() ) m_tag->removeFrames( field ); else { TagLib::ID3v2::TextIdentificationFrame *frame = NULL; if( !m_tag->frameListMap()[field].isEmpty() ) frame = dynamic_cast< TagLib::ID3v2::TextIdentificationFrame * >( m_tag->frameListMap()[field].front() ); if( !frame ) { frame = new TagLib::ID3v2::TextIdentificationFrame( field ); m_tag->addFrame( frame ); } // note: TagLib is smart enough to automatically set UTF8 encoding if needed. frame->setText( tValue ); } modified = true; } else if( key == Meta::valScore || key == Meta::valRating || key == Meta::valPlaycount ) { TagLib::String description; TagLib::String tValue; if( key == Meta::valRating ) { description = fmpsFieldName( FMPSRating ); tValue = Qt4QStringToTString( QString::number( value.toFloat() / 10.0 ) ); } else if( key == Meta::valScore ) { description = fmpsFieldName( FMPSScore ); tValue = Qt4QStringToTString( QString::number( value.toFloat() / 100.0 ) ); } else if( key == Meta::valPlaycount ) { description = fmpsFieldName( FMPSPlayCount ); tValue = Qt4QStringToTString( QString::number( value.toInt() ) ); } if( key == Meta::valRating || key == Meta::valPlaycount ) { TagLib::ID3v2::PopularimeterFrame *popFrame = NULL; if( !m_tag->frameListMap()[POPM_Frame].isEmpty() ) popFrame = dynamic_cast< TagLib::ID3v2::PopularimeterFrame * >( m_tag->frameListMap()[POPM_Frame].front() ); if( !popFrame ) { popFrame = new TagLib::ID3v2::PopularimeterFrame( POPM_Frame ); m_tag->addFrame( popFrame ); } if( key == Meta::valRating ) popFrame->setRating( qBound(0, int(qRound(value.toDouble() / 10.0 * 256)), 255) ); else popFrame->setCounter( value.toInt() ); modified = true; } TagLib::ID3v2::FrameList list = m_tag->frameList(); for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if( ( *it )->frameID() == TXXX_Frame ) { TagLib::ID3v2::UserTextIdentificationFrame *frame = dynamic_cast< TagLib::ID3v2::UserTextIdentificationFrame * >( *it ); if( !frame ) continue; if( frame->description() == description ) { m_tag->removeFrame( frame ); modified = true; break; } } } if( value.toBool() ) { TagLib::ID3v2::UserTextIdentificationFrame *frame = new TagLib::ID3v2::UserTextIdentificationFrame( TXXX_Frame ); frame->setDescription( description ); frame->setText( tValue ); m_tag->addFrame( frame ); modified = true; } } } return modified; }