diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 383105d0d4382e6d108acb3f17af34a21f4951b3..a42717f79db984d836b71c037c869e65856512fb 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -163,6 +163,8 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/medialibrary/mlgrouplistmodel.hpp \
 	gui/qt/medialibrary/mlhelper.cpp \
 	gui/qt/medialibrary/mlhelper.hpp \
+	gui/qt/medialibrary/mlitemcover.cpp \
+	gui/qt/medialibrary/mlitemcover.hpp \
 	gui/qt/medialibrary/mlqmltypes.hpp \
 	gui/qt/medialibrary/mlqueryparams.cpp \
 	gui/qt/medialibrary/mlqueryparams.hpp \
diff --git a/modules/gui/qt/medialibrary/mlgenre.cpp b/modules/gui/qt/medialibrary/mlgenre.cpp
index 640b35e6cfa52c5d2ad2299ed76526baf56e8eda..9d2b61c02cfa074eb78699156ec756198806caf4 100644
--- a/modules/gui/qt/medialibrary/mlgenre.cpp
+++ b/modules/gui/qt/medialibrary/mlgenre.cpp
@@ -19,9 +19,8 @@
 #include "mlgenre.hpp"
 
 MLGenre::MLGenre(vlc_medialibrary_t* ml, const vlc_ml_genre_t *_data )
-    : MLItem     ( MLItemId( _data->i_id, VLC_ML_PARENT_GENRE ) )
+    : MLItemCover( MLItemId( _data->i_id, VLC_ML_PARENT_GENRE ) )
     , m_ml       ( ml )
-    , m_generator( nullptr )
     , m_name     ( QString::fromUtf8( _data->psz_name ) )
     , m_nbTracks ( (unsigned int)_data->i_nb_tracks )
 
@@ -29,16 +28,6 @@ MLGenre::MLGenre(vlc_medialibrary_t* ml, const vlc_ml_genre_t *_data )
     assert(_data);
 }
 
-bool MLGenre::hasGenerator() const
-{
-    return m_generator.get();
-}
-
-void MLGenre::setGenerator(CoverGenerator * generator)
-{
-    m_generator.reset(generator);
-}
-
 QString MLGenre::getName() const
 {
     return m_name;
@@ -48,14 +37,3 @@ unsigned int MLGenre::getNbTracks() const
 {
     return m_nbTracks;
 }
-
-QString MLGenre::getCover() const
-{
-    return m_cover;
-}
-
-void MLGenre::setCover(const QString & fileName)
-{
-    m_cover = fileName;
-}
-
diff --git a/modules/gui/qt/medialibrary/mlgenre.hpp b/modules/gui/qt/medialibrary/mlgenre.hpp
index ebeb6c108229d305b6f60ce1ceaa437fbf1932f9..1af666ff43e4c52d6f9e6cf5d564121d4474cd04 100644
--- a/modules/gui/qt/medialibrary/mlgenre.hpp
+++ b/modules/gui/qt/medialibrary/mlgenre.hpp
@@ -23,36 +23,22 @@
 #include "config.h"
 #endif
 
-// Util includes
-#include "util/covergenerator.hpp"
-
 // MediaLibrary includes
-#include "mlqmltypes.hpp"
+#include "mlitemcover.hpp"
 
-class MLGenre : public MLItem
+class MLGenre : public MLItemCover
 {
 public:
-    MLGenre( vlc_medialibrary_t* _ml, const vlc_ml_genre_t *_data );
-
-    bool hasGenerator() const;
-    void setGenerator(CoverGenerator * generator);
+    MLGenre(vlc_medialibrary_t * _ml, const vlc_ml_genre_t * _data);
 
     QString getName() const;
-    unsigned int getNbTracks() const;
 
-    QString getCover() const;
-    void    setCover(const QString & fileName);
-
-private slots:
-    void generateThumbnail();
+    unsigned int getNbTracks() const;
 
 private:
-    vlc_medialibrary_t* m_ml;
-
-    TaskHandle<CoverGenerator> m_generator;
+    vlc_medialibrary_t * m_ml;
 
     QString m_name;
-    QString m_cover;
 
     unsigned int m_nbTracks;
 };
diff --git a/modules/gui/qt/medialibrary/mlgroup.cpp b/modules/gui/qt/medialibrary/mlgroup.cpp
index 88faafc5e5ecc82f0d646ad0f82d013f6459b7c1..65ea406bb495792271b8221824a580e952d10493 100644
--- a/modules/gui/qt/medialibrary/mlgroup.cpp
+++ b/modules/gui/qt/medialibrary/mlgroup.cpp
@@ -28,9 +28,8 @@
 //-------------------------------------------------------------------------------------------------
 
 MLGroup::MLGroup(vlc_medialibrary_t * ml, const vlc_ml_group_t * data)
-    : MLItem(MLItemId(data->i_id, VLC_ML_PARENT_GROUP))
+    : MLItemCover(MLItemId(data->i_id, VLC_ML_PARENT_GROUP))
     , m_ml(ml)
-    , m_generator(nullptr)
     , m_name(qfu(data->psz_name))
     , m_duration(data->i_duration)
     , m_date(data->i_creation_date)
@@ -43,18 +42,6 @@ MLGroup::MLGroup(vlc_medialibrary_t * ml, const vlc_ml_group_t * data)
 // Interface
 //-------------------------------------------------------------------------------------------------
 
-bool MLGroup::hasGenerator() const
-{
-    return m_generator.get();
-}
-
-void MLGroup::setGenerator(CoverGenerator * generator)
-{
-    m_generator.reset(generator);
-}
-
-//-------------------------------------------------------------------------------------------------
-
 QString MLGroup::getName() const
 {
     return m_name;
@@ -62,18 +49,6 @@ QString MLGroup::getName() const
 
 //-------------------------------------------------------------------------------------------------
 
-QString MLGroup::getCover() const
-{
-    return m_cover;
-}
-
-void MLGroup::setCover(const QString & fileName)
-{
-    m_cover = fileName;
-}
-
-//-------------------------------------------------------------------------------------------------
-
 int64_t MLGroup::getDuration() const
 {
     return m_duration;
diff --git a/modules/gui/qt/medialibrary/mlgroup.hpp b/modules/gui/qt/medialibrary/mlgroup.hpp
index 598594a0733e3c6473d084578dfe8e2113d2349e..576d4f1a4e71c9e669f8426cb5ffefdeb810a886 100644
--- a/modules/gui/qt/medialibrary/mlgroup.hpp
+++ b/modules/gui/qt/medialibrary/mlgroup.hpp
@@ -25,26 +25,17 @@
 #include "config.h"
 #endif
 
-// Util includes
-#include "util/covergenerator.hpp"
-
 // MediaLibrary includes
-#include "mlqmltypes.hpp"
+#include "mlitemcover.hpp"
 
-class MLGroup : public MLItem
+class MLGroup : public MLItemCover
 {
 public:
     MLGroup(vlc_medialibrary_t * ml, const vlc_ml_group_t * data);
 
 public: // Interface
-    bool hasGenerator() const;
-    void setGenerator(CoverGenerator * generator);
-
     QString getName() const;
 
-    QString getCover() const;
-    void    setCover(const QString & fileName);
-
     int64_t getDuration() const;
 
     unsigned int getDate() const;
@@ -54,12 +45,8 @@ public: // Interface
 private:
     vlc_medialibrary_t * m_ml;
 
-    TaskHandle<CoverGenerator> m_generator;
-
     QString m_name;
 
-    QString m_cover;
-
     int64_t m_duration;
 
     unsigned int m_date;
diff --git a/modules/gui/qt/medialibrary/mlitemcover.cpp b/modules/gui/qt/medialibrary/mlitemcover.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..484103e9b27fb90e3a1365d1fd2f91cbc74eed3f
--- /dev/null
+++ b/modules/gui/qt/medialibrary/mlitemcover.cpp
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * Authors: Benjamin Arnaud <bunjee@omega.gg>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "mlitemcover.hpp"
+
+//-------------------------------------------------------------------------------------------------
+// Ctor / dtor
+//-------------------------------------------------------------------------------------------------
+
+MLItemCover::MLItemCover(const MLItemId & id)
+    : MLItem(id)
+    , m_generator(nullptr) {}
+
+//-------------------------------------------------------------------------------------------------
+// Interface
+//-------------------------------------------------------------------------------------------------
+
+bool MLItemCover::hasGenerator() const
+{
+    return m_generator.get();
+}
+
+void MLItemCover::setGenerator(CoverGenerator * generator)
+{
+    m_generator.reset(generator);
+}
+
+//-------------------------------------------------------------------------------------------------
+
+QString MLItemCover::getCover() const
+{
+    return m_cover;
+}
+
+void MLItemCover::setCover(const QString & fileName)
+{
+    m_cover = fileName;
+}
diff --git a/modules/gui/qt/medialibrary/mlitemcover.hpp b/modules/gui/qt/medialibrary/mlitemcover.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1064a67ecd571448d0d39e29f31ea0a2a06b3e9d
--- /dev/null
+++ b/modules/gui/qt/medialibrary/mlitemcover.hpp
@@ -0,0 +1,52 @@
+/*****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * Authors: Benjamin Arnaud <bunjee@omega.gg>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef MLITEMCOVER_HPP
+#define MLITEMCOVER_HPP
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+// Util includes
+#include "util/covergenerator.hpp"
+
+// MediaLibrary includes
+#include "mlqmltypes.hpp"
+
+class MLItemCover : public MLItem
+{
+public:
+    /* explicit */ MLItemCover(const MLItemId & id);
+
+public: // Interface
+    bool hasGenerator() const;
+    void setGenerator(CoverGenerator * generator);
+
+    QString getCover() const;
+    void    setCover(const QString & fileName);
+
+private:
+    TaskHandle<CoverGenerator> m_generator;
+
+    QString m_cover;
+};
+
+#endif
diff --git a/modules/gui/qt/medialibrary/mlplaylist.cpp b/modules/gui/qt/medialibrary/mlplaylist.cpp
index ea4a9dc90d75b93f0bc39f4ad3782478cdc49f46..3adef6ee89d8d9635e1c11c989fcc94054463501 100644
--- a/modules/gui/qt/medialibrary/mlplaylist.cpp
+++ b/modules/gui/qt/medialibrary/mlplaylist.cpp
@@ -26,9 +26,8 @@
 //-------------------------------------------------------------------------------------------------
 
 MLPlaylist::MLPlaylist(vlc_medialibrary_t * ml, const vlc_ml_playlist_t * data)
-    : MLItem(MLItemId(data->i_id, VLC_ML_PARENT_PLAYLIST))
+    : MLItemCover(MLItemId(data->i_id, VLC_ML_PARENT_PLAYLIST))
     , m_ml(ml)
-    , m_generator(nullptr)
     , m_name(qfu(data->psz_name))
     , m_duration(0) // TODO m_duration
     , m_count(data->i_nb_media)
@@ -40,18 +39,6 @@ MLPlaylist::MLPlaylist(vlc_medialibrary_t * ml, const vlc_ml_playlist_t * data)
 // Interface
 //-------------------------------------------------------------------------------------------------
 
-bool MLPlaylist::hasGenerator() const
-{
-    return m_generator.get();
-}
-
-void MLPlaylist::setGenerator(CoverGenerator * generator)
-{
-    m_generator.reset(generator);
-}
-
-//-------------------------------------------------------------------------------------------------
-
 QString MLPlaylist::getName() const
 {
     return m_name;
@@ -59,18 +46,6 @@ QString MLPlaylist::getName() const
 
 //-------------------------------------------------------------------------------------------------
 
-QString MLPlaylist::getCover() const
-{
-    return m_cover;
-}
-
-void MLPlaylist::setCover(const QString & fileName)
-{
-    m_cover = fileName;
-}
-
-//-------------------------------------------------------------------------------------------------
-
 int64_t MLPlaylist::getDuration() const
 {
     return m_duration;
diff --git a/modules/gui/qt/medialibrary/mlplaylist.hpp b/modules/gui/qt/medialibrary/mlplaylist.hpp
index 5df9ab0371491dac25d2bb789748c5c760be2ead..cf76d7b26d8f21c6de677c60f2c46b8ec82e736e 100644
--- a/modules/gui/qt/medialibrary/mlplaylist.hpp
+++ b/modules/gui/qt/medialibrary/mlplaylist.hpp
@@ -23,26 +23,17 @@
 #include "config.h"
 #endif
 
-// Util includes
-#include "util/covergenerator.hpp"
-
 // MediaLibrary includes
-#include "mlqmltypes.hpp"
+#include "mlitemcover.hpp"
 
-class MLPlaylist : public MLItem
+class MLPlaylist : public MLItemCover
 {
 public:
     MLPlaylist(vlc_medialibrary_t * ml, const vlc_ml_playlist_t * data);
 
 public: // Interface
-    bool hasGenerator() const;
-    void setGenerator(CoverGenerator * generator);
-
     QString getName() const;
 
-    QString getCover() const;
-    void    setCover(const QString & fileName);
-
     int64_t getDuration() const;
 
     unsigned int getCount() const;
@@ -50,10 +41,7 @@ public: // Interface
 private:
     vlc_medialibrary_t * m_ml;
 
-    TaskHandle<CoverGenerator> m_generator;
-
     QString m_name;
-    QString m_cover;
 
     int64_t m_duration;
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8cb3df8eaa3e05b320f948ff4c289b441a08109c..04a3985b64d06a28bcb06810b8734df16992603a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -777,6 +777,8 @@ modules/gui/qt/medialibrary/mlgroup.cpp
 modules/gui/qt/medialibrary/mlgroup.hpp
 modules/gui/qt/medialibrary/mlgrouplistmodel.cpp
 modules/gui/qt/medialibrary/mlgrouplistmodel.hpp
+modules/gui/qt/medialibrary/mlitemcover.cpp
+modules/gui/qt/medialibrary/mlitemcover.hpp
 modules/gui/qt/medialibrary/mlplaylistlistmodel.cpp
 modules/gui/qt/medialibrary/mlplaylistlistmodel.hpp
 modules/gui/qt/medialibrary/mlplaylistmedia.cpp