void TrackInfoObject::parse() { // Log parsing of header information in developer mode. This is useful for // tracking down corrupt files. const QString& canonicalLocation = m_fileInfo.canonicalFilePath(); if (CmdlineArgs::Instance().getDeveloper()) { qDebug() << "TrackInfoObject::parse()" << canonicalLocation; } // Parse the information stored in the sound file. SoundSourceProxy proxy(canonicalLocation, m_pSecurityToken); Mixxx::SoundSource* pProxiedSoundSource = proxy.getProxiedSoundSource(); if (pProxiedSoundSource != NULL && proxy.parseHeader() == OK) { // Dump the metadata extracted from the file into the track. // TODO(XXX): This involves locking the mutex for every setXXX // method. We should figure out an optimization where there are private // setters that don't lock the mutex. // If Artist, Title and Type fields are not blank, modify them. // Otherwise, keep their current values. // TODO(rryan): Should we re-visit this decision? if (!(pProxiedSoundSource->getArtist().isEmpty())) { setArtist(pProxiedSoundSource->getArtist()); } if (!(pProxiedSoundSource->getTitle().isEmpty())) { setTitle(pProxiedSoundSource->getTitle()); } if (!(pProxiedSoundSource->getType().isEmpty())) { setType(pProxiedSoundSource->getType()); } setAlbum(pProxiedSoundSource->getAlbum()); setAlbumArtist(pProxiedSoundSource->getAlbumArtist()); setYear(pProxiedSoundSource->getYear()); setGenre(pProxiedSoundSource->getGenre()); setComposer(pProxiedSoundSource->getComposer()); setGrouping(pProxiedSoundSource->getGrouping()); setComment(pProxiedSoundSource->getComment()); setTrackNumber(pProxiedSoundSource->getTrackNumber()); setReplayGain(pProxiedSoundSource->getReplayGain()); setBpm(pProxiedSoundSource->getBPM()); setDuration(pProxiedSoundSource->getDuration()); setBitrate(pProxiedSoundSource->getBitrate()); setSampleRate(pProxiedSoundSource->getSampleRate()); setChannels(pProxiedSoundSource->getChannels()); setKeyText(pProxiedSoundSource->getKey(), mixxx::track::io::key::FILE_METADATA); setHeaderParsed(true); } else { qDebug() << "TrackInfoObject::parse() error at file" << canonicalLocation; setHeaderParsed(false); // Add basic information derived from the filename: parseFilename(); } }
TEST_F( DeviceFs, PartialAlbumRemoval ) { ml->discover( mock::FileSystemFactory::Root ); bool discovered = cbMock->waitDiscovery(); ASSERT_TRUE( discovered ); { auto album = ml->createAlbum( "album" ); auto media = ml->media( mock::FileSystemFactory::SubFolder + "subfile.mp4" ); auto media2 = ml->media( RemovableDeviceMountpoint + "removablefile2.mp3" ); auto newArtist = ml->createArtist( "artist" ); album->addTrack( std::static_pointer_cast<Media>( media ), 1, 1, newArtist->id(), nullptr ); album->addTrack( std::static_pointer_cast<Media>( media2 ), 2, 1, newArtist->id(), nullptr ); album->setAlbumArtist( newArtist ); newArtist->updateNbTrack( 2 ); newArtist->addMedia( static_cast<Media&>( *media ) ); newArtist->addMedia( static_cast<Media&>( *media2 ) ); } auto albums = ml->albums( nullptr )->all(); ASSERT_EQ( 1u, albums.size() ); auto artists = ml->artists( true, nullptr )->all(); ASSERT_EQ( 1u, artists.size() ); auto artist = artists[0]; ASSERT_EQ( 2u, artist->tracks( nullptr )->count() ); auto device = fsMock->removeDevice( RemovableDeviceUuid ); Reload(); albums = ml->albums( nullptr )->all(); ASSERT_EQ( 1u, albums.size() ); artists = ml->artists( true, nullptr )->all(); ASSERT_EQ( 1u, artists.size() ); ASSERT_EQ( 1u, albums[0]->tracks( nullptr )->count() ); ASSERT_EQ( 1u, artists[0]->tracks( nullptr )->count() ); }
TEST_F( DeviceFs, RemoveAlbumAndArtist ) { ml->discover( mock::FileSystemFactory::Root ); bool discovered = cbMock->waitDiscovery(); ASSERT_TRUE( discovered ); // Create an album on a non-removable device { auto album = std::static_pointer_cast<Album>( ml->createAlbum( "album" ) ); auto media = ml->media( mock::FileSystemFactory::Root + "audio.mp3" ); auto artist = ml->createArtist( "artist" ); album->addTrack( std::static_pointer_cast<Media>( media ), 1, 1, artist->id(), 0 ); album->setAlbumArtist( artist ); artist->updateNbTrack( 1 ); } // And an album that will disappear, along with its artist { auto album = std::static_pointer_cast<Album>( ml->createAlbum( "album 2" ) ); auto album2 = std::static_pointer_cast<Album>( ml->createAlbum( "album 3" ) ); auto media1 = std::static_pointer_cast<Media>( ml->media( RemovableDeviceMountpoint + "removablefile.mp3" ) ); auto media2 = std::static_pointer_cast<Media>( ml->media( RemovableDeviceMountpoint + "removablefile2.mp3" ) ); auto media3 = std::static_pointer_cast<Media>( ml->media( RemovableDeviceMountpoint + "removablefile3.mp3" ) ); auto media4 = std::static_pointer_cast<Media>( ml->media( RemovableDeviceMountpoint + "removablefile4.mp3" ) ); auto artist = ml->createArtist( "artist 2" ); album->addTrack( std::static_pointer_cast<Media>( media1 ), 1, 1, artist->id(), nullptr ); album->addTrack( std::static_pointer_cast<Media>( media2 ), 2, 1, artist->id(), nullptr ); album2->addTrack( std::static_pointer_cast<Media>( media3 ), 1, 1, artist->id(), nullptr ); album2->addTrack( std::static_pointer_cast<Media>( media4 ), 2, 1, artist->id(), nullptr ); album->setAlbumArtist( artist ); album2->setAlbumArtist( artist ); artist->updateNbTrack( 4 ); media1->save(); media2->save(); media3->save(); media4->save(); } auto albums = ml->albums( nullptr )->all(); ASSERT_EQ( 3u, albums.size() ); auto artists = ml->artists( true, nullptr )->all(); ASSERT_EQ( 2u, artists.size() ); auto device = fsMock->removeDevice( RemovableDeviceUuid ); Reload(); albums = ml->albums( nullptr )->all(); ASSERT_EQ( 1u, albums.size() ); artists = ml->artists( true, nullptr )->all(); ASSERT_EQ( 1u, artists.size() ); // Now check that everything appears again when we plug the device back in fsMock->addDevice( device ); Reload(); albums = ml->albums( nullptr )->all(); ASSERT_EQ( 3u, albums.size() ); artists = ml->artists( true, nullptr )->all(); ASSERT_EQ( 2u, artists.size() ); }
foreach( TrackEditorPtr ec, m_editors ) ec->beginUpdate(); } void endUpdate() { foreach( TrackEditorPtr ec, m_editors ) ec->endUpdate(); m_batchMode = false; QTimer::singleShot( 0, m_collection, SLOT(slotUpdated()) ); } void setComment( const QString &newComment ) { FORWARD( setComment( newComment ) ) } void setTrackNumber( int newTrackNumber ) { FORWARD( setTrackNumber( newTrackNumber ) ) } void setDiscNumber( int newDiscNumber ) { FORWARD( setDiscNumber( newDiscNumber ) ) } void setBpm( const qreal newBpm ) { FORWARD( setBpm( newBpm ) ) } void setTitle( const QString &newTitle ) { FORWARD( setTitle( newTitle ) ) } void setArtist( const QString &newArtist ) { FORWARD( setArtist( newArtist ) ) } void setAlbum( const QString &newAlbum ) { FORWARD( setAlbum( newAlbum ) ) } void setAlbumArtist( const QString &newAlbumArtist ) { FORWARD( setAlbumArtist ( newAlbumArtist ) ) } void setGenre( const QString &newGenre ) { FORWARD( setGenre( newGenre ) ) } void setComposer( const QString &newComposer ) { FORWARD( setComposer( newComposer ) ) } void setYear( int newYear ) { FORWARD( setYear( newYear ) ) } private: bool m_batchMode; Collections::AggregateCollection *m_collection; QList<TrackEditorPtr> m_editors; }; #undef FORWARD AggregateTrack::AggregateTrack( Collections::AggregateCollection *coll, const TrackPtr &track ) : Track() , Observer() , m_collection( coll )