196 lines
5.8 KiB
C++
196 lines
5.8 KiB
C++
/* This file is part of Clementine.
|
|
Copyright 2014, Andre Siviero <altsiviero@gmail.com>
|
|
|
|
Clementine is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Clementine is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "ripper.h"
|
|
|
|
#include <QFile>
|
|
#include <QMutexLocker>
|
|
#include <QUrl>
|
|
#include <QtConcurrentRun>
|
|
|
|
#include "core/closure.h"
|
|
#include "core/logging.h"
|
|
#include "core/tagreaderclient.h"
|
|
#include "core/utilities.h"
|
|
#include "devices/cddadevice.h"
|
|
#include "transcoder/transcoder.h"
|
|
|
|
// winspool.h defines this :(
|
|
#ifdef AddJob
|
|
#undef AddJob
|
|
#endif
|
|
|
|
Ripper::Ripper(int track_count, QObject* parent)
|
|
: QObject(parent),
|
|
track_count_(track_count),
|
|
transcoder_(new Transcoder(this)),
|
|
cancel_requested_(false),
|
|
finished_success_(0),
|
|
finished_failed_(0),
|
|
files_tagged_(0) {
|
|
Q_ASSERT(track_count >= 0);
|
|
|
|
transcoder_->set_max_threads(1); // we want transcoder to read only one song
|
|
// at once from disc to prevent seeking
|
|
connect(transcoder_, SIGNAL(JobComplete(QUrl, QString, bool)),
|
|
SLOT(TranscodingJobComplete(QUrl, QString, bool)));
|
|
connect(transcoder_, SIGNAL(AllJobsComplete()),
|
|
SLOT(AllTranscodingJobsComplete()));
|
|
connect(transcoder_, SIGNAL(LogLine(QString)), SLOT(LogLine(QString)));
|
|
}
|
|
|
|
Ripper::~Ripper() {}
|
|
|
|
void Ripper::AddTrack(int track_number, const QString& title,
|
|
const QString& transcoded_filename,
|
|
const TranscoderPreset& preset, bool overwrite_existing) {
|
|
if (track_number < 1 || track_number > TracksOnDisc()) {
|
|
qLog(Warning) << "Invalid track number:" << track_number << "Ignoring";
|
|
return;
|
|
}
|
|
TrackInformation track(track_number, title, transcoded_filename, preset,
|
|
overwrite_existing);
|
|
tracks_.append(track);
|
|
}
|
|
|
|
void Ripper::SetAlbumInformation(const QString& album, const QString& artist,
|
|
const QString& genre, int year, int disc,
|
|
Song::FileType type) {
|
|
album_.album = album;
|
|
album_.artist = artist;
|
|
album_.genre = genre;
|
|
album_.year = year;
|
|
album_.disc = disc;
|
|
album_.type = type;
|
|
}
|
|
|
|
int Ripper::TracksOnDisc() const { return track_count_; }
|
|
|
|
int Ripper::AddedTracks() const { return tracks_.length(); }
|
|
|
|
void Ripper::ClearTracks() { tracks_.clear(); }
|
|
|
|
void Ripper::Start() {
|
|
{
|
|
QMutexLocker l(&mutex_);
|
|
cancel_requested_ = false;
|
|
}
|
|
|
|
qLog(Debug) << "Ripping" << AddedTracks() << "tracks.";
|
|
QtConcurrent::run(this, &Ripper::Rip);
|
|
}
|
|
|
|
void Ripper::Cancel() {
|
|
{
|
|
QMutexLocker l(&mutex_);
|
|
cancel_requested_ = true;
|
|
}
|
|
transcoder_->Cancel();
|
|
emit(Cancelled());
|
|
}
|
|
|
|
void Ripper::TranscodingJobComplete(const QUrl& input, const QString& output,
|
|
bool success) {
|
|
if (success)
|
|
finished_success_++;
|
|
else
|
|
finished_failed_++;
|
|
|
|
// The transcoder does not necessarily overwrite files. If not, it changes
|
|
// the name of the output file. We need to update the transcoded
|
|
// filename for the corresponding track so that we tag the correct
|
|
// file later on.
|
|
for (QList<TrackInformation>::iterator it = tracks_.begin();
|
|
it != tracks_.end(); ++it) {
|
|
QUrl track_url =
|
|
CddaDevice::TrackStrToUrl(QString("cdda://%1").arg(it->track_number));
|
|
if (track_url == input) {
|
|
it->transcoded_filename = output;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Ripper::AllTranscodingJobsComplete() { TagFiles(); }
|
|
|
|
void Ripper::LogLine(const QString& message) { qLog(Debug) << message; }
|
|
|
|
void Ripper::Rip() {
|
|
if (tracks_.isEmpty()) {
|
|
emit Finished();
|
|
return;
|
|
}
|
|
|
|
finished_success_ = 0;
|
|
finished_failed_ = 0;
|
|
|
|
for (QList<TrackInformation>::iterator it = tracks_.begin();
|
|
it != tracks_.end(); ++it) {
|
|
QUrl track_url =
|
|
CddaDevice::TrackStrToUrl(QString("cdda://%1").arg(it->track_number));
|
|
transcoder_->AddJob(track_url, it->preset, it->transcoded_filename);
|
|
}
|
|
transcoder_->Start();
|
|
emit RippingComplete();
|
|
}
|
|
|
|
float Ripper::GetProgress() const {
|
|
int added_tracks = AddedTracks();
|
|
if (added_tracks == 0) return 1.0f;
|
|
|
|
float progress = finished_success_ + finished_failed_;
|
|
QList<float> current_job_progress_ = transcoder_->GetProgress().values();
|
|
progress += std::accumulate(current_job_progress_.begin(),
|
|
current_job_progress_.end(), 0.0f);
|
|
progress /= added_tracks;
|
|
|
|
qLog(Debug) << "Progress: " << progress;
|
|
return progress;
|
|
}
|
|
|
|
void Ripper::TagFiles() {
|
|
files_tagged_ = 0;
|
|
for (const TrackInformation& track : tracks_) {
|
|
Song song;
|
|
song.InitFromFilePartial(track.transcoded_filename);
|
|
song.set_track(track.track_number);
|
|
song.set_title(track.title);
|
|
song.set_album(album_.album);
|
|
song.set_artist(album_.artist);
|
|
song.set_genre(album_.genre);
|
|
song.set_year(album_.year);
|
|
song.set_disc(album_.disc);
|
|
song.set_filetype(album_.type);
|
|
|
|
TagReaderReply* reply =
|
|
TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
|
NewClosure(reply, SIGNAL(Finished(bool)), this,
|
|
SLOT(FileTagged(TagReaderReply*)), reply);
|
|
}
|
|
}
|
|
|
|
void Ripper::FileTagged(TagReaderReply* reply) {
|
|
files_tagged_++;
|
|
qLog(Debug) << "Tagged" << files_tagged_ << "of" << tracks_.length()
|
|
<< "files";
|
|
if (files_tagged_ == tracks_.length()) {
|
|
qLog(Debug) << "CD ripper finished.";
|
|
emit Finished();
|
|
}
|
|
|
|
reply->deleteLater();
|
|
}
|