Merge pull request #4145 from sobkas/master
Initial support for "Copy to device" in a podcast section
This commit is contained in:
commit
7ddf3aab45
@ -56,16 +56,14 @@ struct sqlite3_tokenizer_module {
|
||||
int (*xCreate)(
|
||||
int argc, /* Size of argv array */
|
||||
const char *const*argv, /* Tokenizer argument strings */
|
||||
sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */
|
||||
);
|
||||
sqlite3_tokenizer **ppTokenizer); /* OUT: Created tokenizer */
|
||||
|
||||
int (*xDestroy)(sqlite3_tokenizer *pTokenizer);
|
||||
|
||||
int (*xOpen)(
|
||||
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
|
||||
const char *pInput, int nBytes, /* Input buffer */
|
||||
sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */
|
||||
);
|
||||
sqlite3_tokenizer_cursor **ppCursor);/* OUT: Created tokenizer cursor */
|
||||
|
||||
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
|
||||
|
||||
@ -74,8 +72,7 @@ struct sqlite3_tokenizer_module {
|
||||
const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */
|
||||
int *piStartOffset, /* OUT: Byte offset of token in input buffer */
|
||||
int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */
|
||||
int *piPosition /* OUT: Number of tokens returned before this one */
|
||||
);
|
||||
int *piPosition); /* OUT: Number of tokens returned before this one */
|
||||
};
|
||||
|
||||
struct sqlite3_tokenizer {
|
||||
@ -221,7 +218,7 @@ Database::Database(Application* app, QObject* parent, const QString& database_na
|
||||
{
|
||||
{
|
||||
QMutexLocker l(&sNextConnectionIdMutex);
|
||||
connection_id_ = sNextConnectionId ++;
|
||||
connection_id_ = sNextConnectionId++;
|
||||
}
|
||||
|
||||
directory_ = QDir::toNativeSeparators(
|
||||
@ -288,7 +285,7 @@ QSqlDatabase Database::Connect() {
|
||||
}
|
||||
|
||||
// Attach external databases
|
||||
foreach (const QString& key, attached_databases_.keys()) {
|
||||
for (const QString& key : attached_databases_.keys()) {
|
||||
QString filename = attached_databases_[key].filename_;
|
||||
|
||||
if (!injected_database_name_.isNull())
|
||||
@ -303,13 +300,13 @@ QSqlDatabase Database::Connect() {
|
||||
}
|
||||
}
|
||||
|
||||
if(startup_schema_version_ == -1) {
|
||||
if (startup_schema_version_ == -1) {
|
||||
UpdateMainSchema(&db);
|
||||
}
|
||||
|
||||
// We might have to initialise the schema in some attached databases now, if
|
||||
// they were deleted and don't match up with the main schema version.
|
||||
foreach (const QString& key, attached_databases_.keys()) {
|
||||
for (const QString& key : attached_databases_.keys()) {
|
||||
if (attached_databases_[key].is_temporary_ &&
|
||||
attached_databases_[key].schema_.isEmpty())
|
||||
continue;
|
||||
@ -344,7 +341,7 @@ void Database::UpdateMainSchema(QSqlDatabase* db) {
|
||||
}
|
||||
if (schema_version < kSchemaVersion) {
|
||||
// Update the schema
|
||||
for (int v=schema_version+1 ; v<= kSchemaVersion ; ++v) {
|
||||
for (int v = schema_version+1; v <= kSchemaVersion; ++v) {
|
||||
UpdateDatabaseSchema(v, *db);
|
||||
}
|
||||
}
|
||||
@ -377,7 +374,7 @@ void Database::RecreateAttachedDb(const QString& database_name) {
|
||||
// We can't just re-attach the database now because it needs to be done for
|
||||
// each thread. Close all the database connections, so each thread will
|
||||
// re-attach it when they next connect.
|
||||
foreach (const QString& name, QSqlDatabase::connectionNames()) {
|
||||
for (const QString& name : QSqlDatabase::connectionNames()) {
|
||||
QSqlDatabase::removeDatabase(name);
|
||||
}
|
||||
}
|
||||
@ -432,7 +429,7 @@ void Database::UpdateDatabaseSchema(int version, QSqlDatabase &db) {
|
||||
UrlEncodeFilenameColumn("songs", db);
|
||||
UrlEncodeFilenameColumn("playlist_items", db);
|
||||
|
||||
foreach (const QString& table, db.tables()) {
|
||||
for (const QString& table : db.tables()) {
|
||||
if (table.startsWith("device_") && table.endsWith("_songs")) {
|
||||
UrlEncodeFilenameColumn(table, db);
|
||||
}
|
||||
@ -511,12 +508,12 @@ void Database::ExecSchemaCommands(QSqlDatabase& db,
|
||||
void Database::ExecSongTablesCommands(QSqlDatabase& db,
|
||||
const QStringList& song_tables,
|
||||
const QStringList& commands) {
|
||||
foreach (const QString& command, commands) {
|
||||
for (const QString& command : commands) {
|
||||
// There are now lots of "songs" tables that need to have the same schema:
|
||||
// songs, magnatune_songs, and device_*_songs. We allow a magic value
|
||||
// in the schema files to update all songs tables at once.
|
||||
if (command.contains(kMagicAllSongsTables)) {
|
||||
foreach (const QString& table, song_tables) {
|
||||
for (const QString& table : song_tables) {
|
||||
// Another horrible hack: device songs tables don't have matching _fts
|
||||
// tables, so if this command tries to touch one, ignore it.
|
||||
if (table.startsWith("device_") &&
|
||||
@ -543,17 +540,17 @@ QStringList Database::SongsTables(QSqlDatabase& db, int schema_version) const {
|
||||
QStringList ret;
|
||||
|
||||
// look for the tables in the main db
|
||||
foreach (const QString& table, db.tables()) {
|
||||
for (const QString& table : db.tables()) {
|
||||
if (table == "songs" || table.endsWith("_songs"))
|
||||
ret << table;
|
||||
}
|
||||
|
||||
// look for the tables in attached dbs
|
||||
foreach (const QString& key, attached_databases_.keys()) {
|
||||
for (const QString& key : attached_databases_.keys()) {
|
||||
QSqlQuery q(QString("SELECT NAME FROM %1.sqlite_master"
|
||||
" WHERE type='table' AND name='songs' OR name LIKE '%songs'").arg(key), db);
|
||||
if (q.exec()) {
|
||||
while(q.next()) {
|
||||
while (q.next()) {
|
||||
QString tab_name = key + "." + q.value(0).toString();
|
||||
ret << tab_name;
|
||||
}
|
||||
@ -575,7 +572,6 @@ bool Database::CheckErrors(const QSqlQuery& query) {
|
||||
qLog(Error) << "faulty query: " << query.lastQuery();
|
||||
qLog(Error) << "bound values: " << query.boundValues();
|
||||
|
||||
app_->AddError("LibraryBackend: " + last_error.text());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ const int Organise::kTranscodeProgressInterval = 500;
|
||||
Organise::Organise(TaskManager* task_manager,
|
||||
boost::shared_ptr<MusicStorage> destination,
|
||||
const OrganiseFormat &format, bool copy, bool overwrite,
|
||||
const QStringList& files, bool eject_after)
|
||||
const SongList& songs, bool eject_after)
|
||||
: thread_(NULL),
|
||||
task_manager_(task_manager),
|
||||
transcoder_(new Transcoder(this)),
|
||||
@ -44,7 +44,7 @@ Organise::Organise(TaskManager* task_manager,
|
||||
copy_(copy),
|
||||
overwrite_(overwrite),
|
||||
eject_after_(eject_after),
|
||||
task_count_(files.count()),
|
||||
task_count_(songs.count()),
|
||||
transcode_suffix_(1),
|
||||
tasks_complete_(0),
|
||||
started_(false),
|
||||
@ -53,8 +53,8 @@ Organise::Organise(TaskManager* task_manager,
|
||||
{
|
||||
original_thread_ = thread();
|
||||
|
||||
foreach (const QString& filename, files) {
|
||||
tasks_pending_ << Task(filename);
|
||||
for (const Song& song : songs) {
|
||||
tasks_pending_ << Task(song);
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ void Organise::Start() {
|
||||
|
||||
thread_ = new QThread;
|
||||
connect(thread_, SIGNAL(started()), SLOT(ProcessSomeFiles()));
|
||||
connect(transcoder_, SIGNAL(JobComplete(QString,bool)), SLOT(FileTranscoded(QString,bool)));
|
||||
connect(transcoder_, SIGNAL(JobComplete(QString, bool)), SLOT(FileTranscoded(QString, bool)));
|
||||
|
||||
moveToThread(thread_);
|
||||
thread_->start();
|
||||
@ -79,8 +79,8 @@ void Organise::ProcessSomeFiles() {
|
||||
|
||||
if (!destination_->StartCopy(&supported_filetypes_)) {
|
||||
// Failed to start - mark everything as failed :(
|
||||
foreach (const Task& task, tasks_pending_)
|
||||
files_with_errors_ << task.filename_;
|
||||
for (const Task& task : tasks_pending_)
|
||||
files_with_errors_ << task.song_.url().toLocalFile();
|
||||
tasks_pending_.clear();
|
||||
}
|
||||
started_ = true;
|
||||
@ -116,29 +116,17 @@ void Organise::ProcessSomeFiles() {
|
||||
}
|
||||
|
||||
// We process files in batches so we can be cancelled part-way through.
|
||||
for (int i=0 ; i<kBatchSize ; ++i) {
|
||||
for (int i = 0; i < kBatchSize; ++i) {
|
||||
SetSongProgress(0);
|
||||
|
||||
if (tasks_pending_.isEmpty())
|
||||
break;
|
||||
|
||||
Task task = tasks_pending_.takeFirst();
|
||||
qLog(Info) << "Processing" << task.filename_;
|
||||
qLog(Info) << "Processing" << task.song_.url().toLocalFile();
|
||||
|
||||
// Is it a directory?
|
||||
if (QFileInfo(task.filename_).isDir()) {
|
||||
QDir dir(task.filename_);
|
||||
foreach (const QString& entry, dir.entryList(
|
||||
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Readable)) {
|
||||
tasks_pending_ << Task(task.filename_ + "/" + entry);
|
||||
task_count_ ++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read metadata from the file
|
||||
Song song;
|
||||
TagReaderClient::Instance()->ReadFileBlocking(task.filename_, &song);
|
||||
// Use a Song instead of a tag reader
|
||||
Song song = task.song_;
|
||||
if (!song.is_valid())
|
||||
continue;
|
||||
|
||||
@ -150,7 +138,7 @@ void Organise::ProcessSomeFiles() {
|
||||
song.set_filetype(task.new_filetype_);
|
||||
|
||||
// Fiddle the filename extension as well to match the new type
|
||||
song.set_url(QUrl::fromLocalFile(FiddleFileExtension(song.url().toLocalFile(), task.new_extension_)));
|
||||
song.set_url(QUrl::fromLocalFile(FiddleFileExtension(song.basefilename(), task.new_extension_)));
|
||||
song.set_basefilename(FiddleFileExtension(song.basefilename(), task.new_extension_));
|
||||
|
||||
// Have to set this to the size of the new file or else funny stuff happens
|
||||
@ -168,14 +156,14 @@ void Organise::ProcessSomeFiles() {
|
||||
QString::number(transcode_suffix_++);
|
||||
task.new_extension_ = preset.extension_;
|
||||
task.new_filetype_ = dest_type;
|
||||
tasks_transcoding_[task.filename_] = task;
|
||||
tasks_transcoding_[task.song_.url().toLocalFile()] = task;
|
||||
|
||||
qLog(Debug) << "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_->AddJob(task.song_.url().toLocalFile(), preset, task.transcoded_filename_);
|
||||
transcoder_->Start();
|
||||
continue;
|
||||
}
|
||||
@ -183,7 +171,7 @@ void Organise::ProcessSomeFiles() {
|
||||
|
||||
MusicStorage::CopyJob job;
|
||||
job.source_ = task.transcoded_filename_.isEmpty() ?
|
||||
task.filename_ : task.transcoded_filename_;
|
||||
task.song_.url().toLocalFile() : task.transcoded_filename_;
|
||||
job.destination_ = format_.GetFilenameForSong(song);
|
||||
job.metadata_ = song;
|
||||
job.overwrite_ = overwrite_;
|
||||
@ -192,7 +180,7 @@ void Organise::ProcessSomeFiles() {
|
||||
this, _1, !task.transcoded_filename_.isEmpty());
|
||||
|
||||
if (!destination_->CopyToStorage(job)) {
|
||||
files_with_errors_ << task.filename_;
|
||||
files_with_errors_ << task.song_.basefilename();
|
||||
}
|
||||
|
||||
// Clean up the temporary transcoded file
|
||||
@ -240,7 +228,7 @@ Song::FileType Organise::CheckTranscode(Song::FileType original_type) const {
|
||||
void Organise::SetSongProgress(float progress, bool transcoded) {
|
||||
const int max = transcoded ? 50 : 100;
|
||||
current_copy_progress_ = (transcoded ? 50 : 0) +
|
||||
qBound(0, int(progress * max), max-1);
|
||||
qBound(0, static_cast<int>(progress * max), max-1);
|
||||
UpdateProgress();
|
||||
}
|
||||
|
||||
@ -249,7 +237,7 @@ void Organise::UpdateProgress() {
|
||||
|
||||
// Update transcoding progress
|
||||
QMap<QString, float> transcode_progress = transcoder_->GetProgress();
|
||||
foreach (const QString& filename, transcode_progress.keys()) {
|
||||
for (const QString& filename : transcode_progress.keys()) {
|
||||
if (!tasks_transcoding_.contains(filename))
|
||||
continue;
|
||||
tasks_transcoding_[filename].transcode_progress_ = transcode_progress[filename];
|
||||
@ -260,11 +248,11 @@ void Organise::UpdateProgress() {
|
||||
// only need to be copied total 100.
|
||||
int progress = tasks_complete_ * 100;
|
||||
|
||||
foreach (const Task& task, tasks_pending_) {
|
||||
progress += qBound(0, int(task.transcode_progress_ * 50), 50);
|
||||
for (const Task& task : tasks_pending_) {
|
||||
progress += qBound(0, static_cast<int>(task.transcode_progress_ * 50), 50);
|
||||
}
|
||||
foreach (const Task& task, tasks_transcoding_.values()) {
|
||||
progress += qBound(0, int(task.transcode_progress_ * 50), 50);
|
||||
for (const Task& task : tasks_transcoding_.values()) {
|
||||
progress += qBound(0, static_cast<int>(task.transcode_progress_ * 50), 50);
|
||||
}
|
||||
|
||||
// Add the progress of the track that's currently copying
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
Organise(TaskManager* task_manager,
|
||||
boost::shared_ptr<MusicStorage> destination,
|
||||
const OrganiseFormat& format, bool copy, bool overwrite,
|
||||
const QStringList& files, bool eject_after);
|
||||
const SongList& songs, bool eject_after);
|
||||
|
||||
static const int kBatchSize;
|
||||
static const int kTranscodeProgressInterval;
|
||||
@ -63,10 +63,10 @@ private:
|
||||
|
||||
private:
|
||||
struct Task {
|
||||
explicit Task(const QString& filename = QString())
|
||||
: filename_(filename), transcode_progress_(0.0) {}
|
||||
explicit Task(const Song& song = Song())
|
||||
: song_(song), transcode_progress_(0.0) {}
|
||||
|
||||
QString filename_;
|
||||
Song song_;
|
||||
|
||||
float transcode_progress_;
|
||||
QString transcoded_filename_;
|
||||
|
@ -62,7 +62,7 @@ void PodcastBackend::Subscribe(Podcast* podcast) {
|
||||
|
||||
// Update the IDs of any episodes.
|
||||
PodcastEpisodeList* episodes = podcast->mutable_episodes();
|
||||
for (PodcastEpisodeList::iterator it = episodes->begin() ; it != episodes->end() ; ++it) {
|
||||
for (auto it = episodes->begin() ; it != episodes->end() ; ++it) {
|
||||
it->set_podcast_database_id(database_id);
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ void PodcastBackend::AddEpisodes(PodcastEpisodeList* episodes, QSqlDatabase* db)
|
||||
QSqlQuery q("INSERT INTO podcast_episodes (" + PodcastEpisode::kColumnSpec + ")"
|
||||
" VALUES (" + PodcastEpisode::kBindSpec + ")", *db);
|
||||
|
||||
for (PodcastEpisodeList::iterator it = episodes->begin() ; it != episodes->end() ; ++it) {
|
||||
for (auto it = episodes->begin() ; it != episodes->end() ; ++it) {
|
||||
it->BindToQuery(&q);
|
||||
q.exec();
|
||||
if (db_->CheckErrors(q))
|
||||
@ -141,7 +141,7 @@ void PodcastBackend::UpdateEpisodes(const PodcastEpisodeList& episodes) {
|
||||
" local_url = :local_url"
|
||||
" WHERE ROWID = :id", db);
|
||||
|
||||
foreach (const PodcastEpisode& episode, episodes) {
|
||||
for (const PodcastEpisode& episode : episodes) {
|
||||
q.bindValue(":listened", episode.listened());
|
||||
q.bindValue(":listened_date", episode.listened_date().toTime_t());
|
||||
q.bindValue(":downloaded", episode.downloaded());
|
||||
@ -313,3 +313,26 @@ PodcastEpisodeList PodcastBackend::GetOldDownloadedEpisodes(const QDateTime& max
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PodcastEpisodeList PodcastBackend::GetNewDownloadedEpisodes() {
|
||||
PodcastEpisodeList ret;
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
QSqlQuery q("SELECT ROWID, " + PodcastEpisode::kColumnSpec +
|
||||
" FROM podcast_episodes"
|
||||
" WHERE downloaded = 'true'"
|
||||
" AND listened = 'false'", db);
|
||||
q.exec();
|
||||
if (db_->CheckErrors(q))
|
||||
return ret;
|
||||
|
||||
while (q.next()) {
|
||||
PodcastEpisode episode;
|
||||
episode.InitFromQuery(q);
|
||||
ret << episode;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ public:
|
||||
// last listened to before the given QDateTime. This query is NOT indexed so
|
||||
// it involves a full search of the table.
|
||||
PodcastEpisodeList GetOldDownloadedEpisodes(const QDateTime& max_listened_date);
|
||||
PodcastEpisodeList GetNewDownloadedEpisodes();
|
||||
|
||||
// Adds episodes to the database. Every episode must have a valid
|
||||
// podcast_database_id set already.
|
||||
@ -73,10 +74,10 @@ signals:
|
||||
void SubscriptionRemoved(const Podcast& podcast);
|
||||
|
||||
// Emitted when episodes are added to a subscription that *already exists*.
|
||||
void EpisodesAdded(const QList<PodcastEpisode>& episodes);
|
||||
void EpisodesAdded(const PodcastEpisodeList& episodes);
|
||||
|
||||
// Emitted when existing episodes are updated.
|
||||
void EpisodesUpdated(const QList<PodcastEpisode>& episodes);
|
||||
void EpisodesUpdated(const PodcastEpisodeList& episodes);
|
||||
|
||||
private:
|
||||
// Adds each episode to the database, setting their IDs after inserting each
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "core/application.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/network.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "core/utilities.h"
|
||||
#include "library/librarydirectorymodel.h"
|
||||
@ -55,8 +56,8 @@ PodcastDownloader::PodcastDownloader(Application* app, QObject* parent)
|
||||
last_progress_signal_(0),
|
||||
auto_delete_timer_(new QTimer(this))
|
||||
{
|
||||
connect(backend_, SIGNAL(EpisodesAdded(QList<PodcastEpisode>)),
|
||||
SLOT(EpisodesAdded(QList<PodcastEpisode>)));
|
||||
connect(backend_, SIGNAL(EpisodesAdded(PodcastEpisodeList)),
|
||||
SLOT(EpisodesAdded(PodcastEpisodeList)));
|
||||
connect(backend_, SIGNAL(SubscriptionAdded(Podcast)),
|
||||
SLOT(SubscriptionAdded(Podcast)));
|
||||
connect(app_, SIGNAL(SettingsChanged()), SLOT(ReloadSettings()));
|
||||
@ -125,9 +126,15 @@ void PodcastDownloader::DeleteEpisode(const PodcastEpisode& episode) {
|
||||
}
|
||||
|
||||
void PodcastDownloader::FinishAndDelete(Task* task) {
|
||||
Podcast podcast =
|
||||
backend_->GetSubscriptionById(task->episode.podcast_database_id());
|
||||
Song song = task->episode.ToSong(podcast);
|
||||
|
||||
downloading_episode_ids_.remove(task->episode.database_id());
|
||||
emit ProgressChanged(task->episode, Finished, 0);
|
||||
|
||||
// I didn't ecountered even a single podcast with a corect metadata
|
||||
TagReaderClient::Instance()->SaveFileBlocking(task->file->fileName(), song);
|
||||
delete task;
|
||||
|
||||
NextTask();
|
||||
@ -137,17 +144,17 @@ QString PodcastDownloader::FilenameForEpisode(const QString& directory,
|
||||
const PodcastEpisode& episode) const {
|
||||
const QString file_extension = QFileInfo(episode.url().path()).suffix();
|
||||
int count = 0;
|
||||
|
||||
|
||||
// The file name contains the publication date and episode title
|
||||
QString base_filename =
|
||||
episode.publication_date().date().toString(Qt::ISODate) + "-" +
|
||||
SanitiseFilenameComponent(episode.title());
|
||||
|
||||
|
||||
// Add numbers on to the end of the filename until we find one that doesn't
|
||||
// exist.
|
||||
forever {
|
||||
QString filename;
|
||||
|
||||
|
||||
if (count == 0) {
|
||||
filename = QString("%1/%2.%3").arg(
|
||||
directory, base_filename, file_extension);
|
||||
@ -155,12 +162,12 @@ QString PodcastDownloader::FilenameForEpisode(const QString& directory,
|
||||
filename = QString("%1/%2 (%3).%4").arg(
|
||||
directory, base_filename, QString::number(count), file_extension);
|
||||
}
|
||||
|
||||
|
||||
if (!QFile::exists(filename)) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
count ++;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,8 +204,8 @@ void PodcastDownloader::StartDownloading(Task* task) {
|
||||
RedirectFollower* reply = new RedirectFollower(network_->get(req));
|
||||
connect(reply, SIGNAL(readyRead()), SLOT(ReplyReadyRead()));
|
||||
connect(reply, SIGNAL(finished()), SLOT(ReplyFinished()));
|
||||
connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
|
||||
SLOT(ReplyDownloadProgress(qint64,qint64)));
|
||||
connect(reply, SIGNAL(downloadProgress(qint64, qint64)),
|
||||
SLOT(ReplyDownloadProgress(qint64, qint64)));
|
||||
|
||||
emit ProgressChanged(task->episode, Downloading, 0);
|
||||
}
|
||||
@ -235,7 +242,7 @@ void PodcastDownloader::ReplyDownloadProgress(qint64 received, qint64 total) {
|
||||
last_progress_signal_ = current_time;
|
||||
|
||||
emit ProgressChanged(current_task_->episode, Downloading,
|
||||
float(received) / total * 100);
|
||||
static_cast<float>(received) / total * 100);
|
||||
}
|
||||
|
||||
void PodcastDownloader::ReplyFinished() {
|
||||
@ -275,9 +282,9 @@ void PodcastDownloader::SubscriptionAdded(const Podcast& podcast) {
|
||||
EpisodesAdded(podcast.episodes());
|
||||
}
|
||||
|
||||
void PodcastDownloader::EpisodesAdded(const QList<PodcastEpisode>& episodes) {
|
||||
void PodcastDownloader::EpisodesAdded(const PodcastEpisodeList& episodes) {
|
||||
if (auto_download_) {
|
||||
foreach (const PodcastEpisode& episode, episodes) {
|
||||
for (const PodcastEpisode& episode : episodes) {
|
||||
DownloadEpisode(episode);
|
||||
}
|
||||
}
|
||||
@ -300,7 +307,7 @@ void PodcastDownloader::AutoDelete() {
|
||||
<< (delete_after_secs_ / kSecsPerDay)
|
||||
<< "days ago";
|
||||
|
||||
foreach (const PodcastEpisode& episode, old_episodes) {
|
||||
for (const PodcastEpisode& episode : old_episodes) {
|
||||
DeleteEpisode(episode);
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +174,9 @@ Song PodcastEpisode::ToSong(const Podcast& podcast) const {
|
||||
if (podcast.is_valid()) {
|
||||
ret.set_album(podcast.title().simplified());
|
||||
ret.set_art_automatic(podcast.ImageUrlLarge().toString());
|
||||
}
|
||||
|
||||
if (author().isNull() || author().isEmpty())
|
||||
ret.set_artist(podcast.title().simplified());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -25,9 +25,14 @@
|
||||
#include "core/application.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/mergedproxymodel.h"
|
||||
#include "devices/devicemanager.h"
|
||||
#include "devices/devicestatefiltermodel.h"
|
||||
#include "devices/deviceview.h"
|
||||
#include "internet/internetmodel.h"
|
||||
#include "library/libraryview.h"
|
||||
#include "ui/iconloader.h"
|
||||
#include "ui/organisedialog.h"
|
||||
#include "ui/organiseerrordialog.h"
|
||||
#include "ui/standarditemiconloader.h"
|
||||
|
||||
#include <QMenu>
|
||||
@ -54,7 +59,8 @@ PodcastService::PodcastService(Application* app, InternetModel* parent)
|
||||
model_(new PodcastServiceModel(this)),
|
||||
proxy_(new PodcastSortProxyModel(this)),
|
||||
context_menu_(NULL),
|
||||
root_(NULL)
|
||||
root_(NULL),
|
||||
organise_dialog_(new OrganiseDialog(app_->task_manager()))
|
||||
{
|
||||
icon_loader_->SetModel(model_);
|
||||
proxy_->setSourceModel(model_);
|
||||
@ -63,8 +69,8 @@ PodcastService::PodcastService(Application* app, InternetModel* parent)
|
||||
|
||||
connect(backend_, SIGNAL(SubscriptionAdded(Podcast)), SLOT(SubscriptionAdded(Podcast)));
|
||||
connect(backend_, SIGNAL(SubscriptionRemoved(Podcast)), SLOT(SubscriptionRemoved(Podcast)));
|
||||
connect(backend_, SIGNAL(EpisodesAdded(QList<PodcastEpisode>)), SLOT(EpisodesAdded(QList<PodcastEpisode>)));
|
||||
connect(backend_, SIGNAL(EpisodesUpdated(QList<PodcastEpisode>)), SLOT(EpisodesUpdated(QList<PodcastEpisode>)));
|
||||
connect(backend_, SIGNAL(EpisodesAdded(PodcastEpisodeList)), SLOT(EpisodesAdded(PodcastEpisodeList)));
|
||||
connect(backend_, SIGNAL(EpisodesUpdated(PodcastEpisodeList)), SLOT(EpisodesUpdated(PodcastEpisodeList)));
|
||||
|
||||
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)), SLOT(CurrentSongChanged(Song)));
|
||||
}
|
||||
@ -112,6 +118,59 @@ QStandardItem* PodcastService::CreateRootItem() {
|
||||
return root_;
|
||||
}
|
||||
|
||||
void PodcastService::CopyToDevice() {
|
||||
if (selected_episodes_.isEmpty() && explicitly_selected_podcasts_.isEmpty()) {
|
||||
CopyToDevice(backend_->GetNewDownloadedEpisodes());
|
||||
} else {
|
||||
CopyToDevice(selected_episodes_, explicitly_selected_podcasts_);
|
||||
}
|
||||
}
|
||||
|
||||
void PodcastService::CopyToDevice(const PodcastEpisodeList& episodes_list) {
|
||||
SongList songs;
|
||||
Podcast podcast;
|
||||
for (const PodcastEpisode& episode : episodes_list) {
|
||||
podcast = backend_->GetSubscriptionById(episode.podcast_database_id());
|
||||
songs.append(episode.ToSong(podcast));
|
||||
}
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organise_dialog_->SetCopy(true);
|
||||
if (organise_dialog_->SetSongs(songs))
|
||||
organise_dialog_->show();
|
||||
}
|
||||
|
||||
void PodcastService::CopyToDevice(const QModelIndexList& episode_indexes,
|
||||
const QModelIndexList& podcast_indexes) {
|
||||
PodcastEpisode episode_tmp;
|
||||
SongList songs;
|
||||
PodcastEpisodeList episodes;
|
||||
Podcast podcast;
|
||||
for (const QModelIndex& index : episode_indexes) {
|
||||
episode_tmp = index.data(Role_Episode).value<PodcastEpisode>();
|
||||
if (episode_tmp.downloaded())
|
||||
episodes << episode_tmp;
|
||||
}
|
||||
|
||||
for (const QModelIndex& podcast : podcast_indexes) {
|
||||
for (int i = 0; i < podcast.model()->rowCount(podcast); ++i) {
|
||||
const QModelIndex& index = podcast.child(i, 0);
|
||||
episode_tmp = index.data(Role_Episode).value<PodcastEpisode>();
|
||||
if (episode_tmp.downloaded() && !episode_tmp.listened())
|
||||
episodes << episode_tmp;
|
||||
}
|
||||
}
|
||||
for (const PodcastEpisode& episode : episodes) {
|
||||
podcast = backend_->GetSubscriptionById(episode.podcast_database_id());
|
||||
songs.append(episode.ToSong(podcast));
|
||||
}
|
||||
|
||||
organise_dialog_->SetDestinationModel(app_->device_manager()->connected_devices_model(), true);
|
||||
organise_dialog_->SetCopy(true);
|
||||
if (organise_dialog_->SetSongs(songs))
|
||||
organise_dialog_->show();
|
||||
}
|
||||
|
||||
void PodcastService::LazyPopulate(QStandardItem* parent) {
|
||||
switch (parent->data(InternetModel::Role_Type).toInt()) {
|
||||
case InternetModel::Type_Service:
|
||||
@ -124,14 +183,14 @@ void PodcastService::LazyPopulate(QStandardItem* parent) {
|
||||
void PodcastService::PopulatePodcastList(QStandardItem* parent) {
|
||||
// Do this here since the downloader won't be created yet in the ctor.
|
||||
connect(app_->podcast_downloader(),
|
||||
SIGNAL(ProgressChanged(PodcastEpisode,PodcastDownloader::State,int)),
|
||||
SLOT(DownloadProgressChanged(PodcastEpisode,PodcastDownloader::State,int)));
|
||||
SIGNAL(ProgressChanged(PodcastEpisode, PodcastDownloader::State, int)),
|
||||
SLOT(DownloadProgressChanged(PodcastEpisode, PodcastDownloader::State, int)));
|
||||
|
||||
if (default_icon_.isNull()) {
|
||||
default_icon_ = QIcon(":providers/podcast16.png");
|
||||
}
|
||||
|
||||
foreach (const Podcast& podcast, backend_->GetAllSubscriptions()) {
|
||||
for (const Podcast& podcast : backend_->GetAllSubscriptions()) {
|
||||
parent->appendRow(CreatePodcastItem(podcast));
|
||||
}
|
||||
}
|
||||
@ -211,9 +270,9 @@ QStandardItem* PodcastService::CreatePodcastItem(const Podcast& podcast) {
|
||||
|
||||
// Add the episodes in this podcast and gather aggregate stats.
|
||||
int unlistened_count = 0;
|
||||
foreach (const PodcastEpisode& episode, backend_->GetEpisodes(podcast.database_id())) {
|
||||
for (const PodcastEpisode& episode : backend_->GetEpisodes(podcast.database_id())) {
|
||||
if (!episode.listened()) {
|
||||
unlistened_count ++;
|
||||
unlistened_count++;
|
||||
}
|
||||
|
||||
item->appendRow(CreatePodcastEpisodeItem(episode));
|
||||
@ -259,7 +318,7 @@ void PodcastService::ShowContextMenu(const QPoint& global_pos) {
|
||||
context_menu_->addAction(
|
||||
IconLoader::Load("view-refresh"), tr("Update all podcasts"),
|
||||
app_->podcast_updater(), SLOT(UpdateAllPodcastsNow()));
|
||||
|
||||
|
||||
context_menu_->addSeparator();
|
||||
context_menu_->addActions(GetPlaylistActions());
|
||||
|
||||
@ -273,6 +332,9 @@ void PodcastService::ShowContextMenu(const QPoint& global_pos) {
|
||||
delete_downloaded_action_ = context_menu_->addAction(
|
||||
IconLoader::Load("edit-delete"), tr("Delete downloaded data"),
|
||||
this, SLOT(DeleteDownloadedData()));
|
||||
copy_to_device_ = context_menu_->addAction(
|
||||
IconLoader::Load("multimedia-player-ipod-mini-blue"), tr("Copy to device..."),
|
||||
this, SLOT(CopyToDevice()));
|
||||
remove_selected_action_ = context_menu_->addAction(
|
||||
IconLoader::Load("list-remove"), tr("Unsubscribe"),
|
||||
this, SLOT(RemoveSelectedPodcast()));
|
||||
@ -287,6 +349,10 @@ void PodcastService::ShowContextMenu(const QPoint& global_pos) {
|
||||
context_menu_->addAction(
|
||||
IconLoader::Load("configure"), tr("Configure podcasts..."),
|
||||
this, SLOT(ShowConfig()));
|
||||
|
||||
copy_to_device_->setDisabled(app_->device_manager()->connected_devices_model()->rowCount() == 0);
|
||||
connect(app_->device_manager()->connected_devices_model(), SIGNAL(IsEmptyChanged(bool)),
|
||||
copy_to_device_, SLOT(setDisabled(bool)));
|
||||
}
|
||||
|
||||
selected_episodes_.clear();
|
||||
@ -294,7 +360,7 @@ void PodcastService::ShowContextMenu(const QPoint& global_pos) {
|
||||
explicitly_selected_podcasts_.clear();
|
||||
QSet<int> podcast_ids;
|
||||
|
||||
foreach (const QModelIndex& index, model()->selected_indexes()) {
|
||||
for (const QModelIndex& index : model()->selected_indexes()) {
|
||||
switch (index.data(InternetModel::Role_Type).toInt()) {
|
||||
case Type_Podcast: {
|
||||
const int id = index.data(Role_Podcast).value<Podcast>().database_id();
|
||||
@ -346,12 +412,17 @@ void PodcastService::ShowContextMenu(const QPoint& global_pos) {
|
||||
delete_downloaded_action_->setEnabled(episodes);
|
||||
}
|
||||
|
||||
if (explicitly_selected_podcasts_.isEmpty() && selected_episodes_.isEmpty()) {
|
||||
PodcastEpisodeList epis = backend_->GetNewDownloadedEpisodes();
|
||||
set_listened_action_->setEnabled(!epis.isEmpty());
|
||||
}
|
||||
|
||||
if (selected_episodes_.count() > 1) {
|
||||
download_selected_action_->setText(tr("Download %n episodes", "", selected_episodes_.count()));
|
||||
} else {
|
||||
download_selected_action_->setText(tr("Download this episode"));
|
||||
}
|
||||
|
||||
|
||||
GetAppendToPlaylistAction()->setEnabled(episodes || podcasts);
|
||||
GetReplacePlaylistAction()->setEnabled(episodes || podcasts);
|
||||
GetOpenInNewPlaylistAction()->setEnabled(episodes || podcasts);
|
||||
@ -360,14 +431,14 @@ void PodcastService::ShowContextMenu(const QPoint& global_pos) {
|
||||
}
|
||||
|
||||
void PodcastService::UpdateSelectedPodcast() {
|
||||
foreach (const QModelIndex& index, selected_podcasts_) {
|
||||
for (const QModelIndex& index : selected_podcasts_) {
|
||||
app_->podcast_updater()->UpdatePodcastNow(
|
||||
index.data(Role_Podcast).value<Podcast>());
|
||||
}
|
||||
}
|
||||
|
||||
void PodcastService::RemoveSelectedPodcast() {
|
||||
foreach (const QModelIndex& index, selected_podcasts_) {
|
||||
for (const QModelIndex& index : selected_podcasts_) {
|
||||
backend_->Unsubscribe(index.data(Role_Podcast).value<Podcast>());
|
||||
}
|
||||
}
|
||||
@ -394,7 +465,7 @@ void PodcastService::AddPodcast() {
|
||||
void PodcastService::SubscriptionAdded(const Podcast& podcast) {
|
||||
// Ensure the root item is lazy loaded already
|
||||
LazyLoadRoot();
|
||||
|
||||
|
||||
// The podcast might already be in the list - maybe the LazyLoadRoot() above
|
||||
// added it.
|
||||
QStandardItem* item = podcasts_by_database_id_[podcast.database_id()];
|
||||
@ -410,7 +481,7 @@ void PodcastService::SubscriptionRemoved(const Podcast& podcast) {
|
||||
QStandardItem* item = podcasts_by_database_id_.take(podcast.database_id());
|
||||
if (item) {
|
||||
// Remove any episode ID -> item mappings for the episodes in this podcast.
|
||||
for (int i=0 ; i<item->rowCount() ; ++i) {
|
||||
for (int i = 0; i < item->rowCount(); ++i) {
|
||||
QStandardItem* episode_item = item->child(i);
|
||||
const int episode_id =
|
||||
episode_item->data(Role_Episode).value<PodcastEpisode>().database_id();
|
||||
@ -423,10 +494,10 @@ void PodcastService::SubscriptionRemoved(const Podcast& podcast) {
|
||||
}
|
||||
}
|
||||
|
||||
void PodcastService::EpisodesAdded(const QList<PodcastEpisode>& episodes) {
|
||||
void PodcastService::EpisodesAdded(const PodcastEpisodeList& episodes) {
|
||||
QSet<int> seen_podcast_ids;
|
||||
|
||||
foreach (const PodcastEpisode& episode, episodes) {
|
||||
for (const PodcastEpisode& episode : episodes) {
|
||||
const int database_id = episode.podcast_database_id();
|
||||
QStandardItem* parent = podcasts_by_database_id_[database_id];
|
||||
if (!parent)
|
||||
@ -437,9 +508,9 @@ void PodcastService::EpisodesAdded(const QList<PodcastEpisode>& episodes) {
|
||||
if (!seen_podcast_ids.contains(database_id)) {
|
||||
// Update the unlistened count text once for each podcast
|
||||
int unlistened_count = 0;
|
||||
foreach (const PodcastEpisode& episode, backend_->GetEpisodes(database_id)) {
|
||||
for (const PodcastEpisode& episode : backend_->GetEpisodes(database_id)) {
|
||||
if (!episode.listened()) {
|
||||
unlistened_count ++;
|
||||
unlistened_count++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,10 +520,10 @@ void PodcastService::EpisodesAdded(const QList<PodcastEpisode>& episodes) {
|
||||
}
|
||||
}
|
||||
|
||||
void PodcastService::EpisodesUpdated(const QList<PodcastEpisode>& episodes) {
|
||||
void PodcastService::EpisodesUpdated(const PodcastEpisodeList& episodes) {
|
||||
QSet<int> seen_podcast_ids;
|
||||
|
||||
foreach (const PodcastEpisode& episode, episodes) {
|
||||
for (const PodcastEpisode& episode : episodes) {
|
||||
const int podcast_database_id = episode.podcast_database_id();
|
||||
QStandardItem* item = episodes_by_database_id_[episode.database_id()];
|
||||
QStandardItem* parent = podcasts_by_database_id_[podcast_database_id];
|
||||
@ -467,9 +538,9 @@ void PodcastService::EpisodesUpdated(const QList<PodcastEpisode>& episodes) {
|
||||
if (!seen_podcast_ids.contains(podcast_database_id)) {
|
||||
// Update the unlistened count text once for each podcast
|
||||
int unlistened_count = 0;
|
||||
foreach (const PodcastEpisode& episode, backend_->GetEpisodes(podcast_database_id)) {
|
||||
for (const PodcastEpisode& episode : backend_->GetEpisodes(podcast_database_id)) {
|
||||
if (!episode.listened()) {
|
||||
unlistened_count ++;
|
||||
unlistened_count++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -480,14 +551,14 @@ void PodcastService::EpisodesUpdated(const QList<PodcastEpisode>& episodes) {
|
||||
}
|
||||
|
||||
void PodcastService::DownloadSelectedEpisode() {
|
||||
foreach (const QModelIndex& index, selected_episodes_) {
|
||||
for (const QModelIndex& index : selected_episodes_) {
|
||||
app_->podcast_downloader()->DownloadEpisode(
|
||||
index.data(Role_Episode).value<PodcastEpisode>());
|
||||
}
|
||||
}
|
||||
|
||||
void PodcastService::DeleteDownloadedData() {
|
||||
foreach (const QModelIndex& index, selected_episodes_) {
|
||||
for (const QModelIndex& index : selected_episodes_) {
|
||||
app_->podcast_downloader()->DeleteEpisode(
|
||||
index.data(Role_Episode).value<PodcastEpisode>());
|
||||
}
|
||||
@ -526,7 +597,25 @@ void PodcastService::SetNew() {
|
||||
}
|
||||
|
||||
void PodcastService::SetListened() {
|
||||
SetListened(selected_episodes_, explicitly_selected_podcasts_, true);
|
||||
if (selected_episodes_.isEmpty() && explicitly_selected_podcasts_.isEmpty())
|
||||
SetListened(backend_->GetNewDownloadedEpisodes(), true);
|
||||
else
|
||||
SetListened(selected_episodes_, explicitly_selected_podcasts_, true);
|
||||
}
|
||||
|
||||
void PodcastService::SetListened(const PodcastEpisodeList& episodes_list,
|
||||
bool listened) {
|
||||
PodcastEpisodeList episodes;
|
||||
QDateTime current_date_time = QDateTime::currentDateTime();
|
||||
for (PodcastEpisode episode : episodes_list) {
|
||||
episode.set_listened(listened);
|
||||
if (listened) {
|
||||
episode.set_listened_date(current_date_time);
|
||||
}
|
||||
episodes << episode;
|
||||
}
|
||||
|
||||
backend_->UpdateEpisodes(episodes);
|
||||
}
|
||||
|
||||
void PodcastService::SetListened(const QModelIndexList& episode_indexes,
|
||||
@ -535,12 +624,12 @@ void PodcastService::SetListened(const QModelIndexList& episode_indexes,
|
||||
PodcastEpisodeList episodes;
|
||||
|
||||
// Get all the episodes from the indexes.
|
||||
foreach (const QModelIndex& index, episode_indexes) {
|
||||
for (const QModelIndex& index : episode_indexes) {
|
||||
episodes << index.data(Role_Episode).value<PodcastEpisode>();
|
||||
}
|
||||
|
||||
foreach (const QModelIndex& podcast, podcast_indexes) {
|
||||
for (int i=0 ; i<podcast.model()->rowCount(podcast) ; ++i) {
|
||||
for (const QModelIndex& podcast : podcast_indexes) {
|
||||
for (int i = 0; i < podcast.model()->rowCount(podcast); ++i) {
|
||||
const QModelIndex& index = podcast.child(i, 0);
|
||||
episodes << index.data(Role_Episode).value<PodcastEpisode>();
|
||||
}
|
||||
@ -548,7 +637,7 @@ void PodcastService::SetListened(const QModelIndexList& episode_indexes,
|
||||
|
||||
// Update each one with the new state and maybe the listened time.
|
||||
QDateTime current_date_time = QDateTime::currentDateTime();
|
||||
for (int i=0 ; i<episodes.count() ; ++i) {
|
||||
for (int i = 0; i < episodes.count(); ++i) {
|
||||
PodcastEpisode* episode = &episodes[i];
|
||||
episode->set_listened(listened);
|
||||
if (listened) {
|
||||
|
@ -22,9 +22,11 @@
|
||||
#include "internet/internetmodel.h"
|
||||
#include "internet/internetservice.h"
|
||||
|
||||
#include <memory>
|
||||
#include <QScopedPointer>
|
||||
|
||||
class AddPodcastDialog;
|
||||
class OrganiseDialog;
|
||||
class Podcast;
|
||||
class PodcastBackend;
|
||||
class PodcastEpisode;
|
||||
@ -78,8 +80,8 @@ private slots:
|
||||
|
||||
void SubscriptionAdded(const Podcast& podcast);
|
||||
void SubscriptionRemoved(const Podcast& podcast);
|
||||
void EpisodesAdded(const QList<PodcastEpisode>& episodes);
|
||||
void EpisodesUpdated(const QList<PodcastEpisode>& episodes);
|
||||
void EpisodesAdded(const PodcastEpisodeList& episodes);
|
||||
void EpisodesUpdated(const PodcastEpisodeList& episodes);
|
||||
|
||||
void DownloadProgressChanged(const PodcastEpisode& episode,
|
||||
PodcastDownloader::State state,
|
||||
@ -87,6 +89,11 @@ private slots:
|
||||
|
||||
void CurrentSongChanged(const Song& metadata);
|
||||
|
||||
void CopyToDevice();
|
||||
void CopyToDevice(const PodcastEpisodeList& episodes_list);
|
||||
void CopyToDevice(const QModelIndexList& episode_indexes,
|
||||
const QModelIndexList& podcast_indexes);
|
||||
|
||||
private:
|
||||
void EnsureAddPodcastDialogCreated();
|
||||
|
||||
@ -104,7 +111,9 @@ private:
|
||||
void SetListened(const QModelIndexList& episode_indexes,
|
||||
const QModelIndexList& podcast_indexes,
|
||||
bool listened);
|
||||
|
||||
void SetListened(const PodcastEpisodeList& episodes_list,
|
||||
bool listened);
|
||||
|
||||
void LazyLoadRoot();
|
||||
|
||||
private:
|
||||
@ -130,7 +139,9 @@ private:
|
||||
QAction* delete_downloaded_action_;
|
||||
QAction* set_new_action_;
|
||||
QAction* set_listened_action_;
|
||||
QAction* copy_to_device_;
|
||||
QStandardItem* root_;
|
||||
std::unique_ptr<OrganiseDialog> organise_dialog_;
|
||||
|
||||
QModelIndexList explicitly_selected_podcasts_;
|
||||
QModelIndexList selected_podcasts_;
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include <QSignalMapper>
|
||||
#include <QtDebug>
|
||||
|
||||
const int OrganiseDialog::kNumberOfPreviews = 10;
|
||||
const char* OrganiseDialog::kDefaultFormat =
|
||||
"%artist/%album{ (Disc %disc)}/{%track - }%title.%extension";
|
||||
const char* OrganiseDialog::kSettingsGroup = "OrganiseDialog";
|
||||
@ -86,7 +85,7 @@ OrganiseDialog::OrganiseDialog(TaskManager* task_manager, QWidget *parent)
|
||||
// Build the insert menu
|
||||
QMenu* tag_menu = new QMenu(this);
|
||||
QSignalMapper* tag_mapper = new QSignalMapper(this);
|
||||
foreach (const QString& title, tag_titles) {
|
||||
for (const QString& title : tag_titles) {
|
||||
QAction* action = tag_menu->addAction(title, tag_mapper, SLOT(map()));
|
||||
tag_mapper->setMapping(action, tags[title]);
|
||||
}
|
||||
@ -107,78 +106,52 @@ void OrganiseDialog::SetDestinationModel(QAbstractItemModel *model, bool devices
|
||||
|
||||
int OrganiseDialog::SetSongs(const SongList& songs) {
|
||||
total_size_ = 0;
|
||||
filenames_.clear();
|
||||
preview_songs_.clear();
|
||||
songs_.clear();
|
||||
|
||||
foreach (const Song& song, songs) {
|
||||
for (const Song& song : songs) {
|
||||
if (song.url().scheme() != "file") {
|
||||
continue;
|
||||
};
|
||||
}
|
||||
|
||||
if (song.filesize() > 0)
|
||||
total_size_ += song.filesize();
|
||||
filenames_ << song.url().toLocalFile();
|
||||
|
||||
if (preview_songs_.count() < kNumberOfPreviews)
|
||||
preview_songs_ << song;
|
||||
songs_ << song;
|
||||
}
|
||||
|
||||
ui_->free_space->set_additional_bytes(total_size_);
|
||||
UpdatePreviews();
|
||||
|
||||
return filenames_.count();
|
||||
return songs_.count();
|
||||
}
|
||||
|
||||
int OrganiseDialog::SetUrls(const QList<QUrl> &urls, quint64 total_size) {
|
||||
QStringList filenames;
|
||||
SongList songs;
|
||||
Song song;
|
||||
|
||||
// Only add file:// URLs
|
||||
foreach (const QUrl& url, urls) {
|
||||
for (const QUrl& url : urls) {
|
||||
if (url.scheme() != "file")
|
||||
continue;
|
||||
filenames << url.toLocalFile();
|
||||
TagReaderClient::Instance()->ReadFileBlocking(url.toLocalFile(), &song);
|
||||
if (song.is_valid())
|
||||
songs << song;
|
||||
}
|
||||
|
||||
return SetFilenames(filenames, total_size);
|
||||
return SetSongs(songs);
|
||||
}
|
||||
|
||||
int OrganiseDialog::SetFilenames(const QStringList& filenames, quint64 total_size) {
|
||||
filenames_ = filenames;
|
||||
preview_songs_.clear();
|
||||
SongList songs;
|
||||
Song song;
|
||||
|
||||
// Load some of the songs to show in the preview
|
||||
const int n = qMin(filenames_.count(), kNumberOfPreviews);
|
||||
for (int i=0 ; i<n ; ++i) {
|
||||
LoadPreviewSongs(filenames_[i]);
|
||||
for (const QString& filename : filenames) {
|
||||
TagReaderClient::Instance()->ReadFileBlocking(filename, &song);
|
||||
if (song.is_valid())
|
||||
songs << song;
|
||||
}
|
||||
|
||||
ui_->free_space->set_additional_bytes(total_size);
|
||||
total_size_ = total_size;
|
||||
|
||||
UpdatePreviews();
|
||||
|
||||
return filenames_.count();
|
||||
}
|
||||
|
||||
void OrganiseDialog::LoadPreviewSongs(const QString& filename) {
|
||||
if (preview_songs_.count() >= kNumberOfPreviews)
|
||||
return;
|
||||
|
||||
if (QFileInfo(filename).isDir()) {
|
||||
QDir dir(filename);
|
||||
QStringList entries = dir.entryList(
|
||||
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Readable);
|
||||
foreach (const QString& entry, entries) {
|
||||
LoadPreviewSongs(filename + "/" + entry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Song song;
|
||||
TagReaderClient::Instance()->ReadFileBlocking(filename, &song);
|
||||
|
||||
if (song.is_valid())
|
||||
preview_songs_ << song;
|
||||
return SetSongs(songs);
|
||||
}
|
||||
|
||||
void OrganiseDialog::SetCopy(bool copy) {
|
||||
@ -224,7 +197,7 @@ void OrganiseDialog::UpdatePreviews() {
|
||||
const bool format_valid = !has_local_destination || format_.IsValid();
|
||||
|
||||
// Are we gonna enable the ok button?
|
||||
bool ok = format_valid && !filenames_.isEmpty();
|
||||
bool ok = format_valid && !songs_.isEmpty();
|
||||
if (capacity != 0 && total_size_ > free)
|
||||
ok = false;
|
||||
|
||||
@ -237,7 +210,7 @@ void OrganiseDialog::UpdatePreviews() {
|
||||
ui_->preview_group->setVisible(has_local_destination);
|
||||
ui_->naming_group->setVisible(has_local_destination);
|
||||
if (has_local_destination) {
|
||||
foreach (const Song& song, preview_songs_) {
|
||||
for (const Song& song : songs_) {
|
||||
QString filename = storage->LocalPath() + "/" +
|
||||
format_.GetFilenameForSong(song);
|
||||
ui_->preview->addItem(QDir::toNativeSeparators(filename));
|
||||
@ -305,7 +278,7 @@ void OrganiseDialog::accept() {
|
||||
const bool copy = ui_->aftercopying->currentIndex() == 0;
|
||||
Organise* organise = new Organise(
|
||||
task_manager_, storage, format_, copy, ui_->overwrite->isChecked(),
|
||||
filenames_, ui_->eject_after->isChecked());
|
||||
songs_, ui_->eject_after->isChecked());
|
||||
connect(organise, SIGNAL(Finished(QStringList)), SLOT(OrganiseFinished(QStringList)));
|
||||
organise->Start();
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#ifndef ORGANISEDIALOG_H
|
||||
#define ORGANISEDIALOG_H
|
||||
|
||||
#include <memory>
|
||||
#include <QDialog>
|
||||
#include <QMap>
|
||||
#include <QUrl>
|
||||
@ -25,8 +26,6 @@
|
||||
#include "core/organiseformat.h"
|
||||
#include "core/song.h"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
class LibraryWatcher;
|
||||
class OrganiseErrorDialog;
|
||||
class TaskManager;
|
||||
@ -41,7 +40,6 @@ public:
|
||||
OrganiseDialog(TaskManager* task_manager, QWidget* parent = 0);
|
||||
~OrganiseDialog();
|
||||
|
||||
static const int kNumberOfPreviews;
|
||||
static const char* kDefaultFormat;
|
||||
static const char* kSettingsGroup;
|
||||
|
||||
@ -65,7 +63,6 @@ private slots:
|
||||
void Reset();
|
||||
|
||||
void InsertTag(const QString& tag);
|
||||
void LoadPreviewSongs(const QString& filename);
|
||||
void UpdatePreviews();
|
||||
|
||||
void OrganiseFinished(const QStringList& files_with_errors);
|
||||
@ -76,11 +73,10 @@ private:
|
||||
|
||||
OrganiseFormat format_;
|
||||
|
||||
QStringList filenames_;
|
||||
SongList preview_songs_;
|
||||
SongList songs_;
|
||||
quint64 total_size_;
|
||||
|
||||
boost::scoped_ptr<OrganiseErrorDialog> error_dialog_;
|
||||
std::unique_ptr<OrganiseErrorDialog> error_dialog_;
|
||||
|
||||
bool resized_by_user_;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user