void ScrobblerAdapter::updateNowPlaying( const Meta::TrackPtr &track ) { lastfm::MutableTrack lfmTrack; if( track ) { if( isToBeSkipped( track ) ) { debug() << "updateNowPlaying(): refusing track" << track->prettyUrl() << "- contains label:" << m_config->filteredLabel() << "which is marked to be skipped"; return; } copyTrackMetadata( lfmTrack, track ); debug() << "nowPlaying: " << lfmTrack.artist() << "-" << lfmTrack.album() << "-" << lfmTrack.title() << "source:" << lfmTrack.source() << "duration:" << lfmTrack.duration(); m_scrobbler.nowPlaying( lfmTrack ); } else { debug() << "removeNowPlaying"; QNetworkReply *reply = lfmTrack.removeNowPlaying(); // works even with empty lfmTrack connect( reply, SIGNAL(finished()), reply, SLOT(deleteLater()) ); // don't leak } }
StatSyncing::ScrobblingService::ScrobbleError ScrobblerAdapter::scrobble( const Meta::TrackPtr &track, double playedFraction, const QDateTime &time ) { Q_ASSERT( track ); if( isToBeSkipped( track ) ) { debug() << "scrobble(): refusing track" << track->prettyUrl() << "- contains label:" << m_config->filteredLabel() << "which is marked to be skipped"; return SkippedByUser; } if( track->length() * qMin( 1.0, playedFraction ) < 30 * 1000 ) { debug() << "scrobble(): refusing track" << track->prettyUrl() << "- played time (" << track->length() / 1000 << "*" << playedFraction << "s) shorter than 30 s"; return TooShort; } int playcount = qRound( playedFraction ); if( playcount <= 0 ) { debug() << "scrobble(): refusing track" << track->prettyUrl() << "- played " << "fraction (" << playedFraction * 100 << "%) less than 50 %"; return TooShort; } lastfm::MutableTrack lfmTrack; copyTrackMetadata( lfmTrack, track ); // since liblastfm >= 1.0.3 it interprets following extra property: lfmTrack.setExtra( "playCount", QString::number( playcount ) ); lfmTrack.setTimeStamp( time.isValid() ? time : QDateTime::currentDateTime() ); debug() << "scrobble: " << lfmTrack.artist() << "-" << lfmTrack.album() << "-" << lfmTrack.title() << "source:" << lfmTrack.source() << "duration:" << lfmTrack.duration(); m_scrobbler.cache( lfmTrack ); m_scrobbler.submit(); // since liblastfm 1.0.7, submit() is not called automatically upon cache() switch( lfmTrack.scrobbleStatus() ) { case lastfm::Track::Cached: case lastfm::Track::Submitted: return NoError; case lastfm::Track::Null: case lastfm::Track::Error: break; } return BadMetadata; }
void OrganizeCollectionDialog::previewNextBatch() //private slot { const int batchSize = 10; QMap<Meta::TrackPtr, QString> dests = m_trackOrganizer->getDestinations( batchSize ); QMapIterator<Meta::TrackPtr, QString> it( dests ); while( it.hasNext() ) { it.next(); Meta::TrackPtr track = it.key(); QString originalPath = track->prettyUrl(); QString newPath = it.value(); int newRow = ui->previewTableWidget->rowCount(); ui->previewTableWidget->insertRow( newRow ); //new path preview in the 1st column QPalette p = ui->previewTableWidget->palette(); QTableWidgetItem *item = new QTableWidgetItem( newPath ); KColorScheme::adjustBackground( p, KColorScheme::NegativeBackground ); if( QFileInfo( newPath ).exists() ) { item->setBackgroundColor( p.color( QPalette::Base ) ); m_conflict = true; } ui->previewTableWidget->setItem( newRow, 0, item ); //original in the second column item = new QTableWidgetItem( originalPath ); ui->previewTableWidget->setItem( newRow, 1, item ); } if( m_conflict ) { if( ui->overwriteCheck->isChecked() ) ui->conflictLabel->setText( i18n( "There is a filename conflict, existing files will be overwritten." ) ); else ui->conflictLabel->setText( i18n( "There is a filename conflict, existing files will not be changed." ) ); } else ui->conflictLabel->setText(""); // we clear the text instead of hiding it to retain the layout spacing //non-blocking way of updating the preview table. if( dests.count() == batchSize ) QTimer::singleShot( 10, this, SLOT(previewNextBatch()) ); else unsetCursor(); // finished }
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(); } }