MythTV  master
imagemanager.cpp
Go to the documentation of this file.
1 #include "imagemanager.h"
2 
3 #include <QImageReader>
4 #include <QRunnable>
5 #include <utility>
6 
7 #include "dbaccess.h" // for FileAssociations
8 #include "mthreadpool.h"
9 #include "mythdate.h"
10 #include "mythmediamonitor.h"
11 
12 
13 #define LOC QString("ImageManager: ")
14 #define DBLOC QString("ImageDb(%1): ").arg(m_table)
15 
16 // Must be empty as it's prepended to path
17 #define STORAGE_GROUP_MOUNT ""
18 
19 #define DB_TABLE "gallery_files"
20 
21 #define RESULT_ERR(ERR, MESG) \
22 { LOG(VB_GENERAL, LOG_ERR, LOC + (MESG)); \
23  return QStringList("ERROR") << (ERR); }
24 
25 #define RESULT_OK(MESG) \
26 { LOG(VB_FILE, LOG_DEBUG, LOC + (MESG)); \
27  return QStringList("OK"); }
28 
29 #define IMPORTDIR "Import"
30 
31 
33 class Device
34 {
35 public:
36  Device(QString name, QString mount,
37  MythMediaDevice *media = nullptr, QTemporaryDir *import = nullptr)
38  : m_present(true), m_name(std::move(name)), m_mount(std::move(mount)),
39  m_media(media), m_dir(import)
40  {
41  // Path relative to TEMP storage group
42  m_thumbs = QString("%1/%2").arg(THUMBNAIL_SUBDIR, m_name);
43  }
44 
45 
48  {
49  Close();
50 
51  // Remove imported images
52  delete m_dir;
53 
54  // Clean up non-SG thumbnails
56  RemoveThumbs();
57  }
58 
59 
61  void Close(bool eject = false)
62  {
63  // Imports remain present; others do not
64  m_present = isImport();
65 
66  // Release device
67  if (m_media)
68  {
69  if (eject)
70  {
71  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Ejecting '%1' at '%2'")
72  .arg(m_name, m_mount));
74  }
75  else
76  LOG(VB_MEDIA, LOG_DEBUG, LOC + QString("Unlocked '%1'").arg(m_name));
77 
79  m_media = nullptr;
80  }
81  }
82 
83 
88  static void RemoveDirContents(const QString& path)
89  {
90  QDir(path).removeRecursively();
91  }
92 
93 
95  void RemoveThumbs(void) const
96  {
97  // Remove thumbnails
98  QString dir = QString("%1/" TEMP_SUBDIR "/%2").arg(GetConfDir(), m_thumbs);
99  LOG(VB_FILE, LOG_INFO, LOC + QString("Removing thumbnails in %1").arg(dir));
101  QDir::root().rmpath(dir);
102  }
103 
104 
105  bool isImport() const { return m_dir; }
106  bool isPresent() const { return m_present; }
107  void setPresent(MythMediaDevice *media) { m_present = true; m_media = media; }
108 
110  bool m_present;
111  QString m_name;
112  QString m_mount;
113  QString m_thumbs;
115  QTemporaryDir *m_dir;
116 };
117 
118 
119 static Device kNullDevice = Device("Unknown Device", "<Invalid Path>");
120 
121 
123 {
124  qDeleteAll(m_devices);
125 }
126 
127 
129 QString DeviceManager::DeviceMount(int devId) const
130 {
131  return m_devices.value(devId, &kNullDevice)->m_mount;
132 }
133 
134 
136 QString DeviceManager::DeviceName(int devId) const
137 {
138  return m_devices.value(devId, &kNullDevice)->m_name;
139 }
140 
141 
142 QString DeviceManager::ThumbDir(int fs) const
143 {
144  return m_devices.value(fs, &kNullDevice)->m_thumbs;
145 }
146 
147 
157 int DeviceManager::OpenDevice(const QString &name, const QString &mount,
158  MythMediaDevice *media, QTemporaryDir *dir)
159 {
160  // Handle devices reappearing at same mountpoint.
161  // If a USB is unplugged whilst in use (without unmounting) we get no event
162  // but we do when it's re-inserted
163  QString state("Known");
164  int id = LocateMount(mount);
165 
166  if (id == DEVICE_INVALID)
167  {
168  state = "New";
169  id = m_devices.isEmpty() ? 0 : (m_devices.constEnd() - 1).key() + 1;
170  m_devices.insert(id, new Device(name, mount, media, dir));
171  }
172  else if (m_devices.value(id))
173  m_devices.value(id)->setPresent(media);
174 
175  LOG(VB_GENERAL, LOG_INFO, LOC +
176  QString("%1 device %2 mounted at '%3' [Id %4]")
177  .arg(state, name, mount).arg(id));
178 
179  return id;
180 }
181 
182 
189 QStringList DeviceManager::CloseDevices(int devId, const QString &action)
190 {
191  QStringList clear;
192 
193  if (action == "DEVICE CLOSE ALL")
194  {
195  // Close all devices but retain their thumbnails
196  for (auto *dev : qAsConst(m_devices))
197  if (dev)
198  dev->Close();
199  }
200  else if (action == "DEVICE CLEAR ALL")
201  {
202  // Remove all thumbnails but retain devices
203  for (const auto *dev : qAsConst(m_devices)) {
204  if (dev)
205  {
206  clear << dev->m_mount;
207  dev->RemoveThumbs();
208  }
209  }
210  }
211  else
212  {
213  // Remove single device & its thumbnails, optionally ejecting it
214  Device *dev = m_devices.take(devId);
215  if (dev)
216  {
217  if (action == "DEVICE EJECT")
218  dev->Close(true);
219  clear << dev->m_mount;
220  delete dev;
221  }
222  }
223  return clear;
224 }
225 
226 
232 int DeviceManager::LocateMount(const QString &mount) const
233 {
234  DeviceMap::const_iterator it = m_devices.constBegin();
235  while (it != m_devices.constEnd())
236  {
237  if (it.value()->m_mount == mount)
238  return it.key();
239  ++it;
240  }
241  return DEVICE_INVALID;
242 }
243 
244 
247 {
249  for (int id : m_devices.keys())
250  {
251  Device *dev = m_devices.value(id);
252  if (dev)
253  paths.insert(id, dev->m_mount);
254  }
255  return paths;
256 }
257 
258 
261 {
262  QList<int> absent;
263  for (int id : m_devices.keys())
264  {
265  Device *dev = m_devices.value(id);
266  if (dev && !dev->isPresent())
267  absent << id;
268  }
269  return absent;
270 }
271 
272 
277  m_imageFileExt(SupportedImages()),
278  m_videoFileExt(SupportedVideos())
279 {
280  // Generate glob list from supported extensions
281  QStringList glob;
282  for (const auto& ext : (m_imageFileExt + m_videoFileExt))
283  glob << "*." + ext;
284 
285  // Apply filters to only detect image files
286  m_dirFilter.setNameFilters(glob);
287  m_dirFilter.setFilter(QDir::AllDirs | QDir::Files | QDir::Readable |
288  QDir::NoDotAndDotDot | QDir::NoSymLinks);
289 
290  // Sync files before dirs to improve thumb generation response
291  // Order by time (oldest first) - this determines the order thumbs appear
292  m_dirFilter.setSorting(QDir::DirsLast | QDir::Time | QDir::Reversed);
293 }
294 
300 {
301  // Determine supported picture formats from Qt
302  QStringList formats;
303  for (const auto& ext : QImageReader::supportedImageFormats())
304  formats << QString(ext);
305  return formats;
306 }
307 
308 
314 {
315  // Determine supported video formats from MythVideo
316  QStringList formats;
319  for (const auto & fa : faList)
320  {
321  if (!fa.use_default && fa.playcommand == "Internal")
322  formats << QString(fa.extension);
323  }
324  return formats;
325 }
326 
327 
336 ImageItem *ImageAdapterLocal::CreateItem(const QFileInfo &fi, int parentId,
337  int devId, const QString & /*base*/) const
338 {
339  auto *im = new ImageItem();
340 
341  im->m_parentId = parentId;
342  im->m_device = devId;
343  im->m_filePath = fi.absoluteFilePath();
344 
345  if (parentId == GALLERY_DB_ID)
346  {
347  // Import devices show time of import, other devices show 'last scan time'
348  im->m_date = im->m_filePath.contains(IMPORTDIR)
349  ? fi.lastModified().toSecsSinceEpoch()
350  : QDateTime::currentSecsSinceEpoch();
351  im->m_modTime = im->m_date;
352  im->m_type = kDevice;
353  return im;
354  }
355 
356  im->m_modTime = fi.lastModified().toSecsSinceEpoch();
357 
358  if (fi.isDir())
359  {
360  im->m_type = kDirectory;
361  return im;
362  }
363 
364  im->m_extension = fi.suffix().toLower();
365  im->m_type = GetImageType(im->m_extension);
366 
367  if (im->m_type == kUnknown)
368  {
369  delete im;
370  return nullptr;
371  }
372 
373  im->m_thumbPath = GetAbsThumbPath(ThumbDir(im->m_device), ThumbPath(*im));
374  im->m_size = fi.size();
375 
376  return im;
377 }
378 
379 
385 void ImageAdapterLocal::Notify(const QString &mesg,
386  const QStringList &extra)
387 {
388  QString host(gCoreContext->GetHostName());
389  gCoreContext->SendEvent(MythEvent(QString("%1 %2").arg(mesg, host), extra));
390 }
391 
392 
401 ImageItem *ImageAdapterSg::CreateItem(const QFileInfo &fi, int parentId,
402  int /*devId*/, const QString &base) const
403 {
404  auto *im = new ImageItem();
405 
406  im->m_device = 0;
407  im->m_parentId = parentId;
408 
409  if (parentId == GALLERY_DB_ID)
410  {
411  // All SG dirs map to a single Db dir
412  im->m_filePath = "";
413  im->m_type = kDevice;
414  im->m_date = QDateTime::currentMSecsSinceEpoch() / 1000;
415  im->m_modTime = im->m_date;
416  return im;
417  }
418 
419  // Strip SG path & leading / to leave a relative path
420  im->m_filePath = fi.absoluteFilePath().mid(base.size() + 1);
421  im->m_modTime = fi.lastModified().toSecsSinceEpoch();
422 
423  if (fi.isDir())
424  {
425  im->m_type = kDirectory;
426  return im;
427  }
428 
429  im->m_extension = fi.suffix().toLower();
430  im->m_type = GetImageType(im->m_extension);
431 
432  if (im->m_type == kUnknown)
433  {
434  delete im;
435  return nullptr;
436  }
437 
438  im->m_thumbPath = GetAbsThumbPath(ThumbDir(im->m_device), ThumbPath(*im));
439  im->m_size = fi.size();
440 
441  return im;
442 }
443 
444 
450 void ImageAdapterSg::Notify(const QString &mesg,
451  const QStringList &extra)
452 {
453  gCoreContext->SendEvent(MythEvent(mesg, extra));
454 }
455 
456 
462 {
463  StringMap map;
464  int i = 0;
465  for (const auto& path : m_sg.GetDirList())
466  map.insert(i++, path);
467  return map;
468 }
469 
470 
478 {
479  if (im->IsDevice())
480  return m_sg.FindNextDirMostFree();
481  return im->m_filePath.startsWith("/") ? im->m_filePath
482  : m_sg.FindFile(im->m_filePath);
483 }
484 
485 
486 // Database fields used by several image queries
487 #define DB_COLUMNS \
488 "file_id, filename, name, dir_id, type, modtime, size, " \
489 "extension, date, hidden, orientation, angle, path, zoom"
490 // Id, filepath, basename, parentId, type, modtime, size,
491 // extension, image date, hidden, orientation, cover id, comment, device id
492 
493 
499 template <class FS>
501 {
502  auto *im = new ImageItem(FS::ImageId(query.value(0).toInt()));
503 
504  // Ordered as per DB_COLUMNS
505  im->m_filePath = query.value(1).toString();
506  im->m_baseName = query.value(2).toString();
507  im->m_parentId = FS::ImageId(query.value(3).toInt());
508  im->m_type = query.value(4).toInt();
509  im->m_modTime = query.value(5).toInt();
510  im->m_size = query.value(6).toInt();
511  im->m_extension = query.value(7).toString();
512  im->m_date = query.value(8).toUInt();
513  im->m_isHidden = query.value(9).toBool();
514  im->m_orientation = query.value(10).toInt();
515  im->m_userThumbnail = FS::ImageId(query.value(11).toInt());
516  im->m_comment = query.value(12).toString();
517  im->m_device = query.value(13).toInt();
518  im->m_url = FS::MakeFileUrl(im->m_filePath);
519 
520  if (im->IsFile())
521  {
522  // Only pics/vids have thumbs
523  QString thumbPath(FS::ThumbPath(*im));
524  QString devPath(FS::ThumbDir(im->m_device));
525  QString url(FS::MakeThumbUrl(devPath, thumbPath));
526 
527  im->m_thumbPath = FS::GetAbsThumbPath(devPath, thumbPath);
528  im->m_thumbNails.append(qMakePair(im->m_id, url));
529  }
530  return im;
531 }
532 
533 
542 template <class FS>
543 int ImageDb<FS>::GetImages(const QString &ids, ImageList &files, ImageList &dirs,
544  const QString &refine) const
545 {
546  if (ids.isEmpty())
547  return 0;
548 
549  QString select = QString("file_id IN (%1) %2").arg(FS::DbIds(ids), refine);
550  return ReadImages(dirs, files, select);
551 }
552 
553 
562 template <class FS>
563 int ImageDb<FS>::GetChildren(QString ids, ImageList &files, ImageList &dirs,
564  const QString &refine) const
565 {
566  QString select = QString("dir_id IN (%1) %2").arg(FS::DbIds(ids), refine);
567  return ReadImages(dirs, files, select);
568 }
569 
570 
580 template <class FS>
582  ImageList &files, ImageList &dirs,
583  const QString &refine) const
584 {
586  query.prepare(QString("SELECT " DB_COLUMNS " FROM %1 "
587  "WHERE (dir_id = :ID1 OR file_id = :ID2) "
588  "%2;").arg(m_table, refine));
589 
590  // Qt < 5.4 won't bind multiple occurrences
591  int dbId = FS::DbId(id);
592  query.bindValue(":ID1", dbId);
593  query.bindValue(":ID2", dbId);
594 
595  if (!query.exec())
596  {
598  return -1;
599  }
600  while (query.next())
601  {
602  ImagePtr im(CreateImage(query));
603 
604  if (im->IsFile())
605  files.append(im);
606  else if (im->m_id == id)
607  parent = im;
608  else
609  dirs.append(im);
610  }
611  return query.size();
612 }
613 
614 
622 template <class FS>
623 bool ImageDb<FS>::GetDescendants(const QString &ids,
624  ImageList &files, ImageList &dirs) const
625 {
626  if (ids.isEmpty())
627  return false;
628 
629  if (ReadImages(dirs, files, QString("file_id IN (%1)").arg(FS::DbIds(ids))) < 0)
630  return false;
631 
633  QString sql =
634  QString("SELECT " DB_COLUMNS
635  ", LENGTH(filename) - LENGTH(REPLACE(filename, '/', ''))"
636  " AS depth "
637  "FROM %1 WHERE filename LIKE :PREFIX "
638  "ORDER BY depth;").arg(m_table);
639 
640  for (const auto& im1 : qAsConst(dirs))
641  {
642  query.prepare(sql);
643  query.bindValue(":PREFIX", im1->m_filePath + "/%");
644 
645  if (!query.exec())
646  {
648  return false;
649  }
650 
651  while (query.next())
652  {
653  ImagePtr im2(CreateImage(query));
654  if (im2->IsDirectory())
655  dirs.append(im2);
656  else
657  files.append(im2);
658  }
659  }
660  return true;
661 }
662 
663 
671 template <class FS>
672 bool ImageDb<FS>::GetImageTree(int id, ImageList &files, const QString &refine) const
673 {
674  // Load starting children
675  ImageList dirs;
676  if (GetChildren(QString::number(id), files, dirs, refine) < 0)
677  return false;
678 
679  for (const auto& im : qAsConst(dirs))
680  if (!GetImageTree(im->m_id, files, refine))
681  return false;
682  return true;
683 }
684 
685 
691 template <class FS>
693 {
695  query.prepare(QString("SELECT " DB_COLUMNS " FROM %1").arg(m_table));
696 
697  if (!query.exec())
698  {
700  return false;
701  }
702 
703  while (query.next())
704  {
705  ImagePtr im(CreateImage(query));
706  if (im->IsDirectory())
707  dirs.insert(im->m_filePath, im);
708  else
709  files.insert(im->m_filePath, im);
710  }
711  return true;
712 }
713 
714 
722 template <class FS>
723 void ImageDb<FS>::ClearDb(int devId, const QString &action)
724 {
725  if (action == "DEVICE CLOSE ALL")
726  // Retain Db images when closing UI
727  return;
728 
730 
731  if (action == "DEVICE CLEAR ALL")
732  {
733  // Clear images from all devices. Reset auto-increment
734  query.prepare(QString("TRUNCATE TABLE %1;").arg(m_table));
735 
736  if (!query.exec())
738  }
739  else // Actions DEVICE REMOVE & DEVICE EJECT
740  {
741  // Delete all images of the device
742  query.prepare(QString("DELETE IGNORE FROM %1 WHERE zoom = :FS;").arg(m_table));
743  query.bindValue(":FS", devId);
744 
745  if (!query.exec())
747  }
748 }
749 
750 
758 template <class FS>
759 int ImageDb<FS>::InsertDbImage(ImageItemK &im, bool checkForDuplicate) const
760 {
762 
763  if (checkForDuplicate)
764  {
765  query.prepare(QString("SELECT file_id FROM %1 WHERE filename = :NAME;")
766  .arg(m_table));
767 
768  query.bindValue(":NAME", im.m_filePath);
769 
770  if (!query.exec())
771  {
773  return -1;
774  }
775 
776  if (query.size() > 0)
777  {
778  LOG(VB_FILE, LOG_DEBUG, QString("Image: %1 already exists in Db")
779  .arg(im.m_filePath));
780  return query.value(0).toInt();
781  }
782  }
783 
784  query.prepare(QString("INSERT INTO %1 (" DB_COLUMNS ") VALUES (0, "
785  ":FILEPATH, :NAME, :PARENT, :TYPE, :MODTIME, "
786  ":SIZE, :EXTENSION, :DATE, :HIDDEN, :ORIENT, "
787  ":COVER, :COMMENT, :FS);").arg(m_table));
788 
789  query.bindValue(":FILEPATH", im.m_filePath);
790  query.bindValue(":NAME", FS::BaseNameOf(im.m_filePath));
791  query.bindValue(":FS", im.m_device);
792  query.bindValue(":PARENT", FS::DbId(im.m_parentId));
793  query.bindValue(":TYPE", im.m_type);
794  query.bindValue(":MODTIME", im.m_modTime);
795  query.bindValue(":SIZE", im.m_size);
796  query.bindValue(":EXTENSION", im.m_extension);
797  query.bindValue(":DATE", im.m_date);
798  query.bindValue(":ORIENT", im.m_orientation);
799  query.bindValue(":COMMENT", im.m_comment.isNull() ? "" : im.m_comment);
800  query.bindValue(":HIDDEN", im.m_isHidden);
801  query.bindValue(":COVER", FS::DbId(im.m_userThumbnail));
802 
803  if (query.exec())
804  return FS::ImageId(query.lastInsertId().toInt());
805 
807  return -1;
808 }
809 
810 
816 template <class FS>
818 {
820  query.prepare(QString
821  ("UPDATE %1 SET "
822  "filename = :FILEPATH, name = :NAME, "
823  "dir_id = :PARENT, type = :TYPE, "
824  "modtime = :MODTIME, size = :SIZE, "
825  "extension = :EXTENSION, date = :DATE, zoom = :FS, "
826  "hidden = :HIDDEN, orientation = :ORIENT, "
827  "angle = :COVER, path = :COMMENT "
828  "WHERE file_id = :ID;").arg(m_table));
829 
830  query.bindValue(":ID", FS::DbId(im.m_id));
831  query.bindValue(":FILEPATH", im.m_filePath);
832  query.bindValue(":NAME", FS::BaseNameOf(im.m_filePath));
833  query.bindValue(":PARENT", FS::DbId(im.m_parentId));
834  query.bindValue(":TYPE", im.m_type);
835  query.bindValue(":MODTIME", im.m_modTime);
836  query.bindValue(":SIZE", im.m_size);
837  query.bindValue(":EXTENSION", im.m_extension);
838  query.bindValue(":DATE", im.m_date);
839  query.bindValue(":FS", im.m_device);
840  query.bindValue(":HIDDEN", im.m_isHidden);
841  query.bindValue(":ORIENT", im.m_orientation);
842  query.bindValue(":COVER", FS::DbId(im.m_userThumbnail));
843  query.bindValue(":COMMENT", im.m_comment.isNull() ? "" : im.m_comment);
844 
845  if (query.exec())
846  return true;
847 
849  return false;
850 }
851 
852 
859 template <class FS>
860 QStringList ImageDb<FS>::RemoveFromDB(const ImageList &imList) const
861 {
862  QStringList ids;
863  if (!imList.isEmpty())
864  {
865  for (const auto& im : qAsConst(imList))
866  ids << QString::number(FS::DbId(im->m_id));
867 
868  QString idents = ids.join(",");
870  query.prepare(QString("DELETE IGNORE FROM %1 WHERE file_id IN (%2);")
871  .arg(m_table, idents));
872 
873  if (!query.exec())
874  {
876  return QStringList();
877  }
878  }
879  return ids;
880 }
881 
882 
889 template <class FS>
890 bool ImageDb<FS>::SetHidden(bool hide, QString ids) const
891 {
892  if (ids.isEmpty())
893  return false;
894 
896 
897  query.prepare(QString("UPDATE %1 SET "
898  "hidden = :HIDDEN "
899  "WHERE file_id IN (%2);").arg(m_table, FS::DbIds(ids)));
900  query.bindValue(":HIDDEN", hide ? 1 : 0);
901 
902  if (query.exec())
903  return true;
904 
906  return false;
907 }
908 
909 
915 template <class FS>
916 bool ImageDb<FS>::SetCover(int dir, int id) const
917 {
919 
920  query.prepare(QString("UPDATE %1 SET "
921  "angle = :COVER "
922  "WHERE file_id = :DIR").arg(m_table));
923  query.bindValue(":COVER", FS::DbId(id));
924  query.bindValue(":DIR", FS::DbId(dir));
925  \
926  if (query.exec())
927  return true;
928 
930  return false;
931 }
932 
933 
939 template <class FS>
940 bool ImageDb<FS>::SetOrientation(int id, int orientation) const
941 {
943 
944  query.prepare(QString("UPDATE %1 SET ").arg(m_table) +
945  "orientation = :ORIENTATION "
946  "WHERE file_id = :ID");
947  query.bindValue(":ORIENTATION", orientation);
948  query.bindValue(":ID", FS::DbId(id));
949  \
950  if (query.exec())
951  return true;
952 
954  return false;
955 }
956 
957 
965 template <class FS>
967  const QString &selector) const
968 {
970  query.prepare(QString("SELECT " DB_COLUMNS " FROM %1 WHERE %2")
971  .arg(m_table, selector));
972  if (!query.exec())
973  {
975  return -1;
976  }
977 
978  while (query.next())
979  {
980  ImagePtr im(CreateImage(query));
981 
982  if (im->IsFile())
983  files.append(im);
984  else
985  dirs.append(im);
986  }
987  return query.size();
988 }
989 
990 
1000 template <class FS>
1001 void ImageDb<FS>::GetDescendantCount(int id, bool all, int &dirs,
1002  int &pics, int &videos, int &sizeKb) const
1003 {
1004  QString whereClause;
1005  if (!all)
1006  {
1007  whereClause = "WHERE filename LIKE "
1008  "( SELECT CONCAT(filename, '/%') "
1009  " FROM %2 WHERE file_id = :ID);";
1010  }
1011 
1013  query.prepare(QString("SELECT SUM(type <= :FLDR) AS Fldr, "
1014  " SUM(type = :PIC) AS Pics, "
1015  " SUM(type = :VID) AS Vids, "
1016  " SUM(size / 1024) "
1017  "FROM %2 %1;").arg(whereClause).arg(m_table));
1018 
1019  query.bindValue(":FLDR", kDirectory);
1020  query.bindValue(":PIC", kImageFile);
1021  query.bindValue(":VID", kVideoFile);
1022  if (!all)
1023  query.bindValue(":ID", FS::DbId(id));
1024 
1025  if (!query.exec())
1026  {
1028  }
1029  else if (query.next())
1030  {
1031  dirs += query.value(0).toInt();
1032  pics += query.value(1).toInt();
1033  videos += query.value(2).toInt();
1034  sizeKb += query.value(3).toInt();
1035  }
1036 }
1037 
1038 
1043 {
1044  // Be has a single SG device
1046 }
1047 
1048 
1053  : ImageDb(QString("`%1_%2`").arg(DB_TABLE, gCoreContext->GetHostName()))
1054 {
1055  // Remove any table leftover from a previous FE crash
1056  DropTable();
1057 }
1058 
1059 
1064 {
1066  query.prepare(QString("DROP TABLE IF EXISTS %1;").arg(m_table));
1067  if (query.exec())
1068  m_dbExists = false;
1069  else
1071 }
1072 
1073 
1078 {
1079  if (m_dbExists)
1080  return true;
1081 
1083 
1084  // Create temporary table
1085  query.prepare(QString("CREATE TABLE %1 LIKE " DB_TABLE ";").arg(m_table));
1086  if (query.exec())
1087  {
1088  // Store it in memory only
1089  query.prepare(QString("ALTER TABLE %1 ENGINE = MEMORY;").arg(m_table));
1090  if (query.exec())
1091  {
1092  m_dbExists = true;
1093  LOG(VB_FILE, LOG_DEBUG, QString("Created Db table %1").arg(m_table));
1094  return true;
1095  }
1096  }
1098 
1099  // Clean up after failure
1100  query.prepare(QString("DROP TABLE IF EXISTS %1;").arg(m_table));
1101  query.exec();
1102  return false;
1103 }
1104 
1105 
1109 class ReadMetaThread : public QRunnable
1110 {
1111 public:
1112  ReadMetaThread(ImagePtrK im, QString path)
1113  : m_im(std::move(im)), m_path(std::move(path)) {}
1114 
1115  void run() override // QRunnable
1116  {
1117  QStringList tags;
1118  QString orientation;
1119  QString size;
1120 
1121  // Read metadata for files only
1122  if (m_im->IsFile())
1123  {
1124  ImageMetaData *metadata = (m_im->m_type == kVideoFile)
1127  tags = metadata->GetAllTags();
1128  orientation = Orientation(m_im->m_orientation).Description();
1129  size = ImageAdapterBase::FormatSize(m_im->m_size / 1024);
1130  delete metadata;
1131  }
1132 
1133  // Add identifier at front
1134  tags.prepend(QString::number(m_im->m_id));
1135 
1136  // Include file info
1137  tags << ImageMetaData::ToString(EXIF_MYTH_HOST, "Host",
1139  tags << ImageMetaData::ToString(EXIF_MYTH_PATH, "Path",
1141  tags << ImageMetaData::ToString(EXIF_MYTH_NAME, "Name",
1143  tags << ImageMetaData::ToString(EXIF_MYTH_SIZE, "Size", size);
1144  tags << ImageMetaData::ToString(EXIF_MYTH_ORIENT, "Orientation",
1145  orientation);
1146 
1147  MythEvent me("IMAGE_METADATA", tags);
1148  gCoreContext->SendEvent(me);
1149  }
1150 
1151 private:
1153  QString m_path;
1154 };
1155 
1156 
1165 template <class DBFS>
1166 QStringList ImageHandler<DBFS>::HandleGetMetadata(const QString &id) const
1167 {
1168  // Find image in DB
1169  ImageList files;
1170  ImageList dirs;
1171  if (DBFS::GetImages(id, files, dirs) != 1)
1172  RESULT_ERR("Image not found", QString("Unknown image %1").arg(id))
1173 
1174  ImagePtr im = files.isEmpty() ? dirs[0] : files[0];
1175 
1176  QString absPath = DBFS::GetAbsFilePath(im);
1177  if (absPath.isEmpty())
1178  RESULT_ERR("Image not found",
1179  QString("File %1 not found").arg(im->m_filePath))
1180 
1181  auto *worker = new ReadMetaThread(im, absPath);
1182 
1183  MThreadPool::globalInstance()->start(worker, "ImageMetaData");
1184 
1185  RESULT_OK(QString("Fetching metadata for %1").arg(id))
1186 }
1187 
1188 
1196 template <class DBFS>
1197 QStringList ImageHandler<DBFS>::HandleRename(const QString &id,
1198  const QString &newBase) const
1199 {
1200  // Sanity check new name
1201  if (newBase.isEmpty() || newBase.contains("/") || newBase.contains("\\"))
1202  RESULT_ERR("Invalid name", QString("Invalid name %1").arg(newBase))
1203 
1204  // Find image in DB
1205  ImageList files;
1206  ImageList dirs;
1207  if (DBFS::GetImages(id, files, dirs) != 1)
1208  RESULT_ERR("Image not found", QString("Image %1 not in Db").arg(id))
1209 
1210  ImagePtr im = files.isEmpty() ? dirs[0] : files[0];
1211 
1212  // Find file
1213  QString oldPath = DBFS::GetAbsFilePath(im);
1214  if (oldPath.isEmpty())
1215  RESULT_ERR("Image not found",
1216  QString("File %1 not found").arg(im->m_filePath))
1217 
1218  // Generate new filename
1219  QFileInfo oldFi = QFileInfo(oldPath);
1220  QString newName = im->IsDirectory()
1221  ? newBase : QString("%1.%2").arg(newBase, oldFi.suffix());
1222 
1223  im->m_filePath = DBFS::ConstructPath(DBFS::PathOf(im->m_filePath), newName);
1224 
1225  // Ensure no SG duplicate files are created. (Creating clone dirs is ok)
1226  if (im->IsFile())
1227  {
1228  QString existPath = DBFS::GetAbsFilePath(im);
1229  if (!existPath.isEmpty())
1230  RESULT_ERR("Filename already used",
1231  QString("Renaming %1 to %2 will create a duplicate of %3")
1232  .arg(oldPath, im->m_filePath, existPath))
1233  }
1234 
1235  // Rename file or directory
1236  QString newPath = oldFi.dir().absoluteFilePath(newName);
1237  if (!QFile::rename(oldPath, newPath))
1238  RESULT_ERR("Rename failed",
1239  QString("Rename of %1 -> %2 failed").arg(oldPath, newPath))
1240 
1241  if (im->IsDirectory())
1242  {
1243  // Dir name change affects path of all sub-dirs & files and their thumbs
1244  HandleScanRequest("START");
1245  }
1246  else // file
1247  {
1248  // Update db
1249  DBFS::UpdateDbImage(*im);
1250 
1251  // Image is modified, not deleted
1252  QStringList mesg("");
1253  mesg << QString::number(im->m_id);
1254 
1255  // Rename thumbnail.
1256  m_thumbGen->MoveThumbnail(im);
1257 
1258  // Notify clients of changed image
1259  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1260  }
1261  RESULT_OK(QString("Renamed %1 -> %2").arg(oldPath, newPath))
1262 }
1263 
1264 
1272 template <class DBFS>
1273 QStringList ImageHandler<DBFS>::HandleDelete(const QString &ids) const
1274 {
1275  // Get subtree of all files
1276  ImageList files;
1277  ImageList dirs;
1278  // Dirs will be in depth-first order, (subdirs after parent)
1279  DBFS::GetDescendants(ids, files, dirs);
1280 
1281  // Remove files from filesystem first
1282  RemoveFiles(files);
1283  // ... then dirs, which should now be empty
1284  RemoveFiles(dirs);
1285 
1286  // Fail if nothing deleted
1287  if (files.isEmpty() && dirs.isEmpty())
1288  RESULT_ERR("Delete failed", QString("Delete of %1 failed").arg(ids))
1289 
1290  // Update Db
1291  DBFS::RemoveFromDB(files + dirs);
1292 
1293  // Clean up thumbnails
1294  QStringList mesg(m_thumbGen->DeleteThumbs(files));
1295 
1296  // Notify clients of deleted ids
1297  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1298 
1299  return QStringList("OK");
1300 }
1301 
1302 
1315 template <class DBFS>
1316 QStringList ImageHandler<DBFS>::HandleDbCreate(QStringList defs) const
1317 {
1318  if (defs.isEmpty())
1319  RESULT_ERR("Copy Failed", "Empty defs")
1320 
1321  // First item is the field seperator
1322  const QString separator = defs.takeFirst();
1323 
1324  // Convert cover ids to their new equivalent. Map<source id, new id>
1325  // Dirs follow their children so new cover ids will be defined before they
1326  // are used
1327  QHash<QString, int> idMap;
1328 
1329  // Create skeleton Db images using copied settings.
1330  // Scanner will update other attributes
1331  ImageItem im;
1332  for (const auto& def : qAsConst(defs))
1333  {
1334  QStringList aDef = def.split(separator);
1335 
1336  // Expects id, type, path, hidden, orientation, cover
1337  if (aDef.size() != 6)
1338  {
1339  // Coding error
1340  LOG(VB_GENERAL, LOG_ERR,
1341  LOC + QString("Bad definition: (%1)").arg(def));
1342  continue;
1343  }
1344 
1345  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Creating %1").arg(aDef.join(",")));
1346 
1347  im.m_type = aDef[1].toInt();
1348  im.m_filePath = aDef[2];
1349  im.m_isHidden = (aDef[3].toInt() != 0);
1350  im.m_orientation = aDef[4].toInt();
1351  im.m_userThumbnail = idMap.value(aDef[5]);
1352 
1353  // Don't insert duplicate filepaths
1354  int newId = DBFS::InsertDbImage(im, true);
1355 
1356  // Record old->new id map in case it's being used as a cover
1357  idMap.insert(aDef[0], newId);
1358  }
1359  HandleScanRequest("START");
1360 
1361  RESULT_OK("Created Db images")
1362 }
1363 
1364 
1374 template <class DBFS>
1375 QStringList ImageHandler<DBFS>::HandleDbMove(const QString &ids,
1376  const QString &srcPath,
1377  QString destPath) const
1378 {
1379  // Sanity check new path
1380  if (destPath.contains(".."))
1381  RESULT_ERR("Invalid path", QString("Invalid path %1").arg(destPath))
1382 
1383  // Get subtrees of renamed files
1384  ImageList images;
1385  ImageList dirs;
1386  ImageList files;
1387  bool ok = DBFS::GetDescendants(ids, files, dirs);
1388  images << dirs << files;
1389 
1390  if (!ok || images.isEmpty())
1391  RESULT_ERR("Image not found", QString("Images %1 not in Db").arg(ids))
1392 
1393  if (!destPath.isEmpty() && !destPath.endsWith(QChar('/')))
1394  destPath.append("/");
1395 
1396  // Update path of images only. Scanner will repair parentId
1397  for (const auto& im : qAsConst(images))
1398  {
1399  QString old = im->m_filePath;
1400 
1401  if (srcPath.isEmpty())
1402  {
1403  // Image in SG root
1404  im->m_filePath.prepend(destPath);
1405  }
1406  else if (im->m_filePath.startsWith(srcPath))
1407  {
1408  // All other images
1409  im->m_filePath.replace(srcPath, destPath);
1410  }
1411  else
1412  {
1413  // Coding error
1414  LOG(VB_GENERAL, LOG_ERR,
1415  LOC + QString("Bad image: (%1 -> %2)").arg(srcPath, destPath));
1416  continue;
1417  }
1418 
1419  LOG(VB_FILE, LOG_DEBUG,
1420  LOC + QString("Db Renaming %1 -> %2").arg(old, im->m_filePath));
1421 
1422  DBFS::UpdateDbImage(*im);
1423 
1424  // Rename thumbnail
1425  if (im->IsFile())
1426  m_thumbGen->MoveThumbnail(im);
1427  }
1428  HandleScanRequest("START");
1429 
1430  RESULT_OK(QString("Moved %1 from %2 -> %3").arg(ids).arg(srcPath, destPath))
1431 }
1432 
1433 
1441 template <class DBFS>
1442 QStringList ImageHandler<DBFS>::HandleHide(bool hide, const QString &ids) const
1443 {
1444  if (!DBFS::SetHidden(hide, ids))
1445  RESULT_ERR("Hide failed", QString("Db hide failed for %1").arg(ids))
1446 
1447  // Send changed ids only (none deleted)
1448  QStringList mesg = QStringList("") << ids;
1449  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1450 
1451  RESULT_OK(QString("Images %1 now %2hidden").arg(ids, hide ? "" : "un"))
1452 }
1453 
1454 
1463 template <class DBFS>
1464 QStringList ImageHandler<DBFS>::HandleTransform(int transform,
1465  const QString &ids) const
1466 {
1467  if (transform < kResetToExif || transform > kFlipVertical)
1468  RESULT_ERR("Transform failed", QString("Bad transform %1").arg(transform))
1469 
1470  ImageList files;
1471  ImageList dirs;
1472  if (DBFS::GetImages(ids, files, dirs) < 1 || files.isEmpty())
1473  RESULT_ERR("Image not found", QString("Images %1 not in Db").arg(ids))
1474 
1475  // Update db
1476  for (const auto& im : qAsConst(files))
1477  {
1478  int old = im->m_orientation;
1479  im->m_orientation = Orientation(im->m_orientation).Transform(transform);
1480 
1481  // Update Db
1482  if (DBFS::SetOrientation(im->m_id, im->m_orientation))
1483  {
1484  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Transformed %1 from %2 to %3")
1485  .arg(im->m_filePath).arg(old).arg(im->m_orientation));
1486  }
1487  }
1488 
1489  // Images are changed, not deleted
1490  QStringList mesg("");
1491 
1492  // Clean up thumbnails
1493  mesg << m_thumbGen->DeleteThumbs(files);
1494 
1495  // Notify clients of changed images
1496  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1497 
1498  return QStringList("OK");
1499 }
1500 
1501 
1510 template <class DBFS>
1511 QStringList ImageHandler<DBFS>::HandleDirs(const QString &destId,
1512  bool rescan,
1513  const QStringList &relPaths) const
1514 {
1515  // Find image in DB
1516  ImageList files;
1517  ImageList dirs;
1518  if (DBFS::GetImages(destId, files, dirs) != 1 || dirs.isEmpty())
1519  RESULT_ERR("Destination not found",
1520  QString("Image %1 not in Db").arg(destId))
1521 
1522  // Find dir. SG device (Photographs) uses most-free filesystem
1523  QString destPath = DBFS::GetAbsFilePath(dirs[0]);
1524  if (destPath.isEmpty())
1525  RESULT_ERR("Destination not found",
1526  QString("Dest dir %1 not found").arg(dirs[0]->m_filePath))
1527 
1528  QDir destDir(destPath);
1529  bool succeeded = false;
1530  for (const auto& relPath : qAsConst(relPaths))
1531  {
1532  // Validate dir name
1533  if (relPath.isEmpty() || relPath.contains("..") || relPath.startsWith(QChar('/')))
1534  continue;
1535 
1536  QString newPath = DBFS::ConstructPath(destDir.absolutePath(), relPath);
1537  if (!destDir.mkpath(relPath))
1538  {
1539  LOG(VB_GENERAL, LOG_ERR,
1540  LOC + QString("Failed to create dir %1").arg(newPath));
1541  continue;
1542  }
1543  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Dir %1 created").arg(newPath));
1544  succeeded = true;
1545  }
1546 
1547  if (!succeeded)
1548  // Failures should only occur due to user input
1549  RESULT_ERR("Invalid Name", QString("Invalid name %1")
1550  .arg(relPaths.join(",")))
1551 
1552  if (rescan)
1553  // Rescan to detect new dir
1554  HandleScanRequest("START");
1555 
1556  return QStringList("OK");
1557 }
1558 
1559 
1566 template <class DBFS>
1567 QStringList ImageHandler<DBFS>::HandleCover(int dir, int cover) const
1568 {
1569  if (!DBFS::SetCover(dir, cover))
1570  RESULT_ERR("Set Cover failed",
1571  QString("Failed to set %1 to cover %2").arg(dir).arg(cover))
1572 
1573  // Image has changed, nothing deleted
1574  QStringList mesg = QStringList("") << QString::number(dir);
1575  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1576 
1577  RESULT_OK(QString("Cover of %1 is now %2").arg(dir).arg(cover));
1578 }
1579 
1580 
1589 template <class DBFS>
1590 QStringList ImageHandler<DBFS>::HandleIgnore(const QString &exclusions) const
1591 {
1592  // Save new setting. FE will have already saved it but not cleared the cache
1593  gCoreContext->SaveSettingOnHost("GalleryIgnoreFilter", exclusions, nullptr);
1594 
1595  // Rescan
1596  HandleScanRequest("START");
1597 
1598  RESULT_OK(QString("Using exclusions '%1'").arg(exclusions))
1599 }
1600 
1601 
1609 template <class DBFS>
1610 QStringList ImageHandler<DBFS>::HandleScanRequest(const QString &command,
1611  int devId) const
1612 {
1613  if (!m_scanner)
1614  RESULT_ERR("Missing Scanner", "Missing Scanner");
1615 
1616  if (command == "START")
1617  {
1618  // Must be dormant to start a scan
1619  if (m_scanner->IsScanning())
1620  RESULT_ERR("", "Scanner is busy");
1621 
1622  m_scanner->ChangeState(true);
1623  RESULT_OK("Scan requested");
1624  }
1625  else if (command == "STOP")
1626  {
1627  // Must be scanning to interrupt
1628  if (!m_scanner->IsScanning())
1629  RESULT_ERR("Scanner not running", "Scanner not running");
1630 
1631  m_scanner->ChangeState(false);
1632  RESULT_OK("Terminate scan requested");
1633  }
1634  else if (command == "QUERY")
1635  {
1636  return QStringList("OK") << m_scanner->GetProgress();
1637  }
1638  else if (command.startsWith(QString("DEVICE")))
1639  {
1640  m_scanner->EnqueueClear(devId, command);
1641  RESULT_OK(QString("Clearing device %1 %2").arg(command).arg(devId))
1642  }
1643  RESULT_ERR("Unknown command", QString("Unknown command %1").arg(command));
1644 }
1645 
1646 
1654 template <class DBFS>
1656 (const QStringList &message) const
1657 {
1658  if (message.size() != 2)
1659  RESULT_ERR("Unknown Command",
1660  QString("Bad request: %1").arg(message.join("|")))
1661 
1662  int priority = message.at(0).toInt()
1664 
1665  // get specific image details from db
1666  ImageList files;
1667  ImageList dirs;
1668  DBFS::GetImages(message.at(1), files, dirs);
1669 
1670  for (const auto& im : qAsConst(files))
1671  // notify clients when done; highest priority
1672  m_thumbGen->CreateThumbnail(im, priority, true);
1673 
1674  return QStringList("OK");
1675 }
1676 
1677 
1687 template <class DBFS>
1689 {
1690  QMutableListIterator<ImagePtr> it(images);
1691  it.toBack();
1692  while (it.hasPrevious())
1693  {
1694  ImagePtrK im = it.previous();
1695 
1696  // Remove file or directory
1697  QString absFilename = DBFS::GetAbsFilePath(im);
1698 
1699  bool success = !absFilename.isEmpty()
1700  && (im->IsFile() ? QFile::remove(absFilename)
1701  : QDir::root().rmdir(absFilename));
1702  if (success)
1703  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Deleted %1").arg(absFilename));
1704  else
1705  {
1706  LOG(VB_GENERAL, LOG_ERR, LOC +
1707  QString("Can't delete %1").arg(absFilename));
1708  // Remove from list
1709  it.remove();
1710  }
1711  }
1712 }
1713 
1714 
1721 {
1722  switch (type)
1723  {
1724  case kPicOnly: return QString("AND type != %1").arg(kVideoFile);
1725  case kVideoOnly: return QString("AND type != %1").arg(kImageFile);
1726  case kPicAndVideo: return "";
1727  }
1728  return "";
1729 }
1730 
1731 
1738 {
1739  m_refineClause = QString("%2 %3 "
1740  "ORDER BY "
1741  "CASE WHEN type <= %1 THEN %4, "
1742  "CASE WHEN type > %1 THEN %5 ")
1743  .arg(kDirectory)
1744  .arg(m_showHidden ? "" : "AND hidden = 0",
1748 }
1749 
1750 
1757 {
1758  // prepare the sorting statement
1759  switch (order)
1760  {
1761  default:
1762  case kSortByNameAsc: return "name END ASC";
1763  case kSortByNameDesc: return "name END DESC";
1764  case kSortByModTimeAsc: return "modtime END ASC";
1765  case kSortByModTimeDesc: return "modtime END DESC";
1766  case kSortByExtAsc: return "extension END ASC, name ASC";
1767  case kSortByExtDesc: return "extension END DESC, name DESC";
1768  case kSortBySizeAsc: return "size END ASC, name ASC";
1769  case kSortBySizeDesc: return "size END DESC, name DESC";
1770  case kSortByDateAsc: return "IF(date=0, modtime, date) END ASC";
1771  case kSortByDateDesc: return "IF(date=0, modtime, date) END DESC";
1772  }
1773 }
1774 
1775 
1785  ImageList &files, ImageList &dirs) const
1786 {
1787  // Only Root node will invoke both Db queries but result set will be small
1788  // For Root the SG is always ordered before local devices
1789  // Root node has no Db entry so the 2 queries will not overwrite the parent.
1790  int count = 0;
1791  if (!ImageItem::IsLocalId(id))
1792  count = m_remote->GetDirectory(id, parent, files, dirs, m_refineClause);
1794  count += ImageHandler::GetDirectory(id, parent, files, dirs, m_refineClause);
1795 
1796  if (id == GALLERY_DB_ID)
1797  {
1798  // Add a Root node
1799  parent = ImagePtr(new ImageItem(GALLERY_DB_ID));
1800  parent->m_parentId = GALLERY_DB_ID;
1801  parent->m_type = kDevice;
1802 
1803  ++count;
1804  }
1805  return count;
1806 }
1807 
1808 
1817  ImageList &files, ImageList &dirs) const
1818 {
1819  // Ids are either all local or all remote. GALLERY_DB_ID not valid
1820  StringPair lists = ImageItem::PartitionIds(ids);
1821 
1822  if (!lists.second.isEmpty())
1823  return m_remote->GetImages(lists.second, files, dirs, m_refineClause);
1824  if (m_dbExists && !lists.first.isEmpty())
1825  return ImageHandler::GetImages(lists.first, files, dirs, m_refineClause);
1826  return 0;
1827 }
1828 
1829 
1837 int ImageDbReader::GetChildren(int id, ImageList &files, ImageList &dirs) const
1838 {
1839  int count = 0;
1840  if (!ImageItem::IsLocalId(id))
1841  count = m_remote->GetChildren(QString::number(id), files, dirs,
1842  m_refineClause);
1844  count += ImageHandler::GetChildren(QString::number(id), files, dirs,
1845  m_refineClause);
1846  return count;
1847 }
1848 
1849 
1857  ImageList &files, ImageList &dirs) const
1858 {
1859  // Ids are either all local or all remote
1860  StringPair lists = ImageItem::PartitionIds(ids);
1861 
1862  if (!lists.second.isEmpty())
1863  m_remote->GetDescendants(lists.second, files, dirs);
1864  if (m_dbExists && !lists.first.isEmpty())
1865  ImageHandler::GetDescendants(lists.first, files, dirs);
1866 }
1867 
1868 
1875 void ImageDbReader::GetImageTree(int id, ImageList &files) const
1876 {
1877  if (!ImageItem::IsLocalId(id))
1878  m_remote->GetImageTree(id, files, m_refineClause);
1880  ImageHandler::GetImageTree(id, files, m_refineClause);
1881 }
1882 
1883 
1892 void ImageDbReader::GetDescendantCount(int id, int &dirs, int &pics,
1893  int &videos, int &sizeKb) const
1894 {
1895  if (id == GALLERY_DB_ID)
1896  {
1897  // Sum both unfiltered tables
1898  m_remote->GetDescendantCount(id, true, dirs, pics, videos, sizeKb);
1899  if (m_dbExists)
1900  ImageHandler::GetDescendantCount(id, true, dirs, pics, videos, sizeKb);
1901  }
1902  else if (!ImageItem::IsLocalId(id))
1903  {
1904  // Don't filter on SG path (it's blank)
1906  dirs, pics, videos, sizeKb);
1907  }
1908  else if (m_dbExists)
1909  {
1910  // Always filter on device/dir
1911  ImageHandler::GetDescendantCount(id, false, dirs, pics, videos, sizeKb);
1912  }
1913 }
1914 
1915 
1920 
1921 
1927 {
1928  if (!s_instance)
1929  s_instance = new ImageManagerBe();
1930  return s_instance;
1931 }
1932 
1933 
1939 {
1940  if (!s_instance)
1941  {
1942  // Use saved settings
1944  (gCoreContext->GetNumSetting("GalleryImageOrder"),
1945  gCoreContext->GetNumSetting("GalleryDirOrder"),
1946  gCoreContext->GetBoolSetting("GalleryShowHidden"),
1947  gCoreContext->GetNumSetting("GalleryShowType"),
1948  gCoreContext->GetSetting("GalleryDateFormat"));
1949  }
1950  return *s_instance;
1951 }
1952 
1953 
1962 void ImageManagerFe::CreateThumbnails(const ImageIdList &ids, bool forFolder)
1963 {
1964  // Split images into <locals, remotes>
1965  StringPair lists = ImageItem::PartitionIds(ids);
1966 
1967  if (!lists.second.isEmpty())
1968  {
1969  LOG(VB_FILE, LOG_DEBUG, LOC +
1970  QString("Sending CREATE_THUMBNAILS %1 (forFolder %2)")
1971  .arg(lists.second).arg(forFolder));
1972 
1973  QStringList message;
1974  message << QString::number(static_cast<int>(forFolder)) << lists.second;
1975  gCoreContext->SendEvent(MythEvent("CREATE_THUMBNAILS", message));
1976  }
1977 
1978  if (!lists.first.isEmpty())
1979  {
1980  LOG(VB_FILE, LOG_DEBUG, LOC +
1981  QString("Creating local thumbnails %1 (forFolder %2)")
1982  .arg(lists.first).arg(forFolder));
1983 
1984  QStringList message;
1985  message << QString::number(static_cast<int>(forFolder)) << lists.first;
1986  HandleCreateThumbnails(message);
1987  }
1988 }
1989 
1990 
1997 QString ImageManagerFe::ScanImagesAction(bool start, bool local)
1998 {
1999  QStringList command;
2000  command << (start ? "START" : "STOP");
2001 
2002  if (!local)
2003  {
2004  command.push_front("IMAGE_SCAN");
2005  bool ok = gCoreContext->SendReceiveStringList(command, true);
2006  return ok ? "" : command[1];
2007  }
2008 
2009  // Create database on first scan
2010  if (!CreateTable())
2011  return "Couldn't create database";
2012 
2013  QStringList err = HandleScanRequest(command[0]);
2014  return err[0] == "OK" ? "" : err[1];
2015 }
2016 
2017 
2024 {
2025  QStringList strList;
2026  strList << "IMAGE_SCAN" << "QUERY";
2027 
2028  if (!gCoreContext->SendReceiveStringList(strList))
2029  {
2030  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Scan query failed : %1")
2031  .arg(strList.join(",")));
2032  }
2033  return strList;
2034 }
2035 
2036 
2043 QString ImageManagerFe::HideFiles(bool hidden, const ImageIdList &ids)
2044 {
2045  // Split images into <locals, remotes>
2046  StringPair lists = ImageItem::PartitionIds(ids);
2047  QString result = "";
2048 
2049  if (!lists.second.isEmpty())
2050  {
2051  QStringList message;
2052  message << "IMAGE_HIDE" << QString::number(static_cast<int>(hidden)) << lists.second;
2053 
2054  if (!gCoreContext->SendReceiveStringList(message, true))
2055  result = message[1];
2056  }
2057 
2058  if (!lists.first.isEmpty())
2059  {
2060  QStringList err = HandleHide(hidden, lists.first);
2061  if (err[0] != "OK")
2062  result = err[1];
2063  }
2064  return result;
2065 }
2066 
2067 
2075  const ImageIdList &ids)
2076 {
2077  // Split images into <locals, remotes>
2078  StringPair lists = ImageItem::PartitionIds(ids);
2079  QString result = "";
2080 
2081  if (!lists.second.isEmpty())
2082  {
2083  QStringList message;
2084  message << "IMAGE_TRANSFORM" << QString::number(transform) << lists.second;
2085 
2086  if (!gCoreContext->SendReceiveStringList(message, true))
2087  result = message[1];
2088  }
2089 
2090  if (!lists.first.isEmpty())
2091  {
2092  QStringList err = HandleTransform(transform, lists.first);
2093  if (err[0] != "OK")
2094  result = err[1];
2095  }
2096  return result;
2097 }
2098 
2099 
2106 QString ImageManagerFe::SetCover(int parent, int cover)
2107 {
2108  if (!ImageItem::IsLocalId(parent))
2109  {
2110  QStringList message;
2111  message << "IMAGE_COVER" << QString::number(parent) << QString::number(cover);
2112 
2113  bool ok = gCoreContext->SendReceiveStringList(message, true);
2114  return ok ? "" : message[1];
2115  }
2116 
2117  QStringList err = HandleCover(parent, cover);
2118  return err[0] == "OK" ? "" : err[1];
2119 }
2120 
2121 
2127 {
2128  if (ImageItem::IsLocalId(id))
2129  HandleGetMetadata(QString::number(id));
2130  else
2131  gCoreContext->SendEvent(MythEvent("IMAGE_GET_METADATA", QString::number(id)));
2132 }
2133 
2134 
2137 {
2138  QStringList message("IMAGE_SCAN");
2139  message << "DEVICE CLEAR ALL";
2140  gCoreContext->SendReceiveStringList(message, true);
2141 }
2142 
2143 
2150 QString ImageManagerFe::IgnoreDirs(const QString &excludes)
2151 {
2152  QStringList message("IMAGE_IGNORE");
2153  message << excludes;
2154  bool ok = gCoreContext->SendReceiveStringList(message, true);
2155  return ok ? "" : message[1];
2156 }
2157 
2158 
2166 QString ImageManagerFe::MakeDir(int parent, const QStringList &names, bool rescan)
2167 {
2168  QString destId = QString::number(parent);
2169 
2170  if (!ImageItem::IsLocalId(parent))
2171  {
2172  QStringList message("IMAGE_CREATE_DIRS");
2173  message << destId << QString::number(static_cast<int>(rescan)) << names;
2174  bool ok = gCoreContext->SendReceiveStringList(message, true);
2175  return ok ? "" : message[1];
2176  }
2177  QStringList err = HandleDirs(destId, rescan, names);
2178  return (err[0] == "OK") ? "" : err[1];
2179 }
2180 
2181 
2188 QString ImageManagerFe::RenameFile(const ImagePtrK& im, const QString &name)
2189 {
2190  if (!im->IsLocal())
2191  {
2192  QStringList message("IMAGE_RENAME");
2193  message << QString::number(im->m_id) << name;
2194  bool ok = gCoreContext->SendReceiveStringList(message, true);
2195  return ok ? "" : message[1];
2196  }
2197  QStringList err = HandleRename(QString::number(im->m_id), name);
2198  return (err[0] == "OK") ? "" : err[1];
2199 }
2200 
2201 
2208 QString ImageManagerFe::CreateImages(int destId, const ImageListK &images)
2209 {
2210  if (images.isEmpty())
2211  return "";
2212 
2213  // Define field seperator & include it in message
2214  const QString seperator("...");
2215  QStringList imageDefs(seperator);
2216  ImageIdList ids;
2217  for (const auto& im : qAsConst(images))
2218  {
2219  ids << im->m_id;
2220 
2221  // Copies preserve hide state, orientation & cover
2222  QStringList aDef;
2223  aDef << QString::number(im->m_id)
2224  << QString::number(im->m_type)
2225  << im->m_filePath
2226  << QString::number(static_cast<int>(im->m_isHidden))
2227  << QString::number(im->m_orientation)
2228  << QString::number(im->m_userThumbnail);
2229 
2230  imageDefs << aDef.join(seperator);
2231  }
2232 
2233  // Images are either all local or all remote
2234  if (ImageItem::IsLocalId(destId))
2235  {
2236  QStringList err = HandleDbCreate(imageDefs);
2237  return (err[0] == "OK") ? "" : err[1];
2238  }
2239  imageDefs.prepend("IMAGE_COPY");
2240  bool ok = gCoreContext->SendReceiveStringList(imageDefs, true);
2241  return ok ? "" : imageDefs[1];
2242 }
2243 
2244 
2252 QString ImageManagerFe::MoveDbImages(const ImagePtrK& destDir, ImageListK &images,
2253  const QString &srcPath)
2254 {
2255  QStringList idents;
2256  for (const auto& im : qAsConst(images))
2257  idents << QString::number(im->m_id);
2258 
2259  // Images are either all local or all remote
2260  if (destDir->IsLocal())
2261  {
2262  QStringList err = HandleDbMove(idents.join(","), srcPath,
2263  destDir->m_filePath);
2264  return (err[0] == "OK") ? "" : err[1];
2265  }
2266 
2267  QStringList message("IMAGE_MOVE");
2268  message << idents.join(",") << srcPath << destDir->m_filePath;
2269  bool ok = gCoreContext->SendReceiveStringList(message, true);
2270  return ok ? "" : message[1];
2271 }
2272 
2273 
2280 {
2281  StringPair lists = ImageItem::PartitionIds(ids);
2282 
2283  QString result = "";
2284  if (!lists.second.isEmpty())
2285  {
2286  QStringList message("IMAGE_DELETE");
2287  message << lists.second;
2288 
2289  bool ok = gCoreContext->SendReceiveStringList(message, true);
2290  if (!ok)
2291  result = message[1];
2292  }
2293  if (!lists.first.isEmpty())
2294  {
2295  QStringList err = HandleDelete(lists.first);
2296  if (err[0] != "OK")
2297  result = err[1];
2298  }
2299  return result;
2300 }
2301 
2302 
2310 {
2311  if (im->m_id == GALLERY_DB_ID)
2312  return "";
2313 
2314  qint64 secs = 0;
2316 
2317  if (im->m_date > 0)
2318  {
2319  secs = im->m_date;
2320  format |= MythDate::kTime;
2321  }
2322  else
2323  secs = im->m_modTime;
2324 
2325  return MythDate::toString(QDateTime::fromSecsSinceEpoch(secs), format);
2326 }
2327 
2328 
2335 QString ImageManagerFe::ShortDateOf(const ImagePtrK& im) const
2336 {
2337  if (im->m_id == GALLERY_DB_ID)
2338  return "";
2339 
2340  qint64 secs(im->m_date > 0 ? im->m_date : im->m_modTime);
2341  return QDateTime::fromSecsSinceEpoch(secs).date().toString(m_dateFormat);
2342 }
2343 
2344 
2351 {
2352  if (im.m_id == GALLERY_DB_ID)
2353  return tr("Gallery");
2354  if (im.m_id == PHOTO_DB_ID)
2355  return tr("Photographs");
2356  return im.IsLocal() ? DeviceName(im.m_device)
2357  : m_remote->DeviceName(im.m_device);
2358 }
2359 
2360 
2368 QString ImageManagerFe::CrumbName(ImageItemK &im, bool getPath) const
2369 {
2370  if (im.IsDevice())
2371  return DeviceCaption(im);
2372 
2373  if (!getPath)
2374  return im.m_baseName;
2375 
2376  QString dev;
2377  QString path(im.m_filePath);
2378 
2379  if (im.IsLocal())
2380  {
2381  // Replace local mount path with device name
2382  path.remove(0, DeviceMount(im.m_device).size());
2383  dev = DeviceName(im.m_device);
2384  }
2385  return dev + path.replace("/", " > ");
2386 }
2387 
2388 
2389 void ImageManagerFe::CloseDevices(int devId, bool eject)
2390 {
2391  QString reason = (devId == DEVICE_INVALID)
2392  ? "DEVICE CLOSE ALL"
2393  : eject ? "DEVICE EJECT" : "DEVICE REMOVE";
2394  HandleScanRequest(reason, devId);
2395 }
2396 
2397 
2403 {
2405  if (!monitor)
2406  return false;
2407 
2408  // Detect all local media
2409  QList<MythMediaDevice*> devices
2411 
2412  for (auto *dev : qAsConst(devices))
2413  {
2414  if (monitor->ValidateAndLock(dev) && dev->isUsable())
2415  OpenDevice(dev->getDeviceModel(), dev->getMountPath(), dev);
2416  else
2417  monitor->Unlock(dev);
2418  }
2419 
2420  if (DeviceCount() > 0)
2421  {
2422  // Close devices that are no longer present
2423  for (int devId : GetAbsentees())
2424  CloseDevices(devId);
2425 
2426  // Start local scan
2427  QString err = ScanImagesAction(true, true);
2428  if (!err.isEmpty())
2429  LOG(VB_GENERAL, LOG_ERR, LOC + err);
2430  }
2431  return DeviceCount() > 0;
2432 }
2433 
2434 
2440 {
2442 
2443  if (!event || !monitor)
2444  return;
2445 
2446  MythMediaDevice *dev = event->getDevice();
2447  if (!dev)
2448  return;
2449 
2450  MythMediaType type = dev->getMediaType();
2451  MythMediaStatus status = dev->getStatus();
2452 
2453  LOG(VB_FILE, LOG_DEBUG, LOC +
2454  QString("Media event for %1 (%2) at %3, type %4, status %5 (was %6)")
2455  .arg(dev->getDeviceModel(), dev->getVolumeID(), dev->getMountPath())
2456  .arg(type).arg(status).arg(event->getOldStatus()));
2457 
2459  {
2460  LOG(VB_FILE, LOG_DEBUG, LOC +
2461  QString("Ignoring event - wrong type %1").arg(type));
2462  return;
2463  }
2464 
2465  if (status == MEDIASTAT_USEABLE || status == MEDIASTAT_MOUNTED)
2466  {
2467  // New device. Lock it & scan
2468  if (monitor->ValidateAndLock(dev))
2469  {
2470  OpenDevice(dev->getDeviceModel(), dev->getMountPath(), dev);
2471  ScanImagesAction(true, true);
2472  }
2473  else
2474  monitor->Unlock(dev);
2475  return;
2476  }
2477 
2478  // Device has disappeared
2479  int devId = LocateMount(dev->getMountPath());
2480  if (devId != DEVICE_INVALID)
2481  CloseDevices(devId);
2482 }
2483 
2484 
2486 {
2487  auto *tmp = new QTemporaryDir(QDir::tempPath() % "/" IMPORTDIR "-XXXXXX");
2488  if (!tmp->isValid())
2489  {
2490  delete tmp;
2491  return "";
2492  }
2493 
2494  QString time(QDateTime::currentDateTime().toString("mm:ss"));
2495  OpenDevice("Import " + time, tmp->path(), nullptr, tmp);
2496  return tmp->path();
2497 }
2498 
2499 
2500 // Must define the valid template implementations to generate code for the
2501 // instantiations (as they are defined in the cpp rather than header).
2502 // Otherwise the linker will fail with undefined references...
2503 template class ImageDb<ImageAdapterSg>;
2504 template class ImageDb<ImageAdapterLocal>;
2505 template class ImageHandler<ImageDbSg>;
2506 template class ImageHandler<ImageDbLocal>;
MythMediaDevice::getMountPath
const QString & getMountPath() const
Definition: mythmedia.h:58
ImageAdapterBase::ImageAdapterBase
ImageAdapterBase()
Constructor.
Definition: imagemanager.cpp:276
MythMediaEvent::getOldStatus
MythMediaStatus getOldStatus(void) const
Definition: mythmedia.h:190
ImageManagerBe::s_instance
static ImageManagerBe * s_instance
BE Gallery instance.
Definition: imagemanager.h:391
kPicAndVideo
@ kPicAndVideo
Show Pictures & Videos.
Definition: imagemanager.h:78
kSortByNameDesc
@ kSortByNameDesc
Name Z-A.
Definition: imagetypes.h:46
ImageManagerFe::m_dateFormat
QString m_dateFormat
UI format for thumbnail date captions.
Definition: imagemanager.h:514
ImageManagerFe::ImageManagerFe
ImageManagerFe(int order, int dirOrder, bool showAll, int showType, QString dateFormat)
Definition: imagemanager.h:501
MEDIATYPE_MIXED
@ MEDIATYPE_MIXED
Definition: mythmedia.h:27
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
ImagePtrK
QSharedPointer< ImageItemK > ImagePtrK
Definition: imagetypes.h:164
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:126
ImageDbReader::m_showType
int m_showType
Type of images to display - pic only/video only/both.
Definition: imagemanager.h:443
ImageHandler::HandleRename
QStringList HandleRename(const QString &id, const QString &newBase) const
Change name of an image/dir.
Definition: imagemanager.cpp:1197
PHOTO_DB_ID
#define PHOTO_DB_ID
Definition: imagetypes.h:28
Device::m_thumbs
QString m_thumbs
Dir sub-path of device thumbnails.
Definition: imagemanager.cpp:113
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:80
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:203
ImageDbReader::GetImages
int GetImages(const ImageIdList &ids, ImageList &files, ImageList &dirs) const
Returns images (local or remote but not a combination)
Definition: imagemanager.cpp:1816
ImageDb::SetHidden
bool SetHidden(bool hide, QString ids) const
Sets hidden status of an image/dir in database.
Definition: imagemanager.cpp:890
DeviceManager::GetDeviceDirs
StringMap GetDeviceDirs() const
Get all known devices.
Definition: imagemanager.cpp:246
root
QDomElement root
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:653
ImageManagerFe::OpenDevice
int OpenDevice(const QString &name, const QString &mount, MythMediaDevice *media=nullptr, QTemporaryDir *dir=nullptr)
Define a new device and assign it a unique id. If the device is already known, its existing id is ret...
Definition: imagemanager.cpp:157
ImageAdapterBase::BaseNameOf
static QString BaseNameOf(const QString &path)
Extracts file name (incl extension) from a filepath.
Definition: imagemanager.h:136
ImageManagerFe::CreateThumbnails
void CreateThumbnails(const ImageIdList &ids, bool forFolder)
Create thumbnails or verify that they already exist.
Definition: imagemanager.cpp:1962
ImageDbLocal::m_dbExists
bool m_dbExists
Definition: imagemanager.h:329
ImageDbReader::GetImageTree
void GetImageTree(int id, ImageList &files) const
Return all files (local or remote) in the sub-trees of a dir.
Definition: imagemanager.cpp:1875
ImageItem::m_type
int m_type
Type of node: dir, video etc.
Definition: imagetypes.h:96
kVideoFile
@ kVideoFile
A video.
Definition: imagetypes.h:39
MediaMonitor::GetMedias
QList< MythMediaDevice * > GetMedias(unsigned mediatypes)
Ask for available media. Must be locked with ValidateAndLock().
Definition: mythmediamonitor.cpp:620
ReadMetaThread
Task to read all metadata from file.
Definition: imagemanager.cpp:1110
Device::isImport
bool isImport() const
Definition: imagemanager.cpp:105
ImageItem::m_id
int m_id
Uniquely identifies an image (file/dir).
Definition: imagetypes.h:88
ImageDb::UpdateDbImage
bool UpdateDbImage(ImageItemK &im) const
Updates or creates database image or dir.
Definition: imagemanager.cpp:817
MythCoreContext::SendReceiveStringList
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
Definition: mythcorecontext.cpp:1379
kSortByExtDesc
@ kSortByExtDesc
Extension Z-A.
Definition: imagetypes.h:50
ImageItem::m_comment
QString m_comment
User comment, from Exif metadata.
Definition: imagetypes.h:101
ImageDbReader::GetDirectory
int GetDirectory(int id, ImagePtr &parent, ImageList &files, ImageList &dirs) const
Return images (local and/or remote) for a dir and its direct children.
Definition: imagemanager.cpp:1784
ImageManagerFe::CreateImages
QString CreateImages(int destId, const ImageListK &images)
Copies database images (but not the files themselves).
Definition: imagemanager.cpp:2208
ImageManagerFe::ScanImagesAction
QString ScanImagesAction(bool start, bool local=false)
Handle scanner start/stop commands.
Definition: imagemanager.cpp:1997
LOC
#define LOC
Definition: imagemanager.cpp:13
ImageHandler::HandleGetMetadata
QStringList HandleGetMetadata(const QString &id) const
Read meta data for an image.
Definition: imagemanager.cpp:1166
MediaMonitor::GetMediaMonitor
static MediaMonitor * GetMediaMonitor(void)
Definition: mythmediamonitor.cpp:84
ImageItem::IsLocal
bool IsLocal() const
Definition: imagetypes.h:118
ImageDbLocal::DropTable
void DropTable()
Remove local image table.
Definition: imagemanager.cpp:1063
ImageMetaData
Abstract class for image metadata.
Definition: imagemetadata.h:100
ImageManagerFe::s_instance
static ImageManagerFe * s_instance
FE Gallery instance.
Definition: imagemanager.h:511
DeviceManager::DeviceName
QString DeviceName(int devId) const
Get model name of the device.
Definition: imagemanager.cpp:136
kNullDevice
static Device kNullDevice
Definition: imagemanager.cpp:119
ImageManagerFe::MakeDir
QString MakeDir(int parent, const QStringList &names, bool rescan=true)
Create directories.
Definition: imagemanager.cpp:2166
ImageDbReader::m_showHidden
bool m_showHidden
Whether hidden images are displayed.
Definition: imagemanager.h:442
ImageItem::m_isHidden
bool m_isHidden
If true, image won't be shown.
Definition: imagetypes.h:104
Device::RemoveDirContents
static void RemoveDirContents(const QString &path)
Clears all files and sub-dirs within a directory.
Definition: imagemanager.cpp:88
StorageGroup::FindFile
QString FindFile(const QString &filename)
Definition: storagegroup.cpp:602
kDirectory
@ kDirectory
A device sub directory.
Definition: imagetypes.h:37
DB_COLUMNS
#define DB_COLUMNS
Definition: imagemanager.cpp:487
ImageManagerFe::DeviceCount
int DeviceCount() const
Definition: imagemanager.h:100
MSqlQuery::lastInsertId
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:888
Device::m_mount
QString m_mount
Mountpoint.
Definition: imagemanager.cpp:112
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:17
ImageManagerFe::DeviceEvent
void DeviceEvent(MythMediaEvent *event)
Manage events for local devices.
Definition: imagemanager.cpp:2439
EXIF_MYTH_SIZE
#define EXIF_MYTH_SIZE
Definition: imagemetadata.h:41
Device::isPresent
bool isPresent() const
Definition: imagemanager.cpp:106
ImageManagerFe::IgnoreDirs
static QString IgnoreDirs(const QString &excludes)
Set directories to ignore during scans of the storage group.
Definition: imagemanager.cpp:2150
Device::m_media
MythMediaDevice * m_media
Set for MediaMonitor devices only.
Definition: imagemanager.cpp:114
RESULT_ERR
#define RESULT_ERR(ERR, MESG)
Definition: imagemanager.cpp:21
imagemanager.h
Manages a collection of images.
Device::Close
void Close(bool eject=false)
Releases device.
Definition: imagemanager.cpp:61
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:198
arg
arg(title).arg(filename).arg(doDelete))
mythmediamonitor.h
MEDIASTAT_USEABLE
@ MEDIASTAT_USEABLE
Definition: mythmedia.h:19
RemoveFromDB
bool RemoveFromDB(Bookmark *site)
Definition: browserdbutil.cpp:158
Device::RemoveThumbs
void RemoveThumbs(void) const
Delete thumbnails associated with device.
Definition: imagemanager.cpp:95
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
MythMediaDevice::getDevicePath
const QString & getDevicePath() const
Definition: mythmedia.h:61
kDirRequestPriority
@ kDirRequestPriority
Client request to display a directory thumbnail.
Definition: imagethumbs.h:35
MythMediaDevice::getStatus
MythMediaStatus getStatus() const
Definition: mythmedia.h:70
ImageAdapterSg::Notify
static void Notify(const QString &mesg, const QStringList &extra)
Send message to all clients about remote ids.
Definition: imagemanager.cpp:450
DEVICE_INVALID
#define DEVICE_INVALID
Definition: imagemanager.h:71
ImageManagerFe::HideFiles
QString HideFiles(bool hidden, const ImageIdList &ids)
Hide/unhide images.
Definition: imagemanager.cpp:2043
IMAGE_STORAGE_GROUP
#define IMAGE_STORAGE_GROUP
Definition: imagemanager.h:63
ImageAdapterSg::m_sg
StorageGroup m_sg
Images storage group.
Definition: imagemanager.h:266
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
FileAssociations::getList
const association_list & getList() const
Definition: dbaccess.cpp:805
STORAGE_GROUP_MOUNT
#define STORAGE_GROUP_MOUNT
Definition: imagemanager.cpp:17
ImageDb::GetImages
int GetImages(const QString &ids, ImageList &files, ImageList &dirs, const QString &refine="") const
Read database images/dirs by id.
Definition: imagemanager.cpp:543
ImageDb::InsertDbImage
int InsertDbImage(ImageItemK &im, bool checkForDuplicate=false) const
Adds new image to database, optionally checking for existing filepath.
Definition: imagemanager.cpp:759
Device
A device containing images (ie. USB stick, CD, storage group etc)
Definition: imagemanager.cpp:34
MEDIASTAT_MOUNTED
@ MEDIASTAT_MOUNTED
Definition: mythmedia.h:21
ImageDb::CreateImage
ImageItem * CreateImage(const MSqlQuery &query) const
Create image from Db query data.
Definition: imagemanager.cpp:500
ImageHandler::HandleCover
QStringList HandleCover(int dir, int cover) const
Updates/resets cover thumbnail for an image dir.
Definition: imagemanager.cpp:1567
DeviceManager::ThumbDir
QString ThumbDir(int fs) const
Definition: imagemanager.cpp:142
ImageManagerBe::ImageManagerBe
ImageManagerBe()
Definition: imagemanager.h:384
ImageDbReader::TypeSelector
static QString TypeSelector(int type)
Generate SQL type filter clause.
Definition: imagemanager.cpp:1720
MythMediaDevice::getDeviceModel
const QString & getDeviceModel() const
Definition: mythmedia.h:67
ImageMetaData::FromVideo
static ImageMetaData * FromVideo(const QString &filePath)
Factory to retrieve metadata from videos.
Definition: imagemetadata.cpp:709
ImageItem::m_device
int m_device
Id of media device. Always 0 (SG) for remotes, 1+ for local devices.
Definition: imagetypes.h:94
ImageManagerFe::CloseDevices
void CloseDevices(int devId=DEVICE_INVALID, bool eject=false)
Definition: imagemanager.cpp:2389
ImageItem::PartitionIds
static StringPair PartitionIds(const ImageIdList &ids)
Separates list of ids into a list of local ids and a list of remote ids.
Definition: imagetypes.h:139
true
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
ImageDbSg::ImageDbSg
ImageDbSg()
SG database constructor.
Definition: imagemanager.cpp:1042
ImageManagerFe::ChangeOrientation
QString ChangeOrientation(ImageFileTransform transform, const ImageIdList &ids)
Apply an orientation transform to images.
Definition: imagemanager.cpp:2074
tmp
static guint32 * tmp
Definition: goom_core.cpp:30
ImageHandler::HandleTransform
QStringList HandleTransform(int transform, const QString &ids) const
Change orientation of pictures by applying a transformation.
Definition: imagemanager.cpp:1464
dbaccess.h
ImageManagerFe::getInstance
static ImageManagerFe & getInstance()
Get Frontend Gallery.
Definition: imagemanager.cpp:1938
ImageAdapterLocal::CreateItem
ImageItem * CreateItem(const QFileInfo &fi, int parentId, int devId, const QString &base) const
Construct a local image from a file.
Definition: imagemanager.cpp:336
ImageManagerFe::DeviceCaption
QString DeviceCaption(ImageItemK &im) const
Return translated device name.
Definition: imagemanager.cpp:2350
kSortByDateDesc
@ kSortByDateDesc
Exif date Latest -> Earliest.
Definition: imagetypes.h:54
Orientation::Transform
int Transform(int transform)
Adjust orientation to apply a transform to an image.
Definition: imagemetadata.cpp:28
ImageHandler::HandleDbCreate
QStringList HandleDbCreate(QStringList defs) const
Creates images for files created by a copy operation.
Definition: imagemanager.cpp:1316
ImageDbReader::m_refineClause
QString m_refineClause
SQL clause for image filtering/ordering.
Definition: imagemanager.h:444
ImageMetaData::ToString
static QString ToString(const QString &name, const QString &label, const QString &value)
Encodes metadata into a string as <tag name><tag label><tag value>
Definition: imagemetadata.h:112
ImageFileTransform
ImageFileTransform
Image transformations.
Definition: imagemetadata.h:46
EXIF_MYTH_ORIENT
#define EXIF_MYTH_ORIENT
Definition: imagemetadata.h:42
ImageDb::GetImageTree
bool GetImageTree(int id, ImageList &files, const QString &refine) const
Returns all files in the sub-tree of a dir.
Definition: imagemanager.cpp:672
MythDate::fromSecsSinceEpoch
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(uint seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
Definition: mythdate.cpp:68
toString
QString toString(MarkTypes type)
Definition: programtypes.cpp:26
ImageItem::m_modTime
qint64 m_modTime
Filesystem modified datestamp.
Definition: imagetypes.h:97
ImageHash
QHash< QString, ImagePtr > ImageHash
Definition: imagetypes.h:160
mythdate.h
ImageHandler::HandleDbMove
QStringList HandleDbMove(const QString &ids, const QString &srcPath, QString destPath) const
Updates images that have been renamed.
Definition: imagemanager.cpp:1375
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
kSortByNameAsc
@ kSortByNameAsc
Name A-Z.
Definition: imagetypes.h:45
kPicOnly
@ kPicOnly
Hide videos.
Definition: imagemanager.h:79
ImageManagerFe::ClearStorageGroup
static void ClearStorageGroup()
Clear database & thumbnails of Storage Group images.
Definition: imagemanager.cpp:2136
ImageList
QList< ImagePtr > ImageList
Definition: imagetypes.h:159
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1539
DeviceManager::~DeviceManager
~DeviceManager()
Definition: imagemanager.cpp:122
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
FileAssociations::association_list
std::vector< file_association > association_list
Definition: dbaccess.h:154
StringMap
QMap< int, QString > StringMap
Definition: imagetypes.h:62
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
ImageHandler< ImageDbSg >
ImageAdapterBase::FormatSize
static QString FormatSize(int sizeKib)
Definition: imagemanager.h:143
ImageDb::SetOrientation
bool SetOrientation(int id, int orientation) const
Sets image orientation in Db.
Definition: imagemanager.cpp:940
formats
const std::array< const std::string, 8 > formats
Definition: vbilut.cpp:189
MythMediaEvent
Definition: mythmedia.h:184
ImageDbReader::GetDescendants
void GetDescendants(const ImageIdList &ids, ImageList &files, ImageList &dirs) const
Return all (local or remote) images that are direct children of a dir.
Definition: imagemanager.cpp:1856
ImageAdapterBase::SupportedImages
static QStringList SupportedImages()
Return recognised pictures.
Definition: imagemanager.cpp:299
ImageDbReader::OrderSelector
static QString OrderSelector(int order)
Generate SQL ordering clause.
Definition: imagemanager.cpp:1756
DBLOC
#define DBLOC
Definition: imagemanager.cpp:14
ImageAdapterBase::PathOf
static QString PathOf(const QString &path)
Extracts path from a filepath.
Definition: imagemanager.h:140
ImageListK
QList< ImagePtrK > ImageListK
Definition: imagetypes.h:165
clear
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:846
MediaMonitor::Unlock
void Unlock(MythMediaDevice *pMedia)
decrements the MythMediaDevices reference count
Definition: mythmediamonitor.cpp:526
Orientation::Description
QString Description() const
Generate text description of orientation.
Definition: imagemetadata.cpp:228
ImageManagerFe::LongDateOf
static QString LongDateOf(const ImagePtrK &im)
Return a timestamp/datestamp for an image or dir.
Definition: imagemanager.cpp:2309
RESULT_OK
#define RESULT_OK(MESG)
Definition: imagemanager.cpp:25
kSortByExtAsc
@ kSortByExtAsc
Extension A-Z.
Definition: imagetypes.h:49
EXIF_MYTH_PATH
#define EXIF_MYTH_PATH
Definition: imagemetadata.h:39
StorageGroup::GetDirList
QStringList GetDirList(void) const
Definition: storagegroup.h:23
ImageManagerFe::SetCover
QString SetCover(int parent, int cover)
Set image to use as a cover thumbnail(s)
Definition: imagemanager.cpp:2106
uint
unsigned int uint
Definition: compat.h:140
ImageMetaData::FromPicture
static ImageMetaData * FromPicture(const QString &filePath)
Factory to retrieve metadata from pictures.
Definition: imagemetadata.cpp:700
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
ImageItem::IsLocalId
static bool IsLocalId(int id)
Determine image type (local/remote) from its id. Root/Gallery is remote.
Definition: imagetypes.h:121
ImageItem::m_orientation
int m_orientation
Image orientation.
Definition: imagetypes.h:100
ImageItem::m_baseName
QString m_baseName
File/Dir name with extension (no path)
Definition: imagetypes.h:91
MediaMonitor
Definition: mythmediamonitor.h:44
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:930
DeviceManager::DeviceMount
QString DeviceMount(int devId) const
Get path at which the device is mounted.
Definition: imagemanager.cpp:129
ImageManagerFe::CreateImport
QString CreateImport()
Definition: imagemanager.cpp:2485
ImageItem::IsLocalParent
static bool IsLocalParent(int id)
Parents of locals are locals or root.
Definition: imagetypes.h:123
ImageHandler::RemoveFiles
void RemoveFiles(ImageList &images) const
Deletes images and dirs from the filesystem.
Definition: imagemanager.cpp:1688
ImageAdapterBase::GetAbsThumbPath
static QString GetAbsThumbPath(const QString &devPath, const QString &path)
Get absolute filepath for thumbnail of an image.
Definition: imagemanager.h:148
ImageMetaData::GetAllTags
virtual QStringList GetAllTags()=0
ImageDbReader::GetDescendantCount
void GetDescendantCount(int id, int &dirs, int &pics, int &videos, int &sizeKb) const
Return counts of dirs, pics and videos in the subtree of a dir. Also dir size.
Definition: imagemanager.cpp:1892
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:924
THUMBNAIL_SUBDIR
#define THUMBNAIL_SUBDIR
Definition: imagemanager.h:69
Device::m_present
bool m_present
True when gallery UI is running & device is useable. Always true for imports.
Definition: imagemanager.cpp:110
FileAssociations::getFileAssociation
static FileAssociations & getFileAssociation()
Definition: dbaccess.cpp:830
kSortByModTimeDesc
@ kSortByModTimeDesc
File modified time Latest -> Earliest.
Definition: imagetypes.h:48
mthreadpool.h
Device::m_dir
QTemporaryDir * m_dir
Dir path of images: import devices only.
Definition: imagemanager.cpp:115
ImageHandler::HandleScanRequest
QStringList HandleScanRequest(const QString &command, int devId=DEVICE_INVALID) const
Process scan requests.
Definition: imagemanager.cpp:1610
ImageHandler::HandleDirs
QStringList HandleDirs(const QString &destId, bool rescan, const QStringList &relPaths) const
Creates new image directories.
Definition: imagemanager.cpp:1511
kImageFile
@ kImageFile
A picture.
Definition: imagetypes.h:38
IMPORTDIR
#define IMPORTDIR
Definition: imagemanager.cpp:29
ImageManagerFe::MoveDbImages
QString MoveDbImages(const ImagePtrK &destDir, ImageListK &images, const QString &srcPath)
Moves database images (but not the files themselves).
Definition: imagemanager.cpp:2252
MythMediaType
MythMediaType
Definition: mythmedia.h:24
kFlipVertical
@ kFlipVertical
Reflect about horizontal axis.
Definition: imagemetadata.h:51
ImagePtr
QSharedPointer< ImageItem > ImagePtr
Definition: imagetypes.h:158
MythDate::kAddYear
@ kAddYear
Add year to string if not included.
Definition: mythdate.h:22
ImageManagerFe
The image manager for use by Frontends.
Definition: imagemanager.h:457
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:671
dir
QDir dir
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1171
ImageDbReader::m_fileOrder
int m_fileOrder
Display ordering of pics/videos.
Definition: imagemanager.h:441
ImageDbReader::m_remote
ImageDbSg * m_remote
Remote database access.
Definition: imagemanager.h:438
ImageItem
Represents a picture, video or directory.
Definition: imagetypes.h:68
MEDIATYPE_MGALLERY
@ MEDIATYPE_MGALLERY
Definition: mythmedia.h:33
ImageDbLocal::ImageDbLocal
ImageDbLocal()
Local database constructor.
Definition: imagemanager.cpp:1052
Device::~Device
~Device()
Delete device, its thumbnails and any imported images.
Definition: imagemanager.cpp:47
MediaMonitor::EjectMedia
void EjectMedia(const QString &path)
Definition: mythmediamonitor.cpp:276
DeviceManager::LocateMount
int LocateMount(const QString &mount) const
Find the id of a device.
Definition: imagemanager.cpp:232
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
ImageDb::GetChildren
int GetChildren(QString ids, ImageList &files, ImageList &dirs, const QString &refine="") const
Read immediate children of a dir.
Definition: imagemanager.cpp:563
Device::Device
Device(QString name, QString mount, MythMediaDevice *media=nullptr, QTemporaryDir *import=nullptr)
Definition: imagemanager.cpp:36
EXIF_MYTH_NAME
#define EXIF_MYTH_NAME
Definition: imagemetadata.h:40
ImageHandler::HandleIgnore
QStringList HandleIgnore(const QString &exclusions) const
Updates exclusion list for images.
Definition: imagemanager.cpp:1590
kSortByDateAsc
@ kSortByDateAsc
Exif date Earliest -> Latest.
Definition: imagetypes.h:53
DeviceManager::OpenDevice
int OpenDevice(const QString &name, const QString &mount, MythMediaDevice *media=nullptr, QTemporaryDir *dir=nullptr)
Define a new device and assign it a unique id. If the device is already known, its existing id is ret...
Definition: imagemanager.cpp:157
ImageDb::SetCover
bool SetCover(int dir, int id) const
Set the thumbnail(s) to be used for a dir.
Definition: imagemanager.cpp:916
ImageIdList
QList< int > ImageIdList
Definition: imagetypes.h:59
ImageAdapterBase::ThumbPath
static QString ThumbPath(const ImageItem &im)
Thumbnails of videos are a JPEG snapshot with jpg suffix appended.
Definition: imagemanager.h:152
ImageDb::ReadImages
int ReadImages(ImageList &dirs, ImageList &files, const QString &selector) const
Read selected database images/dirs.
Definition: imagemanager.cpp:966
ImageManagerFe::CrumbName
QString CrumbName(ImageItemK &im, bool getPath=false) const
Return a displayable name (with optional path) for an image.
Definition: imagemanager.cpp:2368
ImageItem::m_parentId
int m_parentId
Id of parent dir.
Definition: imagetypes.h:95
ImageDb::ClearDb
void ClearDb(int devId, const QString &action)
Clear Db for device & remove device.
Definition: imagemanager.cpp:723
StringPair
QPair< QString, QString > StringPair
Definition: imagetypes.h:60
ImageDbReader::GetChildren
int GetChildren(int id, ImageList &files, ImageList &dirs) const
Return (local or remote) images that are direct children of a dir.
Definition: imagemanager.cpp:1837
MythMediaDevice::getMediaType
MythMediaType getMediaType() const
Definition: mythmedia.h:91
ImageAdapterSg::GetAbsFilePath
QString GetAbsFilePath(const ImagePtrK &im) const
Get absolute filepath for a remote image.
Definition: imagemanager.cpp:477
EXIF_MYTH_HOST
#define EXIF_MYTH_HOST
Definition: imagemetadata.h:38
build_compdb.action
action
Definition: build_compdb.py:9
ImageDbReader::m_dirOrder
int m_dirOrder
Display ordering of dirs.
Definition: imagemanager.h:440
ImageManagerBe::getInstance
static ImageManagerBe * getInstance()
Get Backend Gallery.
Definition: imagemanager.cpp:1926
ImageDb::GetDirectory
int GetDirectory(int id, ImagePtr &parent, ImageList &files, ImageList &dirs, const QString &refine) const
Read a dir and its immediate children from Db.
Definition: imagemanager.cpp:581
DeviceManager::CloseDevices
QStringList CloseDevices(int devId, const QString &action)
Remove a device (or all devices)
Definition: imagemanager.cpp:189
DB_TABLE
#define DB_TABLE
Definition: imagemanager.cpp:19
ImageAdapterLocal::Notify
static void Notify(const QString &mesg, const QStringList &extra)
Send local message to UI about local ids.
Definition: imagemanager.cpp:385
ImageDb::RemoveFromDB
QStringList RemoveFromDB(const ImageList &imList) const
Remove images/dirs from database.
Definition: imagemanager.cpp:860
ImageDb::ReadAllImages
bool ReadAllImages(ImageHash &files, ImageHash &dirs) const
Read all database images and dirs as map. No filters or ordering applied.
Definition: imagemanager.cpp:692
ImageDbLocal::CreateTable
bool CreateTable()
Create local database table, if it doesn't exist.
Definition: imagemanager.cpp:1077
MediaMonitor::ValidateAndLock
bool ValidateAndLock(MythMediaDevice *pMedia)
Validates the MythMediaDevice and increments its reference count.
Definition: mythmediamonitor.cpp:509
MythDate::kDateFull
@ kDateFull
Default local time.
Definition: mythdate.h:16
DeviceManager::GetAbsentees
QList< int > GetAbsentees()
Get list of mountpoints for non-import devices.
Definition: imagemanager.cpp:260
ImageDbReader::SetRefinementClause
void SetRefinementClause()
Sets filter/ordering SQL clause used when reading database according to current filter/sort settings.
Definition: imagemanager.cpp:1737
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:856
ImageItem::m_userThumbnail
int m_userThumbnail
Id of thumbnail to use as cover (dirs only)
Definition: imagetypes.h:105
ImageHandler::HandleDelete
QStringList HandleDelete(const QString &ids) const
Deletes images/dirs.
Definition: imagemanager.cpp:1273
ImageItem::IsDevice
bool IsDevice() const
Definition: imagetypes.h:115
ImageAdapterSg::GetScanDirs
StringMap GetScanDirs() const
Returns SG dirs.
Definition: imagemanager.cpp:461
MythMediaDevice
Definition: mythmedia.h:49
ImageManagerFe::DeleteFiles
QString DeleteFiles(const ImageIdList &ids)
Delete images.
Definition: imagemanager.cpp:2279
kSortByModTimeAsc
@ kSortByModTimeAsc
File modified time Earliest -> Latest.
Definition: imagetypes.h:47
ReadMetaThread::ReadMetaThread
ReadMetaThread(ImagePtrK im, QString path)
Definition: imagemanager.cpp:1112
ImageDb< ImageAdapterLocal >::m_table
QString m_table
Db table name.
Definition: imagemanager.h:310
Device::setPresent
void setPresent(MythMediaDevice *media)
Definition: imagemanager.cpp:107
ReadMetaThread::m_path
QString m_path
Definition: imagemanager.cpp:1153
ImageDb
Database API.
Definition: imagemanager.h:275
ImageItem::m_extension
QString m_extension
Image file extension.
Definition: imagetypes.h:93
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:19
kDevice
@ kDevice
Storage Group and local mounted media.
Definition: imagetypes.h:35
ImageAdapterSg::CreateItem
ImageItem * CreateItem(const QFileInfo &fi, int parentId, int devId, const QString &base) const
Construct a remote image from a file.
Definition: imagemanager.cpp:401
ImageItem::m_date
qint64 m_date
Image creation date, from Exif metadata.
Definition: imagetypes.h:99
ImageManagerBe
The image manager to be used by the Backend.
Definition: imagemanager.h:379
kSortBySizeAsc
@ kSortBySizeAsc
File size Smallest -> Largest.
Definition: imagetypes.h:51
ImageDb::GetDescendants
bool GetDescendants(const QString &ids, ImageList &files, ImageList &dirs) const
Return images and all of their descendants.
Definition: imagemanager.cpp:623
ImageManagerFe::RequestMetaData
void RequestMetaData(int id)
Requests all exif/ffmpeg tags for an image, which returns by event.
Definition: imagemanager.cpp:2126
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:307
MythMediaStatus
MythMediaStatus
Definition: mythmedia.h:12
DeviceManager::m_devices
DeviceMap m_devices
Device store.
Definition: imagemanager.h:119
ImageDb::GetDescendantCount
void GetDescendantCount(int id, bool all, int &dirs, int &pics, int &videos, int &sizeKb) const
Return counts of dirs, pics, videos and size in the subtree of a dir.
Definition: imagemanager.cpp:1001
ImageAdapterBase::GetImageType
ImageNodeType GetImageType(const QString &ext) const
Determine file type from its extension.
Definition: imagemanager.h:165
query
MSqlQuery query(MSqlQuery::InitCon())
ImageManagerFe::ScanQuery
static QStringList ScanQuery()
Returns storage group scanner status.
Definition: imagemanager.cpp:2023
kUnknown
@ kUnknown
Unprocessable file type.
Definition: imagetypes.h:34
MythCoreContext::SaveSettingOnHost
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
Definition: mythcorecontext.cpp:909
ImageManagerFe::RenameFile
QString RenameFile(const ImagePtrK &im, const QString &name)
Rename an image.
Definition: imagemanager.cpp:2188
MythMediaDevice::getVolumeID
const QString & getVolumeID() const
Definition: mythmedia.h:72
Device::m_name
QString m_name
Device model/volume/id.
Definition: imagemanager.cpp:111
ImageManagerFe::ShortDateOf
QString ShortDateOf(const ImagePtrK &im) const
Return a short datestamp for thumbnail captions.
Definition: imagemanager.cpp:2335
ImageHandler::HandleCreateThumbnails
QStringList HandleCreateThumbnails(const QStringList &message) const
Creates thumbnails on-demand.
Definition: imagemanager.cpp:1656
ReadMetaThread::m_im
ImagePtrK m_im
Definition: imagemanager.cpp:1152
ImageHandler::HandleHide
QStringList HandleHide(bool hide, const QString &ids) const
Hides/unhides images/dirs.
Definition: imagemanager.cpp:1442
kSortBySizeDesc
@ kSortBySizeDesc
File size Largest -> Smallest.
Definition: imagetypes.h:52
Orientation
Encapsulates Exif orientation processing.
Definition: imagemetadata.h:63
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:342
ImageItem::m_size
int m_size
Filesize (files only)
Definition: imagetypes.h:98
MEDIATYPE_DATA
@ MEDIATYPE_DATA
Definition: mythmedia.h:26
GALLERY_DB_ID
#define GALLERY_DB_ID
Definition: imagetypes.h:26
kVideoOnly
@ kVideoOnly
Hide pictures.
Definition: imagemanager.h:80
TEMP_SUBDIR
#define TEMP_SUBDIR
Definition: imagemanager.h:67
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:916
ImageAdapterBase::SupportedVideos
static QStringList SupportedVideos()
Return recognised video extensions.
Definition: imagemanager.cpp:313
ReadMetaThread::run
void run() override
Definition: imagemanager.cpp:1115
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
ImageItem::m_filePath
QString m_filePath
Absolute for local images. Usually SG-relative for remotes.
Definition: imagetypes.h:92
kPicRequestPriority
@ kPicRequestPriority
Client request to display an image thumbnail.
Definition: imagethumbs.h:34
build_compdb.paths
paths
Definition: build_compdb.py:13
ImageManagerFe::DetectLocalDevices
bool DetectLocalDevices()
Detect and scan local devices.
Definition: imagemanager.cpp:2402