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 static constexpr const char* STORAGE_GROUP_MOUNT { "" };
18 
19 static constexpr const char* DB_TABLE { "gallery_files" };
20 
21 // NOLINTBEGIN(cppcoreguidelines-macro-usage)
22 #define RESULT_ERR(ERR, MESG) \
23 { LOG(VB_GENERAL, LOG_ERR, LOC + (MESG)); \
24  return QStringList("ERROR") << (ERR); }
25 
26 #define RESULT_OK(MESG) \
27 { LOG(VB_FILE, LOG_DEBUG, LOC + (MESG)); \
28  return QStringList("OK"); }
29 // NOLINTEND(cppcoreguidelines-macro-usage)
30 
31 static constexpr const char* IMPORTDIR { "Import" };
32 
33 
35 class Device
36 {
37 public:
38  Device(QString name, QString mount,
39  MythMediaDevice *media = nullptr, QTemporaryDir *import = nullptr)
40  : m_name(std::move(name)), m_mount(std::move(mount)),
41  m_media(media), m_dir(import)
42  {
43  // Path relative to TEMP storage group
44  m_thumbs = QString("%1/%2").arg(THUMBNAIL_SUBDIR, m_name);
45  }
46 
47 
50  {
51  Close();
52 
53  // Remove imported images
54  delete m_dir;
55 
56  // Clean up non-SG thumbnails
58  RemoveThumbs();
59  }
60 
61 
63  void Close(bool eject = false)
64  {
65  // Imports remain present; others do not
66  m_present = isImport();
67 
68  // Release device
69  if (m_media)
70  {
71  if (eject)
72  {
73  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Ejecting '%1' at '%2'")
74  .arg(m_name, m_mount));
76  }
77  else
78  LOG(VB_MEDIA, LOG_DEBUG, LOC + QString("Unlocked '%1'").arg(m_name));
79 
81  m_media = nullptr;
82  }
83  }
84 
85 
90  static void RemoveDirContents(const QString& path)
91  {
92  QDir(path).removeRecursively();
93  }
94 
95 
97  void RemoveThumbs(void) const
98  {
99  // Remove thumbnails
100  QString dirFmt = QString("%1/") % TEMP_SUBDIR % "/%2";
101  QString dir = dirFmt.arg(GetConfDir(), m_thumbs);
102  LOG(VB_FILE, LOG_INFO, LOC + QString("Removing thumbnails in %1").arg(dir));
103  RemoveDirContents(dir);
104  QDir::root().rmpath(dir);
105  }
106 
107 
108  bool isImport() const { return m_dir; }
109  bool isPresent() const { return m_present; }
110  void setPresent(MythMediaDevice *media) { m_present = true; m_media = media; }
111 
113  bool m_present { true };
114  QString m_name;
115  QString m_mount;
116  QString m_thumbs;
117  MythMediaDevice *m_media { nullptr };
118  QTemporaryDir *m_dir { nullptr };
119 };
120 
121 
122 static Device kNullDevice = Device("Unknown Device", "<Invalid Path>");
123 
124 
126 {
127  qDeleteAll(m_devices);
128 }
129 
130 
132 QString DeviceManager::DeviceMount(int devId) const
133 {
134  return m_devices.value(devId, &kNullDevice)->m_mount;
135 }
136 
137 
139 QString DeviceManager::DeviceName(int devId) const
140 {
141  return m_devices.value(devId, &kNullDevice)->m_name;
142 }
143 
144 
145 QString DeviceManager::ThumbDir(int fs) const
146 {
147  return m_devices.value(fs, &kNullDevice)->m_thumbs;
148 }
149 
150 
160 int DeviceManager::OpenDevice(const QString &name, const QString &mount,
161  MythMediaDevice *media, QTemporaryDir *dir)
162 {
163  // Handle devices reappearing at same mountpoint.
164  // If a USB is unplugged whilst in use (without unmounting) we get no event
165  // but we do when it's re-inserted
166  QString state("Known");
167  int id = LocateMount(mount);
168 
169  if (id == DEVICE_INVALID)
170  {
171  state = "New";
172  id = m_devices.isEmpty() ? 0 : m_devices.lastKey() + 1;
173  m_devices.insert(id, new Device(name, mount, media, dir));
174  }
175  else
176  {
177  Device *dev = m_devices.value(id);
178  if (dev)
179  dev->setPresent(media);
180  }
181 
182  LOG(VB_GENERAL, LOG_INFO, LOC +
183  QString("%1 device %2 mounted at '%3' [Id %4]")
184  .arg(state, name, mount).arg(id));
185 
186  return id;
187 }
188 
189 
196 QStringList DeviceManager::CloseDevices(int devId, const QString &action)
197 {
198  QStringList clear;
199 
200  if (action == "DEVICE CLOSE ALL")
201  {
202  // Close all devices but retain their thumbnails
203  for (auto *dev : qAsConst(m_devices))
204  if (dev)
205  dev->Close();
206  }
207  else if (action == "DEVICE CLEAR ALL")
208  {
209  // Remove all thumbnails but retain devices
210  for (const auto *dev : qAsConst(m_devices)) {
211  if (dev)
212  {
213  clear << dev->m_mount;
214  dev->RemoveThumbs();
215  }
216  }
217  }
218  else
219  {
220  // Remove single device & its thumbnails, optionally ejecting it
221  Device *dev = m_devices.take(devId);
222  if (dev)
223  {
224  if (action == "DEVICE EJECT")
225  dev->Close(true);
226  clear << dev->m_mount;
227  delete dev;
228  }
229  }
230  return clear;
231 }
232 
233 
239 int DeviceManager::LocateMount(const QString &mount) const
240 {
241  DeviceMap::const_iterator it = m_devices.constBegin();
242  while (it != m_devices.constEnd())
243  {
244  if (it.value()->m_mount == mount)
245  return it.key();
246  ++it;
247  }
248  return DEVICE_INVALID;
249 }
250 
251 
254 {
256 #if QT_VERSION < QT_VERSION_CHECK(5,15,0)
257  for (auto it = m_devices.constKeyValueBegin();
258  it != m_devices.constKeyValueEnd(); ++it)
259  {
260  if ((*it).second)
261  paths.insert((*it).first, (*it).second->m_mount);
262  }
263 #else
264  for (auto it = m_devices.constKeyValueBegin();
265  it != m_devices.constKeyValueEnd(); ++it)
266  {
267  if (it->second)
268  paths.insert(it->first, it->second->m_mount);
269  }
270 #endif
271  return paths;
272 }
273 
274 
277 {
278  QList<int> absent;
279 #if QT_VERSION < QT_VERSION_CHECK(5,15,0)
280  for (auto it = m_devices.constKeyValueBegin();
281  it != m_devices.constKeyValueEnd(); it++)
282  {
283  Device *dev = (*it).second;
284  if (dev && !dev->isPresent())
285  absent << (*it).first;
286  }
287 #else
288  for (auto it = m_devices.constKeyValueBegin();
289  it != m_devices.constKeyValueEnd(); it++)
290  {
291  Device *dev = it->second;
292  if (dev && !dev->isPresent())
293  absent << it->first;
294  }
295 #endif
296  return absent;
297 }
298 
299 
304  m_imageFileExt(SupportedImages()),
305  m_videoFileExt(SupportedVideos())
306 {
307  // Generate glob list from supported extensions
308  QStringList glob;
309  QStringList allExt = m_imageFileExt + m_videoFileExt;
310  for (const auto& ext : qAsConst(allExt))
311  glob << "*." + ext;
312 
313  // Apply filters to only detect image files
314  m_dirFilter.setNameFilters(glob);
315  m_dirFilter.setFilter(QDir::AllDirs | QDir::Files | QDir::Readable |
316  QDir::NoDotAndDotDot | QDir::NoSymLinks);
317 
318  // Sync files before dirs to improve thumb generation response
319  // Order by time (oldest first) - this determines the order thumbs appear
320  m_dirFilter.setSorting(QDir::DirsLast | QDir::Time | QDir::Reversed);
321 }
322 
328 {
329  // Determine supported picture formats from Qt
330  QStringList formats;
331  QList<QByteArray> supported = QImageReader::supportedImageFormats();
332  for (const auto& ext : qAsConst(supported))
333  formats << QString(ext);
334  return formats;
335 }
336 
337 
343 {
344  // Determine supported video formats from MythVideo
345  QStringList formats;
348  for (const auto & fa : faList)
349  {
350  if (!fa.use_default && fa.playcommand == "Internal")
351  formats << QString(fa.extension);
352  }
353  return formats;
354 }
355 
356 
365 ImageItem *ImageAdapterLocal::CreateItem(const QFileInfo &fi, int parentId,
366  int devId, const QString & /*base*/) const
367 {
368  auto *im = new ImageItem();
369 
370  im->m_parentId = parentId;
371  im->m_device = devId;
372  im->m_filePath = fi.absoluteFilePath();
373 
374  if (parentId == GALLERY_DB_ID)
375  {
376  // Import devices show time of import, other devices show 'last scan time'
377  auto secs = im->m_filePath.contains(IMPORTDIR)
378  ? fi.lastModified().toSecsSinceEpoch()
379  : QDateTime::currentSecsSinceEpoch();
380  im->m_date = std::chrono::seconds(secs);
381  im->m_modTime = im->m_date;
382  im->m_type = kDevice;
383  return im;
384  }
385 
386  im->m_modTime = std::chrono::seconds(fi.lastModified().toSecsSinceEpoch());
387 
388  if (fi.isDir())
389  {
390  im->m_type = kDirectory;
391  return im;
392  }
393 
394  im->m_extension = fi.suffix().toLower();
395  im->m_type = GetImageType(im->m_extension);
396 
397  if (im->m_type == kUnknown)
398  {
399  delete im;
400  return nullptr;
401  }
402 
403  im->m_thumbPath = GetAbsThumbPath(ThumbDir(im->m_device), ThumbPath(*im));
404  im->m_size = fi.size();
405 
406  return im;
407 }
408 
409 
415 void ImageAdapterLocal::Notify(const QString &mesg,
416  const QStringList &extra)
417 {
418  QString host(gCoreContext->GetHostName());
419  gCoreContext->SendEvent(MythEvent(QString("%1 %2").arg(mesg, host), extra));
420 }
421 
422 
431 ImageItem *ImageAdapterSg::CreateItem(const QFileInfo &fi, int parentId,
432  int /*devId*/, const QString &base) const
433 {
434  auto *im = new ImageItem();
435 
436  im->m_device = 0;
437  im->m_parentId = parentId;
438 
439  if (parentId == GALLERY_DB_ID)
440  {
441  // All SG dirs map to a single Db dir
442  im->m_filePath = "";
443  im->m_type = kDevice;
444  im->m_date = std::chrono::seconds(QDateTime::currentSecsSinceEpoch());
445  im->m_modTime = im->m_date;
446  return im;
447  }
448 
449  // Strip SG path & leading / to leave a relative path
450  im->m_filePath = fi.absoluteFilePath().mid(base.size() + 1);
451  im->m_modTime = std::chrono::seconds(fi.lastModified().toSecsSinceEpoch());
452 
453  if (fi.isDir())
454  {
455  im->m_type = kDirectory;
456  return im;
457  }
458 
459  im->m_extension = fi.suffix().toLower();
460  im->m_type = GetImageType(im->m_extension);
461 
462  if (im->m_type == kUnknown)
463  {
464  delete im;
465  return nullptr;
466  }
467 
468  im->m_thumbPath = GetAbsThumbPath(ThumbDir(im->m_device), ThumbPath(*im));
469  im->m_size = fi.size();
470 
471  return im;
472 }
473 
474 
480 void ImageAdapterSg::Notify(const QString &mesg,
481  const QStringList &extra)
482 {
483  gCoreContext->SendEvent(MythEvent(mesg, extra));
484 }
485 
486 
492 {
493  StringMap map;
494  int i = 0;
495  QStringList paths = m_sg.GetDirList();
496  for (const auto& path : qAsConst(paths))
497  map.insert(i++, path);
498  return map;
499 }
500 
501 
509 {
510  if (im->IsDevice())
511  return m_sg.FindNextDirMostFree();
512  return im->m_filePath.startsWith("/") ? im->m_filePath
513  : m_sg.FindFile(im->m_filePath);
514 }
515 
516 
517 // Database fields used by several image queries
518 static constexpr const char* kDBColumns {
519 "file_id, filename, name, dir_id, type, modtime, size, "
520 "extension, date, hidden, orientation, angle, path, zoom"
521 // Id, filepath, basename, parentId, type, modtime, size,
522 // extension, image date, hidden, orientation, cover id, comment, device id
523 };
524 
530 template <class FS>
532 {
533  auto *im = new ImageItem(FS::ImageId(query.value(0).toInt()));
534 
535  // Ordered as per kDBColumns
536  im->m_filePath = query.value(1).toString();
537  im->m_baseName = query.value(2).toString();
538  im->m_parentId = FS::ImageId(query.value(3).toInt());
539  im->m_type = query.value(4).toInt();
540  im->m_modTime = std::chrono::seconds(query.value(5).toInt());
541  im->m_size = query.value(6).toInt();
542  im->m_extension = query.value(7).toString();
543  im->m_date = std::chrono::seconds(query.value(8).toUInt());
544  im->m_isHidden = query.value(9).toBool();
545  im->m_orientation = query.value(10).toInt();
546  im->m_userThumbnail = FS::ImageId(query.value(11).toInt());
547  im->m_comment = query.value(12).toString();
548  im->m_device = query.value(13).toInt();
549  im->m_url = FS::MakeFileUrl(im->m_filePath);
550 
551  if (im->IsFile())
552  {
553  // Only pics/vids have thumbs
554  QString thumbPath(FS::ThumbPath(*im));
555  QString devPath(FS::ThumbDir(im->m_device));
556  QString url(FS::MakeThumbUrl(devPath, thumbPath));
557 
558  im->m_thumbPath = FS::GetAbsThumbPath(devPath, thumbPath);
559  im->m_thumbNails.append(qMakePair(im->m_id, url));
560  }
561  return im;
562 }
563 
564 
573 template <class FS>
574 int ImageDb<FS>::GetImages(const QString &ids, ImageList &files, ImageList &dirs,
575  const QString &refine) const
576 {
577  if (ids.isEmpty())
578  return 0;
579 
580  QString select = QString("file_id IN (%1) %2").arg(FS::DbIds(ids), refine);
581  return ReadImages(dirs, files, select);
582 }
583 
584 
593 template <class FS>
594 int ImageDb<FS>::GetChildren(const QString &ids, ImageList &files, ImageList &dirs,
595  const QString &refine) const
596 {
597  QString select = QString("dir_id IN (%1) %2").arg(FS::DbIds(ids), refine);
598  return ReadImages(dirs, files, select);
599 }
600 
601 
611 template <class FS>
613  ImageList &files, ImageList &dirs,
614  const QString &refine) const
615 {
616  MSqlQuery query(MSqlQuery::InitCon());
617  query.prepare(QString("SELECT %1 FROM %2 "
618  "WHERE (dir_id = :ID1 OR file_id = :ID2) "
619  "%3;").arg(kDBColumns, m_table, refine));
620 
621  // Qt < 5.4 won't bind multiple occurrences
622  int dbId = FS::DbId(id);
623  query.bindValue(":ID1", dbId);
624  query.bindValue(":ID2", dbId);
625 
626  if (!query.exec())
627  {
628  MythDB::DBError(DBLOC, query);
629  return -1;
630  }
631  while (query.next())
632  {
633  ImagePtr im(CreateImage(query));
634 
635  if (im->IsFile())
636  files.append(im);
637  else if (im->m_id == id)
638  parent = im;
639  else
640  dirs.append(im);
641  }
642  return query.size();
643 }
644 
645 
653 template <class FS>
654 bool ImageDb<FS>::GetDescendants(const QString &ids,
655  ImageList &files, ImageList &dirs) const
656 {
657  if (ids.isEmpty())
658  return false;
659 
660  if (ReadImages(dirs, files, QString("file_id IN (%1)").arg(FS::DbIds(ids))) < 0)
661  return false;
662 
663  MSqlQuery query(MSqlQuery::InitCon());
664  QString sql =
665  QString("SELECT %1"
666  ", LENGTH(filename) - LENGTH(REPLACE(filename, '/', ''))"
667  " AS depth "
668  "FROM %2 WHERE filename LIKE :PREFIX "
669  "ORDER BY depth;").arg(kDBColumns,m_table);
670 
671  for (const auto& im1 : qAsConst(dirs))
672  {
673  query.prepare(sql);
674  query.bindValue(":PREFIX", im1->m_filePath + "/%");
675 
676  if (!query.exec())
677  {
678  MythDB::DBError(DBLOC, query);
679  return false;
680  }
681 
682  while (query.next())
683  {
684  ImagePtr im2(CreateImage(query));
685  if (im2->IsDirectory())
686  dirs.append(im2);
687  else
688  files.append(im2);
689  }
690  }
691  return true;
692 }
693 
694 
702 template <class FS>
703 bool ImageDb<FS>::GetImageTree(int id, ImageList &files, const QString &refine) const
704 {
705  // Load starting children
706  ImageList dirs;
707  if (GetChildren(QString::number(id), files, dirs, refine) < 0)
708  return false;
709 
710  for (const auto& im : qAsConst(dirs))
711  if (!GetImageTree(im->m_id, files, refine))
712  return false;
713  return true;
714 }
715 
716 
722 template <class FS>
724 {
725  MSqlQuery query(MSqlQuery::InitCon());
726  query.prepare(QString("SELECT %1 FROM %2").arg(kDBColumns, m_table));
727 
728  if (!query.exec())
729  {
730  MythDB::DBError(DBLOC, query);
731  return false;
732  }
733 
734  while (query.next())
735  {
736  ImagePtr im(CreateImage(query));
737  if (im->IsDirectory())
738  dirs.insert(im->m_filePath, im);
739  else
740  files.insert(im->m_filePath, im);
741  }
742  return true;
743 }
744 
745 
753 template <class FS>
754 void ImageDb<FS>::ClearDb(int devId, const QString &action)
755 {
756  if (action == "DEVICE CLOSE ALL")
757  // Retain Db images when closing UI
758  return;
759 
760  MSqlQuery query(MSqlQuery::InitCon());
761 
762  if (action == "DEVICE CLEAR ALL")
763  {
764  // Clear images from all devices. Reset auto-increment
765  query.prepare(QString("TRUNCATE TABLE %1;").arg(m_table));
766 
767  if (!query.exec())
768  MythDB::DBError(DBLOC, query);
769  }
770  else // Actions DEVICE REMOVE & DEVICE EJECT
771  {
772  // Delete all images of the device
773  query.prepare(QString("DELETE IGNORE FROM %1 WHERE zoom = :FS;").arg(m_table));
774  query.bindValue(":FS", devId);
775 
776  if (!query.exec())
777  MythDB::DBError(DBLOC, query);
778  }
779 }
780 
781 
789 template <class FS>
790 int ImageDb<FS>::InsertDbImage(ImageItemK &im, bool checkForDuplicate) const
791 {
792  MSqlQuery query(MSqlQuery::InitCon());
793 
794  if (checkForDuplicate)
795  {
796  query.prepare(QString("SELECT file_id FROM %1 WHERE filename = :NAME;")
797  .arg(m_table));
798 
799  query.bindValue(":NAME", im.m_filePath);
800 
801  if (!query.exec())
802  {
803  MythDB::DBError(DBLOC, query);
804  return -1;
805  }
806 
807  if (query.size() > 0)
808  {
809  LOG(VB_FILE, LOG_DEBUG, QString("Image: %1 already exists in Db")
810  .arg(im.m_filePath));
811  return query.value(0).toInt();
812  }
813  }
814 
815  query.prepare(QString("INSERT INTO %1 (%2) VALUES (0, "
816  ":FILEPATH, :NAME, :PARENT, :TYPE, :MODTIME, "
817  ":SIZE, :EXTENSION, :DATE, :HIDDEN, :ORIENT, "
818  ":COVER, :COMMENT, :FS);").arg(m_table, kDBColumns));
819 
820  query.bindValueNoNull(":FILEPATH", im.m_filePath);
821  query.bindValueNoNull(":NAME", FS::BaseNameOf(im.m_filePath));
822  query.bindValue(":FS", im.m_device);
823  query.bindValue(":PARENT", FS::DbId(im.m_parentId));
824  query.bindValue(":TYPE", im.m_type);
825  query.bindValue(":MODTIME", static_cast<qint64>(im.m_modTime.count()));
826  query.bindValue(":SIZE", im.m_size);
827  query.bindValueNoNull(":EXTENSION", im.m_extension);
828  query.bindValue(":DATE", static_cast<qint64>(im.m_date.count()));
829  query.bindValue(":ORIENT", im.m_orientation);
830  query.bindValueNoNull(":COMMENT", im.m_comment);
831  query.bindValue(":HIDDEN", im.m_isHidden);
832  query.bindValue(":COVER", FS::DbId(im.m_userThumbnail));
833 
834  if (query.exec())
835  return FS::ImageId(query.lastInsertId().toInt());
836 
837  MythDB::DBError(DBLOC, query);
838  return -1;
839 }
840 
841 
847 template <class FS>
849 {
850  MSqlQuery query(MSqlQuery::InitCon());
851  query.prepare(QString
852  ("UPDATE %1 SET "
853  "filename = :FILEPATH, name = :NAME, "
854  "dir_id = :PARENT, type = :TYPE, "
855  "modtime = :MODTIME, size = :SIZE, "
856  "extension = :EXTENSION, date = :DATE, zoom = :FS, "
857  "hidden = :HIDDEN, orientation = :ORIENT, "
858  "angle = :COVER, path = :COMMENT "
859  "WHERE file_id = :ID;").arg(m_table));
860 
861  query.bindValue(":ID", FS::DbId(im.m_id));
862  query.bindValue(":FILEPATH", im.m_filePath);
863  query.bindValue(":NAME", FS::BaseNameOf(im.m_filePath));
864  query.bindValue(":PARENT", FS::DbId(im.m_parentId));
865  query.bindValue(":TYPE", im.m_type);
866  query.bindValue(":MODTIME", static_cast<qint64>(im.m_modTime.count()));
867  query.bindValue(":SIZE", im.m_size);
868  query.bindValue(":EXTENSION", im.m_extension);
869  query.bindValue(":DATE", static_cast<qint64>(im.m_date.count()));
870  query.bindValue(":FS", im.m_device);
871  query.bindValue(":HIDDEN", im.m_isHidden);
872  query.bindValue(":ORIENT", im.m_orientation);
873  query.bindValue(":COVER", FS::DbId(im.m_userThumbnail));
874  query.bindValueNoNull(":COMMENT", im.m_comment);
875 
876  if (query.exec())
877  return true;
878 
879  MythDB::DBError(DBLOC, query);
880  return false;
881 }
882 
883 
890 template <class FS>
891 QStringList ImageDb<FS>::RemoveFromDB(const ImageList &imList) const
892 {
893  QStringList ids;
894  if (!imList.isEmpty())
895  {
896  for (const auto& im : qAsConst(imList))
897  ids << QString::number(FS::DbId(im->m_id));
898 
899  QString idents = ids.join(",");
900  MSqlQuery query(MSqlQuery::InitCon());
901  query.prepare(QString("DELETE IGNORE FROM %1 WHERE file_id IN (%2);")
902  .arg(m_table, idents));
903 
904  if (!query.exec())
905  {
906  MythDB::DBError(DBLOC, query);
907  return {};
908  }
909  }
910  return ids;
911 }
912 
913 
920 template <class FS>
921 bool ImageDb<FS>::SetHidden(bool hide, const QString &ids) const
922 {
923  if (ids.isEmpty())
924  return false;
925 
926  MSqlQuery query(MSqlQuery::InitCon());
927 
928  query.prepare(QString("UPDATE %1 SET "
929  "hidden = :HIDDEN "
930  "WHERE file_id IN (%2);").arg(m_table, FS::DbIds(ids)));
931  query.bindValue(":HIDDEN", hide ? 1 : 0);
932 
933  if (query.exec())
934  return true;
935 
936  MythDB::DBError(DBLOC, query);
937  return false;
938 }
939 
940 
946 template <class FS>
947 bool ImageDb<FS>::SetCover(int dir, int id) const
948 {
949  MSqlQuery query(MSqlQuery::InitCon());
950 
951  query.prepare(QString("UPDATE %1 SET "
952  "angle = :COVER "
953  "WHERE file_id = :DIR").arg(m_table));
954  query.bindValue(":COVER", FS::DbId(id));
955  query.bindValue(":DIR", FS::DbId(dir));
956  \
957  if (query.exec())
958  return true;
959 
960  MythDB::DBError(DBLOC, query);
961  return false;
962 }
963 
964 
970 template <class FS>
971 bool ImageDb<FS>::SetOrientation(int id, int orientation) const
972 {
973  MSqlQuery query(MSqlQuery::InitCon());
974 
975  query.prepare(QString("UPDATE %1 SET ").arg(m_table) +
976  "orientation = :ORIENTATION "
977  "WHERE file_id = :ID");
978  query.bindValue(":ORIENTATION", orientation);
979  query.bindValue(":ID", FS::DbId(id));
980  \
981  if (query.exec())
982  return true;
983 
984  MythDB::DBError(DBLOC, query);
985  return false;
986 }
987 
988 
996 template <class FS>
998  const QString &selector) const
999 {
1000  MSqlQuery query(MSqlQuery::InitCon());
1001  query.prepare(QString("SELECT %1 FROM %2 WHERE %3")
1002  .arg(kDBColumns, m_table, selector));
1003  if (!query.exec())
1004  {
1005  MythDB::DBError(DBLOC, query);
1006  return -1;
1007  }
1008 
1009  while (query.next())
1010  {
1011  ImagePtr im(CreateImage(query));
1012 
1013  if (im->IsFile())
1014  files.append(im);
1015  else
1016  dirs.append(im);
1017  }
1018  return query.size();
1019 }
1020 
1021 
1031 template <class FS>
1032 void ImageDb<FS>::GetDescendantCount(int id, bool all, int &dirs,
1033  int &pics, int &videos, int &sizeKb) const
1034 {
1035  QString whereClause;
1036  if (!all)
1037  {
1038  whereClause = "WHERE filename LIKE "
1039  "( SELECT CONCAT(filename, '/%') "
1040  " FROM %2 WHERE file_id = :ID);";
1041  }
1042 
1043  MSqlQuery query(MSqlQuery::InitCon());
1044  query.prepare(QString("SELECT SUM(type <= :FLDR) AS Fldr, "
1045  " SUM(type = :PIC) AS Pics, "
1046  " SUM(type = :VID) AS Vids, "
1047  " SUM(size / 1024) "
1048  "FROM %2 %1;").arg(whereClause, m_table));
1049 
1050  query.bindValue(":FLDR", kDirectory);
1051  query.bindValue(":PIC", kImageFile);
1052  query.bindValue(":VID", kVideoFile);
1053  if (!all)
1054  query.bindValue(":ID", FS::DbId(id));
1055 
1056  if (!query.exec())
1057  {
1058  MythDB::DBError(DBLOC, query);
1059  }
1060  else if (query.next())
1061  {
1062  dirs += query.value(0).toInt();
1063  pics += query.value(1).toInt();
1064  videos += query.value(2).toInt();
1065  sizeKb += query.value(3).toInt();
1066  }
1067 }
1068 
1069 
1074 {
1075  // Be has a single SG device
1077 }
1078 
1079 
1084  : ImageDb(QString("`%1_%2`").arg(DB_TABLE, gCoreContext->GetHostName()))
1085 {
1086  // Remove any table leftover from a previous FE crash
1087  DropTable();
1088 }
1089 
1090 
1095 {
1096  MSqlQuery query(MSqlQuery::InitCon());
1097  query.prepare(QString("DROP TABLE IF EXISTS %1;").arg(m_table));
1098  if (query.exec())
1099  m_dbExists = false;
1100  else
1101  MythDB::DBError(DBLOC, query);
1102 }
1103 
1104 
1109 {
1110  if (m_dbExists)
1111  return true;
1112 
1113  MSqlQuery query(MSqlQuery::InitCon());
1114 
1115  // Create temporary table
1116  query.prepare(QString("CREATE TABLE %1 LIKE %2;").arg(m_table, DB_TABLE));
1117  if (query.exec())
1118  {
1119  // Store it in memory only
1120  query.prepare(QString("ALTER TABLE %1 ENGINE = MEMORY;").arg(m_table));
1121  if (query.exec())
1122  {
1123  m_dbExists = true;
1124  LOG(VB_FILE, LOG_DEBUG, QString("Created Db table %1").arg(m_table));
1125  return true;
1126  }
1127  }
1128  MythDB::DBError(DBLOC, query);
1129 
1130  // Clean up after failure
1131  query.prepare(QString("DROP TABLE IF EXISTS %1;").arg(m_table));
1132  query.exec();
1133  return false;
1134 }
1135 
1136 
1140 class ReadMetaThread : public QRunnable
1141 {
1142 public:
1143  ReadMetaThread(ImagePtrK im, QString path)
1144  : m_im(std::move(im)), m_path(std::move(path)) {}
1145 
1146  void run() override // QRunnable
1147  {
1148  QStringList tags;
1149  QString orientation;
1150  QString size;
1151 
1152  // Read metadata for files only
1153  if (m_im->IsFile())
1154  {
1155  ImageMetaData *metadata = (m_im->m_type == kVideoFile)
1158  tags = metadata->GetAllTags();
1159  orientation = Orientation(m_im->m_orientation).Description();
1160  size = ImageAdapterBase::FormatSize(m_im->m_size / 1024);
1161  delete metadata;
1162  }
1163 
1164  // Add identifier at front
1165  tags.prepend(QString::number(m_im->m_id));
1166 
1167  // Include file info
1168  tags << ImageMetaData::ToString(EXIF_MYTH_HOST, "Host",
1170  tags << ImageMetaData::ToString(EXIF_MYTH_PATH, "Path",
1172  tags << ImageMetaData::ToString(EXIF_MYTH_NAME, "Name",
1174  tags << ImageMetaData::ToString(EXIF_MYTH_SIZE, "Size", size);
1175  tags << ImageMetaData::ToString(EXIF_MYTH_ORIENT, "Orientation",
1176  orientation);
1177 
1178  MythEvent me("IMAGE_METADATA", tags);
1179  gCoreContext->SendEvent(me);
1180  }
1181 
1182 private:
1184  QString m_path;
1185 };
1186 
1187 
1196 template <class DBFS>
1197 QStringList ImageHandler<DBFS>::HandleGetMetadata(const QString &id) const
1198 {
1199  // Find image in DB
1200  ImageList files;
1201  ImageList dirs;
1202  if (DBFS::GetImages(id, files, dirs) != 1)
1203  RESULT_ERR("Image not found", QString("Unknown image %1").arg(id))
1204 
1205  ImagePtr im = files.isEmpty() ? dirs[0] : files[0];
1206 
1207  QString absPath = DBFS::GetAbsFilePath(im);
1208  if (absPath.isEmpty())
1209  RESULT_ERR("Image not found",
1210  QString("File %1 not found").arg(im->m_filePath))
1211 
1212  auto *worker = new ReadMetaThread(im, absPath);
1213 
1214  MThreadPool::globalInstance()->start(worker, "ImageMetaData");
1215 
1216  RESULT_OK(QString("Fetching metadata for %1").arg(id))
1217 }
1218 
1219 
1227 template <class DBFS>
1228 QStringList ImageHandler<DBFS>::HandleRename(const QString &id,
1229  const QString &newBase) const
1230 {
1231  // Sanity check new name
1232  if (newBase.isEmpty() || newBase.contains("/") || newBase.contains("\\"))
1233  RESULT_ERR("Invalid name", QString("Invalid name %1").arg(newBase))
1234 
1235  // Find image in DB
1236  ImageList files;
1237  ImageList dirs;
1238  if (DBFS::GetImages(id, files, dirs) != 1)
1239  RESULT_ERR("Image not found", QString("Image %1 not in Db").arg(id))
1240 
1241  ImagePtr im = files.isEmpty() ? dirs[0] : files[0];
1242 
1243  // Find file
1244  QString oldPath = DBFS::GetAbsFilePath(im);
1245  if (oldPath.isEmpty())
1246  RESULT_ERR("Image not found",
1247  QString("File %1 not found").arg(im->m_filePath))
1248 
1249  // Generate new filename
1250  QFileInfo oldFi = QFileInfo(oldPath);
1251  QString newName = im->IsDirectory()
1252  ? newBase : QString("%1.%2").arg(newBase, oldFi.suffix());
1253 
1254  im->m_filePath = DBFS::ConstructPath(DBFS::PathOf(im->m_filePath), newName);
1255 
1256  // Ensure no SG duplicate files are created. (Creating clone dirs is ok)
1257  if (im->IsFile())
1258  {
1259  QString existPath = DBFS::GetAbsFilePath(im);
1260  if (!existPath.isEmpty())
1261  RESULT_ERR("Filename already used",
1262  QString("Renaming %1 to %2 will create a duplicate of %3")
1263  .arg(oldPath, im->m_filePath, existPath))
1264  }
1265 
1266  // Rename file or directory
1267  QString newPath = oldFi.dir().absoluteFilePath(newName);
1268  if (!QFile::rename(oldPath, newPath))
1269  RESULT_ERR("Rename failed",
1270  QString("Rename of %1 -> %2 failed").arg(oldPath, newPath))
1271 
1272  if (im->IsDirectory())
1273  {
1274  // Dir name change affects path of all sub-dirs & files and their thumbs
1275  HandleScanRequest("START");
1276  }
1277  else // file
1278  {
1279  // Update db
1280  DBFS::UpdateDbImage(*im);
1281 
1282  // Image is modified, not deleted
1283  QStringList mesg("");
1284  mesg << QString::number(im->m_id);
1285 
1286  // Rename thumbnail.
1287  m_thumbGen->MoveThumbnail(im);
1288 
1289  // Notify clients of changed image
1290  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1291  }
1292  RESULT_OK(QString("Renamed %1 -> %2").arg(oldPath, newPath))
1293 }
1294 
1295 
1303 template <class DBFS>
1304 QStringList ImageHandler<DBFS>::HandleDelete(const QString &ids) const
1305 {
1306  // Get subtree of all files
1307  ImageList files;
1308  ImageList dirs;
1309  // Dirs will be in depth-first order, (subdirs after parent)
1310  DBFS::GetDescendants(ids, files, dirs);
1311 
1312  // Remove files from filesystem first
1313  RemoveFiles(files);
1314  // ... then dirs, which should now be empty
1315  RemoveFiles(dirs);
1316 
1317  // Fail if nothing deleted
1318  if (files.isEmpty() && dirs.isEmpty())
1319  RESULT_ERR("Delete failed", QString("Delete of %1 failed").arg(ids))
1320 
1321  // Update Db
1322  DBFS::RemoveFromDB(files + dirs);
1323 
1324  // Clean up thumbnails
1325  QStringList mesg(m_thumbGen->DeleteThumbs(files));
1326 
1327  // Notify clients of deleted ids
1328  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1329 
1330  return QStringList("OK");
1331 }
1332 
1333 
1346 template <class DBFS>
1347 QStringList ImageHandler<DBFS>::HandleDbCreate(QStringList defs) const
1348 {
1349  if (defs.isEmpty())
1350  RESULT_ERR("Copy Failed", "Empty defs")
1351 
1352  // First item is the field seperator
1353  const QString separator = defs.takeFirst();
1354 
1355  // Convert cover ids to their new equivalent. Map<source id, new id>
1356  // Dirs follow their children so new cover ids will be defined before they
1357  // are used
1358  QHash<QString, int> idMap;
1359 
1360  // Create skeleton Db images using copied settings.
1361  // Scanner will update other attributes
1362  ImageItem im;
1363  for (const auto& def : qAsConst(defs))
1364  {
1365  QStringList aDef = def.split(separator);
1366 
1367  // Expects id, type, path, hidden, orientation, cover
1368  if (aDef.size() != 6)
1369  {
1370  // Coding error
1371  LOG(VB_GENERAL, LOG_ERR,
1372  LOC + QString("Bad definition: (%1)").arg(def));
1373  continue;
1374  }
1375 
1376  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Creating %1").arg(aDef.join(",")));
1377 
1378  im.m_type = aDef[1].toInt();
1379  im.m_filePath = aDef[2];
1380  im.m_isHidden = (aDef[3].toInt() != 0);
1381  im.m_orientation = aDef[4].toInt();
1382  im.m_userThumbnail = idMap.value(aDef[5]);
1383 
1384  // Don't insert duplicate filepaths
1385  int newId = DBFS::InsertDbImage(im, true);
1386 
1387  // Record old->new id map in case it's being used as a cover
1388  idMap.insert(aDef[0], newId);
1389  }
1390  HandleScanRequest("START");
1391 
1392  RESULT_OK("Created Db images")
1393 }
1394 
1395 
1405 template <class DBFS>
1406 QStringList ImageHandler<DBFS>::HandleDbMove(const QString &ids,
1407  const QString &srcPath,
1408  QString destPath) const
1409 {
1410  // Sanity check new path
1411  if (destPath.contains(".."))
1412  RESULT_ERR("Invalid path", QString("Invalid path %1").arg(destPath))
1413 
1414  // Get subtrees of renamed files
1415  ImageList images;
1416  ImageList dirs;
1417  ImageList files;
1418  bool ok = DBFS::GetDescendants(ids, files, dirs);
1419  images << dirs << files;
1420 
1421  if (!ok || images.isEmpty())
1422  RESULT_ERR("Image not found", QString("Images %1 not in Db").arg(ids))
1423 
1424  if (!destPath.isEmpty() && !destPath.endsWith(QChar('/')))
1425  destPath.append("/");
1426 
1427  // Update path of images only. Scanner will repair parentId
1428  for (const auto& im : qAsConst(images))
1429  {
1430  QString old = im->m_filePath;
1431 
1432  if (srcPath.isEmpty())
1433  {
1434  // Image in SG root
1435  im->m_filePath.prepend(destPath);
1436  }
1437  else if (im->m_filePath.startsWith(srcPath))
1438  {
1439  // All other images
1440  im->m_filePath.replace(srcPath, destPath);
1441  }
1442  else
1443  {
1444  // Coding error
1445  LOG(VB_GENERAL, LOG_ERR,
1446  LOC + QString("Bad image: (%1 -> %2)").arg(srcPath, destPath));
1447  continue;
1448  }
1449 
1450  LOG(VB_FILE, LOG_DEBUG,
1451  LOC + QString("Db Renaming %1 -> %2").arg(old, im->m_filePath));
1452 
1453  DBFS::UpdateDbImage(*im);
1454 
1455  // Rename thumbnail
1456  if (im->IsFile())
1457  m_thumbGen->MoveThumbnail(im);
1458  }
1459  HandleScanRequest("START");
1460 
1461  RESULT_OK(QString("Moved %1 from %2 -> %3").arg(ids, srcPath, destPath))
1462 }
1463 
1464 
1472 template <class DBFS>
1473 QStringList ImageHandler<DBFS>::HandleHide(bool hide, const QString &ids) const
1474 {
1475  if (!DBFS::SetHidden(hide, ids))
1476  RESULT_ERR("Hide failed", QString("Db hide failed for %1").arg(ids))
1477 
1478  // Send changed ids only (none deleted)
1479  QStringList mesg = QStringList("") << ids;
1480  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1481 
1482  RESULT_OK(QString("Images %1 now %2hidden").arg(ids, hide ? "" : "un"))
1483 }
1484 
1485 
1494 template <class DBFS>
1495 QStringList ImageHandler<DBFS>::HandleTransform(int transform,
1496  const QString &ids) const
1497 {
1498  if (transform < kResetToExif || transform > kFlipVertical)
1499  RESULT_ERR("Transform failed", QString("Bad transform %1").arg(transform))
1500 
1501  ImageList files;
1502  ImageList dirs;
1503  if (DBFS::GetImages(ids, files, dirs) < 1 || files.isEmpty())
1504  RESULT_ERR("Image not found", QString("Images %1 not in Db").arg(ids))
1505 
1506  // Update db
1507  for (const auto& im : qAsConst(files))
1508  {
1509  int old = im->m_orientation;
1510  im->m_orientation = Orientation(im->m_orientation).Transform(transform);
1511 
1512  // Update Db
1513  if (DBFS::SetOrientation(im->m_id, im->m_orientation))
1514  {
1515  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Transformed %1 from %2 to %3")
1516  .arg(im->m_filePath).arg(old).arg(im->m_orientation));
1517  }
1518  }
1519 
1520  // Images are changed, not deleted
1521  QStringList mesg("");
1522 
1523  // Clean up thumbnails
1524  mesg << m_thumbGen->DeleteThumbs(files);
1525 
1526  // Notify clients of changed images
1527  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1528 
1529  return QStringList("OK");
1530 }
1531 
1532 
1541 template <class DBFS>
1542 QStringList ImageHandler<DBFS>::HandleDirs(const QString &destId,
1543  bool rescan,
1544  const QStringList &relPaths) const
1545 {
1546  // Find image in DB
1547  ImageList files;
1548  ImageList dirs;
1549  if (DBFS::GetImages(destId, files, dirs) != 1 || dirs.isEmpty())
1550  RESULT_ERR("Destination not found",
1551  QString("Image %1 not in Db").arg(destId))
1552 
1553  // Find dir. SG device (Photographs) uses most-free filesystem
1554  QString destPath = DBFS::GetAbsFilePath(dirs[0]);
1555  if (destPath.isEmpty())
1556  RESULT_ERR("Destination not found",
1557  QString("Dest dir %1 not found").arg(dirs[0]->m_filePath))
1558 
1559  QDir destDir(destPath);
1560  bool succeeded = false;
1561  for (const auto& relPath : qAsConst(relPaths))
1562  {
1563  // Validate dir name
1564  if (relPath.isEmpty() || relPath.contains("..") || relPath.startsWith(QChar('/')))
1565  continue;
1566 
1567  QString newPath = DBFS::ConstructPath(destDir.absolutePath(), relPath);
1568  if (!destDir.mkpath(relPath))
1569  {
1570  LOG(VB_GENERAL, LOG_ERR,
1571  LOC + QString("Failed to create dir %1").arg(newPath));
1572  continue;
1573  }
1574  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Dir %1 created").arg(newPath));
1575  succeeded = true;
1576  }
1577 
1578  if (!succeeded)
1579  // Failures should only occur due to user input
1580  RESULT_ERR("Invalid Name", QString("Invalid name %1")
1581  .arg(relPaths.join(",")))
1582 
1583  if (rescan)
1584  // Rescan to detect new dir
1585  HandleScanRequest("START");
1586 
1587  return QStringList("OK");
1588 }
1589 
1590 
1597 template <class DBFS>
1598 QStringList ImageHandler<DBFS>::HandleCover(int dir, int cover) const
1599 {
1600  if (!DBFS::SetCover(dir, cover))
1601  RESULT_ERR("Set Cover failed",
1602  QString("Failed to set %1 to cover %2").arg(dir).arg(cover))
1603 
1604  // Image has changed, nothing deleted
1605  QStringList mesg = QStringList("") << QString::number(dir);
1606  DBFS::Notify("IMAGE_DB_CHANGED", mesg);
1607 
1608  RESULT_OK(QString("Cover of %1 is now %2").arg(dir).arg(cover));
1609 }
1610 
1611 
1620 template <class DBFS>
1621 QStringList ImageHandler<DBFS>::HandleIgnore(const QString &exclusions) const
1622 {
1623  // Save new setting. FE will have already saved it but not cleared the cache
1624  gCoreContext->SaveSettingOnHost("GalleryIgnoreFilter", exclusions, nullptr);
1625 
1626  // Rescan
1627  HandleScanRequest("START");
1628 
1629  RESULT_OK(QString("Using exclusions '%1'").arg(exclusions))
1630 }
1631 
1632 
1640 template <class DBFS>
1641 QStringList ImageHandler<DBFS>::HandleScanRequest(const QString &command,
1642  int devId) const
1643 {
1644  if (!m_scanner)
1645  RESULT_ERR("Missing Scanner", "Missing Scanner");
1646 
1647  if (command == "START")
1648  {
1649  // Must be dormant to start a scan
1650  if (m_scanner->IsScanning())
1651  RESULT_ERR("", "Scanner is busy");
1652 
1653  m_scanner->ChangeState(true);
1654  RESULT_OK("Scan requested");
1655  }
1656  else if (command == "STOP")
1657  {
1658  // Must be scanning to interrupt
1659  if (!m_scanner->IsScanning())
1660  RESULT_ERR("Scanner not running", "Scanner not running");
1661 
1662  m_scanner->ChangeState(false);
1663  RESULT_OK("Terminate scan requested");
1664  }
1665  else if (command == "QUERY")
1666  {
1667  return QStringList("OK") << m_scanner->GetProgress();
1668  }
1669  else if (command.startsWith(QString("DEVICE")))
1670  {
1671  m_scanner->EnqueueClear(devId, command);
1672  RESULT_OK(QString("Clearing device %1 %2").arg(command).arg(devId))
1673  }
1674  RESULT_ERR("Unknown command", QString("Unknown command %1").arg(command));
1675 }
1676 
1677 
1685 template <class DBFS>
1687 (const QStringList &message) const
1688 {
1689  if (message.size() != 2)
1690  RESULT_ERR("Unknown Command",
1691  QString("Bad request: %1").arg(message.join("|")))
1692 
1693  int priority = message.at(0).toInt()
1695 
1696  // get specific image details from db
1697  ImageList files;
1698  ImageList dirs;
1699  DBFS::GetImages(message.at(1), files, dirs);
1700 
1701  for (const auto& im : qAsConst(files))
1702  // notify clients when done; highest priority
1703  m_thumbGen->CreateThumbnail(im, priority, true);
1704 
1705  return QStringList("OK");
1706 }
1707 
1708 
1718 template <class DBFS>
1720 {
1721 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1722  QMutableVectorIterator<ImagePtr> it(images);
1723 #else
1724  QMutableListIterator<ImagePtr> it(images);
1725 #endif
1726  it.toBack();
1727  while (it.hasPrevious())
1728  {
1729  ImagePtrK im = it.previous();
1730 
1731  // Remove file or directory
1732  QString absFilename = DBFS::GetAbsFilePath(im);
1733 
1734  bool success = !absFilename.isEmpty()
1735  && (im->IsFile() ? QFile::remove(absFilename)
1736  : QDir::root().rmdir(absFilename));
1737  if (success)
1738  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Deleted %1").arg(absFilename));
1739  else
1740  {
1741  LOG(VB_GENERAL, LOG_ERR, LOC +
1742  QString("Can't delete %1").arg(absFilename));
1743  // Remove from list
1744  it.remove();
1745  }
1746  }
1747 }
1748 
1749 
1756 {
1757  switch (type)
1758  {
1759  case kPicOnly: return QString("AND type != %1").arg(kVideoFile);
1760  case kVideoOnly: return QString("AND type != %1").arg(kImageFile);
1761  case kPicAndVideo: return "";
1762  }
1763  return "";
1764 }
1765 
1766 
1773 {
1774  m_refineClause = QString("%2 %3 "
1775  "ORDER BY "
1776  "CASE WHEN type <= %1 THEN %4, "
1777  "CASE WHEN type > %1 THEN %5 ")
1778  .arg(kDirectory)
1779  .arg(m_showHidden ? "" : "AND hidden = 0",
1783 }
1784 
1785 
1792 {
1793  // prepare the sorting statement
1794  switch (order)
1795  {
1796  default:
1797  case kSortByNameAsc: return "name END ASC";
1798  case kSortByNameDesc: return "name END DESC";
1799  case kSortByModTimeAsc: return "modtime END ASC";
1800  case kSortByModTimeDesc: return "modtime END DESC";
1801  case kSortByExtAsc: return "extension END ASC, name ASC";
1802  case kSortByExtDesc: return "extension END DESC, name DESC";
1803  case kSortBySizeAsc: return "size END ASC, name ASC";
1804  case kSortBySizeDesc: return "size END DESC, name DESC";
1805  case kSortByDateAsc: return "IF(date=0, modtime, date) END ASC";
1806  case kSortByDateDesc: return "IF(date=0, modtime, date) END DESC";
1807  }
1808 }
1809 
1810 
1820  ImageList &files, ImageList &dirs) const
1821 {
1822  // Only Root node will invoke both Db queries but result set will be small
1823  // For Root the SG is always ordered before local devices
1824  // Root node has no Db entry so the 2 queries will not overwrite the parent.
1825  int count = 0;
1826  if (!ImageItem::IsLocalId(id))
1827  count = m_remote->GetDirectory(id, parent, files, dirs, m_refineClause);
1829  count += ImageHandler::GetDirectory(id, parent, files, dirs, m_refineClause);
1830 
1831  if (id == GALLERY_DB_ID)
1832  {
1833  // Add a Root node
1834  parent = ImagePtr(new ImageItem(GALLERY_DB_ID));
1835  parent->m_parentId = GALLERY_DB_ID;
1836  parent->m_type = kDevice;
1837 
1838  ++count;
1839  }
1840  return count;
1841 }
1842 
1843 
1852  ImageList &files, ImageList &dirs) const
1853 {
1854  // Ids are either all local or all remote. GALLERY_DB_ID not valid
1855  StringPair lists = ImageItem::PartitionIds(ids);
1856 
1857  if (!lists.second.isEmpty())
1858  return m_remote->GetImages(lists.second, files, dirs, m_refineClause);
1859  if (m_dbExists && !lists.first.isEmpty())
1860  return ImageHandler::GetImages(lists.first, files, dirs, m_refineClause);
1861  return 0;
1862 }
1863 
1864 
1872 int ImageDbReader::GetChildren(int id, ImageList &files, ImageList &dirs) const
1873 {
1874  int count = 0;
1875  if (!ImageItem::IsLocalId(id))
1876  count = m_remote->GetChildren(QString::number(id), files, dirs,
1877  m_refineClause);
1879  count += ImageHandler::GetChildren(QString::number(id), files, dirs,
1880  m_refineClause);
1881  return count;
1882 }
1883 
1884 
1892  ImageList &files, ImageList &dirs) const
1893 {
1894  // Ids are either all local or all remote
1895  StringPair lists = ImageItem::PartitionIds(ids);
1896 
1897  if (!lists.second.isEmpty())
1898  m_remote->GetDescendants(lists.second, files, dirs);
1899  if (m_dbExists && !lists.first.isEmpty())
1900  ImageHandler::GetDescendants(lists.first, files, dirs);
1901 }
1902 
1903 
1910 void ImageDbReader::GetImageTree(int id, ImageList &files) const
1911 {
1912  if (!ImageItem::IsLocalId(id))
1913  m_remote->GetImageTree(id, files, m_refineClause);
1915  ImageHandler::GetImageTree(id, files, m_refineClause);
1916 }
1917 
1918 
1927 void ImageDbReader::GetDescendantCount(int id, int &dirs, int &pics,
1928  int &videos, int &sizeKb) const
1929 {
1930  if (id == GALLERY_DB_ID)
1931  {
1932  // Sum both unfiltered tables
1933  m_remote->GetDescendantCount(id, true, dirs, pics, videos, sizeKb);
1934  if (m_dbExists)
1935  ImageHandler::GetDescendantCount(id, true, dirs, pics, videos, sizeKb);
1936  }
1937  else if (!ImageItem::IsLocalId(id))
1938  {
1939  // Don't filter on SG path (it's blank)
1941  dirs, pics, videos, sizeKb);
1942  }
1943  else if (m_dbExists)
1944  {
1945  // Always filter on device/dir
1946  ImageHandler::GetDescendantCount(id, false, dirs, pics, videos, sizeKb);
1947  }
1948 }
1949 
1950 
1955 
1956 
1962 {
1963  if (!s_instance)
1964  s_instance = new ImageManagerBe();
1965  return s_instance;
1966 }
1967 
1968 
1974 {
1975  if (!s_instance)
1976  {
1977  // Use saved settings
1979  (gCoreContext->GetNumSetting("GalleryImageOrder"),
1980  gCoreContext->GetNumSetting("GalleryDirOrder"),
1981  gCoreContext->GetBoolSetting("GalleryShowHidden"),
1982  gCoreContext->GetNumSetting("GalleryShowType"),
1983  gCoreContext->GetSetting("GalleryDateFormat"));
1984  }
1985  return *s_instance;
1986 }
1987 
1988 
1997 void ImageManagerFe::CreateThumbnails(const ImageIdList &ids, bool forFolder)
1998 {
1999  // Split images into <locals, remotes>
2000  StringPair lists = ImageItem::PartitionIds(ids);
2001 
2002  if (!lists.second.isEmpty())
2003  {
2004  LOG(VB_FILE, LOG_DEBUG, LOC +
2005  QString("Sending CREATE_THUMBNAILS %1 (forFolder %2)")
2006  .arg(lists.second).arg(forFolder));
2007 
2008  QStringList message;
2009  message << QString::number(static_cast<int>(forFolder)) << lists.second;
2010  gCoreContext->SendEvent(MythEvent("CREATE_THUMBNAILS", message));
2011  }
2012 
2013  if (!lists.first.isEmpty())
2014  {
2015  LOG(VB_FILE, LOG_DEBUG, LOC +
2016  QString("Creating local thumbnails %1 (forFolder %2)")
2017  .arg(lists.first).arg(forFolder));
2018 
2019  QStringList message;
2020  message << QString::number(static_cast<int>(forFolder)) << lists.first;
2021  HandleCreateThumbnails(message);
2022  }
2023 }
2024 
2025 
2032 QString ImageManagerFe::ScanImagesAction(bool start, bool local)
2033 {
2034  QStringList command;
2035  command << (start ? "START" : "STOP");
2036 
2037  if (!local)
2038  {
2039  command.push_front("IMAGE_SCAN");
2040  bool ok = gCoreContext->SendReceiveStringList(command, true);
2041  return ok ? "" : command[1];
2042  }
2043 
2044  // Create database on first scan
2045  if (!CreateTable())
2046  return "Couldn't create database";
2047 
2048  QStringList err = HandleScanRequest(command[0]);
2049  return err[0] == "OK" ? "" : err[1];
2050 }
2051 
2052 
2059 {
2060  QStringList strList;
2061  strList << "IMAGE_SCAN" << "QUERY";
2062 
2063  if (!gCoreContext->SendReceiveStringList(strList))
2064  {
2065  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Scan query failed : %1")
2066  .arg(strList.join(",")));
2067  }
2068  return strList;
2069 }
2070 
2071 
2078 QString ImageManagerFe::HideFiles(bool hidden, const ImageIdList &ids)
2079 {
2080  // Split images into <locals, remotes>
2081  StringPair lists = ImageItem::PartitionIds(ids);
2082  QString result = "";
2083 
2084  if (!lists.second.isEmpty())
2085  {
2086  QStringList message;
2087  message << "IMAGE_HIDE" << QString::number(static_cast<int>(hidden)) << lists.second;
2088 
2089  if (!gCoreContext->SendReceiveStringList(message, true))
2090  result = message[1];
2091  }
2092 
2093  if (!lists.first.isEmpty())
2094  {
2095  QStringList err = HandleHide(hidden, lists.first);
2096  if (err[0] != "OK")
2097  result = err[1];
2098  }
2099  return result;
2100 }
2101 
2102 
2110  const ImageIdList &ids)
2111 {
2112  // Split images into <locals, remotes>
2113  StringPair lists = ImageItem::PartitionIds(ids);
2114  QString result = "";
2115 
2116  if (!lists.second.isEmpty())
2117  {
2118  QStringList message;
2119  message << "IMAGE_TRANSFORM" << QString::number(transform) << lists.second;
2120 
2121  if (!gCoreContext->SendReceiveStringList(message, true))
2122  result = message[1];
2123  }
2124 
2125  if (!lists.first.isEmpty())
2126  {
2127  QStringList err = HandleTransform(transform, lists.first);
2128  if (err[0] != "OK")
2129  result = err[1];
2130  }
2131  return result;
2132 }
2133 
2134 
2141 QString ImageManagerFe::SetCover(int parent, int cover)
2142 {
2143  if (!ImageItem::IsLocalId(parent))
2144  {
2145  QStringList message;
2146  message << "IMAGE_COVER" << QString::number(parent) << QString::number(cover);
2147 
2148  bool ok = gCoreContext->SendReceiveStringList(message, true);
2149  return ok ? "" : message[1];
2150  }
2151 
2152  QStringList err = HandleCover(parent, cover);
2153  return err[0] == "OK" ? "" : err[1];
2154 }
2155 
2156 
2162 {
2163  if (ImageItem::IsLocalId(id))
2164  HandleGetMetadata(QString::number(id));
2165  else
2166  gCoreContext->SendEvent(MythEvent("IMAGE_GET_METADATA", QString::number(id)));
2167 }
2168 
2169 
2172 {
2173  QStringList message("IMAGE_SCAN");
2174  message << "DEVICE CLEAR ALL";
2175  gCoreContext->SendReceiveStringList(message, true);
2176 }
2177 
2178 
2185 QString ImageManagerFe::IgnoreDirs(const QString &excludes)
2186 {
2187  QStringList message("IMAGE_IGNORE");
2188  message << excludes;
2189  bool ok = gCoreContext->SendReceiveStringList(message, true);
2190  return ok ? "" : message[1];
2191 }
2192 
2193 
2201 QString ImageManagerFe::MakeDir(int parent, const QStringList &names, bool rescan)
2202 {
2203  QString destId = QString::number(parent);
2204 
2205  if (!ImageItem::IsLocalId(parent))
2206  {
2207  QStringList message("IMAGE_CREATE_DIRS");
2208  message << destId << QString::number(static_cast<int>(rescan)) << names;
2209  bool ok = gCoreContext->SendReceiveStringList(message, true);
2210  return ok ? "" : message[1];
2211  }
2212  QStringList err = HandleDirs(destId, rescan, names);
2213  return (err[0] == "OK") ? "" : err[1];
2214 }
2215 
2216 
2223 QString ImageManagerFe::RenameFile(const ImagePtrK& im, const QString &name)
2224 {
2225  if (!im->IsLocal())
2226  {
2227  QStringList message("IMAGE_RENAME");
2228  message << QString::number(im->m_id) << name;
2229  bool ok = gCoreContext->SendReceiveStringList(message, true);
2230  return ok ? "" : message[1];
2231  }
2232  QStringList err = HandleRename(QString::number(im->m_id), name);
2233  return (err[0] == "OK") ? "" : err[1];
2234 }
2235 
2236 
2243 QString ImageManagerFe::CreateImages(int destId, const ImageListK &images)
2244 {
2245  if (images.isEmpty())
2246  return "";
2247 
2248  // Define field seperator & include it in message
2249  const QString seperator("...");
2250  QStringList imageDefs(seperator);
2251  ImageIdList ids;
2252  for (const auto& im : qAsConst(images))
2253  {
2254  ids << im->m_id;
2255 
2256  // Copies preserve hide state, orientation & cover
2257  QStringList aDef;
2258  aDef << QString::number(im->m_id)
2259  << QString::number(im->m_type)
2260  << im->m_filePath
2261  << QString::number(static_cast<int>(im->m_isHidden))
2262  << QString::number(im->m_orientation)
2263  << QString::number(im->m_userThumbnail);
2264 
2265  imageDefs << aDef.join(seperator);
2266  }
2267 
2268  // Images are either all local or all remote
2269  if (ImageItem::IsLocalId(destId))
2270  {
2271  QStringList err = HandleDbCreate(imageDefs);
2272  return (err[0] == "OK") ? "" : err[1];
2273  }
2274  imageDefs.prepend("IMAGE_COPY");
2275  bool ok = gCoreContext->SendReceiveStringList(imageDefs, true);
2276  return ok ? "" : imageDefs[1];
2277 }
2278 
2279 
2287 QString ImageManagerFe::MoveDbImages(const ImagePtrK& destDir, ImageListK &images,
2288  const QString &srcPath)
2289 {
2290  QStringList idents;
2291  for (const auto& im : qAsConst(images))
2292  idents << QString::number(im->m_id);
2293 
2294  // Images are either all local or all remote
2295  if (destDir->IsLocal())
2296  {
2297  QStringList err = HandleDbMove(idents.join(","), srcPath,
2298  destDir->m_filePath);
2299  return (err[0] == "OK") ? "" : err[1];
2300  }
2301 
2302  QStringList message("IMAGE_MOVE");
2303  message << idents.join(",") << srcPath << destDir->m_filePath;
2304  bool ok = gCoreContext->SendReceiveStringList(message, true);
2305  return ok ? "" : message[1];
2306 }
2307 
2308 
2315 {
2316  StringPair lists = ImageItem::PartitionIds(ids);
2317 
2318  QString result = "";
2319  if (!lists.second.isEmpty())
2320  {
2321  QStringList message("IMAGE_DELETE");
2322  message << lists.second;
2323 
2324  bool ok = gCoreContext->SendReceiveStringList(message, true);
2325  if (!ok)
2326  result = message[1];
2327  }
2328  if (!lists.first.isEmpty())
2329  {
2330  QStringList err = HandleDelete(lists.first);
2331  if (err[0] != "OK")
2332  result = err[1];
2333  }
2334  return result;
2335 }
2336 
2337 
2345 {
2346  if (im->m_id == GALLERY_DB_ID)
2347  return "";
2348 
2349  std::chrono::seconds secs = 0s;
2351 
2352  if (im->m_date > 0s)
2353  {
2354  secs = im->m_date;
2355  format |= MythDate::kTime;
2356  }
2357  else
2358  secs = im->m_modTime;
2359 
2360  return MythDate::toString(QDateTime::fromSecsSinceEpoch(secs.count()), format);
2361 }
2362 
2363 
2370 QString ImageManagerFe::ShortDateOf(const ImagePtrK& im) const
2371 {
2372  if (im->m_id == GALLERY_DB_ID)
2373  return "";
2374 
2375  std::chrono::seconds secs(im->m_date > 0s ? im->m_date : im->m_modTime);
2376  return QDateTime::fromSecsSinceEpoch(secs.count()).date().toString(m_dateFormat);
2377 }
2378 
2379 
2386 {
2387  if (im.m_id == GALLERY_DB_ID)
2388  return tr("Gallery");
2389  if (im.m_id == PHOTO_DB_ID)
2390  return tr("Photographs");
2391  return im.IsLocal() ? DeviceName(im.m_device)
2392  : m_remote->DeviceName(im.m_device);
2393 }
2394 
2395 
2403 QString ImageManagerFe::CrumbName(ImageItemK &im, bool getPath) const
2404 {
2405  if (im.IsDevice())
2406  return DeviceCaption(im);
2407 
2408  if (!getPath)
2409  return im.m_baseName;
2410 
2411  QString dev;
2412  QString path(im.m_filePath);
2413 
2414  if (im.IsLocal())
2415  {
2416  // Replace local mount path with device name
2417  path.remove(0, DeviceMount(im.m_device).size());
2418  dev = DeviceName(im.m_device);
2419  }
2420  return dev + path.replace("/", " > ");
2421 }
2422 
2423 
2424 void ImageManagerFe::CloseDevices(int devId, bool eject)
2425 {
2426  QString reason = (devId == DEVICE_INVALID)
2427  ? "DEVICE CLOSE ALL"
2428  : eject ? "DEVICE EJECT" : "DEVICE REMOVE";
2429  HandleScanRequest(reason, devId);
2430 }
2431 
2432 
2438 {
2440  if (!monitor)
2441  return false;
2442 
2443  // Detect all local media
2444  QList<MythMediaDevice*> devices
2446 
2447  for (auto *dev : qAsConst(devices))
2448  {
2449  if (monitor->ValidateAndLock(dev) && dev->isUsable())
2450  OpenDevice(dev->getDeviceModel(), dev->getMountPath(), dev);
2451  else
2452  monitor->Unlock(dev);
2453  }
2454 
2455  if (DeviceCount() > 0)
2456  {
2457  // Close devices that are no longer present
2458  QList absentees = GetAbsentees();
2459  for (int devId : qAsConst(absentees))
2460  CloseDevices(devId);
2461 
2462  // Start local scan
2463  QString err = ScanImagesAction(true, true);
2464  if (!err.isEmpty())
2465  LOG(VB_GENERAL, LOG_ERR, LOC + err);
2466  }
2467  return DeviceCount() > 0;
2468 }
2469 
2470 
2476 {
2478 
2479  if (!event || !monitor)
2480  return;
2481 
2482  MythMediaDevice *dev = event->getDevice();
2483  if (!dev)
2484  return;
2485 
2486  MythMediaType type = dev->getMediaType();
2487  MythMediaStatus status = dev->getStatus();
2488 
2489  LOG(VB_FILE, LOG_DEBUG, LOC +
2490  QString("Media event for %1 (%2) at %3, type %4, status %5 (was %6)")
2491  .arg(dev->getDeviceModel(), dev->getVolumeID(), dev->getMountPath())
2492  .arg(type).arg(status).arg(event->getOldStatus()));
2493 
2495  {
2496  LOG(VB_FILE, LOG_DEBUG, LOC +
2497  QString("Ignoring event - wrong type %1").arg(type));
2498  return;
2499  }
2500 
2501  if (status == MEDIASTAT_USEABLE || status == MEDIASTAT_MOUNTED)
2502  {
2503  // New device. Lock it & scan
2504  if (monitor->ValidateAndLock(dev))
2505  {
2506  OpenDevice(dev->getDeviceModel(), dev->getMountPath(), dev);
2507  ScanImagesAction(true, true);
2508  }
2509  else
2510  monitor->Unlock(dev);
2511  return;
2512  }
2513 
2514  // Device has disappeared
2515  int devId = LocateMount(dev->getMountPath());
2516  if (devId != DEVICE_INVALID)
2517  CloseDevices(devId);
2518 }
2519 
2520 
2522 {
2523  auto *tmp = new QTemporaryDir(QDir::tempPath() % "/" % IMPORTDIR % "-XXXXXX");
2524  if (!tmp->isValid())
2525  {
2526  delete tmp;
2527  return "";
2528  }
2529 
2530  QString time(QDateTime::currentDateTime().toString("mm:ss"));
2531  OpenDevice("Import " + time, tmp->path(), nullptr, tmp);
2532  return tmp->path();
2533 }
2534 
2535 
2536 // Must define the valid template implementations to generate code for the
2537 // instantiations (as they are defined in the cpp rather than header).
2538 // Otherwise the linker will fail with undefined references...
2539 template class ImageDb<ImageAdapterSg>;
2540 template class ImageDb<ImageAdapterLocal>;
2541 template class ImageHandler<ImageDbSg>;
2542 template class ImageHandler<ImageDbLocal>;
MythMediaDevice::getMountPath
const QString & getMountPath() const
Definition: mythmedia.h:58
ImageAdapterBase::ImageAdapterBase
ImageAdapterBase()
Constructor.
Definition: imagemanager.cpp:303
MythMediaEvent::getOldStatus
MythMediaStatus getOldStatus(void) const
Definition: mythmedia.h:190
ImageManagerBe::s_instance
static ImageManagerBe * s_instance
BE Gallery instance.
Definition: imagemanager.h:394
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:517
ImageManagerFe::ImageManagerFe
ImageManagerFe(int order, int dirOrder, bool showAll, int showType, QString dateFormat)
Definition: imagemanager.h:504
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:811
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:446
ImageHandler::HandleRename
QStringList HandleRename(const QString &id, const QString &newBase) const
Change name of an image/dir.
Definition: imagemanager.cpp:1228
ImageDb::SetHidden
bool SetHidden(bool hide, const QString &ids) const
Sets hidden status of an image/dir in database.
Definition: imagemanager.cpp:921
Device::m_thumbs
QString m_thumbs
Dir sub-path of device thumbnails.
Definition: imagemanager.cpp:116
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:901
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:1851
DeviceManager::GetDeviceDirs
StringMap GetDeviceDirs() const
Get all known devices.
Definition: imagemanager.cpp:253
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:1997
ImageDbLocal::m_dbExists
bool m_dbExists
Definition: imagemanager.h:332
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:1910
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:603
ReadMetaThread
Task to read all metadata from file.
Definition: imagemanager.cpp:1140
Device::isImport
bool isImport() const
Definition: imagemanager.cpp:108
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:848
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:1370
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:1819
ImageManagerFe::CreateImages
QString CreateImages(int destId, const ImageListK &images)
Copies database images (but not the files themselves).
Definition: imagemanager.cpp:2243
ImageManagerFe::ScanImagesAction
QString ScanImagesAction(bool start, bool local=false)
Handle scanner start/stop commands.
Definition: imagemanager.cpp:2032
LOC
#define LOC
Definition: imagemanager.cpp:13
ImageHandler::HandleGetMetadata
QStringList HandleGetMetadata(const QString &id) const
Read meta data for an image.
Definition: imagemanager.cpp:1197
MediaMonitor::GetMediaMonitor
static MediaMonitor * GetMediaMonitor(void)
Definition: mythmediamonitor.cpp:75
ImageItem::IsLocal
bool IsLocal() const
Definition: imagetypes.h:119
ImageDbLocal::DropTable
void DropTable()
Remove local image table.
Definition: imagemanager.cpp:1094
ImageMetaData
Abstract class for image metadata.
Definition: imagemetadata.h:99
ImageManagerFe::s_instance
static ImageManagerFe * s_instance
FE Gallery instance.
Definition: imagemanager.h:514
DeviceManager::DeviceName
QString DeviceName(int devId) const
Get model name of the device.
Definition: imagemanager.cpp:139
kNullDevice
static Device kNullDevice
Definition: imagemanager.cpp:122
ImageManagerFe::MakeDir
QString MakeDir(int parent, const QStringList &names, bool rescan=true)
Create directories.
Definition: imagemanager.cpp:2201
ImageDbReader::m_showHidden
bool m_showHidden
Whether hidden images are displayed.
Definition: imagemanager.h:445
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:90
StorageGroup::FindFile
QString FindFile(const QString &filename)
Definition: storagegroup.cpp:602
kDirectory
@ kDirectory
A device sub directory.
Definition: imagetypes.h:38
MSqlQuery::lastInsertId
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:934
Device::m_mount
QString m_mount
Mountpoint.
Definition: imagemanager.cpp:115
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:2475
Device::isPresent
bool isPresent() const
Definition: imagemanager.cpp:109
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:2185
ImageAdapterBase::m_videoFileExt
QStringList m_videoFileExt
List of file extensions recognised as videos.
Definition: imagemanager.h:182
Device::m_media
MythMediaDevice * m_media
Set for MediaMonitor devices only.
Definition: imagemanager.cpp:117
RESULT_ERR
#define RESULT_ERR(ERR, MESG)
Definition: imagemanager.cpp:22
imagemanager.h
Manages a collection of images.
Device::Close
void Close(bool eject=false)
Releases device.
Definition: imagemanager.cpp:63
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:97
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:617
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:480
ImageManagerFe::HideFiles
QString HideFiles(bool hidden, const ImageIdList &ids)
Hide/unhide images.
Definition: imagemanager.cpp:2078
ImageAdapterSg::m_sg
StorageGroup m_sg
Images storage group.
Definition: imagemanager.h:269
EXIF_MYTH_NAME
static constexpr const char * EXIF_MYTH_NAME
Definition: imagemetadata.h:40
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
FileAssociations::getList
const association_list & getList() const
Definition: dbaccess.cpp:805
DB_TABLE
static constexpr const char * DB_TABLE
Definition: imagemanager.cpp:19
ImageDb::GetImages
int GetImages(const QString &ids, ImageList &files, ImageList &dirs, const QString &refine="") const
Read database images/dirs by id.
Definition: imagemanager.cpp:574
ImageDb::InsertDbImage
int InsertDbImage(ImageItemK &im, bool checkForDuplicate=false) const
Adds new image to database, optionally checking for existing filepath.
Definition: imagemanager.cpp:790
Device
A device containing images (ie. USB stick, CD, storage group etc)
Definition: imagemanager.cpp:35
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:531
ImageHandler::HandleCover
QStringList HandleCover(int dir, int cover) const
Updates/resets cover thumbnail for an image dir.
Definition: imagemanager.cpp:1598
DeviceManager::ThumbDir
QString ThumbDir(int fs) const
Definition: imagemanager.cpp:145
ImageManagerBe::ImageManagerBe
ImageManagerBe()
Definition: imagemanager.h:387
ImageDbReader::TypeSelector
static QString TypeSelector(int type)
Generate SQL type filter clause.
Definition: imagemanager.cpp:1755
IMPORTDIR
static constexpr const char * IMPORTDIR
Definition: imagemanager.cpp:31
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:2424
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:1073
ImageManagerFe::ChangeOrientation
QString ChangeOrientation(ImageFileTransform transform, const ImageIdList &ids)
Apply an orientation transform to images.
Definition: imagemanager.cpp:2109
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
ImageHandler::HandleTransform
QStringList HandleTransform(int transform, const QString &ids) const
Change orientation of pictures by applying a transformation.
Definition: imagemanager.cpp:1495
dbaccess.h
ImageManagerFe::getInstance
static ImageManagerFe & getInstance()
Get Frontend Gallery.
Definition: imagemanager.cpp:1973
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:365
ImageManagerFe::DeviceCaption
QString DeviceCaption(ImageItemK &im) const
Return translated device name.
Definition: imagemanager.cpp:2385
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:1347
ImageDbReader::m_refineClause
QString m_refineClause
SQL clause for image filtering/ordering.
Definition: imagemanager.h:447
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
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:703
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:1406
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:256
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:2171
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1529
DeviceManager::~DeviceManager
~DeviceManager()
Definition: imagemanager.cpp:125
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:549
IMAGE_STORAGE_GROUP
static constexpr const char * IMAGE_STORAGE_GROUP
Definition: imagemanager.h:63
FileAssociations::association_list
std::vector< file_association > association_list
Definition: dbaccess.h:154
StringMap
QMap< int, QString > StringMap
Definition: imagetypes.h:63
EXIF_MYTH_ORIENT
static constexpr const char * EXIF_MYTH_ORIENT
Definition: imagemetadata.h:42
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
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:971
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:1891
ImageAdapterBase::SupportedImages
static QStringList SupportedImages()
Return recognised pictures.
Definition: imagemanager.cpp:327
ImageDbReader::OrderSelector
static QString OrderSelector(int order)
Generate SQL ordering clause.
Definition: imagemanager.cpp:1791
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:897
MediaMonitor::Unlock
void Unlock(MythMediaDevice *pMedia)
decrements the MythMediaDevices reference count
Definition: mythmediamonitor.cpp:509
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:2344
RESULT_OK
#define RESULT_OK(MESG)
Definition: imagemanager.cpp:26
kSortByExtAsc
@ kSortByExtAsc
Extension A-Z.
Definition: imagetypes.h:50
kDBColumns
static constexpr const char * kDBColumns
Definition: imagemanager.cpp:518
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:2141
uint
unsigned int uint
Definition: compat.h:81
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:55
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:49
ImageList
QVector< ImagePtr > ImageList
Definition: imagetypes.h:160
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:911
DeviceManager::DeviceMount
QString DeviceMount(int devId) const
Get path at which the device is mounted.
Definition: imagemanager.cpp:132
ImageManagerFe::CreateImport
QString CreateImport()
Definition: imagemanager.cpp:2521
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:1719
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:1927
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:905
Device::m_present
bool m_present
True when gallery UI is running & device is useable. Always true for imports.
Definition: imagemanager.cpp:113
FileAssociations::getFileAssociation
static FileAssociations & getFileAssociation()
Definition: dbaccess.cpp:830
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:118
ImageHandler::HandleScanRequest
QStringList HandleScanRequest(const QString &command, int devId=DEVICE_INVALID) const
Process scan requests.
Definition: imagemanager.cpp:1641
ImageHandler::HandleDirs
QStringList HandleDirs(const QString &destId, bool rescan, const QStringList &relPaths) const
Creates new image directories.
Definition: imagemanager.cpp:1542
kImageFile
@ kImageFile
A picture.
Definition: imagetypes.h:39
ImageManagerFe::MoveDbImages
QString MoveDbImages(const ImagePtrK &destDir, ImageListK &images, const QString &srcPath)
Moves database images (but not the files themselves).
Definition: imagemanager.cpp:2287
ImageAdapterBase::m_dirFilter
QDir m_dirFilter
A pre-configured dir for reading image/video files.
Definition: imagemanager.h:178
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:459
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:671
ImageDbReader::m_fileOrder
int m_fileOrder
Display ordering of pics/videos.
Definition: imagemanager.h:444
ImageDbReader::m_remote
ImageDbSg * m_remote
Remote database access.
Definition: imagemanager.h:441
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:1083
Device::~Device
~Device()
Delete device, its thumbnails and any imported images.
Definition: imagemanager.cpp:49
MediaMonitor::EjectMedia
void EjectMedia(const QString &path)
Definition: mythmediamonitor.cpp:265
TEMP_SUBDIR
static constexpr const char * TEMP_SUBDIR
Definition: imagemanager.h:67
DeviceManager::LocateMount
int LocateMount(const QString &mount) const
Find the id of a device.
Definition: imagemanager.cpp:239
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:887
Device::Device
Device(QString name, QString mount, MythMediaDevice *media=nullptr, QTemporaryDir *import=nullptr)
Definition: imagemanager.cpp:38
std
Definition: mythchrono.h:23
ImageHandler::HandleIgnore
QStringList HandleIgnore(const QString &exclusions) const
Updates exclusion list for images.
Definition: imagemanager.cpp:1621
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:160
ImageDb::SetCover
bool SetCover(int dir, int id) const
Set the thumbnail(s) to be used for a dir.
Definition: imagemanager.cpp:947
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:155
ImageDb::ReadImages
int ReadImages(ImageList &dirs, ImageList &files, const QString &selector) const
Read selected database images/dirs.
Definition: imagemanager.cpp:997
ImageManagerFe::CrumbName
QString CrumbName(ImageItemK &im, bool getPath=false) const
Return a displayable name (with optional path) for an image.
Definition: imagemanager.cpp:2403
EXIF_MYTH_HOST
static constexpr const char * EXIF_MYTH_HOST
Definition: imagemetadata.h:38
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:754
THUMBNAIL_SUBDIR
static constexpr const char * THUMBNAIL_SUBDIR
Definition: imagemanager.h:69
PHOTO_DB_ID
static constexpr int PHOTO_DB_ID
Definition: imagetypes.h:29
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:1872
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:508
build_compdb.action
action
Definition: build_compdb.py:9
ImageDbReader::m_dirOrder
int m_dirOrder
Display ordering of dirs.
Definition: imagemanager.h:443
ImageManagerBe::getInstance
static ImageManagerBe * getInstance()
Get Backend Gallery.
Definition: imagemanager.cpp:1961
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:612
DeviceManager::CloseDevices
QStringList CloseDevices(int devId, const QString &action)
Remove a device (or all devices)
Definition: imagemanager.cpp:196
ImageAdapterLocal::Notify
static void Notify(const QString &mesg, const QStringList &extra)
Send local message to UI about local ids.
Definition: imagemanager.cpp:415
ImageDb::RemoveFromDB
QStringList RemoveFromDB(const ImageList &imList) const
Remove images/dirs from database.
Definition: imagemanager.cpp:891
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:723
ImageDbLocal::CreateTable
bool CreateTable()
Create local database table, if it doesn't exist.
Definition: imagemanager.cpp:1108
MediaMonitor::ValidateAndLock
bool ValidateAndLock(MythMediaDevice *pMedia)
Validates the MythMediaDevice and increments its reference count.
Definition: mythmediamonitor.cpp:492
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:276
ImageDbReader::SetRefinementClause
void SetRefinementClause()
Sets filter/ordering SQL clause used when reading database according to current filter/sort settings.
Definition: imagemanager.cpp:1772
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:837
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:1304
ImageItem::IsDevice
bool IsDevice() const
Definition: imagetypes.h:116
ImageAdapterSg::GetScanDirs
StringMap GetScanDirs() const
Returns SG dirs.
Definition: imagemanager.cpp:491
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:2314
kSortByModTimeAsc
@ kSortByModTimeAsc
File modified time Earliest -> Latest.
Definition: imagetypes.h:48
ReadMetaThread::ReadMetaThread
ReadMetaThread(ImagePtrK im, QString path)
Definition: imagemanager.cpp:1143
ImageDb< ImageAdapterLocal >::m_table
QString m_table
Db table name.
Definition: imagemanager.h:313
Device::setPresent
void setPresent(MythMediaDevice *media)
Definition: imagemanager.cpp:110
ImageDb::GetChildren
int GetChildren(const QString &ids, ImageList &files, ImageList &dirs, const QString &refine="") const
Read immediate children of a dir.
Definition: imagemanager.cpp:594
ReadMetaThread::m_path
QString m_path
Definition: imagemanager.cpp:1184
ImageDb
Database API.
Definition: imagemanager.h:277
ImageItem::m_extension
QString m_extension
Image file extension.
Definition: imagetypes.h:94
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:22
GALLERY_DB_ID
static constexpr int GALLERY_DB_ID
Definition: imagetypes.h:27
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:431
ImageManagerBe
The image manager to be used by the Backend.
Definition: imagemanager.h:381
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:654
ImageManagerFe::RequestMetaData
void RequestMetaData(int id)
Requests all exif/ffmpeg tags for an image, which returns by event.
Definition: imagemanager.cpp:2161
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:1032
ImageAdapterBase::GetImageType
ImageNodeType GetImageType(const QString &ext) const
Determine file type from its extension.
Definition: imagemanager.h:168
ImageManagerFe::ScanQuery
static QStringList ScanQuery()
Returns storage group scanner status.
Definition: imagemanager.cpp:2058
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:890
ImageManagerFe::RenameFile
QString RenameFile(const ImagePtrK &im, const QString &name)
Rename an image.
Definition: imagemanager.cpp:2223
MythMediaDevice::getVolumeID
const QString & getVolumeID() const
Definition: mythmedia.h:72
Device::m_name
QString m_name
Device model/volume/id.
Definition: imagemanager.cpp:114
ImageManagerFe::ShortDateOf
QString ShortDateOf(const ImagePtrK &im) const
Return a short datestamp for thumbnail captions.
Definition: imagemanager.cpp:2370
ImageHandler::HandleCreateThumbnails
QStringList HandleCreateThumbnails(const QStringList &message) const
Creates thumbnails on-demand.
Definition: imagemanager.cpp:1687
ReadMetaThread::m_im
ImagePtrK m_im
Definition: imagemanager.cpp:1183
ImageAdapterBase::m_imageFileExt
QStringList m_imageFileExt
List of file extensions recognised as pictures.
Definition: imagemanager.h:180
ImageHandler::HandleHide
QStringList HandleHide(bool hide, const QString &ids) const
Hides/unhides images/dirs.
Definition: imagemanager.cpp:1473
kSortBySizeDesc
@ kSortBySizeDesc
File size Largest -> Smallest.
Definition: imagetypes.h:53
STORAGE_GROUP_MOUNT
static constexpr const char * STORAGE_GROUP_MOUNT
Definition: imagemanager.cpp:17
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
kVideoOnly
@ kVideoOnly
Hide pictures.
Definition: imagemanager.h:80
DEVICE_INVALID
static constexpr int DEVICE_INVALID
Definition: imagemanager.h:71
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:897
ImageAdapterBase::SupportedVideos
static QStringList SupportedVideos()
Return recognised video extensions.
Definition: imagemanager.cpp:342
ReadMetaThread::run
void run() override
Definition: imagemanager.cpp:1146
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:836
EXIF_MYTH_PATH
static constexpr const char * EXIF_MYTH_PATH
Definition: imagemetadata.h:39
EXIF_MYTH_SIZE
static constexpr const char * EXIF_MYTH_SIZE
Definition: imagemetadata.h:41
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:2437