1
0
mirror of https://github.com/clementine-player/Clementine synced 2024-12-18 20:34:39 +01:00

'show duplicates only' view for library where you can see which songs in your library are duplicated and delete unnecessary duplicates (fixes issue #1328)

This commit is contained in:
Paweł Bara 2011-01-30 21:00:49 +00:00
parent 35441d829e
commit 2959dbff85
57 changed files with 241 additions and 17 deletions

View File

@ -297,5 +297,6 @@
<file>schema/schema-25.sql</file>
<file>schema/schema-26.sql</file>
<file>pythonstartup.py</file>
<file>schema/schema-27.sql</file>
</qresource>
</RCC>

12
data/schema/schema-27.sql Normal file
View File

@ -0,0 +1,12 @@
CREATE INDEX idx_title ON songs (title);
CREATE VIEW duplicated_songs as
select artist dup_artist, album dup_album, title dup_title
from songs as inner_songs
where artist != ''
and album != ''
and title != ''
group by artist, album , title
having count(*) > 1;
UPDATE schema_version SET version=27;

View File

@ -31,7 +31,7 @@
#include <QVariant>
const char* Database::kDatabaseFilename = "clementine.db";
const int Database::kSchemaVersion = 26;
const int Database::kSchemaVersion = 27;
const char* Database::kMagicAllSongsTables = "%allsongstables";
int Database::sNextConnectionId = 1;

View File

@ -192,6 +192,14 @@ void LibraryFilterWidget::SetFilterHint(const QString& hint) {
filter_->set_hint(hint);
}
void LibraryFilterWidget::SetDuplicatesOnly(bool duplicates_only) {
// no filtering in duplicates_only mode
ui_->filter->setText("");
ui_->filter->setEnabled(!duplicates_only);
model_->SetFilterDuplicatesOnly(duplicates_only);
}
void LibraryFilterWidget::SetAgeFilterEnabled(bool enabled) {
filter_age_menu_->setEnabled(enabled);
}
@ -204,6 +212,10 @@ void LibraryFilterWidget::AddMenuAction(QAction* action) {
library_menu_->addAction(action);
}
void LibraryFilterWidget::AddSeparator() {
library_menu_->addSeparator();
}
void LibraryFilterWidget::AppendAndFocus(const QString& text) {
ui_->filter->setText(ui_->filter->text() + text);
ui_->filter->setFocus();

View File

@ -45,13 +45,16 @@ class LibraryFilterWidget : public QWidget {
void SetFilterHint(const QString& hint);
void SetAgeFilterEnabled(bool enabled);
void SetGroupByEnabled(bool enabled);
void AddMenuAction(QAction* action);
void AddSeparator();
void SetSettingsGroup(const QString& group) { settings_group_ = group; }
void SetLibraryModel(LibraryModel* model);
public slots:
void AppendAndFocus(const QString& text);
void SetDuplicatesOnly(bool duplicates_only);
signals:
void UpPressed();

View File

@ -986,7 +986,18 @@ void LibraryModel::SetFilterAge(int age) {
}
void LibraryModel::SetFilterText(const QString& text) {
// duplicates_only and filter are mutually exclusive
query_options_.filter = text;
query_options_.duplicates_only = false;
ResetAsync();
}
void LibraryModel::SetFilterDuplicatesOnly(bool duplicates_only) {
// duplicates_only and filter are mutually exclusive
query_options_.duplicates_only = duplicates_only;
query_options_.filter = "";
ResetAsync();
}

View File

@ -138,6 +138,8 @@ class LibraryModel : public SimpleTreeModel<LibraryItem> {
public slots:
void SetFilterAge(int age);
void SetFilterText(const QString& text);
void SetFilterDuplicatesOnly(bool duplicates_only);
void SetGroupBy(const LibraryModel::Grouping& g);
void Init();
void Reset();

View File

@ -23,7 +23,8 @@
#include <QSqlError>
QueryOptions::QueryOptions()
: max_age(-1)
: max_age(-1),
duplicates_only(false)
{
}
@ -62,23 +63,43 @@ LibraryQuery::LibraryQuery(const QueryOptions& options)
where_clauses_ << "ctime > ?";
bound_values_ << cutoff;
}
duplicates_only_ = false;
if(options.duplicates_only) {
// TODO: currently you cannot use the duplicates_only flag and fts at the same time.
// joining songs, duplicated_songs and songs_fts all together takes a huge amount of
// time. the query takes about 20 seconds then. why?
Q_ASSERT(!join_with_fts_);
duplicates_only_ = true;
}
}
void LibraryQuery::AddWhere(const QString& column, const QVariant& value, const QString& op) {
// Do integers inline - sqlite seems to get confused when you pass integers
// to bound parameters
QString LibraryQuery::GetInnerQuery() {
return duplicates_only_
? QString(" INNER JOIN (select * from duplicated_songs) dsongs "
"ON (%songs_table.artist = dsongs.dup_artist "
"AND %songs_table.album = dsongs.dup_album "
"AND %songs_table.title = dsongs.dup_title) ")
: QString();
}
if (value.type() == QVariant::Int)
where_clauses_ << QString("%1 %2 %3").arg(column, op, value.toString());
else {
if(!op.compare("IN", Qt::CaseInsensitive)) {
QStringList final;
foreach(const QString& single_value, value.toStringList()) {
final.append("?");
bound_values_ << single_value;
}
void LibraryQuery::AddWhere(const QString& column, const QVariant& value,
const QString& op) {
// ignore 'literal' for IN
if(!op.compare("IN", Qt::CaseInsensitive)) {
QStringList final;
foreach(const QString& single_value, value.toStringList()) {
final.append("?");
bound_values_ << single_value;
}
where_clauses_ << QString("%1 IN (" + final.join(",") + ")").arg(column);
where_clauses_ << QString("%1 IN (" + final.join(",") + ")").arg(column);
} else {
// Do integers inline - sqlite seems to get confused when you pass integers
// to bound parameters
if(value.type() == QVariant::Int) {
where_clauses_ << QString("%1 %2 %3").arg(column, op, value.toString());
} else {
where_clauses_ << QString("%1 %2 ?").arg(column, op);
bound_values_ << value;
@ -98,8 +119,8 @@ QSqlError LibraryQuery::Exec(QSqlDatabase db, const QString& songs_table,
sql = QString("SELECT %1 FROM %2 INNER JOIN %3 AS fts ON %2.ROWID = fts.ROWID")
.arg(column_spec_, songs_table, fts_table);
} else {
sql = QString("SELECT %1 FROM %2")
.arg(column_spec_, songs_table);
sql = QString("SELECT %1 FROM %2 %3")
.arg(column_spec_, songs_table, GetInnerQuery());
}
if (!where_clauses_.isEmpty())

View File

@ -32,20 +32,31 @@ struct QueryOptions {
bool Matches(const Song& song) const;
// Please note that this attribute is mutually exclusive with the 'duplicates_only'
// flag!
QString filter;
int max_age;
// If true, the query will operate not on the whole songs table but only on those rows
// which are duplicated. By duplication we mean a situation where two or more songs
// with equal (artist, album, title) tuple exist (case sensitive).
// Please note that this flag is mutually exclusive with the 'filter' attribute!
bool duplicates_only;
};
class LibraryQuery {
public:
LibraryQuery(const QueryOptions& options = QueryOptions());
// Sets contents of SELECT clause on the query (list of columns to get).
void SetColumnSpec(const QString& spec) { column_spec_ = spec; }
// Sets an ORDER BY clause on the query.
void SetOrderBy(const QString& order_by) { order_by_ = order_by; }
// Adds a fragment of WHERE clause. When executed, this Query will connect all
// the fragments with AND operator.
// Please note that IN operator expects a QStringList as value.
void AddWhere(const QString& column, const QVariant& value, const QString& op = "=");
void AddCompilationRequirement(bool compilation);
void SetLimit(int limit) { limit_ = limit; }
@ -56,12 +67,15 @@ class LibraryQuery {
operator const QSqlQuery& () const { return query_; }
private:
QString GetInnerQuery();
bool join_with_fts_;
QString column_spec_;
QString order_by_;
QStringList where_clauses_;
QVariantList bound_values_;
int limit_;
bool duplicates_only_;
QSqlQuery query_;
};

View File

@ -11,6 +11,7 @@ public:
QString filter;
int max_age;
bool duplicates_only;
};
class LibraryQuery {
@ -25,7 +26,9 @@ public:
void SetColumnSpec(const QString& spec);
void SetOrderBy(const QString& order_by);
void AddWhere(const QString& column, const QVariant& value, const QString& op = "=");
void AddCompilationRequirement(bool compilation);
void SetLimit(int limit);

View File

@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2114,6 +2114,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2138,6 +2138,9 @@ msgstr "Покажи всичките песни"
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Покажи в пълен размер..."

View File

@ -2102,6 +2102,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2138,6 +2138,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Mostra a mida completa..."

View File

@ -2140,6 +2140,9 @@ msgstr "Ukázat všechny písničky"
msgid "Show cover art in library"
msgstr "Ukázat obal v knihovně"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Ukázat plnou velikost..."

View File

@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2107,6 +2107,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Vis i fuld størrelse..."

View File

@ -2142,6 +2142,9 @@ msgstr "Alle Titel anzeigen"
msgid "Show cover art in library"
msgstr "Zeigt Cover in Musiksammlung an"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Vollbild..."

View File

@ -2151,6 +2151,9 @@ msgstr "Εμφάνιση όλλων των τραγουδιών"
msgid "Show cover art in library"
msgstr "Εμφάνιση του εξώφυλλου στην βιβλιοθήκη"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Εμφάνισε σε πλήρες μέγεθος..."

View File

@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2105,6 +2105,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Show fullsize..."

View File

@ -2102,6 +2102,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Show fullsize..."

View File

@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2151,6 +2151,9 @@ msgstr "Mostrar todas las canciones"
msgid "Show cover art in library"
msgstr "Mostrar portadas en la librería"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Mostrar carátula..."

View File

@ -2102,6 +2102,9 @@ msgstr "Näita kõiki laule"
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2102,6 +2102,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2156,6 +2156,9 @@ msgstr "Afficher tous les morceaux"
msgid "Show cover art in library"
msgstr "Afficher les jaquettes des albums dans la bibliothèque"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Afficher en taille réelle..."

View File

@ -2110,6 +2110,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2121,6 +2121,9 @@ msgstr "הצג את כל השירים"
msgid "Show cover art in library"
msgstr "הצגת עטיפת אלבום בספרייה"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "הצג על מסך מלא..."

View File

@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2133,6 +2133,9 @@ msgstr "Prikaži sve pjesme"
msgid "Show cover art in library"
msgstr "Prikaži omot albuma u zbirci"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Prikaži u punoj veličini..."

View File

@ -2139,6 +2139,9 @@ msgstr "Minden számot mutasson"
msgid "Show cover art in library"
msgstr "Albumborító megjelenítése a zenetárban"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Jelenítse meg teljes méretben..."

View File

@ -2146,6 +2146,9 @@ msgstr "Mostra tutti i brani"
msgid "Show cover art in library"
msgstr "Mostra le copertine nella raccolta"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Mostra a dimensioni originali..."

View File

@ -2131,6 +2131,9 @@ msgstr "すべての曲を表示"
msgid "Show cover art in library"
msgstr "ライブラリにカバー アートを表示"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "原寸表示"

View File

@ -2102,6 +2102,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2135,6 +2135,9 @@ msgstr "Rodyti visas dainas"
msgid "Show cover art in library"
msgstr "Rodyti albumo viršelius fonotekoje"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Rodyti viso dydžio..."

View File

@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2114,6 +2114,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Vis i fullskjerm..."

View File

@ -2138,6 +2138,9 @@ msgstr "Alle nummers weergeven"
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Volledig weergeven..."

View File

@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2138,6 +2138,9 @@ msgstr "Pokaż wszystkie ścieżki"
msgid "Show cover art in library"
msgstr "Pokazuj okładki w bibliotece"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Pokaż w pełnej wielkości..."

View File

@ -2141,6 +2141,9 @@ msgstr "Mostrar todas as músicas"
msgid "Show cover art in library"
msgstr "Mostrar capa de álbum na coleção"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Mostrar tamanho total..."

View File

@ -2139,6 +2139,9 @@ msgstr "Mostrar todas as músicas"
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Exibir tamanho real..."

View File

@ -2101,6 +2101,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2133,6 +2133,9 @@ msgstr "Показать все песни"
msgid "Show cover art in library"
msgstr "Показывать обложки в библиотеке"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Показать полный размер..."

View File

@ -2130,6 +2130,9 @@ msgstr "Zobraziť všetky piesne"
msgid "Show cover art in library"
msgstr "Zobraziť obaly albumov v zbierke"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Zobraziť celú veľkosť..."

View File

@ -2132,6 +2132,9 @@ msgstr "Pokaži vse skladbe"
msgid "Show cover art in library"
msgstr "Kaži ovitek albuma v knjižnici"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Pokaži v polni velikosti ..."

View File

@ -2105,6 +2105,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2134,6 +2134,9 @@ msgstr "Visa alla låtarna"
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Visa full storlek..."

View File

@ -2132,6 +2132,9 @@ msgstr "Tüm şarkıları göster"
msgid "Show cover art in library"
msgstr "Kapak resmini kütüphanede göster"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Tam boyutta göster"

View File

@ -2090,6 +2090,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2132,6 +2132,9 @@ msgstr "Показати всі композиції"
msgid "Show cover art in library"
msgstr "Показувати обкладинки у фонотеці"
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "Показати на повний розмір..."

View File

@ -2103,6 +2103,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr ""

View File

@ -2105,6 +2105,9 @@ msgstr "顯示所有的歌曲"
msgid "Show cover art in library"
msgstr ""
msgid "Show duplicates only"
msgstr ""
msgid "Show fullsize..."
msgstr "全螢幕..."

View File

@ -419,11 +419,18 @@ MainWindow::MainWindow(
connect(device_view_, SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
// Library filter widget
QAction* duplicates_only_action = new QAction(tr("Show duplicates only"), this);
duplicates_only_action->setCheckable(true);
connect(duplicates_only_action, SIGNAL(toggled(bool)), library_view_->filter(), SLOT(SetDuplicatesOnly(bool)));
QAction* library_config_action = new QAction(
IconLoader::Load("configure"), tr("Configure library..."), this);
connect(library_config_action, SIGNAL(triggered()), SLOT(ShowLibraryConfig()));
library_view_->filter()->SetSettingsGroup(kSettingsGroup);
library_view_->filter()->SetLibraryModel(library_->model());
library_view_->filter()->AddMenuAction(duplicates_only_action);
library_view_->filter()->AddSeparator();
library_view_->filter()->AddMenuAction(library_config_action);
// Playlist menu