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