Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (7)
Showing
with 781 additions and 284 deletions
......@@ -218,6 +218,8 @@ libqt_plugin_la_SOURCES = \
gui/qt/util/audio_device_model.cpp \
gui/qt/util/audio_device_model.hpp \
gui/qt/util/color_scheme_model.cpp gui/qt/util/color_scheme_model.hpp \
gui/qt/util/covergenerator.cpp \
gui/qt/util/covergenerator.hpp \
gui/qt/util/imageluminanceextractor.cpp gui/qt/util/imageluminanceextractor.hpp \
gui/qt/util/imagehelper.cpp gui/qt/util/imagehelper.hpp \
gui/qt/util/i18n.cpp gui/qt/util/i18n.hpp \
......@@ -343,9 +345,7 @@ nodist_libqt_plugin_la_SOURCES = \
gui/qt/medialibrary/mlartistmodel.moc.cpp \
gui/qt/medialibrary/mlbasemodel.moc.cpp \
gui/qt/medialibrary/mlfoldersmodel.moc.cpp \
gui/qt/medialibrary/mlgenre.moc.cpp \
gui/qt/medialibrary/mlgenremodel.moc.cpp \
gui/qt/medialibrary/mlgroup.moc.cpp \
gui/qt/medialibrary/mlgrouplistmodel.moc.cpp \
gui/qt/medialibrary/mlqmltypes.moc.cpp \
gui/qt/medialibrary/mlrecentsmodel.moc.cpp \
......@@ -374,6 +374,7 @@ nodist_libqt_plugin_la_SOURCES = \
gui/qt/util/asynctask.moc.cpp \
gui/qt/util/audio_device_model.moc.cpp \
gui/qt/util/color_scheme_model.moc.cpp \
gui/qt/util/covergenerator.moc.cpp \
gui/qt/util/imageluminanceextractor.moc.cpp \
gui/qt/util/i18n.moc.cpp \
gui/qt/util/listcache.moc.cpp \
......
......@@ -199,7 +199,6 @@ void MainUI::registerQMLTypes()
registerAnonymousType<MLAlbum>("org.videolan.medialib", 1);
registerAnonymousType<MLArtist>("org.videolan.medialib", 1);
registerAnonymousType<MLAlbumTrack>("org.videolan.medialib", 1);
registerAnonymousType<MLGenre>("org.videolan.medialib", 1);
registerAnonymousType<MLPlaylist>("org.videolan.medialib", 1);
qmlRegisterType<AlbumContextMenu>( "org.videolan.medialib", 0, 1, "AlbumContextMenu" );
......
......@@ -408,19 +408,37 @@ void MLBaseModel::invalidateCache()
m_cache.reset();
}
//-------------------------------------------------------------------------------------------------
MLItem *MLBaseModel::item(int signedidx) const
{
validateCache();
ssize_t count = m_cache->count();
if (count == COUNT_UNINITIALIZED || signedidx < 0
|| signedidx >= count)
if (count == COUNT_UNINITIALIZED || signedidx < 0 || signedidx >= count)
return nullptr;
unsigned int idx = static_cast<unsigned int>(signedidx);
m_cache->refer(idx);
const std::unique_ptr<MLItem> *item = m_cache->get(idx);
if (!item)
/* Not in cache */
return nullptr;
/* Return raw pointer */
return item->get();
}
MLItem *MLBaseModel::itemCache(int signedidx) const
{
unsigned int idx = static_cast<unsigned int>(signedidx);
const std::unique_ptr<MLItem> *item = m_cache->get(idx);
if (!item)
/* Not in cache */
return nullptr;
......@@ -429,6 +447,8 @@ MLItem *MLBaseModel::item(int signedidx) const
return item->get();
}
//-------------------------------------------------------------------------------------------------
MLBaseModel::BaseLoader::BaseLoader(vlc_medialibrary_t *ml, MLItemId parent, QString searchPattern,
vlc_ml_sorting_criteria_t sort, bool sort_desc)
: m_ml(ml)
......
......@@ -107,7 +107,12 @@ protected:
void validateCache() const;
void invalidateCache();
MLItem* item(int signedidx) const;
MLItem *item(int signedidx) const;
// NOTE: This is faster because it only returns items available in cache.
MLItem *itemCache(int signedidx) const;
virtual void onVlcMlEvent( const MLEvent &event );
virtual ListCacheLoader<std::unique_ptr<MLItem>> *createLoader() const = 0;
......
......@@ -16,220 +16,27 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include <cassert>
#include <QPainter>
#include <QImage>
#include <QThreadPool>
#include <QMutex>
#include <QWaitCondition>
#include <QDir>
#include <QGradient>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QGraphicsBlurEffect>
#include <algorithm>
#include "mlgenre.hpp"
#include "qt.hpp"
namespace {
#define THUMBNAIL_WIDTH 260
#define THUMBNAIL_HEIGHT 130
QImage blurImage(const QImage& src)
{
QGraphicsScene scene;
QGraphicsPixmapItem item;
item.setPixmap(QPixmap::fromImage(src));
QGraphicsBlurEffect blurEffect;
blurEffect.setBlurRadius(4);
blurEffect.setBlurHints(QGraphicsBlurEffect::QualityHint);
item.setGraphicsEffect(&blurEffect);
scene.addItem(&item);
QImage res(src.size(), QImage::Format_ARGB32);
QPainter ptr(&res);
scene.render(&ptr);
return res;
}
MLGenre::MLGenre(vlc_medialibrary_t* ml, const vlc_ml_genre_t *_data )
: MLItem ( 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 )
class GenerateCoverTask : public QRunnable
{
public:
GenerateCoverTask(vlc_medialibrary_t* ml, MLGenre* genre, QString filepath)
: QRunnable()
, m_ml(ml)
, m_genre(genre)
, m_filepath(filepath)
{
}
void drawRegion(QPainter& target, QString source, const QRect& rect)
{
QImage tmpImage;
if (tmpImage.load(source))
{
QRect sourceRect;
int size = std::min(tmpImage.width(), tmpImage.height());
if (rect.width() == rect.height())
{
sourceRect = QRect( (tmpImage.width() - size) / 2,
(tmpImage.height() - size) / 2,
size,
size);
}
else if (rect.width() > rect.height())
{
sourceRect = QRect( (tmpImage.width() - size) / 2,
(tmpImage.height() - size/2) / 2,
size,
size/2);
}
else
{
sourceRect = QRect( (tmpImage.width() - size / 2) / 2,
(tmpImage.height() - size) / 2,
size/2,
size);
}
target.drawImage(rect, tmpImage, sourceRect);
}
else
{
target.setPen(Qt::black);
target.drawRect(rect);
}
}
void run() override
{
{
QMutexLocker lock(&m_taskLock);
if (m_canceled) {
m_taskCond.wakeAll();
return;
}
m_running = true;
}
int64_t genreId = m_genre->getId().id;
ml_unique_ptr<vlc_ml_album_list_t> album_list;
//TODO only retreive albums with a cover.
vlc_ml_query_params_t queryParams;
memset(&queryParams, 0, sizeof(vlc_ml_query_params_t));
album_list.reset( vlc_ml_list_genre_albums(m_ml, &queryParams, genreId) );
QStringList thumbnails;
thumbnails.reserve(8);
for( const vlc_ml_album_t& media: ml_range_iterate<vlc_ml_album_t>( album_list ) ) {
if (media.thumbnails[VLC_ML_THUMBNAIL_SMALL].i_status ==
VLC_ML_THUMBNAIL_STATUS_AVAILABLE) {
QUrl mediaURL( media.thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl );
//QImage only accept local file
if (mediaURL.isValid() && mediaURL.isLocalFile()) {
thumbnails.append(mediaURL.path());
if (thumbnails.size() == 8)
break;
}
}
}
if (thumbnails.empty()) {
thumbnails.append(":/noart_album.svg");
}
assert(thumbnails.size() <= 8);
std::copy(thumbnails.begin(), ( thumbnails.begin() + ( 8 - thumbnails.size() ) ), std::back_inserter(thumbnails));
assert(thumbnails.size() == 8);
{
QMutexLocker lock(&m_taskLock);
if (m_canceled) {
m_running = false;
m_taskCond.wakeAll();
return;
}
}
QImage image(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, QImage::Format_RGB32);
image.fill(Qt::white);
QPainter painter;
painter.begin(&image);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 4; j++) {
drawRegion(painter, thumbnails[2*j+1], QRect( ( THUMBNAIL_WIDTH / 4 ) * j, ( THUMBNAIL_HEIGHT / 2 ) * i, THUMBNAIL_WIDTH / 4, THUMBNAIL_HEIGHT / 2 ));
}
}
painter.end();
image = blurImage(image);
QLinearGradient gradient;
gradient.setColorAt(0, QColor(0, 0, 0, 255*.3));
gradient.setColorAt(1, QColor(0, 0, 0, 255*.7));
painter.begin(&image);
painter.setOpacity(.7);
painter.fillRect(image.rect(), gradient);
painter.end();
if (image.save(m_filepath, "jpg"))
/* Set the cover from the main thread */
QMetaObject::invokeMethod(m_genre, [genre = m_genre, cover = QUrl::fromLocalFile(m_filepath).toString()]
{
genre->setCover(std::move(cover));
});
{
QMutexLocker lock(&m_taskLock);
m_running = false;
m_taskCond.wakeAll();
}
}
void cancel()
{
QMutexLocker lock(&m_taskLock);
m_canceled = true;
if (!m_running)
return;
m_taskCond.wait(&m_taskLock);
}
private:
bool m_canceled = false;
bool m_running = false;
QMutex m_taskLock;
QWaitCondition m_taskCond;
vlc_medialibrary_t* m_ml = nullptr;
MLGenre* m_genre = nullptr;
QString m_filepath;
};
assert(_data);
}
MLGenre::MLGenre(vlc_medialibrary_t* ml, const vlc_ml_genre_t *_data, QObject *_parent )
: QObject(_parent)
, MLItem ( MLItemId( _data->i_id, VLC_ML_PARENT_GENRE ) )
, m_ml ( ml )
, m_name ( QString::fromUtf8( _data->psz_name ) )
, m_nbTracks ( (unsigned int)_data->i_nb_tracks )
bool MLGenre::hasGenerator() const
{
assert(_data);
connect(this, &MLGenre::askGenerateCover, this, &MLGenre::generateThumbnail);
return m_generator.get();
}
MLGenre::~MLGenre()
void MLGenre::setGenerator(CoverGenerator * generator)
{
if (m_coverTask) {
if (!QThreadPool::globalInstance()->tryTake(m_coverTask)) {
//task is done or running
static_cast<GenerateCoverTask*>(m_coverTask)->cancel();
}
delete m_coverTask;
}
m_generator.reset(generator);
}
QString MLGenre::getName() const
......@@ -244,43 +51,11 @@ unsigned int MLGenre::getNbTracks() const
QString MLGenre::getCover() const
{
if (!m_cover.isEmpty())
return m_cover;
if (!m_coverTask) {
emit askGenerateCover( QPrivateSignal() );
}
return m_cover;
}
void MLGenre::setCover(QString cover)
{
m_cover = cover;
//TODO store in media library
}
void MLGenre::generateThumbnail()
void MLGenre::setCover(const QString & fileName)
{
if (!m_coverTask && m_cover.isNull()) {
QDir dir(config_GetUserDir(VLC_CACHE_DIR));
dir.mkdir("art");
dir.cd("art");
dir.mkdir("qt-genre-covers");
dir.cd("qt-genre-covers");
QString filename = QString("genre_thumbnail_%1.jpg").arg(getId().id);
QString absoluteFilePath = dir.absoluteFilePath(filename);
if (dir.exists(filename))
{
setCover(QUrl::fromLocalFile(absoluteFilePath).toString());
}
else
{
GenerateCoverTask* coverTask = new GenerateCoverTask(m_ml, this, absoluteFilePath);
coverTask->setAutoDelete(false);
m_coverTask = coverTask;
QThreadPool::globalInstance()->start(coverTask);
}
}
m_cover = fileName;
}
......@@ -22,33 +22,26 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "vlc_common.h"
#include <memory>
#include <QObject>
#include <QString>
#include <QList>
#include <QRunnable>
#include <vlc_media_library.h>
#include "mlhelper.hpp"
// Util includes
#include "util/covergenerator.hpp"
// MediaLibrary includes
#include "mlqmltypes.hpp"
class MLGenre : public QObject, public MLItem
class MLGenre : public MLItem
{
Q_OBJECT
public:
MLGenre( vlc_medialibrary_t* _ml, const vlc_ml_genre_t *_data, QObject *_parent = nullptr);
~MLGenre();
MLGenre( vlc_medialibrary_t* _ml, const vlc_ml_genre_t *_data );
bool hasGenerator() const;
void setGenerator(CoverGenerator * generator);
QString getName() const;
unsigned int getNbTracks() const;
QString getCover() const;
void setCover(QString cover);
signals:
void askGenerateCover( QPrivateSignal ) const;
QString getCover() const;
void setCover(const QString & fileName);
private slots:
void generateThumbnail();
......@@ -56,9 +49,11 @@ private slots:
private:
vlc_medialibrary_t* m_ml;
TaskHandle<CoverGenerator> m_generator;
QString m_name;
QString m_cover;
QRunnable* m_coverTask = nullptr;
unsigned int m_nbTracks;
};
......
......@@ -18,8 +18,25 @@
#include "mlgenremodel.hpp"
// Util includes
#include "util/covergenerator.hpp"
// MediaLibrary includes
#include "mlartistmodel.hpp"
//-------------------------------------------------------------------------------------------------
// Static variables
// NOTE: We multiply by 2 to cover most dpi settings.
static const int MLGENREMODEL_COVER_WIDTH = 260 * 2;
static const int MLGENREMODEL_COVER_HEIGHT = 130 * 2;
static const int MLGENREMODEL_COVER_COUNTX = 4;
static const int MLGENREMODEL_COVER_COUNTY = 2;
static const int MLGENREMODEL_COVER_BLUR = 4;
//-------------------------------------------------------------------------------------------------
QHash<QByteArray, vlc_ml_sorting_criteria_t> MLGenreModel::M_names_to_criteria = {
{"title", VLC_ML_SORTING_ALPHA}
......@@ -32,10 +49,12 @@ MLGenreModel::MLGenreModel(QObject *parent)
QVariant MLGenreModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0)
int row = index.row();
if (!index.isValid() || row < 0)
return QVariant();
const MLGenre* ml_genre = static_cast<MLGenre *>(item(index.row()));
MLGenre* ml_genre = static_cast<MLGenre *>(item(row));
if (!ml_genre)
return QVariant();
......@@ -49,7 +68,7 @@ QVariant MLGenreModel::data(const QModelIndex &index, int role) const
case GENRE_NB_TRACKS:
return QVariant::fromValue( ml_genre->getNbTracks() );
case GENRE_COVER:
return QVariant::fromValue( ml_genre->getCover() );
return getCover(ml_genre, row);
default :
return QVariant();
}
......@@ -102,6 +121,72 @@ vlc_ml_sorting_criteria_t MLGenreModel::nameToCriteria(QByteArray name) const
return M_names_to_criteria.value(name, VLC_ML_SORTING_DEFAULT);
}
QString MLGenreModel::getCover(MLGenre * genre, int index) const
{
QString cover = genre->getCover();
// NOTE: Making sure we're not already generating a cover.
if (cover.isNull() == false || genre->hasGenerator())
return cover;
CoverGenerator * generator = new CoverGenerator(m_ml, genre->getId(), index);
generator->setSize(QSize(MLGENREMODEL_COVER_WIDTH,
MLGENREMODEL_COVER_HEIGHT));
generator->setCountX(MLGENREMODEL_COVER_COUNTX);
generator->setCountY(MLGENREMODEL_COVER_COUNTY);
generator->setSplit(CoverGenerator::Duplicate);
generator->setBlur(MLGENREMODEL_COVER_BLUR);
generator->setDefaultThumbnail(":/noart_album.svg");
// NOTE: We'll apply the new cover once it's loaded.
connect(generator, &CoverGenerator::result, this, &MLGenreModel::onCover);
generator->start(*QThreadPool::globalInstance());
genre->setGenerator(generator);
return cover;
}
//-------------------------------------------------------------------------------------------------
// Private slots
//-------------------------------------------------------------------------------------------------
void MLGenreModel::onCover()
{
CoverGenerator * generator = static_cast<CoverGenerator *> (sender());
int index = generator->getIndex();
// NOTE: We want to avoid calling 'MLBaseModel::item' for performance issues.
MLItem * item = this->itemCache(index);
// NOTE: When the item is no longer cached or has been moved we return right away.
if (item == nullptr || item->getId() != generator->getId())
{
generator->deleteLater();
return;
}
MLGenre * genre = static_cast<MLGenre *> (item);
QString fileName = QUrl::fromLocalFile(generator->takeResult()).toString();
genre->setCover(fileName);
genre->setGenerator(nullptr);
thumbnailUpdated(index);
}
//-------------------------------------------------------------------------------------------------
ListCacheLoader<std::unique_ptr<MLItem>> *
MLGenreModel::createLoader() const
{
......
......@@ -60,15 +60,21 @@ private:
vlc_ml_sorting_criteria_t roleToCriteria(int role) const override;
vlc_ml_sorting_criteria_t nameToCriteria(QByteArray name) const override;
QString getCover(MLGenre * genre, int index) const;
static QHash<QByteArray, vlc_ml_sorting_criteria_t> M_names_to_criteria;
private slots:
void onCover();
private:
struct Loader : public BaseLoader
{
Loader(const MLGenreModel &model) : BaseLoader(model) {}
size_t count() const override;
std::vector<std::unique_ptr<MLItem>> load(size_t index, size_t count) const override;
};
private: // Variables
static QHash<QByteArray, vlc_ml_sorting_criteria_t> M_names_to_criteria;
};
......
......@@ -21,17 +21,16 @@
#include "mlgroup.hpp"
// VLC includes
#include <vlc_media_library.h>
#include "qt.hpp"
//-------------------------------------------------------------------------------------------------
// Ctor / dtor
//-------------------------------------------------------------------------------------------------
MLGroup::MLGroup(vlc_medialibrary_t * ml, const vlc_ml_group_t * data, QObject * parent)
: QObject(parent)
, MLItem(MLItemId(data->i_id, VLC_ML_PARENT_GROUP))
MLGroup::MLGroup(vlc_medialibrary_t * ml, const vlc_ml_group_t * data)
: MLItem(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)
......@@ -44,16 +43,37 @@ MLGroup::MLGroup(vlc_medialibrary_t * ml, const vlc_ml_group_t * data, QObject *
// 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;
}
QString MLGroup::getThumbnail()
//-------------------------------------------------------------------------------------------------
QString MLGroup::getCover() const
{
return QString();
return m_cover;
}
void MLGroup::setCover(const QString & fileName)
{
m_cover = fileName;
}
//-------------------------------------------------------------------------------------------------
int64_t MLGroup::getDuration() const
{
return m_duration;
......
......@@ -25,23 +25,25 @@
#include "config.h"
#endif
// Util includes
#include "util/covergenerator.hpp"
// MediaLibrary includes
#include "mlqmltypes.hpp"
// Qt includes
#include <QObject>
class MLGroup : public QObject, public MLItem
class MLGroup : public MLItem
{
Q_OBJECT
public:
MLGroup(vlc_medialibrary_t * ml, const vlc_ml_group_t * data, QObject * parent = nullptr);
MLGroup(vlc_medialibrary_t * ml, const vlc_ml_group_t * data);
public: // Interface
bool hasGenerator() const;
void setGenerator(CoverGenerator * generator);
QString getName() const;
QString getThumbnail();
QString getCover() const;
void setCover(const QString & fileName);
int64_t getDuration() const;
......@@ -52,8 +54,12 @@ 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;
......
......@@ -27,6 +27,9 @@
// VLC includes
#include <vlc_media_library.h>
// Util includes
#include "util/covergenerator.hpp"
// MediaLibrary includes
#include "mlhelper.hpp"
#include "mlgroup.hpp"
......@@ -35,6 +38,10 @@
//-------------------------------------------------------------------------------------------------
// Static variables
// NOTE: We multiply by 2 to cover most dpi settings.
static const int MLGROUPLISTMODEL_COVER_WIDTH = 512 * 2; // 16 / 10 ratio
static const int MLGROUPLISTMODEL_COVER_HEIGHT = 320 * 2;
static const QHash<QByteArray, vlc_ml_sorting_criteria_t> criterias =
{
{"id", VLC_ML_SORTING_DEFAULT},
......@@ -85,8 +92,9 @@ QHash<int, QByteArray> MLGroupListModel::roleNames() const /* override */
QVariant MLGroupListModel::data(const QModelIndex & index, int role) const /* override */
{
int row = index.row();
MLItem * item = this->item(index.row());
MLItem * item = this->item(row);
if (item == nullptr)
return QVariant();
......@@ -109,7 +117,7 @@ QVariant MLGroupListModel::data(const QModelIndex & index, int role) const /* ov
case GROUP_NAME:
return QVariant::fromValue(group->getName());
case GROUP_THUMBNAIL:
return QVariant::fromValue(group->getThumbnail());
return getCover(group, row);
case GROUP_DURATION:
return QVariant::fromValue(group->getDuration());
case GROUP_DATE:
......@@ -207,6 +215,35 @@ ListCacheLoader<std::unique_ptr<MLItem>> * MLGroupListModel::createLoader() cons
return new Loader(*this);
}
//-------------------------------------------------------------------------------------------------
// Private functions
//-------------------------------------------------------------------------------------------------
QString MLGroupListModel::getCover(MLGroup * group, int index) const
{
QString cover = group->getCover();
// NOTE: Making sure we're not already generating a cover.
if (cover.isNull() == false || group->hasGenerator())
return cover;
CoverGenerator * generator = new CoverGenerator(m_ml, group->getId(), index);
generator->setSize(QSize(MLGROUPLISTMODEL_COVER_WIDTH,
MLGROUPLISTMODEL_COVER_HEIGHT));
generator->setDefaultThumbnail(":/noart_videoCover.svg");
// NOTE: We'll apply the new thumbnail once it's loaded.
connect(generator, &CoverGenerator::result, this, &MLGroupListModel::onCover);
generator->start(*QThreadPool::globalInstance());
group->setGenerator(generator);
return cover;
}
//-------------------------------------------------------------------------------------------------
// Private MLBaseModel reimplementation
//-------------------------------------------------------------------------------------------------
......@@ -230,7 +267,41 @@ void MLGroupListModel::onVlcMlEvent(const MLEvent & event) /* override */
void MLGroupListModel::thumbnailUpdated(int idx) /* override */
{
emit dataChanged(index(idx), index(idx), { GROUP_THUMBNAIL });
QModelIndex index = this->index(idx);
emit dataChanged(index, index, { GROUP_THUMBNAIL });
}
//-------------------------------------------------------------------------------------------------
// Private slots
//-------------------------------------------------------------------------------------------------
void MLGroupListModel::onCover()
{
CoverGenerator * generator = static_cast<CoverGenerator *> (sender());
int index = generator->getIndex();
// NOTE: We want to avoid calling 'MLBaseModel::item' for performance issues.
MLItem * item = this->itemCache(index);
// NOTE: When the item is no longer cached or has been moved we return right away.
if (item == nullptr || item->getId() != generator->getId())
{
generator->deleteLater();
return;
}
MLGroup * group = static_cast<MLGroup *> (item);
QString fileName = QUrl::fromLocalFile(generator->takeResult()).toString();
group->setCover(fileName);
group->setGenerator(nullptr);
thumbnailUpdated(index);
}
//=================================================================================================
......
......@@ -26,6 +26,7 @@
// Forward declarations
class vlc_medialibrary_t;
class MLGroup;
class MLGroupListModel : public MLBaseModel
{
......@@ -72,11 +73,17 @@ protected: // MLBaseModel implementation
ListCacheLoader<std::unique_ptr<MLItem>> * createLoader() const override;
private: // Functions
QString getCover(MLGroup * group, int index) const;
private: // MLBaseModel implementation
void onVlcMlEvent(const MLEvent & event) override;
void thumbnailUpdated(int idx) override;
private slots:
void onCover();
private:
struct Loader : public MLBaseModel::BaseLoader
{
......
......@@ -187,6 +187,18 @@ Widgets.NavigableFocusScope {
}
pictureOverlay: Item {
Rectangle
{
anchors.fill: parent
radius: VLCStyle.gridCover_radius
gradient: Gradient {
GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, 0.3) }
GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.7) }
}
}
Column {
anchors.centerIn: parent
......
/*****************************************************************************
* 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 "covergenerator.hpp"
// VLC includes
#include "qt.hpp"
// MediaLibrary includes
#include "medialibrary/mlhelper.hpp"
// Qt includes
#include <QDir>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QGraphicsBlurEffect>
//-------------------------------------------------------------------------------------------------
// Static variables
static const QString COVERGENERATOR_STORAGE = "/art/qt-covers";
static const int COVERGENERATOR_COUNT = 2;
static const QString COVERGENERATOR_DEFAULT = ":/noart.png";
//-------------------------------------------------------------------------------------------------
// Ctor / dtor
//-------------------------------------------------------------------------------------------------
CoverGenerator::CoverGenerator(vlc_medialibrary_t * ml, const MLItemId & itemId, int index)
: m_ml(ml)
, m_id(itemId)
, m_index(index)
, m_countX(COVERGENERATOR_COUNT)
, m_countY(COVERGENERATOR_COUNT)
, m_split(Divide)
, m_smooth(false)
, m_blur(0)
, m_default(COVERGENERATOR_DEFAULT) {}
//-------------------------------------------------------------------------------------------------
// Interface
//-------------------------------------------------------------------------------------------------
/* Q_INVOKABLE */ MLItemId CoverGenerator::getId()
{
return m_id;
}
/* Q_INVOKABLE */ int CoverGenerator::getIndex()
{
return m_index;
}
//-------------------------------------------------------------------------------------------------
/* Q_INVOKABLE */ void CoverGenerator::setSize(const QSize & size)
{
m_size = size;
}
/* Q_INVOKABLE */ void CoverGenerator::setCountX(int x)
{
m_countX = x;
}
/* Q_INVOKABLE */ void CoverGenerator::setCountY(int y)
{
m_countY = y;
}
/* Q_INVOKABLE */ void CoverGenerator::setSplit(Split split)
{
m_split = split;
}
/* Q_INVOKABLE */ void CoverGenerator::setSmooth(bool enabled)
{
m_smooth = enabled;
}
/* Q_INVOKABLE */ void CoverGenerator::setBlur(int radius)
{
m_blur = radius;
}
/* Q_INVOKABLE */ void CoverGenerator::setDefaultThumbnail(const QString & fileName)
{
m_default = fileName;
}
//-------------------------------------------------------------------------------------------------
// QRunnable implementation
//-------------------------------------------------------------------------------------------------
QString CoverGenerator::execute() /* override */
{
QDir dir(config_GetUserDir(VLC_CACHE_DIR) + COVERGENERATOR_STORAGE);
dir.mkpath(dir.absolutePath());
vlc_ml_parent_type type = m_id.type;
int64_t id = m_id.id;
QString string = getStringType(type);
QString fileName = QString("%1_thumbnail_%2.jpg").arg(string).arg(id);
fileName = dir.absoluteFilePath(fileName);
if (dir.exists(fileName))
{
return fileName;
}
QStringList thumbnails;
int count = m_countX * m_countY;
if (type == VLC_ML_PARENT_GENRE)
thumbnails = getGenre(count, id);
else
thumbnails = getMedias(count, id, type);
if (thumbnails.isEmpty())
{
if (m_split == CoverGenerator::Duplicate)
{
while (thumbnails.count() != count)
{
thumbnails.append(m_default);
}
}
else
{
thumbnails.append(m_default);
m_countX = 1;
m_countY = 1;
}
}
else if (m_split == CoverGenerator::Duplicate)
{
int index = 0;
while (thumbnails.count() != count)
{
thumbnails.append(thumbnails.at(index));
index++;
}
}
else // if (m_split == CoverGenerator::Divide)
{
// NOTE: This handles the 2x2 case.
if (thumbnails.count() == 2)
{
m_countX = 2;
m_countY = 1;
}
}
QImage image(m_size, QImage::Format_RGB32);
image.fill(Qt::white);
QPainter painter;
painter.begin(&image);
draw(painter, thumbnails);
painter.end();
if (m_blur > 0)
blur(&image);
image.save(fileName, "jpg");
return fileName;
}
//-------------------------------------------------------------------------------------------------
// Private functions
//-------------------------------------------------------------------------------------------------
void CoverGenerator::draw(QPainter & painter, const QStringList & fileNames)
{
int count = fileNames.count();
int width = m_size.width() / m_countX;
int height = m_size.height() / m_countY;
for (int y = 0; y < m_countY; y++)
{
for (int x = 0; x < m_countX; x++)
{
int index = m_countX * y + x;
if (index == count) return;
QRect rect;
// NOTE: This handles the wider thumbnail case (e.g. for a 2x1 grid).
if (index == count - 1 && x != m_countX - 1)
{
rect = QRect(width * x, height * y, width * m_countX - x, height);
}
else
rect = QRect(width * x, height * y, width, height);
drawImage(painter, fileNames.at(index), rect);
}
}
}
void CoverGenerator::drawImage(QPainter & painter, const QString & fileName, const QRect & target)
{
QImage image;
if (fileName.isEmpty())
image.load(m_default);
else
image.load(fileName);
// NOTE: This image does not seem valid so we paint the placeholder instead.
if (image.isNull())
{
image.load(m_default);
}
// NOTE: Should we use Qt::SmoothTransformation or favor efficiency ?
if (m_smooth)
image = image.scaled(target.size(), Qt::KeepAspectRatioByExpanding,
Qt::SmoothTransformation);
else
image = image.scaled(target.size(), Qt::KeepAspectRatioByExpanding);
int x = (image.width () - target.width ()) / 2;
int y = (image.height() - target.height()) / 2;
QRect source(x, y, target.width(), target.height());
painter.drawImage(target, image, source);
}
//-------------------------------------------------------------------------------------------------
// FIXME: This implementation is not ideal and uses a dedicated QGraphicsScene.
void CoverGenerator::blur(QImage * image)
{
assert(image);
QGraphicsScene scene;
QGraphicsPixmapItem item(QPixmap::fromImage(*image));
QGraphicsBlurEffect effect;
effect.setBlurRadius(m_blur);
effect.setBlurHints(QGraphicsBlurEffect::QualityHint);
item.setGraphicsEffect(&effect);
scene.addItem(&item);
QImage result(image->size(), QImage::Format_ARGB32);
QPainter painter(&result);
scene.render(&painter);
*image = result;
}
//-------------------------------------------------------------------------------------------------
QString CoverGenerator::getStringType(vlc_ml_parent_type type) const
{
switch (type)
{
case VLC_ML_PARENT_GENRE:
return "genre";
case VLC_ML_PARENT_GROUP:
return "group";
case VLC_ML_PARENT_PLAYLIST:
return "playlist";
default:
return "unknown";
}
}
//-------------------------------------------------------------------------------------------------
QStringList CoverGenerator::getGenre(int count, int64_t id) const
{
QStringList thumbnails;
vlc_ml_query_params_t params;
memset(&params, 0, sizeof(vlc_ml_query_params_t));
// NOTE: We retrieve twice the count to maximize our chances to get a valid thumbnail.
params.i_nbResults = count * 2;
ml_unique_ptr<vlc_ml_album_list_t> list(vlc_ml_list_genre_albums(m_ml, &params, id));
for (const vlc_ml_album_t & album : ml_range_iterate<vlc_ml_album_t>(list))
{
if (album.thumbnails[VLC_ML_THUMBNAIL_SMALL].i_status != VLC_ML_THUMBNAIL_STATUS_AVAILABLE)
continue;
QUrl url(album.thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl);
// NOTE: We only want local files to compose the cover.
if (url.isLocalFile() == false)
continue;
thumbnails.append(url.path());
if (thumbnails.count() == count)
return thumbnails;
}
return thumbnails;
}
QStringList CoverGenerator::getMedias(int count, int64_t id, vlc_ml_parent_type type) const
{
QStringList thumbnails;
vlc_ml_query_params_t params;
memset(&params, 0, sizeof(vlc_ml_query_params_t));
// NOTE: We retrieve twice the count to maximize our chances to get a valid thumbnail.
params.i_nbResults = count * 2;
ml_unique_ptr<vlc_ml_media_list_t> list(vlc_ml_list_media_of(m_ml, &params, type, id));
for (const vlc_ml_media_t & media : ml_range_iterate<vlc_ml_media_t>(list))
{
if (media.thumbnails[VLC_ML_THUMBNAIL_SMALL].i_status != VLC_ML_THUMBNAIL_STATUS_AVAILABLE)
continue;
QUrl url(media.thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl);
// NOTE: We only want local files to compose the cover.
if (url.isLocalFile() == false)
continue;
thumbnails.append(url.path());
if (thumbnails.count() == count)
return thumbnails;
}
return thumbnails;
}
/*****************************************************************************
* 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 COVERGENERATOR_HPP
#define COVERGENERATOR_HPP
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
// MediaLibrary includes
#include "medialibrary/mlqmltypes.hpp"
// Util includes
#include "util/asynctask.hpp"
// Qt includes
#include <QPainter>
// Forward declarations
class vlc_medialibrary_t;
class MLItemId;
class CoverGenerator : public AsyncTask<QString>
{
Q_OBJECT
Q_ENUMS(Split)
public: // Enums
enum Split
{
Divide,
Duplicate
};
public:
CoverGenerator(vlc_medialibrary_t * ml, const MLItemId & itemId, int index = -1);
public: // Interface
Q_INVOKABLE MLItemId getId();
Q_INVOKABLE int getIndex();
Q_INVOKABLE void setSize(const QSize & size);
Q_INVOKABLE void setCountX(int x);
Q_INVOKABLE void setCountY(int y);
// NOTE: Do we want to divide or duplicate thumbnails to reach the proper count ?
Q_INVOKABLE void setSplit(Split split);
// NOTE: Applies SmoothTransformation to thumbnails. Disabled by default.
Q_INVOKABLE void setSmooth(bool enabled);
// NOTE: You need to specify a radius to enable blur, 8 looks good.
Q_INVOKABLE void setBlur(int radius);
Q_INVOKABLE void setDefaultThumbnail(const QString & fileName);
public: // AsyncTask implementation
QString execute() override;
private: // Functions
void draw(QPainter & painter, const QStringList & fileNames);
void drawImage(QPainter & painter, const QString & fileName, const QRect & rect);
void blur(QImage * image);
QString getStringType(vlc_ml_parent_type type) const;
QStringList getMedias(int count, int64_t id, vlc_ml_parent_type type) const;
QStringList getGenre (int count, int64_t id) const;
private:
vlc_medialibrary_t * m_ml;
MLItemId m_id;
int m_index;
QSize m_size;
int m_countX;
int m_countY;
Split m_split;
bool m_smooth;
int m_blur;
QString m_default;
};
#endif // COVERGENERATOR_HPP
......@@ -791,6 +791,8 @@ modules/gui/qt/widgets/native/animators.cpp
modules/gui/qt/widgets/native/animators.hpp
modules/gui/qt/widgets/native/customwidgets.cpp
modules/gui/qt/widgets/native/customwidgets.hpp
modules/gui/qt/util/covergenerator.cpp
modules/gui/qt/util/covergenerator.hpp
modules/gui/qt/util/imagehelper.cpp
modules/gui/qt/util/imagehelper.hpp
modules/gui/qt/util/qt_dirs.cpp
......