diff --git a/data/data.qrc b/data/data.qrc
index 63882f474..cf7d66424 100644
--- a/data/data.qrc
+++ b/data/data.qrc
@@ -297,5 +297,6 @@
schema/schema-25.sql
schema/schema-26.sql
pythonstartup.py
+ schema/schema-27.sql
diff --git a/data/schema/schema-27.sql b/data/schema/schema-27.sql
new file mode 100644
index 000000000..7062bfce7
--- /dev/null
+++ b/data/schema/schema-27.sql
@@ -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;
diff --git a/src/core/database.cpp b/src/core/database.cpp
index b9c3dc471..b449581ba 100644
--- a/src/core/database.cpp
+++ b/src/core/database.cpp
@@ -31,7 +31,7 @@
#include
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;
diff --git a/src/library/libraryfilterwidget.cpp b/src/library/libraryfilterwidget.cpp
index 16b8aee04..5a2c4fa9f 100644
--- a/src/library/libraryfilterwidget.cpp
+++ b/src/library/libraryfilterwidget.cpp
@@ -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();
diff --git a/src/library/libraryfilterwidget.h b/src/library/libraryfilterwidget.h
index 77bb9013f..53cc699c7 100644
--- a/src/library/libraryfilterwidget.h
+++ b/src/library/libraryfilterwidget.h
@@ -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();
diff --git a/src/library/librarymodel.cpp b/src/library/librarymodel.cpp
index 78e4a61c3..af2ca6fdf 100644
--- a/src/library/librarymodel.cpp
+++ b/src/library/librarymodel.cpp
@@ -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();
}
diff --git a/src/library/librarymodel.h b/src/library/librarymodel.h
index 35ef05cfd..5aacdf62b 100644
--- a/src/library/librarymodel.h
+++ b/src/library/librarymodel.h
@@ -138,6 +138,8 @@ class LibraryModel : public SimpleTreeModel {
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();
diff --git a/src/library/libraryquery.cpp b/src/library/libraryquery.cpp
index dc3a568fb..41583f15a 100644
--- a/src/library/libraryquery.cpp
+++ b/src/library/libraryquery.cpp
@@ -23,7 +23,8 @@
#include
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())
diff --git a/src/library/libraryquery.h b/src/library/libraryquery.h
index 2d84d2cb8..53ce7c5b7 100644
--- a/src/library/libraryquery.h
+++ b/src/library/libraryquery.h
@@ -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_;
};
diff --git a/src/scripting/python/libraryquery.sip b/src/scripting/python/libraryquery.sip
index c4a2548df..4f30e0938 100644
--- a/src/scripting/python/libraryquery.sip
+++ b/src/scripting/python/libraryquery.sip
@@ -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);
diff --git a/src/translations/ar.po b/src/translations/ar.po
index 1a11bfc04..6a0c65c31 100644
--- a/src/translations/ar.po
+++ b/src/translations/ar.po
@@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/be.po b/src/translations/be.po
index 924662160..b899b15cc 100644
--- a/src/translations/be.po
+++ b/src/translations/be.po
@@ -2114,6 +2114,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/bg.po b/src/translations/bg.po
index a26966c44..ba2a4e363 100644
--- a/src/translations/bg.po
+++ b/src/translations/bg.po
@@ -2138,6 +2138,9 @@ msgstr "Покажи всичките песни"
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "Покажи в пълен размер..."
diff --git a/src/translations/br.po b/src/translations/br.po
index 3ddeef90b..597c45475 100644
--- a/src/translations/br.po
+++ b/src/translations/br.po
@@ -2102,6 +2102,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/ca.po b/src/translations/ca.po
index 02502de1b..16e5bcf24 100644
--- a/src/translations/ca.po
+++ b/src/translations/ca.po
@@ -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..."
diff --git a/src/translations/cs.po b/src/translations/cs.po
index d227b47ff..7d5c252f3 100644
--- a/src/translations/cs.po
+++ b/src/translations/cs.po
@@ -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..."
diff --git a/src/translations/cy.po b/src/translations/cy.po
index 9257113b3..fac5c4983 100644
--- a/src/translations/cy.po
+++ b/src/translations/cy.po
@@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/da.po b/src/translations/da.po
index 3b4ecedd9..26da2e7a1 100644
--- a/src/translations/da.po
+++ b/src/translations/da.po
@@ -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..."
diff --git a/src/translations/de.po b/src/translations/de.po
index 4c89eb880..8a0709dcf 100644
--- a/src/translations/de.po
+++ b/src/translations/de.po
@@ -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..."
diff --git a/src/translations/el.po b/src/translations/el.po
index b599e650b..e48611a2c 100644
--- a/src/translations/el.po
+++ b/src/translations/el.po
@@ -2151,6 +2151,9 @@ msgstr "Εμφάνιση όλλων των τραγουδιών"
msgid "Show cover art in library"
msgstr "Εμφάνιση του εξώφυλλου στην βιβλιοθήκη"
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "Εμφάνισε σε πλήρες μέγεθος..."
diff --git a/src/translations/en.po b/src/translations/en.po
index 194831eeb..d71dfc78a 100644
--- a/src/translations/en.po
+++ b/src/translations/en.po
@@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/en_CA.po b/src/translations/en_CA.po
index 0e16293dd..92daeb2ec 100644
--- a/src/translations/en_CA.po
+++ b/src/translations/en_CA.po
@@ -2105,6 +2105,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "Show fullsize..."
diff --git a/src/translations/en_GB.po b/src/translations/en_GB.po
index 9b362b36e..05888840e 100644
--- a/src/translations/en_GB.po
+++ b/src/translations/en_GB.po
@@ -2102,6 +2102,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "Show fullsize..."
diff --git a/src/translations/eo.po b/src/translations/eo.po
index 30faad581..d4f240eed 100644
--- a/src/translations/eo.po
+++ b/src/translations/eo.po
@@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/es.po b/src/translations/es.po
index da9ebe5cf..a8754e124 100644
--- a/src/translations/es.po
+++ b/src/translations/es.po
@@ -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..."
diff --git a/src/translations/et.po b/src/translations/et.po
index 6525df25a..f82434737 100644
--- a/src/translations/et.po
+++ b/src/translations/et.po
@@ -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 ""
diff --git a/src/translations/eu.po b/src/translations/eu.po
index f640e663f..d3f90b0b1 100644
--- a/src/translations/eu.po
+++ b/src/translations/eu.po
@@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/fi.po b/src/translations/fi.po
index 110c2c6e7..7fd99a50d 100644
--- a/src/translations/fi.po
+++ b/src/translations/fi.po
@@ -2102,6 +2102,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/fr.po b/src/translations/fr.po
index f008f0eff..b8a9dc7c9 100644
--- a/src/translations/fr.po
+++ b/src/translations/fr.po
@@ -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..."
diff --git a/src/translations/gl.po b/src/translations/gl.po
index 2f6e0e53b..fee4936b4 100644
--- a/src/translations/gl.po
+++ b/src/translations/gl.po
@@ -2110,6 +2110,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/he.po b/src/translations/he.po
index b68db309c..780b079a1 100644
--- a/src/translations/he.po
+++ b/src/translations/he.po
@@ -2121,6 +2121,9 @@ msgstr "הצג את כל השירים"
msgid "Show cover art in library"
msgstr "הצגת עטיפת אלבום בספרייה"
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "הצג על מסך מלא..."
diff --git a/src/translations/hi.po b/src/translations/hi.po
index 146404f8c..317907439 100644
--- a/src/translations/hi.po
+++ b/src/translations/hi.po
@@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/hr.po b/src/translations/hr.po
index b29af5271..9eaa888d4 100644
--- a/src/translations/hr.po
+++ b/src/translations/hr.po
@@ -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..."
diff --git a/src/translations/hu.po b/src/translations/hu.po
index 72278b421..d06e5cfd5 100644
--- a/src/translations/hu.po
+++ b/src/translations/hu.po
@@ -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..."
diff --git a/src/translations/it.po b/src/translations/it.po
index 61d789461..3e211450c 100644
--- a/src/translations/it.po
+++ b/src/translations/it.po
@@ -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..."
diff --git a/src/translations/ja.po b/src/translations/ja.po
index 9e7e1409d..74ab174ce 100644
--- a/src/translations/ja.po
+++ b/src/translations/ja.po
@@ -2131,6 +2131,9 @@ msgstr "すべての曲を表示"
msgid "Show cover art in library"
msgstr "ライブラリにカバー アートを表示"
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "原寸表示"
diff --git a/src/translations/kk.po b/src/translations/kk.po
index eebd5fbdf..f4a2ed582 100644
--- a/src/translations/kk.po
+++ b/src/translations/kk.po
@@ -2102,6 +2102,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/lt.po b/src/translations/lt.po
index 34b023314..1de1b93a5 100644
--- a/src/translations/lt.po
+++ b/src/translations/lt.po
@@ -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..."
diff --git a/src/translations/lv.po b/src/translations/lv.po
index 6869c7c66..d31f8c9d7 100644
--- a/src/translations/lv.po
+++ b/src/translations/lv.po
@@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/nb.po b/src/translations/nb.po
index 1285c807e..61983806f 100644
--- a/src/translations/nb.po
+++ b/src/translations/nb.po
@@ -2114,6 +2114,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "Vis i fullskjerm..."
diff --git a/src/translations/nl.po b/src/translations/nl.po
index 10a2a54f5..90d99fa55 100644
--- a/src/translations/nl.po
+++ b/src/translations/nl.po
@@ -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..."
diff --git a/src/translations/oc.po b/src/translations/oc.po
index 85d4636ed..7891119cc 100644
--- a/src/translations/oc.po
+++ b/src/translations/oc.po
@@ -2100,6 +2100,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/pl.po b/src/translations/pl.po
index fd9e6c579..eaa7aac4a 100644
--- a/src/translations/pl.po
+++ b/src/translations/pl.po
@@ -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..."
diff --git a/src/translations/pt.po b/src/translations/pt.po
index 4e0f55d77..7b352c91a 100644
--- a/src/translations/pt.po
+++ b/src/translations/pt.po
@@ -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..."
diff --git a/src/translations/pt_BR.po b/src/translations/pt_BR.po
index d6190c4ac..04cec238a 100644
--- a/src/translations/pt_BR.po
+++ b/src/translations/pt_BR.po
@@ -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..."
diff --git a/src/translations/ro.po b/src/translations/ro.po
index 35e694d76..62ec3ef47 100644
--- a/src/translations/ro.po
+++ b/src/translations/ro.po
@@ -2101,6 +2101,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/ru.po b/src/translations/ru.po
index 36b728254..8a5bf8efc 100644
--- a/src/translations/ru.po
+++ b/src/translations/ru.po
@@ -2133,6 +2133,9 @@ msgstr "Показать все песни"
msgid "Show cover art in library"
msgstr "Показывать обложки в библиотеке"
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "Показать полный размер..."
diff --git a/src/translations/sk.po b/src/translations/sk.po
index 149dfca97..abb81f4c7 100644
--- a/src/translations/sk.po
+++ b/src/translations/sk.po
@@ -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ť..."
diff --git a/src/translations/sl.po b/src/translations/sl.po
index 6c2a0e0ef..d2a8037a2 100644
--- a/src/translations/sl.po
+++ b/src/translations/sl.po
@@ -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 ..."
diff --git a/src/translations/sr.po b/src/translations/sr.po
index ec67d0b23..ec29f5725 100644
--- a/src/translations/sr.po
+++ b/src/translations/sr.po
@@ -2105,6 +2105,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/sv.po b/src/translations/sv.po
index de9cd73d9..672956050 100644
--- a/src/translations/sv.po
+++ b/src/translations/sv.po
@@ -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..."
diff --git a/src/translations/tr.po b/src/translations/tr.po
index 2019dd5c5..0c6d123cf 100644
--- a/src/translations/tr.po
+++ b/src/translations/tr.po
@@ -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"
diff --git a/src/translations/translations.pot b/src/translations/translations.pot
index e31c44d2d..b1a58ce49 100644
--- a/src/translations/translations.pot
+++ b/src/translations/translations.pot
@@ -2090,6 +2090,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/uk.po b/src/translations/uk.po
index 5ef1bf4d8..d37937b58 100644
--- a/src/translations/uk.po
+++ b/src/translations/uk.po
@@ -2132,6 +2132,9 @@ msgstr "Показати всі композиції"
msgid "Show cover art in library"
msgstr "Показувати обкладинки у фонотеці"
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "Показати на повний розмір..."
diff --git a/src/translations/zh_CN.po b/src/translations/zh_CN.po
index 9bebea787..1cb92ccff 100644
--- a/src/translations/zh_CN.po
+++ b/src/translations/zh_CN.po
@@ -2103,6 +2103,9 @@ msgstr ""
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr ""
diff --git a/src/translations/zh_TW.po b/src/translations/zh_TW.po
index b82d7130a..33e16cf9f 100644
--- a/src/translations/zh_TW.po
+++ b/src/translations/zh_TW.po
@@ -2105,6 +2105,9 @@ msgstr "顯示所有的歌曲"
msgid "Show cover art in library"
msgstr ""
+msgid "Show duplicates only"
+msgstr ""
+
msgid "Show fullsize..."
msgstr "全螢幕..."
diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp
index 65a24cfdc..bf00d33e4 100644
--- a/src/ui/mainwindow.cpp
+++ b/src/ui/mainwindow.cpp
@@ -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