Transcode files when copying them to devices
This commit is contained in:
parent
eae74f6ad8
commit
4b381e00fd
|
@ -36,6 +36,13 @@ public:
|
||||||
Role_FreeSpace,
|
Role_FreeSpace,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Values are saved in the database - don't change
|
||||||
|
enum TranscodeMode {
|
||||||
|
Transcode_Always = 1,
|
||||||
|
Transcode_Never = 2,
|
||||||
|
Transcode_Unsupported = 3,
|
||||||
|
};
|
||||||
|
|
||||||
typedef boost::function<void (float progress)> ProgressFunction;
|
typedef boost::function<void (float progress)> ProgressFunction;
|
||||||
|
|
||||||
struct CopyJob {
|
struct CopyJob {
|
||||||
|
@ -53,6 +60,10 @@ public:
|
||||||
|
|
||||||
virtual QString LocalPath() const { return QString(); }
|
virtual QString LocalPath() const { return QString(); }
|
||||||
|
|
||||||
|
virtual TranscodeMode GetTranscodeMode() const { return Transcode_Never; }
|
||||||
|
virtual Song::FileType GetTranscodeFormat() const { return Song::Type_Unknown; }
|
||||||
|
virtual QList<Song::FileType> SupportedFiletypes() { return QList<Song::FileType>(); }
|
||||||
|
|
||||||
virtual void StartCopy() {}
|
virtual void StartCopy() {}
|
||||||
virtual bool CopyToStorage(const CopyJob& job) = 0;
|
virtual bool CopyToStorage(const CopyJob& job) = 0;
|
||||||
virtual void FinishCopy(bool success) {}
|
virtual void FinishCopy(bool success) {}
|
||||||
|
|
|
@ -33,18 +33,24 @@ Organise::Organise(TaskManager* task_manager,
|
||||||
const QStringList& files, bool eject_after)
|
const QStringList& files, bool eject_after)
|
||||||
: thread_(NULL),
|
: thread_(NULL),
|
||||||
task_manager_(task_manager),
|
task_manager_(task_manager),
|
||||||
|
transcoder_(new Transcoder(this)),
|
||||||
destination_(destination),
|
destination_(destination),
|
||||||
format_(format),
|
format_(format),
|
||||||
copy_(copy),
|
copy_(copy),
|
||||||
overwrite_(overwrite),
|
overwrite_(overwrite),
|
||||||
files_(files),
|
|
||||||
eject_after_(eject_after),
|
eject_after_(eject_after),
|
||||||
|
task_count_(files.count()),
|
||||||
|
transcode_suffix_(1),
|
||||||
started_(false),
|
started_(false),
|
||||||
task_id_(0),
|
task_id_(0),
|
||||||
progress_(0),
|
progress_(0),
|
||||||
song_progress_(0)
|
song_progress_(0)
|
||||||
{
|
{
|
||||||
original_thread_ = thread();
|
original_thread_ = thread();
|
||||||
|
|
||||||
|
foreach (const QString& filename, files) {
|
||||||
|
tasks_pending_ << Task(filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Organise::Start() {
|
void Organise::Start() {
|
||||||
|
@ -56,6 +62,7 @@ void Organise::Start() {
|
||||||
|
|
||||||
thread_ = new QThread;
|
thread_ = new QThread;
|
||||||
connect(thread_, SIGNAL(started()), SLOT(ProcessSomeFiles()));
|
connect(thread_, SIGNAL(started()), SLOT(ProcessSomeFiles()));
|
||||||
|
connect(transcoder_, SIGNAL(JobComplete(QString,bool)), SLOT(FileTranscoded(QString,bool)));
|
||||||
|
|
||||||
moveToThread(thread_);
|
moveToThread(thread_);
|
||||||
thread_->start();
|
thread_->start();
|
||||||
|
@ -63,12 +70,21 @@ void Organise::Start() {
|
||||||
|
|
||||||
void Organise::ProcessSomeFiles() {
|
void Organise::ProcessSomeFiles() {
|
||||||
if (!started_) {
|
if (!started_) {
|
||||||
|
transcode_temp_name_.open();
|
||||||
|
supported_filetypes_ = destination_->SupportedFiletypes();
|
||||||
|
|
||||||
destination_->StartCopy();
|
destination_->StartCopy();
|
||||||
started_ = true;
|
started_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// None left?
|
// None left?
|
||||||
if (progress_ >= files_.count()) {
|
if (tasks_pending_.isEmpty()) {
|
||||||
|
if (!tasks_transcoding_.isEmpty()) {
|
||||||
|
// Just wait - FileTranscoded will start us off again in a little while
|
||||||
|
qDebug() << "Waiting for transcoding jobs";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateProgress();
|
UpdateProgress();
|
||||||
|
|
||||||
destination_->FinishCopy(files_with_errors_.isEmpty());
|
destination_->FinishCopy(files_with_errors_.isEmpty());
|
||||||
|
@ -89,34 +105,75 @@ void Organise::ProcessSomeFiles() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir dir;
|
|
||||||
|
|
||||||
// We process files in batches so we can be cancelled part-way through.
|
// We process files in batches so we can be cancelled part-way through.
|
||||||
|
for (int i=0 ; i<kBatchSize ; ++i) {
|
||||||
const int n = qMin(files_.count(), progress_ + kBatchSize);
|
|
||||||
for ( ; progress_<n ; ++progress_) {
|
|
||||||
SetSongProgress(0);
|
SetSongProgress(0);
|
||||||
|
|
||||||
const QString filename = files_[progress_];
|
if (tasks_pending_.isEmpty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
Task task = tasks_pending_.takeFirst();
|
||||||
|
qDebug() << "Processing" << task.filename_;
|
||||||
|
|
||||||
// Is it a directory?
|
// Is it a directory?
|
||||||
if (QFileInfo(filename).isDir()) {
|
if (QFileInfo(task.filename_).isDir()) {
|
||||||
QDir dir(filename);
|
QDir dir(task.filename_);
|
||||||
foreach (const QString& entry, dir.entryList(
|
foreach (const QString& entry, dir.entryList(
|
||||||
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)) {
|
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)) {
|
||||||
files_ << filename + "/" + entry;
|
tasks_pending_ << Task(task.filename_ + "/" + entry);
|
||||||
|
task_count_ ++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read metadata from the file
|
// Read metadata from the file
|
||||||
Song song;
|
Song song;
|
||||||
song.InitFromFile(filename, -1);
|
song.InitFromFile(task.filename_, -1);
|
||||||
if (!song.is_valid())
|
if (!song.is_valid())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Maybe this file is one that's been transcoded already?
|
||||||
|
if (!task.transcoded_filename_.isEmpty()) {
|
||||||
|
qDebug() << "This file has already been transcoded";
|
||||||
|
|
||||||
|
// Set the new filetype on the song so the formatter gets it right
|
||||||
|
song.set_filetype(task.new_filetype_);
|
||||||
|
|
||||||
|
// Fiddle the filename extension as well to match the new type
|
||||||
|
song.set_filename(song.filename().section('.', 0, -2) + "." + task.new_extension_);
|
||||||
|
song.set_basefilename(song.basefilename().section('.', 0, -2) + "." + task.new_extension_);
|
||||||
|
|
||||||
|
// Have to set this to the size of the new file or else funny stuff happens
|
||||||
|
song.set_filesize(QFileInfo(task.transcoded_filename_).size());
|
||||||
|
} else {
|
||||||
|
// Figure out if we need to transcode it
|
||||||
|
Song::FileType dest_type = CheckTranscode(song.filetype());
|
||||||
|
if (dest_type != Song::Type_Unknown) {
|
||||||
|
// Get the preset
|
||||||
|
TranscoderPreset preset = Transcoder::PresetForFileType(dest_type);
|
||||||
|
qDebug() << "Transcoding with" << preset.name_;
|
||||||
|
|
||||||
|
// Get a temporary name for the transcoded file
|
||||||
|
task.transcoded_filename_ = transcode_temp_name_.fileName() + "-" +
|
||||||
|
QString::number(transcode_suffix_++);
|
||||||
|
task.new_extension_ = preset.extension_;
|
||||||
|
task.new_filetype_ = dest_type;
|
||||||
|
tasks_transcoding_[task.filename_] = task;
|
||||||
|
|
||||||
|
qDebug() << "Transcoding to" << task.transcoded_filename_;
|
||||||
|
|
||||||
|
// Start the transcoding - this will happen in the background and
|
||||||
|
// FileTranscoded() will get called when it's done. At that point the
|
||||||
|
// task will get re-added to the pending queue with the new filename.
|
||||||
|
transcoder_->AddJob(task.filename_, preset, task.transcoded_filename_);
|
||||||
|
transcoder_->Start();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MusicStorage::CopyJob job;
|
MusicStorage::CopyJob job;
|
||||||
job.source_ = filename;
|
job.source_ = task.transcoded_filename_.isEmpty() ?
|
||||||
|
task.filename_ : task.transcoded_filename_;
|
||||||
job.destination_ = format_.GetFilenameForSong(song);
|
job.destination_ = format_.GetFilenameForSong(song);
|
||||||
job.metadata_ = song;
|
job.metadata_ = song;
|
||||||
job.overwrite_ = overwrite_;
|
job.overwrite_ = overwrite_;
|
||||||
|
@ -124,14 +181,47 @@ void Organise::ProcessSomeFiles() {
|
||||||
job.progress_ = boost::bind(&Organise::SetSongProgress, this, _1);
|
job.progress_ = boost::bind(&Organise::SetSongProgress, this, _1);
|
||||||
|
|
||||||
if (!destination_->CopyToStorage(job)) {
|
if (!destination_->CopyToStorage(job)) {
|
||||||
files_with_errors_ << filename;
|
files_with_errors_ << task.filename_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
progress_++;
|
||||||
}
|
}
|
||||||
SetSongProgress(0);
|
SetSongProgress(0);
|
||||||
|
|
||||||
QTimer::singleShot(0, this, SLOT(ProcessSomeFiles()));
|
QTimer::singleShot(0, this, SLOT(ProcessSomeFiles()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Song::FileType Organise::CheckTranscode(Song::FileType original_type) const {
|
||||||
|
if (original_type == Song::Type_Stream)
|
||||||
|
return Song::Type_Unknown;
|
||||||
|
|
||||||
|
const MusicStorage::TranscodeMode mode = destination_->GetTranscodeMode();
|
||||||
|
const Song::FileType format = destination_->GetTranscodeFormat();
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case MusicStorage::Transcode_Never:
|
||||||
|
return Song::Type_Unknown;
|
||||||
|
|
||||||
|
case MusicStorage::Transcode_Always:
|
||||||
|
if (original_type == format)
|
||||||
|
return Song::Type_Unknown;
|
||||||
|
return format;
|
||||||
|
|
||||||
|
case MusicStorage::Transcode_Unsupported:
|
||||||
|
if (supported_filetypes_.isEmpty() || supported_filetypes_.contains(original_type))
|
||||||
|
return Song::Type_Unknown;
|
||||||
|
|
||||||
|
if (format != Song::Type_Unknown)
|
||||||
|
return format;
|
||||||
|
|
||||||
|
// The user hasn't visited the device properties page yet to set a
|
||||||
|
// preferred format for the device, so we have to pick the best
|
||||||
|
// available one.
|
||||||
|
return Transcoder::PickBestFormat(supported_filetypes_);
|
||||||
|
}
|
||||||
|
return Song::Type_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
void Organise::SetSongProgress(float progress) {
|
void Organise::SetSongProgress(float progress) {
|
||||||
song_progress_ = qBound(0, int(progress * 100), 99);
|
song_progress_ = qBound(0, int(progress * 100), 99);
|
||||||
UpdateProgress();
|
UpdateProgress();
|
||||||
|
@ -139,6 +229,18 @@ void Organise::SetSongProgress(float progress) {
|
||||||
|
|
||||||
void Organise::UpdateProgress() {
|
void Organise::UpdateProgress() {
|
||||||
const int progress = progress_ * 100 + song_progress_;
|
const int progress = progress_ * 100 + song_progress_;
|
||||||
const int total = files_.count() * 100;
|
const int total = task_count_ * 100;
|
||||||
task_manager_->SetTaskProgress(task_id_, progress, total);
|
task_manager_->SetTaskProgress(task_id_, progress, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Organise::FileTranscoded(const QString& filename, bool success) {
|
||||||
|
qDebug() << "File finished" << filename << success;
|
||||||
|
|
||||||
|
Task task = tasks_transcoding_.take(filename);
|
||||||
|
if (!success) {
|
||||||
|
files_with_errors_ << filename;
|
||||||
|
} else {
|
||||||
|
tasks_pending_ << task;
|
||||||
|
}
|
||||||
|
QTimer::singleShot(0, this, SLOT(ProcessSomeFiles()));
|
||||||
|
}
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
#define ORGANISE_H
|
#define ORGANISE_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include "organiseformat.h"
|
#include "organiseformat.h"
|
||||||
|
#include "transcoder/transcoder.h"
|
||||||
|
|
||||||
class MusicStorage;
|
class MusicStorage;
|
||||||
class TaskManager;
|
class TaskManager;
|
||||||
|
@ -44,20 +46,41 @@ signals:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ProcessSomeFiles();
|
void ProcessSomeFiles();
|
||||||
void SetSongProgress(float progress);
|
void FileTranscoded(const QString& filename, bool success);
|
||||||
void UpdateProgress();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SetSongProgress(float progress);
|
||||||
|
void UpdateProgress();
|
||||||
|
Song::FileType CheckTranscode(Song::FileType original_type) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Task {
|
||||||
|
Task(const QString& filename = QString()) : filename_(filename) {}
|
||||||
|
|
||||||
|
QString filename_;
|
||||||
|
QString transcoded_filename_;
|
||||||
|
QString new_extension_;
|
||||||
|
Song::FileType new_filetype_;
|
||||||
|
};
|
||||||
|
|
||||||
QThread* thread_;
|
QThread* thread_;
|
||||||
QThread* original_thread_;
|
QThread* original_thread_;
|
||||||
TaskManager* task_manager_;
|
TaskManager* task_manager_;
|
||||||
|
Transcoder* transcoder_;
|
||||||
boost::shared_ptr<MusicStorage> destination_;
|
boost::shared_ptr<MusicStorage> destination_;
|
||||||
|
QList<Song::FileType> supported_filetypes_;
|
||||||
|
|
||||||
const OrganiseFormat format_;
|
const OrganiseFormat format_;
|
||||||
const bool copy_;
|
const bool copy_;
|
||||||
const bool overwrite_;
|
const bool overwrite_;
|
||||||
QStringList files_;
|
|
||||||
const bool eject_after_;
|
const bool eject_after_;
|
||||||
|
int task_count_;
|
||||||
|
|
||||||
|
QTemporaryFile transcode_temp_name_;
|
||||||
|
int transcode_suffix_;
|
||||||
|
|
||||||
|
QList<Task> tasks_pending_;
|
||||||
|
QMap<QString, Task> tasks_transcoding_;
|
||||||
|
|
||||||
bool started_;
|
bool started_;
|
||||||
|
|
||||||
|
|
|
@ -94,3 +94,15 @@ void ConnectedDevice::FinishCopy(bool) {
|
||||||
void ConnectedDevice::FinishDelete(bool) {
|
void ConnectedDevice::FinishDelete(bool) {
|
||||||
lister_->UpdateDeviceFreeSpace(unique_id_);
|
lister_->UpdateDeviceFreeSpace(unique_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MusicStorage::TranscodeMode ConnectedDevice::GetTranscodeMode() const {
|
||||||
|
int index = manager_->FindDeviceById(unique_id_);
|
||||||
|
return MusicStorage::TranscodeMode(
|
||||||
|
manager_->index(index).data(DeviceManager::Role_TranscodeMode).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
Song::FileType ConnectedDevice::GetTranscodeFormat() const {
|
||||||
|
int index = manager_->FindDeviceById(unique_id_);
|
||||||
|
return Song::FileType(
|
||||||
|
manager_->index(index).data(DeviceManager::Role_TranscodeFormat).toInt());
|
||||||
|
}
|
||||||
|
|
|
@ -44,7 +44,8 @@ public:
|
||||||
|
|
||||||
virtual void Init() = 0;
|
virtual void Init() = 0;
|
||||||
|
|
||||||
virtual QList<Song::FileType> SupportedFiletypes() { return QList<Song::FileType>(); }
|
virtual TranscodeMode GetTranscodeMode() const;
|
||||||
|
virtual Song::FileType GetTranscodeFormat() const;
|
||||||
|
|
||||||
DeviceLister* lister() const { return lister_; }
|
DeviceLister* lister() const { return lister_; }
|
||||||
QString unique_id() const { return unique_id_; }
|
QString unique_id() const { return unique_id_; }
|
||||||
|
|
|
@ -52,7 +52,7 @@ DeviceDatabaseBackend::DeviceList DeviceDatabaseBackend::GetAllDevices() {
|
||||||
dev.friendly_name_ = q.value(2).toString();
|
dev.friendly_name_ = q.value(2).toString();
|
||||||
dev.size_ = q.value(3).toLongLong();
|
dev.size_ = q.value(3).toLongLong();
|
||||||
dev.icon_name_ = q.value(4).toString();
|
dev.icon_name_ = q.value(4).toString();
|
||||||
dev.transcode_mode_ = TranscodeMode(q.value(5).toInt());
|
dev.transcode_mode_ = MusicStorage::TranscodeMode(q.value(5).toInt());
|
||||||
dev.transcode_format_ = Song::FileType(q.value(6).toInt());
|
dev.transcode_format_ = Song::FileType(q.value(6).toInt());
|
||||||
ret << dev;
|
ret << dev;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ void DeviceDatabaseBackend::RemoveDevice(int id) {
|
||||||
|
|
||||||
void DeviceDatabaseBackend::SetDeviceOptions(int id,
|
void DeviceDatabaseBackend::SetDeviceOptions(int id,
|
||||||
const QString &friendly_name, const QString &icon_name,
|
const QString &friendly_name, const QString &icon_name,
|
||||||
TranscodeMode mode, Song::FileType format) {
|
MusicStorage::TranscodeMode mode, Song::FileType format) {
|
||||||
QMutexLocker l(db_->Mutex());
|
QMutexLocker l(db_->Mutex());
|
||||||
QSqlDatabase db(db_->Connect());
|
QSqlDatabase db(db_->Connect());
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include "core/musicstorage.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
|
||||||
class Database;
|
class Database;
|
||||||
|
@ -31,13 +32,6 @@ class DeviceDatabaseBackend : public QObject {
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE DeviceDatabaseBackend(QObject* parent = 0);
|
Q_INVOKABLE DeviceDatabaseBackend(QObject* parent = 0);
|
||||||
|
|
||||||
// Values are saved in the database - don't change
|
|
||||||
enum TranscodeMode {
|
|
||||||
Transcode_Always = 1,
|
|
||||||
Transcode_Never = 2,
|
|
||||||
Transcode_Unsupported = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Device {
|
struct Device {
|
||||||
Device() : id_(-1) {}
|
Device() : id_(-1) {}
|
||||||
|
|
||||||
|
@ -47,7 +41,7 @@ public:
|
||||||
quint64 size_;
|
quint64 size_;
|
||||||
QString icon_name_;
|
QString icon_name_;
|
||||||
|
|
||||||
TranscodeMode transcode_mode_;
|
MusicStorage::TranscodeMode transcode_mode_;
|
||||||
Song::FileType transcode_format_;
|
Song::FileType transcode_format_;
|
||||||
};
|
};
|
||||||
typedef QList<Device> DeviceList;
|
typedef QList<Device> DeviceList;
|
||||||
|
@ -63,7 +57,7 @@ public:
|
||||||
|
|
||||||
void SetDeviceOptions(int id,
|
void SetDeviceOptions(int id,
|
||||||
const QString& friendly_name, const QString& icon_name,
|
const QString& friendly_name, const QString& icon_name,
|
||||||
TranscodeMode mode, Song::FileType format);
|
MusicStorage::TranscodeMode mode, Song::FileType format);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::shared_ptr<Database> db_;
|
boost::shared_ptr<Database> db_;
|
||||||
|
|
|
@ -60,7 +60,7 @@ const int DeviceManager::kDeviceIconOverlaySize = 16;
|
||||||
|
|
||||||
DeviceManager::DeviceInfo::DeviceInfo()
|
DeviceManager::DeviceInfo::DeviceInfo()
|
||||||
: database_id_(-1),
|
: database_id_(-1),
|
||||||
transcode_mode_(DeviceDatabaseBackend::Transcode_Unsupported),
|
transcode_mode_(MusicStorage::Transcode_Unsupported),
|
||||||
transcode_format_(Song::Type_Unknown),
|
transcode_format_(Song::Type_Unknown),
|
||||||
task_percentage_(-1)
|
task_percentage_(-1)
|
||||||
{
|
{
|
||||||
|
@ -618,7 +618,7 @@ void DeviceManager::Forget(int row) {
|
||||||
|
|
||||||
void DeviceManager::SetDeviceOptions(int row,
|
void DeviceManager::SetDeviceOptions(int row,
|
||||||
const QString& friendly_name, const QString& icon_name,
|
const QString& friendly_name, const QString& icon_name,
|
||||||
DeviceDatabaseBackend::TranscodeMode mode, Song::FileType format) {
|
MusicStorage::TranscodeMode mode, Song::FileType format) {
|
||||||
DeviceInfo& info = devices_[row];
|
DeviceInfo& info = devices_[row];
|
||||||
info.friendly_name_ = friendly_name;
|
info.friendly_name_ = friendly_name;
|
||||||
info.LoadIcon(QVariantList() << icon_name, friendly_name);
|
info.LoadIcon(QVariantList() << icon_name, friendly_name);
|
||||||
|
@ -676,6 +676,8 @@ void DeviceManager::TasksChanged() {
|
||||||
DeviceInfo& info = devices_[index.row()];
|
DeviceInfo& info = devices_[index.row()];
|
||||||
info.task_percentage_ = -1;
|
info.task_percentage_ = -1;
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
|
|
||||||
|
active_tasks_.remove(active_tasks_.key(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ public:
|
||||||
|
|
||||||
void SetDeviceOptions(int row,
|
void SetDeviceOptions(int row,
|
||||||
const QString& friendly_name, const QString& icon_name,
|
const QString& friendly_name, const QString& icon_name,
|
||||||
DeviceDatabaseBackend::TranscodeMode mode, Song::FileType format);
|
MusicStorage::TranscodeMode mode, Song::FileType format);
|
||||||
|
|
||||||
// QAbstractListModel
|
// QAbstractListModel
|
||||||
int rowCount(const QModelIndex &parent) const;
|
int rowCount(const QModelIndex &parent) const;
|
||||||
|
@ -151,7 +151,7 @@ private:
|
||||||
QString icon_name_;
|
QString icon_name_;
|
||||||
QIcon icon_;
|
QIcon icon_;
|
||||||
|
|
||||||
DeviceDatabaseBackend::TranscodeMode transcode_mode_;
|
MusicStorage::TranscodeMode transcode_mode_;
|
||||||
Song::FileType transcode_format_;
|
Song::FileType transcode_format_;
|
||||||
|
|
||||||
int task_percentage_;
|
int task_percentage_;
|
||||||
|
|
|
@ -187,18 +187,18 @@ void DeviceProperties::UpdateFormats() {
|
||||||
manager_->GetConnectedDevice(index_.row());
|
manager_->GetConnectedDevice(index_.row());
|
||||||
|
|
||||||
// Transcode mode
|
// Transcode mode
|
||||||
DeviceDatabaseBackend::TranscodeMode mode = DeviceDatabaseBackend::TranscodeMode(
|
MusicStorage::TranscodeMode mode = MusicStorage::TranscodeMode(
|
||||||
index_.data(DeviceManager::Role_TranscodeMode).toInt());
|
index_.data(DeviceManager::Role_TranscodeMode).toInt());
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case DeviceDatabaseBackend::Transcode_Always:
|
case MusicStorage::Transcode_Always:
|
||||||
ui_->transcode_all->setChecked(true);
|
ui_->transcode_all->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceDatabaseBackend::Transcode_Never:
|
case MusicStorage::Transcode_Never:
|
||||||
ui_->transcode_off->setChecked(true);
|
ui_->transcode_off->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceDatabaseBackend::Transcode_Unsupported:
|
case MusicStorage::Transcode_Unsupported:
|
||||||
default:
|
default:
|
||||||
ui_->transcode_unsupported->setChecked(true);
|
ui_->transcode_unsupported->setChecked(true);
|
||||||
break;
|
break;
|
||||||
|
@ -238,13 +238,13 @@ void DeviceProperties::accept() {
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
|
|
||||||
// Transcode mode
|
// Transcode mode
|
||||||
DeviceDatabaseBackend::TranscodeMode mode = DeviceDatabaseBackend::Transcode_Unsupported;
|
MusicStorage::TranscodeMode mode = MusicStorage::Transcode_Unsupported;
|
||||||
if (ui_->transcode_all->isChecked())
|
if (ui_->transcode_all->isChecked())
|
||||||
mode = DeviceDatabaseBackend::Transcode_Always;
|
mode = MusicStorage::Transcode_Always;
|
||||||
else if (ui_->transcode_off->isChecked())
|
else if (ui_->transcode_off->isChecked())
|
||||||
mode = DeviceDatabaseBackend::Transcode_Never;
|
mode = MusicStorage::Transcode_Never;
|
||||||
else if (ui_->transcode_unsupported->isChecked())
|
else if (ui_->transcode_unsupported->isChecked())
|
||||||
mode = DeviceDatabaseBackend::Transcode_Unsupported;
|
mode = MusicStorage::Transcode_Unsupported;
|
||||||
|
|
||||||
// Transcode format
|
// Transcode format
|
||||||
Song::FileType format = Song::FileType(ui_->transcode_format->itemData(
|
Song::FileType format = Song::FileType(ui_->transcode_format->itemData(
|
||||||
|
@ -288,23 +288,7 @@ void DeviceProperties::UpdateFormatsFinished() {
|
||||||
if (preset.type_ == Song::Type_Unknown) {
|
if (preset.type_ == Song::Type_Unknown) {
|
||||||
// The user hasn't chosen a format for this device yet, so work our way down
|
// The user hasn't chosen a format for this device yet, so work our way down
|
||||||
// a list of some preferred formats, picking the first one that is supported
|
// a list of some preferred formats, picking the first one that is supported
|
||||||
QList<Song::FileType> best_formats;
|
preset = Transcoder::PresetForFileType(Transcoder::PickBestFormat(list));
|
||||||
best_formats << Song::Type_Mpeg;
|
|
||||||
best_formats << Song::Type_OggVorbis;
|
|
||||||
best_formats << Song::Type_Asf;
|
|
||||||
|
|
||||||
foreach (Song::FileType type, best_formats) {
|
|
||||||
if (list.isEmpty() || list.contains(type)) {
|
|
||||||
preset = Transcoder::PresetForFileType(type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preset.type_ == Song::Type_Unknown) {
|
|
||||||
// Still haven't found a good format - pick the first one that the
|
|
||||||
// device advertises.
|
|
||||||
preset = Transcoder::PresetForFileType(list[0]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ui_->transcode_format->setCurrentIndex(ui_->transcode_format->findText(preset.name_));
|
ui_->transcode_format->setCurrentIndex(ui_->transcode_format->findText(preset.name_));
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,9 @@ static int ProgressCallback(uint64_t const sent, uint64_t const total,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MtpDevice::CopyToStorage(const CopyJob& job) {
|
bool MtpDevice::CopyToStorage(const CopyJob& job) {
|
||||||
|
if (!connection_->is_valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
// Convert metadata
|
// Convert metadata
|
||||||
LIBMTP_track_t track;
|
LIBMTP_track_t track;
|
||||||
job.metadata_.ToMTP(&track);
|
job.metadata_.ToMTP(&track);
|
||||||
|
@ -165,6 +168,11 @@ QList<Song::FileType> MtpDevice::SupportedFiletypes() {
|
||||||
|
|
||||||
QMutexLocker l(&db_busy_);
|
QMutexLocker l(&db_busy_);
|
||||||
MtpConnection connection(url_.host());
|
MtpConnection connection(url_.host());
|
||||||
|
if (!connection.is_valid()) {
|
||||||
|
qWarning() << "Error connecting to MTP device, couldn't get list of supported filetypes";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (LIBMTP_Get_Supported_Filetypes(connection.device(), &list, &length)
|
if (LIBMTP_Get_Supported_Filetypes(connection.device(), &list, &length)
|
||||||
|| !list || !length)
|
|| !list || !length)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -206,6 +206,23 @@ TranscoderPreset Transcoder::PresetForFileType(Song::FileType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Song::FileType Transcoder::PickBestFormat(QList<Song::FileType> supported) {
|
||||||
|
if (supported.isEmpty())
|
||||||
|
return Song::Type_Unknown;
|
||||||
|
|
||||||
|
QList<Song::FileType> best_formats;
|
||||||
|
best_formats << Song::Type_Mpeg;
|
||||||
|
best_formats << Song::Type_OggVorbis;
|
||||||
|
best_formats << Song::Type_Asf;
|
||||||
|
|
||||||
|
foreach (Song::FileType type, best_formats) {
|
||||||
|
if (supported.isEmpty() || supported.contains(type))
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return supported[0];
|
||||||
|
}
|
||||||
|
|
||||||
void Transcoder::AddJob(const QString& input,
|
void Transcoder::AddJob(const QString& input,
|
||||||
const TranscoderPreset& preset,
|
const TranscoderPreset& preset,
|
||||||
const QString& output) {
|
const QString& output) {
|
||||||
|
|
|
@ -55,6 +55,7 @@ class Transcoder : public QObject {
|
||||||
|
|
||||||
static TranscoderPreset PresetForFileType(Song::FileType type);
|
static TranscoderPreset PresetForFileType(Song::FileType type);
|
||||||
static QList<TranscoderPreset> GetAllPresets();
|
static QList<TranscoderPreset> GetAllPresets();
|
||||||
|
static Song::FileType PickBestFormat(QList<Song::FileType> supported);
|
||||||
|
|
||||||
int max_threads() const { return max_threads_; }
|
int max_threads() const { return max_threads_; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue