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 
9 #include "libmythbase/mythdate.h"
10 
11 #include "dbaccess.h" // for FileAssociations
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_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));
100  RemoveDirContents(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 { true };
111  QString m_name;
112  QString m_mount;
113  QString m_thumbs;
114  MythMediaDevice *m_media { nullptr };
115  QTemporaryDir *m_dir { nullptr };
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.lastKey() + 1;
170  m_devices.insert(id, new Device(name, mount, media, dir));
171  }
172  else
173  {
174  Device *dev = m_devices.value(id);
175  if (dev)
176  dev->setPresent(media);
177  }
178 
179  LOG(VB_GENERAL, LOG_INFO, LOC +
180  QString("%1 device %2 mounted at '%3' [Id %4]")
181  .arg(state, name, mount).arg(id));
182 
183  return id;
184 }
185 
186 
193 QStringList DeviceManager::CloseDevices(int devId, const QString &action)
194 {
195  QStringList clear;
196 
197  if (action == "DEVICE CLOSE ALL")
198  {
199  // Close all devices but retain their thumbnails
200  for (auto *dev : qAsConst(m_devices))
201  if (dev)
202  dev->Close();
203  }
204  else if (action == "DEVICE CLEAR ALL")
205  {
206  // Remove all thumbnails but retain devices
207  for (const auto *dev : qAsConst(m_devices)) {
208  if (dev)
209  {
210  clear << dev->m_mount;
211  dev->RemoveThumbs();
212  }
213  }
214  }
215  else
216  {
217  // Remove single device & its thumbnails, optionally ejecting it
218  Device *dev = m_devices.take(devId);
219  if (dev)
220  {
221  if (action == "DEVICE EJECT")
222  dev->Close(true);
223  clear << dev->m_mount;
224  delete dev;
225  }
226  }
227  return clear;
228 }
229 
230 
236 int DeviceManager::LocateMount(const QString &mount) const
237 {
238  DeviceMap::const_iterator it = m_devices.constBegin();
239  while (it != m_devices.constEnd())
240  {
241  if (it.value()->m_mount == mount)
242  return it.key();
243  ++it;
244  }
245  return DEVICE_INVALID;
246 }
247 
248 
251 {
253 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
254  for (int id : m_devices.keys())
255  {
256  Device *dev = m_devices.value(id);
257  if (dev)
258  paths.insert(id, dev->m_mount);
259  }
260 #elif QT_VERSION < QT_VERSION_CHECK(5,15,0)
261  for (auto it = m_devices.constKeyValueBegin();
262  it != m_devices.constKeyValueEnd(); ++it)
263  {
264  if ((*it).second)
265  paths.insert((*it).first, (*it).second->m_mount);
266  }
267 #else
268  for (auto it = m_devices.constKeyValueBegin();
269  it != m_devices.constKeyValueEnd(); ++it)
270  {
271  if (it->second)
272  paths.insert(it->first, it->second->m_mount);
273  }
274 #endif
275  return paths;
276 }
277 
278 
281 {
282  QList<int> absent;
283 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
284  for (int id : m_devices.keys())
285  {
286  Device *dev = m_devices.value(id);
287  if (dev && !dev->isPresent())
288  absent << id;
289  }
290 #elif QT_VERSION < QT_VERSION_CHECK(5,15,0)
291  for (auto it = m_devices.constKeyValueBegin();
292  it != m_devices.constKeyValueEnd(); it++)
293  {
294  Device *dev = (*it).second;
295  if (dev && !dev->isPresent())
296  absent << (*it).first;
297  }
298 #else
299  for (auto it = m_devices.constKeyValueBegin();
300  it != m_devices.constKeyValueEnd(); it++)
301  {
302  Device *dev = it->second;
303  if (dev && !dev->isPresent())
304  absent << it->first;
305  }
306 #endif
307  return absent;
308 }
309 
310 
315  m_imageFileExt(SupportedImages()),
316  m_videoFileExt(SupportedVideos())
317 {
318  // Generate glob list from supported extensions
319  QStringList glob;
320  QStringList allExt = m_imageFileExt + m_videoFileExt;
321  for (const auto& ext : qAsConst(allExt))
322  glob << "*." + ext;
323 
324  // Apply filters to only detect image files
325  m_dirFilter.setNameFilters(glob);
326  m_dirFilter.setFilter(QDir::AllDirs | QDir::Files | QDir::Readable |
327  QDir::NoDotAndDotDot | QDir::NoSymLinks);
328 
329  // Sync files before dirs to improve thumb generation response
330  // Order by time (oldest first) - this determines the order thumbs appear
331  m_dirFilter.setSorting(QDir::DirsLast | QDir::Time | QDir::Reversed);
332 }
333 
339 {
340  // Determine supported picture formats from Qt
341  QStringList formats;
342  QList<QByteArray> supported = QImageReader::supportedImageFormats();
343  for (const auto& ext : qAsConst(supported))
344  formats << QString(ext);
345  return formats;
346 }
347 
348 
354 {
355  // Determine supported video formats from MythVideo
356  QStringList formats;
359  for (const auto & fa : faList)
360  {
361  if (!fa.use_default && fa.playcommand == "Internal")
362  formats << QString(fa.extension);
363  }
364  return formats;
365 }
366 
367 
376 ImageItem *ImageAdapterLocal::CreateItem(const QFileInfo &fi, int parentId,
377  int devId, const QString & /*base*/) const
378 {
379  auto *im = new ImageItem();
380 
381  im->m_parentId = parentId;
382  im->m_device = devId;
383  im->m_filePath = fi.absoluteFilePath();
384 
385  if (parentId == GALLERY_DB_ID)
386  {
387  // Import devices show time of import, other devices show 'last scan time'
388  auto secs = im->m_filePath.contains(IMPORTDIR)
389  ? fi.lastModified().toSecsSinceEpoch()
390  : QDateTime::currentSecsSinceEpoch();
391  im->m_date = std::chrono::seconds(secs);
392  im->m_modTime = im->m_date;
393  im->m_type = kDevice;
394  return im;
395  }
396 
397  im->m_modTime = std::chrono::seconds(fi.lastModified().toSecsSinceEpoch());
398 
399  if (fi.isDir())
400  {
401  im->m_type = kDirectory;
402  return im;
403  }
404 
405  im->m_extension = fi.suffix().toLower();
406  im->m_type = GetImageType(im->m_extension);
407 
408  if (im->m_type == kUnknown)
409  {
410  delete im;
411  return nullptr;
412  }
413 
414  im->m_thumbPath = GetAbsThumbPath(ThumbDir(im->m_device), ThumbPath(*im));
415  im->m_size = fi.size();
416 
417  return im;
418 }
419 
420 
426 void ImageAdapterLocal::Notify(const QString &mesg,
427  const QStringList &extra)
428 {
429  QString host(gCoreContext->GetHostName());
430  gCoreContext->SendEvent(MythEvent(QString("%1 %2").arg(mesg, host), extra));
431 }
432 
433 
442 ImageItem *ImageAdapterSg::CreateItem(const QFileInfo &fi, int parentId,
443  int /*devId*/, const QString &base) const
444 {
445  auto *im = new ImageItem();
446 
447  im->m_device = 0;
448  im->m_parentId = parentId;
449 
450  if (parentId == GALLERY_DB_ID)
451  {
452  // All SG dirs map to a single Db dir
453  im->m_filePath = "";
454  im->m_type = kDevice;
455  im->m_date = std::chrono::seconds(QDateTime::currentSecsSinceEpoch());
456  im->m_modTime = im->m_date;
457  return im;
458  }
459 
460  // Strip SG path & leading / to leave a relative path
461  im->m_filePath = fi.absoluteFilePath().mid(base.size() + 1);
462  im->m_modTime = std::chrono::seconds(fi.lastModified().toSecsSinceEpoch());
463 
464  if (fi.isDir())
465  {
466  im->m_type = kDirectory;
467  return im;
468  }
469 
470  im->m_extension = fi.suffix().toLower();
471  im->m_type = GetImageType(im->m_extension);
472 
473  if (im->m_type == kUnknown)
474  {
475  delete im;
476  return nullptr;
477  }
478 
479  im->m_thumbPath = GetAbsThumbPath(ThumbDir(im->m_device), ThumbPath(*im));
480  im->m_size = fi.size();
481 
482  return im;
483 }
484 
485 
491 void ImageAdapterSg::Notify(const QString &mesg,
492  const QStringList &extra)
493 {
494  gCoreContext->SendEvent(MythEvent(mesg, extra));
495 }
496 
497 
503 {
504  StringMap map;
505  int i = 0;
506  QStringList paths = m_sg.GetDirList();
507  for (const auto& path : qAsConst(paths))
508  map.insert(i++, path);
509  return map;
510 }
511 
512 
520 {
521  if (im->IsDevice())
522  return m_sg.FindNextDirMostFree();
523  return im->m_filePath.startsWith("/") ? im->m_filePath
524  : m_sg.FindFile(im->m_filePath);
525 }
526 
527 
528 // Database fields used by several image queries
529 #define DB_COLUMNS \
530 "file_id, filename, name, dir_id, type, modtime, size, " \
531 "extension, date, hidden, orientation, angle, path, zoom"
532 // Id, filepath, basename, parentId, type, modtime, size,
533 // extension, image date, hidden, orientation, cover id, comment, device id
534 
535 
541 template <class FS>
543 {
544  auto *im = new ImageItem(FS::ImageId(query.value(0).toInt()));
545 
546  // Ordered as per DB_COLUMNS
547  im->m_filePath = query.value(1).toString();
548  im->m_baseName = query.value(2).toString();
549  im->m_parentId = FS::ImageId(query.value(3).toInt());
550  im->m_type = query.value(4).toInt();
551  im->m_modTime = std::chrono::seconds(query.value(5).toInt());
552  im->m_size = query.value(6).toInt();
553  im->m_extension = query.value(7).toString();
554  im->m_date = std::chrono::seconds(query.value(8).toUInt());
555  im->m_isHidden = query.value(9).toBool();
556  im->m_orientation = query.value(10).toInt();
557  im->m_userThumbnail = FS::ImageId(query.value(11).toInt());
558  im->m_comment = query.value(12).toString();
559  im->m_device = query.value(13).toInt();
560  im->m_url = FS::MakeFileUrl(im->m_filePath);
561 
562  if (im->IsFile())
563  {
564  // Only pics/vids have thumbs
565  QString thumbPath(FS::ThumbPath(*im));
566  QString devPath(FS::ThumbDir(im->m_device));
567  QString url(FS::MakeThumbUrl(devPath, thumbPath));
568 
569  im->m_thumbPath = FS::GetAbsThumbPath(devPath, thumbPath);
570  im->m_thumbNails.append(qMakePair(im->m_id, url));
571  }
572  return im;
573 }
574 
575 
584 template <class FS>
585 int ImageDb<FS>::GetImages(const QString &ids, ImageList &files, ImageList &dirs,
586  const QString &refine) const
587 {
588  if (ids.isEmpty())
589  return 0;
590 
591  QString select = QString("file_id IN (%1) %2").arg(FS::DbIds(ids), refine);
592  return ReadImages(dirs, files, select);
593 }
594 
595 
604 template <class FS>
605 int ImageDb<FS>::GetChildren(const QString &ids, ImageList &files, ImageList &dirs,
606  const QString &refine) const
607 {
608  QString select = QString("dir_id IN (%1) %2").arg(FS::DbIds(ids), refine);
609  return ReadImages(dirs, files, select);
610 }
611 
612 
622 template <class FS>
624  ImageList &files, ImageList &dirs,
625  const QString &refine) const
626 {
627  MSqlQuery query(MSqlQuery::InitCon());
628  query.prepare(QString("SELECT " DB_COLUMNS " FROM %1 "
629  "WHERE (dir_id = :ID1 OR file_id = :ID2) "
630  "%2;").arg(m_table, refine));
631 
632  // Qt < 5.4 won't bind multiple occurrences
633  int dbId = FS::DbId(id);
634  query.bindValue(":ID1", dbId);
635  query.bindValue(":ID2", dbId);
636 
637  if (!query.exec())
638  {
639  MythDB::DBError(DBLOC, query);
640  return -1;
641  }
642  while (query.next())
643  {
644  ImagePtr im(CreateImage(query));
645 
646  if (im->IsFile())
647  files.append(im);
648  else if (im->m_id == id)
649  parent = im;
650  else
651  dirs.append(im);
652  }
653  return query.size();
654 }
655 
656 
664 template <class FS>
665 bool ImageDb<FS>::GetDescendants(const QString &ids,
666  ImageList &files, ImageList &dirs) const
667 {
668  if (ids.isEmpty())
669  return false;
670 
671  if (ReadImages(dirs, files, QString("file_id IN (%1)").arg(FS::DbIds(ids))) < 0)
672  return false;
673 
674  MSqlQuery query(MSqlQuery::InitCon());
675  QString sql =
676  QString("SELECT " DB_COLUMNS
677  ", LENGTH(filename) - LENGTH(REPLACE(filename, '/', ''))"
678  " AS depth "
679  "FROM %1 WHERE filename LIKE :PREFIX "
680  "ORDER BY depth;").arg(m_table);
681 
682  for (const auto& im1 : qAsConst(dirs))
683  {
684  query.prepare(sql);
685  query.bindValue(":PREFIX", im1->m_filePath + "/%");
686 
687  if (!query.exec())
688  {
689  MythDB::DBError(DBLOC, query);
690  return false;
691  }
692 
693  while (query.next())
694  {
695  ImagePtr im2(CreateImage(query));
696  if (im2->IsDirectory())
697  dirs.append(im2);
698  else
699  files.append(im2);
700  }
701  }
702  return true;
703 }
704 
705 
713 template <class FS>
714 bool ImageDb<FS>::GetImageTree(int id, ImageList &files, const QString &refine) const
715 {
716  // Load starting children
717  ImageList dirs;
718  if (GetChildren(QString::number(id), files, dirs, refine) < 0)
719  return false;
720 
721  for (const auto& im : qAsConst(dirs))
722  if (!GetImageTree(im->m_id, files, refine))
723  return false;
724  return true;
725 }
726 
727 
733 template <class FS>
735 {
736  MSqlQuery query(MSqlQuery::InitCon());
737  query.prepare(QString("SELECT " DB_COLUMNS " FROM %1").arg(m_table));
738 
739  if (!query.exec())
740  {
741  MythDB::DBError(DBLOC, query);
742  return false;
743  }
744 
745  while (query.next())
746  {
747  ImagePtr im(CreateImage(query));
748  if (im->IsDirectory())
749  dirs.insert(im->m_filePath, im);
750  else
751  files.insert(im->m_filePath, im);
752  }
753  return true;
754 }
755 
756 
764 template <class FS>
765 void ImageDb<FS>::ClearDb(int devId, const QString &action)
766 {
767  if (action == "DEVICE CLOSE ALL")
768  // Retain Db images when closing UI
769  return;
770 
771  MSqlQuery query(MSqlQuery::InitCon());
772 
773  if (action == "DEVICE CLEAR ALL")
774  {
775  // Clear images from all devices. Reset auto-increment
776  query.prepare(QString("TRUNCATE TABLE %1;").arg(m_table));
777 
778  if (!query.exec())
779  MythDB::DBError(DBLOC, query);
780  }
781  else // Actions DEVICE REMOVE & DEVICE EJECT
782  {
783  // Delete all images of the device
784  query.prepare(QString("DELETE IGNORE FROM %1 WHERE zoom = :FS;").arg(m_table));
785  query.bindValue(":FS", devId);
786 
787  if (!query.exec())
788  MythDB::DBError(DBLOC, query);
789  }
790 }
791 
792 
800 template <class FS>
801 int ImageDb<FS>::InsertDbImage(ImageItemK &im, bool checkForDuplicate) const
802 {
803  MSqlQuery query(MSqlQuery::InitCon());
804 
805  if (checkForDuplicate)
806  {
807  query.prepare(QString("SELECT file_id FROM %1 WHERE filename = :NAME;")
808  .arg(m_table));
809 
810  query.bindValue(":NAME", im.m_filePath);
811 
812  if (!query.exec())
813  {
814  MythDB::DBError(DBLOC, query);
815  return -1;
816  }
817 
818  if (query.size() > 0)
819  {
820  LOG(VB_FILE, LOG_DEBUG, QString("Image: %1 already exists in Db")
821  .arg(im.m_filePath));
822  return query.value(0).toInt();
823  }
824  }
825 
826  query.prepare(QString("INSERT INTO %1 (" DB_COLUMNS ") VALUES (0, "
827  ":FILEPATH, :NAME, :PARENT, :TYPE, :MODTIME, "
828  ":SIZE, :EXTENSION, :DATE, :HIDDEN, :ORIENT, "
829  ":COVER, :COMMENT, :FS);").arg(m_table));
830 
831  query.bindValue(":FILEPATH", im.m_filePath);
832  query.bindValue(":NAME", FS::BaseNameOf(im.m_filePath));
833  query.bindValue(":FS", im.m_device);
834  query.bindValue(":PARENT", FS::DbId(im.m_parentId));
835  query.bindValue(":TYPE", im.m_type);
836  query.bindValue(":MODTIME", static_cast<qint64>(im.m_modTime.count()));
837  query.bindValue(":SIZE", im.m_size);
838  query.bindValue(":EXTENSION", im.m_extension);
839  query.bindValue(":DATE", static_cast<qint64>(im.m_date.count()));
840  query.bindValue(":ORIENT", im.m_orientation);
841  query.bindValueNoNull(":COMMENT", im.m_comment);
842  query.bindValue(":HIDDEN", im.m_isHidden);
843  query.bindValue(":COVER", FS::DbId(im.m_userThumbnail));
844 
845  if (query.exec())
846  return FS::ImageId(query.lastInsertId().toInt());
847 
848  MythDB::DBError(DBLOC, query);
849  return -1;
850 }
851 
852 
858 template <class FS>
860 {
861  MSqlQuery query(MSqlQuery::InitCon());
862  query.prepare(QString
863  ("UPDATE %1 SET "
864  "filename = :FILEPATH, name = :NAME, "
865  "dir_id = :PARENT, type = :TYPE, "
866  "modtime = :MODTIME, size = :SIZE, "
867  "extension = :EXTENSION, date = :DATE, zoom = :FS, "
868  "hidden = :HIDDEN, orientation = :ORIENT, "
869  "angle = :COVER, path = :COMMENT "
870  "WHERE file_id = :ID;").arg(m_table));
871 
872  query.bindValue(":ID", FS::DbId(im.m_id));
873  query.bindValue(":FILEPATH", im.m_filePath);
874  query.bindValue(":NAME", FS::BaseNameOf(im.m_filePath));
875  query.bindValue(":PARENT", FS::DbId(im.m_parentId));
876  query.bindValue(":TYPE", im.m_type);
877  query.bindValue(":MODTIME", static_cast<qint64>(im.m_modTime.count()));
878  query.bindValue(":SIZE", im.m_size);
879  query.bindValue(":EXTENSION", im.m_extension);
880  query.bindValue(":DATE", static_cast<qint64>(im.m_date.count()));
881  query.bindValue(":FS", im.m_device);
882  query.bindValue(":HIDDEN", im.m_isHidden);
883  query.bindValue(":ORIENT", im.m_orientation);
884  query.bindValue(":COVER", FS::DbId(im.m_userThumbnail));
885  query.bindValueNoNull(":COMMENT", im.m_comment);
886 
887  if (query.exec())
888  return true;
889 
890  MythDB::DBError(DBLOC, query);
891  return false;
892 }
893 
894 
901 template <class FS>
902 QStringList ImageDb<FS>::RemoveFromDB(const ImageList &imList) const
903 {
904  QStringList ids;
905  if (!imList.isEmpty())
906  {
907  for (const auto& im : qAsConst(imList))
908  ids << QString::number(FS::DbId(im->m_id));
909 
910  QString idents = ids.join(",");
911  MSqlQuery query(MSqlQuery::InitCon());
912  query.prepare(QString("DELETE IGNORE FROM %1 WHERE file_id IN (%2);")
913  .arg(m_table, idents));
914 
915  if (!query.exec())
916  {
917  MythDB::DBError(DBLOC, query);
918  return {};
919  }
920  }
921  return ids;
922 }
923 
924 
931 template <class FS>
932 bool ImageDb<FS>::SetHidden(bool hide, const QString &ids) const
933 {
934  if (ids.isEmpty())
935  return false;
936 
937  MSqlQuery query(MSqlQuery::InitCon());
938 
939  query.prepare(QString("UPDATE %1 SET "
940  "hidden = :HIDDEN "
941  "WHERE file_id IN (%2);").arg(m_table, FS::DbIds(ids)));
942  query.bindValue(":HIDDEN", hide ? 1 : 0);
943 
944  if (query.exec())
945  return true;
946 
947  MythDB::DBError(DBLOC, query);
948  return false;
949 }
950 
951 
957 template <class FS>
958 bool ImageDb<FS>::SetCover(int dir, int id) const
959 {
960  MSqlQuery query(MSqlQuery::InitCon());
961 
962  query.prepare(QString("UPDATE %1 SET "
963  "angle = :COVER "
964  "WHERE file_id = :DIR").arg(m_table));
965  query.bindValue(":COVER", FS::DbId(id));
966  query.bindValue(":DIR", FS::DbId(dir));
967  \
968  if (query.exec())
969  return true;
970 
971  MythDB::DBError(DBLOC, query);
972  return false;
973 }
974 
975 
981 template <class FS>
982 bool ImageDb<FS>::SetOrientation(int id, int orientation) const
983 {
984  MSqlQuery query(MSqlQuery::InitCon());
985 
986  query.prepare(QString("UPDATE %1 SET ").arg(m_table) +
987  "orientation = :ORIENTATION "
988  "WHERE file_id = :ID");
989  query.bindValue(":ORIENTATION", orientation);
990  query.bindValue(":ID", FS::DbId(id));
991  \
992  if (query.exec())
993  return true;
994 
995  MythDB::DBError(DBLOC, query);
996  return false;
997 }
998 
999 
1007 template <class FS>
1009  const QString &selector) const
1010 {
1011  MSqlQuery query(MSqlQuery::InitCon());
1012  query.prepare(QString("SELECT " DB_COLUMNS " FROM %1 WHERE %2")
1013  .arg(m_table, selector));
1014  if (!query.exec())
1015  {
1016  MythDB::DBError(DBLOC, query);
1017  return -1;
1018  }
1019 
1020  while (query.next())
1021  {
1022  ImagePtr im(CreateImage(query));
1023 
1024  if (im->IsFile())
1025  files.append(im);
1026  else
1027  dirs.append(im);
1028  }
1029  return query.size();
1030 }
1031 
1032 
1042 template <class FS>
1043 void ImageDb<FS>::GetDescendantCount(int id, bool all, int &dirs,
1044  int &pics, int &videos, int &sizeKb) const
1045 {
1046  QString whereClause;
1047  if (!all)
1048  {
1049  whereClause = "WHERE filename LIKE "
1050  "( SELECT CONCAT(filename, '/%') "
1051  " FROM %2 WHERE file_id = :ID);";
1052  }
1053 
1054  MSqlQuery query(MSqlQuery::InitCon());
1055  query.prepare(QString("SELECT SUM(type <= :FLDR) AS Fldr, "
1056  " SUM(type = :PIC) AS Pics, "
1057  " SUM(type = :VID) AS Vids, "
1058  " SUM(size / 1024) "
1059  "FROM %2 %1;").arg(whereClause, m_table));
1060 
1061  query.bindValue(":FLDR", kDirectory);
1062  query.bindValue(":PIC", kImageFile);
1063  query.bindValue(":VID", kVideoFile);
1064  if (!all)
1065  query.bindValue(":ID", FS::DbId(id));
1066 
1067  if (!query.exec())
1068  {
1069  MythDB::DBError(DBLOC, query);
1070  }
1071  else if (query.next())
1072  {
1073  dirs += query.value(0).toInt();
1074  pics += query.value(1).toInt();
1075  videos += query.value(2).toInt();
1076  sizeKb += query.value(3).toInt();
1077  }
1078 }
1079 
1080 
1085 {
1086  // Be has a single SG device
1088 }
1089 
1090 
1095  : ImageDb(QString("`%1_%2`").arg(DB_TABLE, gCoreContext->GetHostName()))
1096 {
1097  // Remove any table leftover from a previous FE crash
1098  DropTable();
1099 }
1100 
1101 
1106 {
1107  MSqlQuery query(MSqlQuery::InitCon());
1108  query.prepare(QString("DROP TABLE IF EXISTS %1;").arg(m_table));
1109  if (query.exec())
1110  m_dbExists = false;
1111  else
1112  MythDB::DBError(DBLOC, query);
1113 }
1114 
1115 
1120 {
1121  if (m_dbExists)
1122  return true;
1123 
1124  MSqlQuery query(MSqlQuery::InitCon());
1125 
1126  // Create temporary table
1127  query.prepare(QString("CREATE TABLE %1 LIKE " DB_TABLE ";").arg(m_table));
1128  if (query.exec())
1129  {
1130  // Store it in memory only
1131  query.prepare(QString("ALTER TABLE %1 ENGINE = MEMORY;").arg(m_table));
1132  if (query.exec())
1133  {
1134  m_dbExists = true;
1135  LOG(VB_FILE, LOG_DEBUG, QString("Created Db table %1").arg(m_table));
1136  return true;
1137  }
1138  }
1139  MythDB::DBError(DBLOC, query);
1140 
1141  // Clean up after failure
1142  query.prepare(QString("DROP TABLE IF EXISTS %1;").arg(m_table));
1143  query.exec();
1144  return false;
1145 }
1146 
1147 
1151 class ReadMetaThread : public QRunnable
1152 {
1153 public:
1154  ReadMetaThread(ImagePtrK im, QString path)
1155  : m_im(std::move(im)), m_path(std::move(path)) {}
1156 
1157  void run() override // QRunnable
1158  {
1159  QStringList tags;
1160  QString orientation;
1161  QString size;
1162 
1163  // Read metadata for files only
1164  if (m_im->IsFile())
1165  {
1166  ImageMetaData *metadata = (m_im->m_type == kVideoFile)
1169  tags = metadata->GetAllTags();
1170  orientation = Orientation(m_im->m_orientation).Description();
1171  size = ImageAdapterBase::FormatSize(m_im->m_size / 1024);
1172  delete metadata;
1173  }
1174 
1175  // Add identifier at front
1176  tags.prepend(QString::number(m_im->m_id));
1177 
1178  // Include file info
1179  tags << ImageMetaData::ToString(EXIF_MYTH_HOST, "Host",
1181  tags << ImageMetaData::ToString(EXIF_MYTH_PATH, "Path",
1183  tags << ImageMetaData::ToString(EXIF_MYTH_NAME, "Name",
1185  tags << ImageMetaData::ToString(EXIF_MYTH_SIZE, "Size", size);
1186  tags << ImageMetaData::ToString(EXIF_MYTH_ORIENT, "Orientation",
1187  orientation);
1188 
1189  MythEvent me("IMAGE_METADATA", tags);
1190  gCoreContext->SendEvent(me);
1191  }
1192 
1193 private:
1195  QString m_path;
1196 };
1197 
1198 
1207 template <class DBFS>
1208 QStringList ImageHandler<DBFS>::HandleGetMetadata(const QString &id) const
1209 {
1210  // Find image in DB
1211  ImageList files;
1212  ImageList dirs;
1213  if (DBFS::GetImages(id, files, dirs) != 1)
1214  RESULT_ERR("Image not found", QString("Unknown image %1").arg(id))
1215 
1216  ImagePtr im = files.isEmpty() ? dirs[0] : files[0];
1217 
1218  QString absPath = DBFS::GetAbsFilePath(im);
1219  if (absPath.isEmpty())
1220  RESULT_ERR("Image not found",
1221  QString("File %1 not found").arg(im->m_filePath))
1222 
1223  auto *worker = new ReadMetaThread(im, absPath);
1224 
1225  MThreadPool::globalInstance()->start(worker, "ImageMetaData");
1226 
1227  RESULT_OK(QString("Fetching metadata for %1").arg(id))
1228 }
1229 
1230 
1238 template <class DBFS>
1239 QStringList ImageHandler<DBFS>::HandleRename(const QString &id,
1240  const QString &newBase) const
1241 {
1242  // Sanity check new name
1243  if (newBase.isEmpty() || newBase.contains("/") || newBase.contains("\\"))
1244  RESULT_ERR("Invalid name", QString("Invalid name %1").arg(newBase))
1245 
1246  // Find image in DB
1247  ImageList files;
1248  ImageList dirs;
1249  if (DBFS::GetImages(id, files, dirs) != 1)
1250  RESULT_ERR("Image not found", QString("Image %1 not in Db").arg(id))
1251 
1252  ImagePtr im = files.isEmpty() ? dirs[0] : files[0];
1253 
1254  // Find file
1255  QString oldPath = DBFS::GetAbsFilePath(im);
1256  if (oldPath.isEmpty())
1257  RESULT_ERR("Image not found",
1258  QString("File %1 not found").arg(im->m_filePath))
1259 
1260  // Generate new filename
1261  QFileInfo oldFi = QFileInfo(oldPath);
1262  QString newName = im->IsDirectory()
1263  ? newBase : QString("%1.%2").arg(newBase, oldFi.suffix());
1264 
1265  im->m_filePath = DBFS::ConstructPath(DBFS::PathOf(im->m_filePath), newName);
1266 
1267  // Ensure no SG duplicate files are created. (Creating clone dirs is ok)
1268  if (im->IsFile())
1269  {
1270  QString existPath = DBFS::GetAbsFilePath(im);
1271  if (!existPath.isEmpty())
1272  RESULT_ERR("Filename already used",
1273  QString("Renaming %1 to %2 will create a duplicate of %3")
1274  .arg(oldPath, im->m_filePath, existPath))
1275  }
1276 
1277  // Rename file or directory
1278  QString newPath = oldFi.dir().absoluteFilePath(newName);
1279  if (!QFile::rename(oldPath, newPath))
1280  RESULT_ERR("Rename failed",
1281  QString("Rename of %1 -> %2 failed").arg(oldPath, newPath))
1282 
1283  if (im->IsDirectory())
1284  {
1285  // Dir name change affects path of all sub-dirs & files and their thumbs
1286  HandleScanRequest("START");
1287  }
1288  else // file
1289  {
1290  // Update db
1291  DBFS::UpdateDbImage(*im);
1292 
1293  // Image is modified, not deleted
1294  QStringList mesg("");
1295  mesg << QString::number(im->m_id);
1296 
1297  // Rename thumbnail.
1298  m_thumbGen->MoveThumbnail(im);
1299 
1300  // Notify clients of changed image
1301  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1302  }
1303  RESULT_OK(QString("Renamed %1 -> %2").arg(oldPath, newPath))
1304 }
1305 
1306 
1314 template <class DBFS>
1315 QStringList ImageHandler<DBFS>::HandleDelete(const QString &ids) const
1316 {
1317  // Get subtree of all files
1318  ImageList files;
1319  ImageList dirs;
1320  // Dirs will be in depth-first order, (subdirs after parent)
1321  DBFS::GetDescendants(ids, files, dirs);
1322 
1323  // Remove files from filesystem first
1324  RemoveFiles(files);
1325  // ... then dirs, which should now be empty
1326  RemoveFiles(dirs);
1327 
1328  // Fail if nothing deleted
1329  if (files.isEmpty() && dirs.isEmpty())
1330  RESULT_ERR("Delete failed", QString("Delete of %1 failed").arg(ids))
1331 
1332  // Update Db
1333  DBFS::RemoveFromDB(files + dirs);
1334 
1335  // Clean up thumbnails
1336  QStringList mesg(m_thumbGen->DeleteThumbs(files));
1337 
1338  // Notify clients of deleted ids
1339  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1340 
1341  return QStringList("OK");
1342 }
1343 
1344 
1357 template <class DBFS>
1358 QStringList ImageHandler<DBFS>::HandleDbCreate(QStringList defs) const
1359 {
1360  if (defs.isEmpty())
1361  RESULT_ERR("Copy Failed", "Empty defs")
1362 
1363  // First item is the field seperator
1364  const QString separator = defs.takeFirst();
1365 
1366  // Convert cover ids to their new equivalent. Map<source id, new id>
1367  // Dirs follow their children so new cover ids will be defined before they
1368  // are used
1369  QHash<QString, int> idMap;
1370 
1371  // Create skeleton Db images using copied settings.
1372  // Scanner will update other attributes
1373  ImageItem im;
1374  for (const auto& def : qAsConst(defs))
1375  {
1376  QStringList aDef = def.split(separator);
1377 
1378  // Expects id, type, path, hidden, orientation, cover
1379  if (aDef.size() != 6)
1380  {
1381  // Coding error
1382  LOG(VB_GENERAL, LOG_ERR,
1383  LOC + QString("Bad definition: (%1)").arg(def));
1384  continue;
1385  }
1386 
1387  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Creating %1").arg(aDef.join(",")));
1388 
1389  im.m_type = aDef[1].toInt();
1390  im.m_filePath = aDef[2];
1391  im.m_isHidden = (aDef[3].toInt() != 0);
1392  im.m_orientation = aDef[4].toInt();
1393  im.m_userThumbnail = idMap.value(aDef[5]);
1394 
1395  // Don't insert duplicate filepaths
1396  int newId = DBFS::InsertDbImage(im, true);
1397 
1398  // Record old->new id map in case it's being used as a cover
1399  idMap.insert(aDef[0], newId);
1400  }
1401  HandleScanRequest("START");
1402 
1403  RESULT_OK("Created Db images")
1404 }
1405 
1406 
1416 template <class DBFS>
1417 QStringList ImageHandler<DBFS>::HandleDbMove(const QString &ids,
1418  const QString &srcPath,
1419  QString destPath) const
1420 {
1421  // Sanity check new path
1422  if (destPath.contains(".."))
1423  RESULT_ERR("Invalid path", QString("Invalid path %1").arg(destPath))
1424 
1425  // Get subtrees of renamed files
1426  ImageList images;
1427  ImageList dirs;
1428  ImageList files;
1429  bool ok = DBFS::GetDescendants(ids, files, dirs);
1430  images << dirs << files;
1431 
1432  if (!ok || images.isEmpty())
1433  RESULT_ERR("Image not found", QString("Images %1 not in Db").arg(ids))
1434 
1435  if (!destPath.isEmpty() && !destPath.endsWith(QChar('/')))
1436  destPath.append("/");
1437 
1438  // Update path of images only. Scanner will repair parentId
1439  for (const auto& im : qAsConst(images))
1440  {
1441  QString old = im->m_filePath;
1442 
1443  if (srcPath.isEmpty())
1444  {
1445  // Image in SG root
1446  im->m_filePath.prepend(destPath);
1447  }
1448  else if (im->m_filePath.startsWith(srcPath))
1449  {
1450  // All other images
1451  im->m_filePath.replace(srcPath, destPath);
1452  }
1453  else
1454  {
1455  // Coding error
1456  LOG(VB_GENERAL, LOG_ERR,
1457  LOC + QString("Bad image: (%1 -> %2)").arg(srcPath, destPath));
1458  continue;
1459  }
1460 
1461  LOG(VB_FILE, LOG_DEBUG,
1462  LOC + QString("Db Renaming %1 -> %2").arg(old, im->m_filePath));
1463 
1464  DBFS::UpdateDbImage(*im);
1465 
1466  // Rename thumbnail
1467  if (im->IsFile())
1468  m_thumbGen->MoveThumbnail(im);
1469  }
1470  HandleScanRequest("START");
1471 
1472  RESULT_OK(QString("Moved %1 from %2 -> %3").arg(ids, srcPath, destPath))
1473 }
1474 
1475 
1483 template <class DBFS>
1484 QStringList ImageHandler<DBFS>::HandleHide(bool hide, const QString &ids) const
1485 {
1486  if (!DBFS::SetHidden(hide, ids))
1487  RESULT_ERR("Hide failed", QString("Db hide failed for %1").arg(ids))
1488 
1489  // Send changed ids only (none deleted)
1490  QStringList mesg = QStringList("") << ids;
1491  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1492 
1493  RESULT_OK(QString("Images %1 now %2hidden").arg(ids, hide ? "" : "un"))
1494 }
1495 
1496 
1505 template <class DBFS>
1506 QStringList ImageHandler<DBFS>::HandleTransform(int transform,
1507  const QString &ids) const
1508 {
1509  if (transform < kResetToExif || transform > kFlipVertical)
1510  RESULT_ERR("Transform failed", QString("Bad transform %1").arg(transform))
1511 
1512  ImageList files;
1513  ImageList dirs;
1514  if (DBFS::GetImages(ids, files, dirs) < 1 || files.isEmpty())
1515  RESULT_ERR("Image not found", QString("Images %1 not in Db").arg(ids))
1516 
1517  // Update db
1518  for (const auto& im : qAsConst(files))
1519  {
1520  int old = im->m_orientation;
1521  im->m_orientation = Orientation(im->m_orientation).Transform(transform);
1522 
1523  // Update Db
1524  if (DBFS::SetOrientation(im->m_id, im->m_orientation))
1525  {
1526  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Transformed %1 from %2 to %3")
1527  .arg(im->m_filePath).arg(old).arg(im->m_orientation));
1528  }
1529  }
1530 
1531  // Images are changed, not deleted
1532  QStringList mesg("");
1533 
1534  // Clean up thumbnails
1535  mesg << m_thumbGen->DeleteThumbs(files);
1536 
1537  // Notify clients of changed images
1538  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1539 
1540  return QStringList("OK");
1541 }
1542 
1543 
1552 template <class DBFS>
1553 QStringList ImageHandler<DBFS>::HandleDirs(const QString &destId,
1554  bool rescan,
1555  const QStringList &relPaths) const
1556 {
1557  // Find image in DB
1558  ImageList files;
1559  ImageList dirs;
1560  if (DBFS::GetImages(destId, files, dirs) != 1 || dirs.isEmpty())
1561  RESULT_ERR("Destination not found",
1562  QString("Image %1 not in Db").arg(destId))
1563 
1564  // Find dir. SG device (Photographs) uses most-free filesystem
1565  QString destPath = DBFS::GetAbsFilePath(dirs[0]);
1566  if (destPath.isEmpty())
1567  RESULT_ERR("Destination not found",
1568  QString("Dest dir %1 not found").arg(dirs[0]->m_filePath))
1569 
1570  QDir destDir(destPath);
1571  bool succeeded = false;
1572  for (const auto& relPath : qAsConst(relPaths))
1573  {
1574  // Validate dir name
1575  if (relPath.isEmpty() || relPath.contains("..") || relPath.startsWith(QChar('/')))
1576  continue;
1577 
1578  QString newPath = DBFS::ConstructPath(destDir.absolutePath(), relPath);
1579  if (!destDir.mkpath(relPath))
1580  {
1581  LOG(VB_GENERAL, LOG_ERR,
1582  LOC + QString("Failed to create dir %1").arg(newPath));
1583  continue;
1584  }
1585  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Dir %1 created").arg(newPath));
1586  succeeded = true;
1587  }
1588 
1589  if (!succeeded)
1590  // Failures should only occur due to user input
1591  RESULT_ERR("Invalid Name", QString("Invalid name %1")
1592  .arg(relPaths.join(",")))
1593 
1594  if (rescan)
1595  // Rescan to detect new dir
1596  HandleScanRequest("START");
1597 
1598  return QStringList("OK");
1599 }
1600 
1601 
1608 template <class DBFS>
1609 QStringList ImageHandler<DBFS>::HandleCover(int dir, int cover) const
1610 {
1611  if (!DBFS::SetCover(dir, cover))
1612  RESULT_ERR("Set Cover failed",
1613  QString("Failed to set %1 to cover %2").arg(dir).arg(cover))
1614 
1615  // Image has changed, nothing deleted
1616  QStringList mesg = QStringList("") << QString::number(dir);
1617  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1618 
1619  RESULT_OK(QString("Cover of %1 is now %2").arg(dir).arg(cover));
1620 }
1621 
1622 
1631 template <class DBFS>
1632 QStringList ImageHandler<DBFS>::HandleIgnore(const QString &exclusions) const
1633 {
1634  // Save new setting. FE will have already saved it but not cleared the cache
1635  gCoreContext->SaveSettingOnHost("GalleryIgnoreFilter", exclusions, nullptr);
1636 
1637  // Rescan
1638  HandleScanRequest("START");
1639 
1640  RESULT_OK(QString("Using exclusions '%1'").arg(exclusions))
1641 }
1642 
1643 
1651 template <class DBFS>
1652 QStringList ImageHandler<DBFS>::HandleScanRequest(const QString &command,
1653  int devId) const
1654 {
1655  if (!m_scanner)
1656  RESULT_ERR("Missing Scanner", "Missing Scanner");
1657 
1658  if (command == "START")
1659  {
1660  // Must be dormant to start a scan
1661  if (m_scanner->IsScanning())
1662  RESULT_ERR("", "Scanner is busy");
1663 
1664  m_scanner->ChangeState(true);
1665  RESULT_OK("Scan requested");
1666  }
1667  else if (command == "STOP")
1668  {
1669  // Must be scanning to interrupt
1670  if (!m_scanner->IsScanning())
1671  RESULT_ERR("Scanner not running", "Scanner not running");
1672 
1673  m_scanner->ChangeState(false);
1674  RESULT_OK("Terminate scan requested");
1675  }
1676  else if (command == "QUERY")
1677  {
1678  return QStringList("OK") << m_scanner->GetProgress();
1679  }
1680  else if (command.startsWith(QString("DEVICE")))
1681  {
1682  m_scanner->EnqueueClear(devId, command);
1683  RESULT_OK(QString("Clearing device %1 %2").arg(command).arg(devId))
1684  }
1685  RESULT_ERR("Unknown command", QString("Unknown command %1").arg(command));
1686 }
1687 
1688 
1696 template <class DBFS>
1698 (const QStringList &message) const
1699 {
1700  if (message.size() != 2)
1701  RESULT_ERR("Unknown Command",
1702  QString("Bad request: %1").arg(message.join("|")))
1703 
1704  int priority = message.at(0).toInt()
1706 
1707  // get specific image details from db
1708  ImageList files;
1709  ImageList dirs;
1710  DBFS::GetImages(message.at(1), files, dirs);
1711 
1712  for (const auto& im : qAsConst(files))
1713  // notify clients when done; highest priority
1714  m_thumbGen->CreateThumbnail(im, priority, true);
1715 
1716  return QStringList("OK");
1717 }
1718 
1719 
1729 template <class DBFS>
1731 {
1732 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1733  QMutableVectorIterator<ImagePtr> it(images);
1734 #else
1735  QMutableListIterator<ImagePtr> it(images);
1736 #endif
1737  it.toBack();
1738  while (it.hasPrevious())
1739  {
1740  ImagePtrK im = it.previous();
1741 
1742  // Remove file or directory
1743  QString absFilename = DBFS::GetAbsFilePath(im);
1744 
1745  bool success = !absFilename.isEmpty()
1746  && (im->IsFile() ? QFile::remove(absFilename)
1747  : QDir::root().rmdir(absFilename));
1748  if (success)
1749  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Deleted %1").arg(absFilename));
1750  else
1751  {
1752  LOG(VB_GENERAL, LOG_ERR, LOC +
1753  QString("Can't delete %1").arg(absFilename));
1754  // Remove from list
1755  it.remove();
1756  }
1757  }
1758 }
1759 
1760 
1767 {
1768  switch (type)
1769  {
1770  case kPicOnly: return QString("AND type != %1").arg(kVideoFile);
1771  case kVideoOnly: return QString("AND type != %1").arg(kImageFile);
1772  case kPicAndVideo: return "";
1773  }
1774  return "";
1775 }
1776 
1777 
1784 {
1785  m_refineClause = QString("%2 %3 "
1786  "ORDER BY "
1787  "CASE WHEN type <= %1 THEN %4, "
1788  "CASE WHEN type > %1 THEN %5 ")
1789  .arg(kDirectory)
1790  .arg(m_showHidden ? "" : "AND hidden = 0",
1794 }
1795 
1796 
1803 {
1804  // prepare the sorting statement
1805  switch (order)
1806  {
1807  default:
1808  case kSortByNameAsc: return "name END ASC";
1809  case kSortByNameDesc: return "name END DESC";
1810  case kSortByModTimeAsc: return "modtime END ASC";
1811  case kSortByModTimeDesc: return "modtime END DESC";
1812  case kSortByExtAsc: return "extension END ASC, name ASC";
1813  case kSortByExtDesc: return "extension END DESC, name DESC";
1814  case kSortBySizeAsc: return "size END ASC, name ASC";
1815  case kSortBySizeDesc: return "size END DESC, name DESC";
1816  case kSortByDateAsc: return "IF(date=0, modtime, date) END ASC";
1817  case kSortByDateDesc: return "IF(date=0, modtime, date) END DESC";
1818  }
1819 }
1820 
1821 
1831  ImageList &files, ImageList &dirs) const
1832 {
1833  // Only Root node will invoke both Db queries but result set will be small
1834  // For Root the SG is always ordered before local devices
1835  // Root node has no Db entry so the 2 queries will not overwrite the parent.
1836  int count = 0;
1837  if (!ImageItem::IsLocalId(id))
1838  count = m_remote->GetDirectory(id, parent, files, dirs, m_refineClause);
1840  count += ImageHandler::GetDirectory(id, parent, files, dirs, m_refineClause);
1841 
1842  if (id == GALLERY_DB_ID)
1843  {
1844  // Add a Root node
1845  parent = ImagePtr(new ImageItem(GALLERY_DB_ID));
1846  parent->m_parentId = GALLERY_DB_ID;
1847  parent->m_type = kDevice;
1848 
1849  ++count;
1850  }
1851  return count;
1852 }
1853 
1854 
1863  ImageList &files, ImageList &dirs) const
1864 {
1865  // Ids are either all local or all remote. GALLERY_DB_ID not valid
1866  StringPair lists = ImageItem::PartitionIds(ids);
1867 
1868  if (!lists.second.isEmpty())
1869  return m_remote->GetImages(lists.second, files, dirs, m_refineClause);
1870  if (m_dbExists && !lists.first.isEmpty())
1871  return ImageHandler::GetImages(lists.first, files, dirs, m_refineClause);
1872  return 0;
1873 }
1874 
1875 
1883 int ImageDbReader::GetChildren(int id, ImageList &files, ImageList &dirs) const
1884 {
1885  int count = 0;
1886  if (!ImageItem::IsLocalId(id))
1887  count = m_remote->GetChildren(QString::number(id), files, dirs,
1888  m_refineClause);
1890  count += ImageHandler::GetChildren(QString::number(id), files, dirs,
1891  m_refineClause);
1892  return count;
1893 }
1894 
1895 
1903  ImageList &files, ImageList &dirs) const
1904 {
1905  // Ids are either all local or all remote
1906  StringPair lists = ImageItem::PartitionIds(ids);
1907 
1908  if (!lists.second.isEmpty())
1909  m_remote->GetDescendants(lists.second, files, dirs);
1910  if (m_dbExists && !lists.first.isEmpty())
1911  ImageHandler::GetDescendants(lists.first, files, dirs);
1912 }
1913 
1914 
1921 void ImageDbReader::GetImageTree(int id, ImageList &files) const
1922 {
1923  if (!ImageItem::IsLocalId(id))
1924  m_remote->GetImageTree(id, files, m_refineClause);
1926  ImageHandler::GetImageTree(id, files, m_refineClause);
1927 }
1928 
1929 
1938 void ImageDbReader::GetDescendantCount(int id, int &dirs, int &pics,
1939  int &videos, int &sizeKb) const
1940 {
1941  if (id == GALLERY_DB_ID)
1942  {
1943  // Sum both unfiltered tables
1944  m_remote->GetDescendantCount(id, true, dirs, pics, videos, sizeKb);
1945  if (m_dbExists)
1946  ImageHandler::GetDescendantCount(id, true, dirs, pics, videos, sizeKb);
1947  }
1948  else if (!ImageItem::IsLocalId(id))
1949  {
1950  // Don't filter on SG path (it's blank)
1952  dirs, pics, videos, sizeKb);
1953  }
1954  else if (m_dbExists)
1955  {
1956  // Always filter on device/dir
1957  ImageHandler::GetDescendantCount(id, false, dirs, pics, videos, sizeKb);
1958  }
1959 }
1960 
1961 
1966 
1967 
1973 {
1974  if (!s_instance)
1975  s_instance = new ImageManagerBe();
1976  return s_instance;
1977 }
1978 
1979 
1985 {
1986  if (!s_instance)
1987  {
1988  // Use saved settings
1990  (gCoreContext->GetNumSetting("GalleryImageOrder"),
1991  gCoreContext->GetNumSetting("GalleryDirOrder"),
1992  gCoreContext->GetBoolSetting("GalleryShowHidden"),
1993  gCoreContext->GetNumSetting("GalleryShowType"),
1994  gCoreContext->GetSetting("GalleryDateFormat"));
1995  }
1996  return *s_instance;
1997 }
1998 
1999 
2008 void ImageManagerFe::CreateThumbnails(const ImageIdList &ids, bool forFolder)
2009 {
2010  // Split images into <locals, remotes>
2011  StringPair lists = ImageItem::PartitionIds(ids);
2012 
2013  if (!lists.second.isEmpty())
2014  {
2015  LOG(VB_FILE, LOG_DEBUG, LOC +
2016  QString("Sending CREATE_THUMBNAILS %1 (forFolder %2)")
2017  .arg(lists.second).arg(forFolder));
2018 
2019  QStringList message;
2020  message << QString::number(static_cast<int>(forFolder)) << lists.second;
2021  gCoreContext->SendEvent(MythEvent("CREATE_THUMBNAILS", message));
2022  }
2023 
2024  if (!lists.first.isEmpty())
2025  {
2026  LOG(VB_FILE, LOG_DEBUG, LOC +
2027  QString("Creating local thumbnails %1 (forFolder %2)")
2028  .arg(lists.first).arg(forFolder));
2029 
2030  QStringList message;
2031  message << QString::number(static_cast<int>(forFolder)) << lists.first;
2032  HandleCreateThumbnails(message);
2033  }
2034 }
2035 
2036 
2043 QString ImageManagerFe::ScanImagesAction(bool start, bool local)
2044 {
2045  QStringList command;
2046  command << (start ? "START" : "STOP");
2047 
2048  if (!local)
2049  {
2050  command.push_front("IMAGE_SCAN");
2051  bool ok = gCoreContext->SendReceiveStringList(command, true);
2052  return ok ? "" : command[1];
2053  }
2054 
2055  // Create database on first scan
2056  if (!CreateTable())
2057  return "Couldn't create database";
2058 
2059  QStringList err = HandleScanRequest(command[0]);
2060  return err[0] == "OK" ? "" : err[1];
2061 }
2062 
2063 
2070 {
2071  QStringList strList;
2072  strList << "IMAGE_SCAN" << "QUERY";
2073 
2074  if (!gCoreContext->SendReceiveStringList(strList))
2075  {
2076  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Scan query failed : %1")
2077  .arg(strList.join(",")));
2078  }
2079  return strList;
2080 }
2081 
2082 
2089 QString ImageManagerFe::HideFiles(bool hidden, const ImageIdList &ids)
2090 {
2091  // Split images into <locals, remotes>
2092  StringPair lists = ImageItem::PartitionIds(ids);
2093  QString result = "";
2094 
2095  if (!lists.second.isEmpty())
2096  {
2097  QStringList message;
2098  message << "IMAGE_HIDE" << QString::number(static_cast<int>(hidden)) << lists.second;
2099 
2100  if (!gCoreContext->SendReceiveStringList(message, true))
2101  result = message[1];
2102  }
2103 
2104  if (!lists.first.isEmpty())
2105  {
2106  QStringList err = HandleHide(hidden, lists.first);
2107  if (err[0] != "OK")
2108  result = err[1];
2109  }
2110  return result;
2111 }
2112 
2113 
2121  const ImageIdList &ids)
2122 {
2123  // Split images into <locals, remotes>
2124  StringPair lists = ImageItem::PartitionIds(ids);
2125  QString result = "";
2126 
2127  if (!lists.second.isEmpty())
2128  {
2129  QStringList message;
2130  message << "IMAGE_TRANSFORM" << QString::number(transform) << lists.second;
2131 
2132  if (!gCoreContext->SendReceiveStringList(message, true))
2133  result = message[1];
2134  }
2135 
2136  if (!lists.first.isEmpty())
2137  {
2138  QStringList err = HandleTransform(transform, lists.first);
2139  if (err[0] != "OK")
2140  result = err[1];
2141  }
2142  return result;
2143 }
2144 
2145 
2152 QString ImageManagerFe::SetCover(int parent, int cover)
2153 {
2154  if (!ImageItem::IsLocalId(parent))
2155  {
2156  QStringList message;
2157  message << "IMAGE_COVER" << QString::number(parent) << QString::number(cover);
2158 
2159  bool ok = gCoreContext->SendReceiveStringList(message, true);
2160  return ok ? "" : message[1];
2161  }
2162 
2163  QStringList err = HandleCover(parent, cover);
2164  return err[0] == "OK" ? "" : err[1];
2165 }
2166 
2167 
2173 {
2174  if (ImageItem::IsLocalId(id))
2175  HandleGetMetadata(QString::number(id));
2176  else
2177  gCoreContext->SendEvent(MythEvent("IMAGE_GET_METADATA", QString::number(id)));
2178 }
2179 
2180 
2183 {
2184  QStringList message("IMAGE_SCAN");
2185  message << "DEVICE CLEAR ALL";
2186  gCoreContext->SendReceiveStringList(message, true);
2187 }
2188 
2189 
2196 QString ImageManagerFe::IgnoreDirs(const QString &excludes)
2197 {
2198  QStringList message("IMAGE_IGNORE");
2199  message << excludes;
2200  bool ok = gCoreContext->SendReceiveStringList(message, true);
2201  return ok ? "" : message[1];
2202 }
2203 
2204 
2212 QString ImageManagerFe::MakeDir(int parent, const QStringList &names, bool rescan)
2213 {
2214  QString destId = QString::number(parent);
2215 
2216  if (!ImageItem::IsLocalId(parent))
2217  {
2218  QStringList message("IMAGE_CREATE_DIRS");
2219  message << destId << QString::number(static_cast<int>(rescan)) << names;
2220  bool ok = gCoreContext->SendReceiveStringList(message, true);
2221  return ok ? "" : message[1];
2222  }
2223  QStringList err = HandleDirs(destId, rescan, names);
2224  return (err[0] == "OK") ? "" : err[1];
2225 }
2226 
2227 
2234 QString ImageManagerFe::RenameFile(const ImagePtrK& im, const QString &name)
2235 {
2236  if (!im->IsLocal())
2237  {
2238  QStringList message("IMAGE_RENAME");
2239  message << QString::number(im->m_id) << name;
2240  bool ok = gCoreContext->SendReceiveStringList(message, true);
2241  return ok ? "" : message[1];
2242  }
2243  QStringList err = HandleRename(QString::number(im->m_id), name);
2244  return (err[0] == "OK") ? "" : err[1];
2245 }
2246 
2247 
2254 QString ImageManagerFe::CreateImages(int destId, const ImageListK &images)
2255 {
2256  if (images.isEmpty())
2257  return "";
2258 
2259  // Define field seperator & include it in message
2260  const QString seperator("...");
2261  QStringList imageDefs(seperator);
2262  ImageIdList ids;
2263  for (const auto& im : qAsConst(images))
2264  {
2265  ids << im->m_id;
2266 
2267  // Copies preserve hide state, orientation & cover
2268  QStringList aDef;
2269  aDef << QString::number(im->m_id)
2270  << QString::number(im->m_type)
2271  << im->m_filePath
2272  << QString::number(static_cast<int>(im->m_isHidden))
2273  << QString::number(im->m_orientation)
2274  << QString::number(im->m_userThumbnail);
2275 
2276  imageDefs << aDef.join(seperator);
2277  }
2278 
2279  // Images are either all local or all remote
2280  if (ImageItem::IsLocalId(destId))
2281  {
2282  QStringList err = HandleDbCreate(imageDefs);
2283  return (err[0] == "OK") ? "" : err[1];
2284  }
2285  imageDefs.prepend("IMAGE_COPY");
2286  bool ok = gCoreContext->SendReceiveStringList(imageDefs, true);
2287  return ok ? "" : imageDefs[1];
2288 }
2289 
2290 
2298 QString ImageManagerFe::MoveDbImages(const ImagePtrK& destDir, ImageListK &images,
2299  const QString &srcPath)
2300 {
2301  QStringList idents;
2302  for (const auto& im : qAsConst(images))
2303  idents << QString::number(im->m_id);
2304 
2305  // Images are either all local or all remote
2306  if (destDir->IsLocal())
2307  {
2308  QStringList err = HandleDbMove(idents.join(","), srcPath,
2309  destDir->m_filePath);
2310  return (err[0] == "OK") ? "" : err[1];
2311  }
2312 
2313  QStringList message("IMAGE_MOVE");
2314  message << idents.join(",") << srcPath << destDir->m_filePath;
2315  bool ok = gCoreContext->SendReceiveStringList(message, true);
2316  return ok ? "" : message[1];
2317 }
2318 
2319 
2326 {
2327  StringPair lists = ImageItem::PartitionIds(ids);
2328 
2329  QString result = "";
2330  if (!lists.second.isEmpty())
2331  {
2332  QStringList message("IMAGE_DELETE");
2333  message << lists.second;
2334 
2335  bool ok = gCoreContext->SendReceiveStringList(message, true);
2336  if (!ok)
2337  result = message[1];
2338  }
2339  if (!lists.first.isEmpty())
2340  {
2341  QStringList err = HandleDelete(lists.first);
2342  if (err[0] != "OK")
2343  result = err[1];
2344  }
2345  return result;
2346 }
2347 
2348 
2356 {
2357  if (im->m_id == GALLERY_DB_ID)
2358  return "";
2359 
2360  std::chrono::seconds secs = 0s;
2362 
2363  if (im->m_date > 0s)
2364  {
2365  secs = im->m_date;
2366  format |= MythDate::kTime;
2367  }
2368  else
2369  secs = im->m_modTime;
2370 
2371  return MythDate::toString(QDateTime::fromSecsSinceEpoch(secs.count()), format);
2372 }
2373 
2374 
2381 QString ImageManagerFe::ShortDateOf(const ImagePtrK& im) const
2382 {
2383  if (im->m_id == GALLERY_DB_ID)
2384  return "";
2385 
2386  std::chrono::seconds secs(im->m_date > 0s ? im->m_date : im->m_modTime);
2387  return QDateTime::fromSecsSinceEpoch(secs.count()).date().toString(m_dateFormat);
2388 }
2389 
2390 
2397 {
2398  if (im.m_id == GALLERY_DB_ID)
2399  return tr("Gallery");
2400  if (im.m_id == PHOTO_DB_ID)
2401  return tr("Photographs");
2402  return im.IsLocal() ? DeviceName(im.m_device)
2403  : m_remote->DeviceName(im.m_device);
2404 }
2405 
2406 
2414 QString ImageManagerFe::CrumbName(ImageItemK &im, bool getPath) const
2415 {
2416  if (im.IsDevice())
2417  return DeviceCaption(im);
2418 
2419  if (!getPath)
2420  return im.m_baseName;
2421 
2422  QString dev;
2423  QString path(im.m_filePath);
2424 
2425  if (im.IsLocal())
2426  {
2427  // Replace local mount path with device name
2428  path.remove(0, DeviceMount(im.m_device).size());
2429  dev = DeviceName(im.m_device);
2430  }
2431  return dev + path.replace("/", " > ");
2432 }
2433 
2434 
2435 void ImageManagerFe::CloseDevices(int devId, bool eject)
2436 {
2437  QString reason = (devId == DEVICE_INVALID)
2438  ? "DEVICE CLOSE ALL"
2439  : eject ? "DEVICE EJECT" : "DEVICE REMOVE";
2440  HandleScanRequest(reason, devId);
2441 }
2442 
2443 
2449 {
2451  if (!monitor)
2452  return false;
2453 
2454  // Detect all local media
2455  QList<MythMediaDevice*> devices
2457 
2458  for (auto *dev : qAsConst(devices))
2459  {
2460  if (monitor->ValidateAndLock(dev) && dev->isUsable())
2461  OpenDevice(dev->getDeviceModel(), dev->getMountPath(), dev);
2462  else
2463  monitor->Unlock(dev);
2464  }
2465 
2466  if (DeviceCount() > 0)
2467  {
2468  // Close devices that are no longer present
2469  QList absentees = GetAbsentees();
2470  for (int devId : qAsConst(absentees))
2471  CloseDevices(devId);
2472 
2473  // Start local scan
2474  QString err = ScanImagesAction(true, true);
2475  if (!err.isEmpty())
2476  LOG(VB_GENERAL, LOG_ERR, LOC + err);
2477  }
2478  return DeviceCount() > 0;
2479 }
2480 
2481 
2487 {
2489 
2490  if (!event || !monitor)
2491  return;
2492 
2493  MythMediaDevice *dev = event->getDevice();
2494  if (!dev)
2495  return;
2496 
2497  MythMediaType type = dev->getMediaType();
2498  MythMediaStatus status = dev->getStatus();
2499 
2500  LOG(VB_FILE, LOG_DEBUG, LOC +
2501  QString("Media event for %1 (%2) at %3, type %4, status %5 (was %6)")
2502  .arg(dev->getDeviceModel(), dev->getVolumeID(), dev->getMountPath())
2503  .arg(type).arg(status).arg(event->getOldStatus()));
2504 
2506  {
2507  LOG(VB_FILE, LOG_DEBUG, LOC +
2508  QString("Ignoring event - wrong type %1").arg(type));
2509  return;
2510  }
2511 
2512  if (status == MEDIASTAT_USEABLE || status == MEDIASTAT_MOUNTED)
2513  {
2514  // New device. Lock it & scan
2515  if (monitor->ValidateAndLock(dev))
2516  {
2517  OpenDevice(dev->getDeviceModel(), dev->getMountPath(), dev);
2518  ScanImagesAction(true, true);
2519  }
2520  else
2521  monitor->Unlock(dev);
2522  return;
2523  }
2524 
2525  // Device has disappeared
2526  int devId = LocateMount(dev->getMountPath());
2527  if (devId != DEVICE_INVALID)
2528  CloseDevices(devId);
2529 }
2530 
2531 
2533 {
2534  auto *tmp = new QTemporaryDir(QDir::tempPath() % "/" IMPORTDIR "-XXXXXX");
2535  if (!tmp->isValid())
2536  {
2537  delete tmp;
2538  return "";
2539  }
2540 
2541  QString time(QDateTime::currentDateTime().toString("mm:ss"));
2542  OpenDevice("Import " + time, tmp->path(), nullptr, tmp);
2543  return tmp->path();
2544 }
2545 
2546 
2547 // Must define the valid template implementations to generate code for the
2548 // instantiations (as they are defined in the cpp rather than header).
2549 // Otherwise the linker will fail with undefined references...
2550 template class ImageDb<ImageAdapterSg>;
2551 template class ImageDb<ImageAdapterLocal>;
2552 template class ImageHandler<ImageDbSg>;
2553 template class ImageHandler<ImageDbLocal>;
MythMediaDevice::getMountPath
const QString & getMountPath() const
Definition: mythmedia.h:58
ImageAdapterBase::ImageAdapterBase
ImageAdapterBase()
Constructor.
Definition: imagemanager.cpp:314
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:47
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:807
ImagePtrK
QSharedPointer< ImageItemK > ImagePtrK
Definition: imagetypes.h:165
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
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:1239
ImageDb::SetHidden
bool SetHidden(bool hide, const QString &ids) const
Sets hidden status of an image/dir in database.
Definition: imagemanager.cpp:932
PHOTO_DB_ID
#define PHOTO_DB_ID
Definition: imagetypes.h:29
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:84
MSqlQuery::bindValueNoNull
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
Definition: mythdbcon.cpp:888
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:215
ImageDbReader::GetImages
int GetImages(const ImageIdList &ids, ImageList &files, ImageList &dirs) const
Returns images (local or remote but not a combination)
Definition: imagemanager.cpp:1862
DeviceManager::GetDeviceDirs
StringMap GetDeviceDirs() const
Get all known devices.
Definition: imagemanager.cpp:250
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:2008
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:1921
ImageItem::m_type
int m_type
Type of node: dir, video etc.
Definition: imagetypes.h:97
kVideoFile
@ kVideoFile
A video.
Definition: imagetypes.h:40
MediaMonitor::GetMedias
QList< MythMediaDevice * > GetMedias(unsigned mediatypes)
Ask for available media. Must be locked with ValidateAndLock().
Definition: mythmediamonitor.cpp:612
ReadMetaThread
Task to read all metadata from file.
Definition: imagemanager.cpp:1151
Device::isImport
bool isImport() const
Definition: imagemanager.cpp:105
ImageItem::m_id
int m_id
Uniquely identifies an image (file/dir).
Definition: imagetypes.h:89
ImageDb::UpdateDbImage
bool UpdateDbImage(ImageItemK &im) const
Updates or creates database image or dir.
Definition: imagemanager.cpp:859
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:1375
kSortByExtDesc
@ kSortByExtDesc
Extension Z-A.
Definition: imagetypes.h:51
ImageItem::m_comment
QString m_comment
User comment, from Exif metadata.
Definition: imagetypes.h:102
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:1830
ImageManagerFe::CreateImages
QString CreateImages(int destId, const ImageListK &images)
Copies database images (but not the files themselves).
Definition: imagemanager.cpp:2254
ImageManagerFe::ScanImagesAction
QString ScanImagesAction(bool start, bool local=false)
Handle scanner start/stop commands.
Definition: imagemanager.cpp:2043
LOC
#define LOC
Definition: imagemanager.cpp:13
ImageHandler::HandleGetMetadata
QStringList HandleGetMetadata(const QString &id) const
Read meta data for an image.
Definition: imagemanager.cpp:1208
MediaMonitor::GetMediaMonitor
static MediaMonitor * GetMediaMonitor(void)
Definition: mythmediamonitor.cpp:84
ImageItem::IsLocal
bool IsLocal() const
Definition: imagetypes.h:119
ImageDbLocal::DropTable
void DropTable()
Remove local image table.
Definition: imagemanager.cpp:1105
ImageMetaData
Abstract class for image metadata.
Definition: imagemetadata.h:99
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:2212
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:105
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:38
DB_COLUMNS
#define DB_COLUMNS
Definition: imagemanager.cpp:529
MSqlQuery::lastInsertId
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:912
Device::m_mount
QString m_mount
Mountpoint.
Definition: imagemanager.cpp:112
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
ImageManagerFe::DeviceEvent
void DeviceEvent(MythMediaEvent *event)
Manage events for local devices.
Definition: imagemanager.cpp:2486
EXIF_MYTH_SIZE
#define EXIF_MYTH_SIZE
Definition: imagemetadata.h:41
Device::isPresent
bool isPresent() const
Definition: imagemanager.cpp:106
DeviceManager::DeviceCount
int DeviceCount() const
Definition: imagemanager.h:100
ImageManagerFe::IgnoreDirs
static QString IgnoreDirs(const QString &excludes)
Set directories to ignore during scans of the storage group.
Definition: imagemanager.cpp:2196
ImageAdapterBase::m_videoFileExt
QStringList m_videoFileExt
List of file extensions recognised as videos.
Definition: imagemanager.h:179
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:205
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:608
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:491
DEVICE_INVALID
#define DEVICE_INVALID
Definition: imagemanager.h:71
ImageManagerFe::HideFiles
QString HideFiles(bool hidden, const ImageIdList &ids)
Hide/unhide images.
Definition: imagemanager.cpp:2089
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:806
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:585
ImageDb::InsertDbImage
int InsertDbImage(ImageItemK &im, bool checkForDuplicate=false) const
Adds new image to database, optionally checking for existing filepath.
Definition: imagemanager.cpp:801
Device
A device containing images (ie. USB stick, CD, storage group etc)
Definition: imagemanager.cpp:33
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:542
ImageHandler::HandleCover
QStringList HandleCover(int dir, int cover) const
Updates/resets cover thumbnail for an image dir.
Definition: imagemanager.cpp:1609
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:1766
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:707
ImageItem::m_device
int m_device
Id of media device. Always 0 (SG) for remotes, 1+ for local devices.
Definition: imagetypes.h:95
ImageManagerFe::CloseDevices
void CloseDevices(int devId=DEVICE_INVALID, bool eject=false)
Definition: imagemanager.cpp:2435
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:140
ImageDbSg::ImageDbSg
ImageDbSg()
SG database constructor.
Definition: imagemanager.cpp:1084
ImageManagerFe::ChangeOrientation
QString ChangeOrientation(ImageFileTransform transform, const ImageIdList &ids)
Apply an orientation transform to images.
Definition: imagemanager.cpp:2120
tmp
static guint32 * tmp
Definition: goom_core.cpp:32
ImageHandler::HandleTransform
QStringList HandleTransform(int transform, const QString &ids) const
Change orientation of pictures by applying a transformation.
Definition: imagemanager.cpp:1506
dbaccess.h
ImageManagerFe::getInstance
static ImageManagerFe & getInstance()
Get Frontend Gallery.
Definition: imagemanager.cpp:1984
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:376
ImageManagerFe::DeviceCaption
QString DeviceCaption(ImageItemK &im) const
Return translated device name.
Definition: imagemanager.cpp:2396
kSortByDateDesc
@ kSortByDateDesc
Exif date Latest -> Earliest.
Definition: imagetypes.h:55
Orientation::Transform
int Transform(int transform)
Adjust orientation to apply a transform to an image.
Definition: imagemetadata.cpp:26
ImageHandler::HandleDbCreate
QStringList HandleDbCreate(QStringList defs) const
Creates images for files created by a copy operation.
Definition: imagemanager.cpp:1358
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:714
ImageHash
QHash< QString, ImagePtr > ImageHash
Definition: imagetypes.h:161
mythdate.h
MythDate::fromSecsSinceEpoch
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(int64_t seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
Definition: mythdate.cpp:72
ImageHandler::HandleDbMove
QStringList HandleDbMove(const QString &ids, const QString &srcPath, QString destPath) const
Updates images that have been renamed.
Definition: imagemanager.cpp:1417
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
kSortByNameAsc
@ kSortByNameAsc
Name A-Z.
Definition: imagetypes.h:46
kPicOnly
@ kPicOnly
Hide videos.
Definition: imagemanager.h:79
ImageManagerFe::ClearStorageGroup
static void ClearStorageGroup()
Clear database & thumbnails of Storage Group images.
Definition: imagemanager.cpp:2182
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1534
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:540
FileAssociations::association_list
std::vector< file_association > association_list
Definition: dbaccess.h:154
StringMap
QMap< int, QString > StringMap
Definition: imagetypes.h:63
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
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:982
formats
const std::array< const std::string, 8 > formats
Definition: vbilut.cpp:189
MythMediaEvent
Definition: mythmedia.h:183
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:1902
ImageAdapterBase::SupportedImages
static QStringList SupportedImages()
Return recognised pictures.
Definition: imagemanager.cpp:338
ImageDbReader::OrderSelector
static QString OrderSelector(int order)
Generate SQL ordering clause.
Definition: imagemanager.cpp:1802
ImageItem::m_modTime
std::chrono::seconds m_modTime
Filesystem modified datestamp.
Definition: imagetypes.h:98
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:166
clear
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:893
MediaMonitor::Unlock
void Unlock(MythMediaDevice *pMedia)
decrements the MythMediaDevices reference count
Definition: mythmediamonitor.cpp:518
Orientation::Description
QString Description() const
Generate text description of orientation.
Definition: imagemetadata.cpp:226
ImageManagerFe::LongDateOf
static QString LongDateOf(const ImagePtrK &im)
Return a timestamp/datestamp for an image or dir.
Definition: imagemanager.cpp:2355
RESULT_OK
#define RESULT_OK(MESG)
Definition: imagemanager.cpp:25
kSortByExtAsc
@ kSortByExtAsc
Extension A-Z.
Definition: imagetypes.h:50
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:2152
uint
unsigned int uint
Definition: compat.h:79
ImageMetaData::FromPicture
static ImageMetaData * FromPicture(const QString &filePath)
Factory to retrieve metadata from pictures.
Definition: imagemetadata.cpp:698
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:59
ImageItem::IsLocalId
static bool IsLocalId(int id)
Determine image type (local/remote) from its id. Root/Gallery is remote.
Definition: imagetypes.h:122
ImageItem::m_orientation
int m_orientation
Image orientation.
Definition: imagetypes.h:101
ImageItem::m_baseName
QString m_baseName
File/Dir name with extension (no path)
Definition: imagetypes.h:92
MediaMonitor
Definition: mythmediamonitor.h:47
ImageList
QVector< ImagePtr > ImageList
Definition: imagetypes.h:160
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
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:2532
ImageItem::IsLocalParent
static bool IsLocalParent(int id)
Parents of locals are locals or root.
Definition: imagetypes.h:124
ImageHandler::RemoveFiles
void RemoveFiles(ImageList &images) const
Deletes images and dirs from the filesystem.
Definition: imagemanager.cpp:1730
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:1938
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:910
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:831
kSortByModTimeDesc
@ kSortByModTimeDesc
File modified time Latest -> Earliest.
Definition: imagetypes.h:49
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:1652
ImageHandler::HandleDirs
QStringList HandleDirs(const QString &destId, bool rescan, const QStringList &relPaths) const
Creates new image directories.
Definition: imagemanager.cpp:1553
kImageFile
@ kImageFile
A picture.
Definition: imagetypes.h:39
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:2298
ImageAdapterBase::m_dirFilter
QDir m_dirFilter
A pre-configured dir for reading image/video files.
Definition: imagemanager.h:175
MythMediaType
MythMediaType
Definition: mythmedia.h:24
kFlipVertical
@ kFlipVertical
Reflect about horizontal axis.
Definition: imagemetadata.h:51
ImagePtr
QSharedPointer< ImageItem > ImagePtr
Definition: imagetypes.h:159
MythDate::kAddYear
@ kAddYear
Add year to string if not included.
Definition: mythdate.h:25
ImageManagerFe
The image manager for use by Frontends.
Definition: imagemanager.h:456
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:671
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:1094
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:274
DeviceManager::LocateMount
int LocateMount(const QString &mount) const
Find the id of a device.
Definition: imagemanager.cpp:236
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
Device::Device
Device(QString name, QString mount, MythMediaDevice *media=nullptr, QTemporaryDir *import=nullptr)
Definition: imagemanager.cpp:36
std
Definition: mythchrono.h:23
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:1632
kSortByDateAsc
@ kSortByDateAsc
Exif date Earliest -> Latest.
Definition: imagetypes.h:54
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:958
ImageIdList
QList< int > ImageIdList
Definition: imagetypes.h:60
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:1008
ImageManagerFe::CrumbName
QString CrumbName(ImageItemK &im, bool getPath=false) const
Return a displayable name (with optional path) for an image.
Definition: imagemanager.cpp:2414
ImageItem::m_parentId
int m_parentId
Id of parent dir.
Definition: imagetypes.h:96
ImageDb::ClearDb
void ClearDb(int devId, const QString &action)
Clear Db for device & remove device.
Definition: imagemanager.cpp:765
StringPair
QPair< QString, QString > StringPair
Definition: imagetypes.h:61
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:1883
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:519
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:1972
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:623
DeviceManager::CloseDevices
QStringList CloseDevices(int devId, const QString &action)
Remove a device (or all devices)
Definition: imagemanager.cpp:193
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:426
ImageDb::RemoveFromDB
QStringList RemoveFromDB(const ImageList &imList) const
Remove images/dirs from database.
Definition: imagemanager.cpp:902
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:734
ImageDbLocal::CreateTable
bool CreateTable()
Create local database table, if it doesn't exist.
Definition: imagemanager.cpp:1119
MediaMonitor::ValidateAndLock
bool ValidateAndLock(MythMediaDevice *pMedia)
Validates the MythMediaDevice and increments its reference count.
Definition: mythmediamonitor.cpp:501
MythDate::kDateFull
@ kDateFull
Default local time.
Definition: mythdate.h:19
DeviceManager::GetAbsentees
QList< int > GetAbsentees()
Get list of mountpoints for non-import devices.
Definition: imagemanager.cpp:280
ImageDbReader::SetRefinementClause
void SetRefinementClause()
Sets filter/ordering SQL clause used when reading database according to current filter/sort settings.
Definition: imagemanager.cpp:1783
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:842
ImageItem::m_userThumbnail
int m_userThumbnail
Id of thumbnail to use as cover (dirs only)
Definition: imagetypes.h:106
ImageHandler::HandleDelete
QStringList HandleDelete(const QString &ids) const
Deletes images/dirs.
Definition: imagemanager.cpp:1315
ImageItem::IsDevice
bool IsDevice() const
Definition: imagetypes.h:116
ImageAdapterSg::GetScanDirs
StringMap GetScanDirs() const
Returns SG dirs.
Definition: imagemanager.cpp:502
MythMediaDevice
Definition: mythmedia.h:48
ImageItem::m_date
std::chrono::seconds m_date
Image creation date, from Exif metadata.
Definition: imagetypes.h:100
ImageManagerFe::DeleteFiles
QString DeleteFiles(const ImageIdList &ids)
Delete images.
Definition: imagemanager.cpp:2325
kSortByModTimeAsc
@ kSortByModTimeAsc
File modified time Earliest -> Latest.
Definition: imagetypes.h:48
ReadMetaThread::ReadMetaThread
ReadMetaThread(ImagePtrK im, QString path)
Definition: imagemanager.cpp:1154
ImageDb< ImageAdapterLocal >::m_table
QString m_table
Db table name.
Definition: imagemanager.h:310
Device::setPresent
void setPresent(MythMediaDevice *media)
Definition: imagemanager.cpp:107
ImageDb::GetChildren
int GetChildren(const QString &ids, ImageList &files, ImageList &dirs, const QString &refine="") const
Read immediate children of a dir.
Definition: imagemanager.cpp:605
ReadMetaThread::m_path
QString m_path
Definition: imagemanager.cpp:1195
ImageDb
Database API.
Definition: imagemanager.h:274
ImageItem::m_extension
QString m_extension
Image file extension.
Definition: imagetypes.h:94
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:22
kDevice
@ kDevice
Storage Group and local mounted media.
Definition: imagetypes.h:36
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:442
ImageManagerBe
The image manager to be used by the Backend.
Definition: imagemanager.h:378
kSortBySizeAsc
@ kSortBySizeAsc
File size Smallest -> Largest.
Definition: imagetypes.h:52
ImageDb::GetDescendants
bool GetDescendants(const QString &ids, ImageList &files, ImageList &dirs) const
Return images and all of their descendants.
Definition: imagemanager.cpp:665
ImageManagerFe::RequestMetaData
void RequestMetaData(int id)
Requests all exif/ffmpeg tags for an image, which returns by event.
Definition: imagemanager.cpp:2172
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:317
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:1043
ImageAdapterBase::GetImageType
ImageNodeType GetImageType(const QString &ext) const
Determine file type from its extension.
Definition: imagemanager.h:165
ImageManagerFe::ScanQuery
static QStringList ScanQuery()
Returns storage group scanner status.
Definition: imagemanager.cpp:2069
kUnknown
@ kUnknown
Unprocessable file type.
Definition: imagetypes.h:35
MythCoreContext::SaveSettingOnHost
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
Definition: mythcorecontext.cpp:895
ImageManagerFe::RenameFile
QString RenameFile(const ImagePtrK &im, const QString &name)
Rename an image.
Definition: imagemanager.cpp:2234
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:2381
ImageHandler::HandleCreateThumbnails
QStringList HandleCreateThumbnails(const QStringList &message) const
Creates thumbnails on-demand.
Definition: imagemanager.cpp:1698
ReadMetaThread::m_im
ImagePtrK m_im
Definition: imagemanager.cpp:1194
ImageAdapterBase::m_imageFileExt
QStringList m_imageFileExt
List of file extensions recognised as pictures.
Definition: imagemanager.h:177
ImageHandler::HandleHide
QStringList HandleHide(bool hide, const QString &ids) const
Hides/unhides images/dirs.
Definition: imagemanager.cpp:1484
kSortBySizeDesc
@ kSortBySizeDesc
File size Largest -> Smallest.
Definition: imagetypes.h:53
Orientation
Encapsulates Exif orientation processing.
Definition: imagemetadata.h:62
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:352
ImageItem::m_size
int m_size
Filesize (files only)
Definition: imagetypes.h:99
MEDIATYPE_DATA
@ MEDIATYPE_DATA
Definition: mythmedia.h:26
GALLERY_DB_ID
#define GALLERY_DB_ID
Definition: imagetypes.h:27
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:902
ImageAdapterBase::SupportedVideos
static QStringList SupportedVideos()
Return recognised video extensions.
Definition: imagemanager.cpp:353
ReadMetaThread::run
void run() override
Definition: imagemanager.cpp:1157
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:832
ImageItem::m_filePath
QString m_filePath
Absolute for local images. Usually SG-relative for remotes.
Definition: imagetypes.h:93
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:2448