MythTV master
importmusic.cpp
Go to the documentation of this file.
1// qt
2#include <QApplication>
3#include <QDir>
4#include <QFontMetrics>
5
6// MythTV
24
25// mythmusic
26#include "editmetadata.h"
27#include "genres.h"
28#include "importmusic.h"
29#include "musicplayer.h"
30
31
33
35 MThread("FileScanner"), m_parent(parent)
36{
37}
38
40{
41 RunProlog();
43 RunEpilog();
44}
45
47
49{
50 RunProlog();
52 RunEpilog();
53}
54
56
57
59 MythScreenType(parent, "musicimportfiles"),
60 m_tracks(new std::vector<TrackInfo*>)
61{
62 QString lastHost = gCoreContext->GetSetting("MythMusicLastImportHost", gCoreContext->GetMasterHostName());
63 QStringList dirs = StorageGroup::getGroupDirs("Music", lastHost);
64 if (dirs.count() > 0)
65 m_musicStorageDir = StorageGroup::getGroupDirs("Music", lastHost).at(0);
66}
67
69{
71 {
73 gPlayer->stop(true);
74 }
75
77 gCoreContext->SaveSetting("MythMusicLastImportDir", m_locationEdit->GetText());
78
79 delete m_tracks;
80
82 emit importFinished();
83}
84
86{
87 if (!m_tracks->empty())
88 {
89 // update current
90 //: %1 is the current track,
91 //: %2 is the number of tracks
92 m_currentText->SetText(tr("%1 of %2", "Current track position")
93 .arg(m_currentTrack + 1).arg(m_tracks->size()));
94
95 MusicMetadata *meta = m_tracks->at(m_currentTrack)->metadata;
99 m_artistText->SetText(meta->Artist());
100 m_albumText->SetText(meta->Album());
101 m_titleText->SetText(meta->Title());
102 m_genreText->SetText(meta->Genre());
103 m_yearText->SetText(QString::number(meta->Year()));
104 m_trackText->SetText(QString::number(meta->Track()));
105 if (m_tracks->at(m_currentTrack)->isNewTune)
106 {
108 m_statusText->SetText(tr("New File"));
109 }
110 else
111 {
113 m_statusText->SetText(tr("Already in Database"));
114 }
115 }
116 else
117 {
118 // update current
119 m_currentText->SetText(tr("Not found"));
127 m_yearText->Reset();
131 }
132}
133
135{
137 return true;
138
139 QStringList actions;
140 bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
141
142 for (int i = 0; i < actions.size() && !handled; i++)
143 {
144 const QString& action = actions[i];
145 handled = true;
146
147 if (action == "LEFT")
148 {
150 }
151 else if (action == "RIGHT")
152 {
154 }
155 else if (action == "EDIT")
156 {
158 }
159 else if (action == "MENU")
160 {
161 ShowMenu();
162 }
163 else if (action == "ESCAPE" && !GetMythMainWindow()->IsExitingToMain())
164 {
165 bool found = false;
166 if (!m_tracks->empty())
167 {
168 uint track = 0;
169 while (track < m_tracks->size())
170 {
171 if (m_tracks->at(track)->isNewTune)
172 {
173 found = true;
174 break;
175 }
176 track++;
177 }
178
179 if (found)
180 {
181 QString msg = tr("You might have unsaved changes.\nAre you sure you want to exit this screen?");
182 ShowOkPopup(msg, this, &ImportMusicDialog::doExit, true);
183 }
184 }
185
186 handled = found;
187 }
188 else if (action == "1")
189 {
191 }
192 else if (action == "2")
193 {
195 }
196 else if (action == "3")
197 {
198 setArtist();
199 }
200 else if (action == "4")
201 {
202 setAlbum();
203 }
204 else if (action == "5")
205 {
206 setGenre();
207 }
208 else if (action == "6")
209 {
210 setYear();
211 }
212 else if (action == "7")
213 {
214 setRating();
215 }
216 else if (action == "8")
217 {
219 }
220 else if (action == "9")
221 {
223 }
224 else if (action == "0")
225 {
226 setTrack();
227 }
228 else
229 {
230 handled = false;
231 }
232 }
233
234 if (!handled && MythScreenType::keyPressEvent(event))
235 handled = true;
236
237 return handled;
238}
239
241{
242 if (!LoadWindowFromXML("music-ui.xml", "import_music", this))
243 return false;
244
245 bool err = false;
246 UIUtilE::Assign(this, m_locationEdit, "location", &err);
247 UIUtilE::Assign(this, m_locationButton, "directoryfinder", &err);
248 UIUtilE::Assign(this, m_scanButton, "scan", &err);
249 UIUtilE::Assign(this, m_coverartButton, "coverart", &err);
250 UIUtilE::Assign(this, m_filenameText, "filename", &err);
251 UIUtilE::Assign(this, m_compartistText, "compartist", &err);
252 UIUtilE::Assign(this, m_artistText, "artist", &err);
253 UIUtilE::Assign(this, m_albumText, "album", &err);
254 UIUtilE::Assign(this, m_titleText, "title", &err);
255 UIUtilE::Assign(this, m_genreText, "genre", &err);
256 UIUtilE::Assign(this, m_yearText, "year", &err);
257 UIUtilE::Assign(this, m_trackText, "track", &err);
258 UIUtilE::Assign(this, m_currentText, "position", &err);
259 UIUtilE::Assign(this, m_statusText, "status", &err);
260 UIUtilE::Assign(this, m_compilationCheck,"compilation", &err);
261 UIUtilE::Assign(this, m_playButton, "play", &err);
262 UIUtilE::Assign(this, m_nextnewButton, "nextnew", &err);
263 UIUtilE::Assign(this, m_addButton, "add", &err);
264 UIUtilE::Assign(this, m_addallnewButton, "addallnew", &err);
265 UIUtilE::Assign(this, m_nextButton, "next", &err);
266 UIUtilE::Assign(this, m_prevButton, "prev", &err);
267
268 if (err)
269 {
270 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'import_music'");
271 return false;
272 }
273
283
284 fillWidgets();
285
287
288 m_locationEdit->SetText(gCoreContext->GetSetting("MythMusicLastImportDir", "/"));
289
290 return true;
291}
292
294{
295 if (ok)
296 Close();
297}
298
300{
301 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
302 auto *fb = new MythUIFileBrowser(popupStack, m_locationEdit->GetText());
303 // TODO Install a name filter on supported music formats
304 fb->SetTypeFilter(QDir::AllDirs | QDir::Readable);
305 if (fb->Create())
306 {
307 fb->SetReturnEvent(this, "locationchange");
308 popupStack->AddScreen(fb);
309 }
310 else
311 {
312 delete fb;
313 }
314}
315
317{
319}
320
322{
323 if (m_tracks->empty())
324 return;
325
327
329}
330
332{
333 if (m_currentTrack > 0)
334 {
336 fillWidgets();
337 }
338}
339
341{
342 if (m_currentTrack < (int) m_tracks->size() - 1)
343 {
345 fillWidgets();
346 }
347}
348
350{
351 if (m_tracks->empty())
352 return;
353
354 MusicMetadata *meta = m_tracks->at(m_currentTrack)->metadata;
355
356 // is the current track a new file?
357 if (m_tracks->at(m_currentTrack)->isNewTune)
358 {
359 // do we need to update the tags?
360 if (m_tracks->at(m_currentTrack)->metadataHasChanged)
361 {
362 MetaIO *tagger = MetaIO::createTagger(meta->Filename());
363 if (tagger)
364 {
365 tagger->write(meta->Filename(), meta);
366 delete tagger;
367 }
368 }
369
370 // get the save filename
371 QString origFilename = meta->Filename();
372 QString saveFilename = filenameFromMetadata(meta);
373 QString fullFilename;
374
375 QUrl url(m_musicStorageDir);
376 fullFilename = MythCoreContext::GenMythURL(url.host(), 0, saveFilename, "Music");
377
378
379 // we need to manually copy the file extension
380 QFileInfo fi(origFilename);
381 saveFilename += "." + fi.suffix();
382 fullFilename += "." + fi.suffix();
383
384 LOG(VB_FILE, LOG_INFO, QString("Copying file from: %1").arg(origFilename));
385 LOG(VB_FILE, LOG_INFO, QString("to: ").arg(fullFilename));
386
387 // copy the file to the new location
388 if (!copyFile(origFilename, fullFilename))
389 {
390 ShowOkPopup(tr("Copy Failed\nCould not copy file to: %1").arg(fullFilename));
391 return;
392 }
393
394 meta->setFilename(saveFilename);
395 meta->setHostname(url.host());
396 meta->setFileSize((quint64)QFileInfo(origFilename).size());
397
398 // update the database
399 meta->dumpToDatabase();
400
401 // find any albumart for this track
404
406
407 m_tracks->at(m_currentTrack)->isNewTune =
408 isNewTune(meta->Artist(), meta->Album(), meta->Title());
409
410 // update the UI
411 fillWidgets();
412 }
413 else
414 {
415 ShowOkPopup(tr("This track is already in the database"));
416 }
417}
418
420{
421 if (m_tracks->empty())
422 return;
423
424 m_currentTrack = 0;
425 int newCount = 0;
426
427 while (m_currentTrack < (int) m_tracks->size())
428 {
429 fillWidgets();
430 QCoreApplication::processEvents();
431
432 if (m_tracks->at(m_currentTrack)->isNewTune)
433 {
434 addPressed();
435 newCount++;
436 }
437
438 QCoreApplication::processEvents();
439
441 }
442
444
445 ShowOkPopup(tr("%1 new tracks were added to the database").arg(newCount));
446}
447
449{
450 if (m_tracks->empty())
451 return;
452
453 uint track = m_currentTrack + 1;
454 while (track < m_tracks->size())
455 {
456 if (m_tracks->at(track)->isNewTune)
457 {
458 m_currentTrack = track;
459 fillWidgets();
460 break;
461 }
462 track++;
463 }
464}
465
466bool ImportMusicDialog::copyFile(const QString &src, const QString &dst)
467{
468 bool res = false;
469 QString host = QUrl(dst).host();
470
471 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
472 auto *busy =
473 new MythUIBusyDialog(tr("Copying music file to the 'Music' storage group on %1").arg(host),
474 popupStack,
475 "scanbusydialog");
476
477 if (busy->Create())
478 {
479 popupStack->AddScreen(busy, false);
480 }
481 else
482 {
483 delete busy;
484 busy = nullptr;
485 }
486
487 auto *copy = new FileCopyThread(src, dst);
488 copy->start();
489
490 while (!copy->isFinished())
491 {
492 const struct timespec halfms {0, 500000};
493 nanosleep(&halfms, nullptr);
494 QCoreApplication::processEvents();
495 }
496
497 res = copy->GetResult();
498
499 delete copy;
500
501 if (busy)
502 busy->Close();
503
504 return res;
505}
506
508{
509 // sanity check - make sure the user isn't trying to import tracks from the music directory
510 QString location = m_locationEdit->GetText();
511 if (!location.endsWith('/'))
512 location.append('/');
513
514 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
515 auto *busy = new MythUIBusyDialog(tr("Searching for music files"),
516 popupStack, "scanbusydialog");
517
518 if (busy->Create())
519 {
520 popupStack->AddScreen(busy, false);
521 }
522 else
523 {
524 delete busy;
525 busy = nullptr;
526 }
527 auto *scanner = new FileScannerThread(this);
528 scanner->start();
529
530 while (!scanner->isFinished())
531 {
532 const struct timespec halfms {0, 500000};
533 nanosleep(&halfms, nullptr);
534 QCoreApplication::processEvents();
535 }
536
537 delete scanner;
538
539 m_currentTrack = 0;
540 fillWidgets();
541
542 if (busy)
543 busy->Close();
544}
545
547{
548 m_tracks->clear();
549 m_sourceFiles.clear();
550 QString location = m_locationEdit->GetText();
551 scanDirectory(location, m_tracks);
552}
553
554void ImportMusicDialog::scanDirectory(QString &directory, std::vector<TrackInfo*> *tracks)
555{
556 QDir d(directory);
557
558 if (!d.exists())
559 return;
560
561 d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
562 const QFileInfoList list = d.entryInfoList();
563 if (list.isEmpty())
564 return;
565
566 QFileInfoList::const_iterator it = list.begin();
567 while (it != list.end())
568 {
569 const QFileInfo *fi = &(*it);
570 ++it;
571 QString filename = fi->absoluteFilePath();
572 if (fi->isDir())
573 scanDirectory(filename, tracks);
574 else
575 {
577 if (tagger)
578 {
579 MusicMetadata *metadata = tagger->read(filename);
580 if (metadata)
581 {
582 auto * track = new TrackInfo;
583 track->metadata = metadata;
584 track->isNewTune = isNewTune(metadata->Artist(), metadata->Album(),
585 metadata->Title());
586 track->metadataHasChanged = false;
587 tracks->push_back(track);
588 m_sourceFiles.append(filename);
589 }
590
591 delete tagger;
592 }
593 }
594 }
595}
596
598{
599 if (m_tracks->empty())
600 return;
601
602 MusicMetadata *editMeta = m_tracks->at(m_currentTrack)->metadata;
603
605
606 auto *editDialog = new EditMetadataDialog(mainStack, editMeta);
607
608 if (!editDialog->Create())
609 {
610 delete editDialog;
611 return;
612 }
613
614 editDialog->setSaveMetadataOnly();
615
617
618 mainStack->AddScreen(editDialog);
619}
620
622{
623 MusicMetadata *editMeta = m_tracks->at(m_currentTrack)->metadata;
624 m_tracks->at(m_currentTrack)->metadataHasChanged = true;
625 m_tracks->at(m_currentTrack)->isNewTune =
626 isNewTune(editMeta->Artist(), editMeta->Album(), editMeta->Title());
627 fillWidgets();
628}
629
631{
632 if (m_tracks->empty())
633 return;
634
635 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
636
637 auto *menu = new MythDialogBox("", popupStack, "importmusicmenu");
638
639 if (menu->Create())
640 popupStack->AddScreen(menu);
641 else
642 {
643 delete menu;
644 return;
645 }
646
647 menu->SetReturnEvent(this, "menu");
648 menu->AddButton(tr("Select Where To Save Tracks"), &ImportMusicDialog::chooseBackend);
649 menu->AddButton(tr("Save Defaults"), &ImportMusicDialog::saveDefaults);
650
651 if (m_haveDefaults)
652 {
653 menu->AddButton(tr("Change Compilation Flag"), &ImportMusicDialog::setCompilation);
654 menu->AddButton(tr("Change Compilation Artist"),
656 menu->AddButton(tr("Change Artist"), &ImportMusicDialog::setArtist);
657 menu->AddButton(tr("Change Album"), &ImportMusicDialog::setAlbum);
658 menu->AddButton(tr("Change Genre"), &ImportMusicDialog::setGenre);
659 menu->AddButton(tr("Change Year"), &ImportMusicDialog::setYear);
660 menu->AddButton(tr("Change Rating"), &ImportMusicDialog::setRating);
661 }
662}
663
665{
666 QStringList hostList;
667
668 // get a list of hosts with a directory defined for the 'Music' storage group
670 QString sql = "SELECT DISTINCT hostname "
671 "FROM storagegroup "
672 "WHERE groupname = 'Music'";
673 if (!query.exec(sql) || !query.isActive())
674 MythDB::DBError("ImportMusicDialog::chooseBackend get host list", query);
675 else
676 {
677 while(query.next())
678 {
679 hostList.append(query.value(0).toString());
680 }
681 }
682
683 if (hostList.isEmpty())
684 {
685 LOG(VB_GENERAL, LOG_ERR, "ImportMusicDialog::chooseBackend: No backends found");
686 return;
687 }
688
689 QString msg = tr("Select where to save tracks");
690
691 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
692 auto *searchDlg = new MythUISearchDialog(popupStack, msg, hostList, false, "");
693
694 if (!searchDlg->Create())
695 {
696 delete searchDlg;
697 return;
698 }
699
701
702 popupStack->AddScreen(searchDlg);
703}
704
705void ImportMusicDialog::setSaveHost(const QString& host)
706{
707 gCoreContext->SaveSetting("MythMusicLastImportHost", host);
708
709 QStringList dirs = StorageGroup::getGroupDirs("Music", host);
710 if (dirs.count() > 0)
711 m_musicStorageDir = StorageGroup::getGroupDirs("Music", host).at(0);
712
713}
714
716{
717 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
720 m_defaultArtist = data->Artist();
721 m_defaultAlbum = data->Album();
722 m_defaultGenre = data->Genre();
723 m_defaultYear = data->Year();
724 m_defaultRating = data->Rating();
725
726 m_haveDefaults = true;
727}
728
730{
731 if (!m_haveDefaults)
732 return;
733
734 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
735
737 {
740 }
741 else
742 {
745 }
746
747 fillWidgets();
748}
749
751{
752 if (!m_haveDefaults)
753 return;
754
755 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
757
758 fillWidgets();
759}
760
762{
763 if (!m_haveDefaults)
764 return;
765
766 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
768
769 m_tracks->at(m_currentTrack)->isNewTune =
770 isNewTune(data->Artist(), data->Album(), data->Title());
771
772 fillWidgets();
773}
774
776{
777 if (!m_haveDefaults)
778 return;
779
780 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
782
783 m_tracks->at(m_currentTrack)->isNewTune =
784 isNewTune(data->Artist(), data->Album(), data->Title());
785
786 fillWidgets();
787}
788
790{
791 if (!m_haveDefaults)
792 return;
793
794 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
795 data->setYear(m_defaultYear);
796
797 fillWidgets();
798}
799
801{
802 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
803 data->setTrack(data->Track() + 100);
804
805 fillWidgets();
806}
807
809{
810 if (!m_haveDefaults)
811 return;
812
813 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
815
816 fillWidgets();
817}
818
820{
821 if (!m_haveDefaults)
822 return;
823
824 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
826}
827
829{
830 QLocale locale = gCoreContext->GetQLocale();
831 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
832 QString title = locale.toLower(data->Title().simplified());
833 title[0] = title[0].toUpper();
834 data->setTitle(title);
835 fillWidgets();
836}
837
839{
840 QLocale locale = gCoreContext->GetQLocale();
841 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
842 QString title = locale.toLower(data->Title().simplified());
843 QStringList title_words = title.split(' ');
844
845 // NOLINTNEXTLINE(modernize-loop-convert)
846 for (int x = 0; x < title_words.size(); ++x)
847 title_words[x][0] = title_words[x][0].toUpper();
848
849 data->setTitle(title_words.join(' '));
850 fillWidgets();
851}
852
854{
855 if (m_tracks->empty())
856 return;
857
858 QFileInfo fi(m_sourceFiles.at(m_currentTrack));
859
861
862 auto *import = new ImportCoverArtDialog(mainStack,
863 fi.absolutePath(),
864 m_tracks->at(m_currentTrack)->metadata,
866
867 if (import->Create())
868 mainStack->AddScreen(import);
869 else
870 delete import;
871}
872
874{
875 if (auto *dce = dynamic_cast<DialogCompletionEvent*>(event))
876 {
877 if (dce->GetId() == "locationchange")
878 {
879 m_locationEdit->SetText(dce->GetResultText());
880 startScan();
881 }
882 }
883}
884
886
888{
890 return true;
891
892 QStringList actions;
893 bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
894
895 for (int i = 0; i < actions.size() && !handled; i++)
896 {
897 const QString& action = actions[i];
898 handled = true;
899
900 if (action == "LEFT")
901 {
903 }
904 else if (action == "RIGHT")
905 {
907 }
908 else
909 {
910 handled = false;
911 }
912 }
913
914 if (!handled && MythScreenType::keyPressEvent(event))
915 handled = true;
916
917 return handled;
918}
919
921{
922 if (!LoadWindowFromXML("music-ui.xml", "import_coverart", this))
923 return false;
924
925 bool err = false;
926 UIUtilE::Assign(this, m_filenameText, "file", &err);
927 UIUtilE::Assign(this, m_currentText, "position", &err);
928 UIUtilE::Assign(this, m_statusText, "status", &err);
929 UIUtilE::Assign(this, m_destinationText, "destination", &err);
930 UIUtilE::Assign(this, m_coverartImage, "coverart", &err);
931 UIUtilE::Assign(this, m_copyButton, "copy", &err);
932 UIUtilE::Assign(this, m_exitButton, "exit", &err);
933 UIUtilE::Assign(this, m_prevButton, "prev", &err);
934 UIUtilE::Assign(this, m_nextButton, "next", &err);
935 UIUtilE::Assign(this, m_typeList, "type", &err);
936
937 if (err)
938 {
939 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'import_coverart'");
940 return false;
941 }
942
943 if (m_typeList)
944 {
945 new MythUIButtonListItem(m_typeList, tr("Front Cover"),
946 QVariant::fromValue((int)IT_FRONTCOVER));
947 new MythUIButtonListItem(m_typeList, tr("Back Cover"),
948 QVariant::fromValue((int)IT_BACKCOVER));
949 new MythUIButtonListItem(m_typeList, tr("CD"),
950 QVariant::fromValue((int)IT_CD));
951 new MythUIButtonListItem(m_typeList, tr("Inlay"),
952 QVariant::fromValue((int)IT_INLAY));
953 new MythUIButtonListItem(m_typeList, tr("<Unknown>"),
954 QVariant::fromValue((int)IT_UNKNOWN));
955
958 }
959
960 if (m_copyButton)
962
963 if (m_exitButton)
965
966 if (m_prevButton)
968
969 if (m_nextButton)
971
973
975
976 return true;
977}
978
980{
981 updateStatus();
982}
983
985{
986 if (!m_filelist.empty())
987 {
989 {
990 //: %1 is the filename
991 ShowOkPopup(tr("Copy CoverArt Failed.\nCopying to %1").arg(m_saveFilename));
992 return;
993 }
994
995 // add the file to the database
996 QString filename = m_saveFilename.section( '/', -1, -1);
997 AlbumArtImage image;
998 image.m_description = "";
999 image.m_embedded = false;
1000 image.m_filename = filename;
1001 image.m_hostname = m_metadata->Hostname();
1002 image.m_imageType = (ImageType)m_typeList->GetItemCurrent()->GetData().toInt();
1003
1006
1007 updateStatus();
1008 }
1009}
1010
1012{
1013 if (m_currentFile > 0)
1014 {
1015 m_currentFile--;
1017 updateStatus();
1018 }
1019}
1020
1022{
1023 if (m_currentFile < m_filelist.size() - 1)
1024 {
1025 m_currentFile++;
1027 updateStatus();
1028 }
1029}
1030
1032{
1033 QDir d(m_sourceDir);
1034
1035 if (!d.exists())
1036 return;
1037
1038 QString nameFilter = gCoreContext->GetSetting("AlbumArtFilter",
1039 "*.png;*.jpg;*.jpeg;*.gif;*.bmp");
1040
1041 QFileInfoList list = d.entryInfoList(nameFilter.split(";"),
1042 QDir::Files | QDir::Dirs |
1043 QDir::NoDotAndDotDot);
1044 if (list.isEmpty())
1045 return;
1046
1047 for (const auto & fi : std::as_const(list))
1048 {
1049 QString filename = fi.absoluteFilePath();
1050 if (!fi.isDir())
1051 {
1052 m_filelist.append(filename);
1053 }
1054 }
1055
1056 m_currentFile = 0;
1058 updateStatus();
1059}
1060
1062{
1063 if (!m_filelist.empty())
1064 {
1065 if (m_currentText)
1066 {
1067 //: %1 is the current position of the file being copied,
1068 //: %2 is the total number of files
1069 m_currentText->SetText(tr("%1 of %2", "Current file copied")
1070 .arg(m_currentFile + 1)
1071 .arg(m_filelist.size()));
1072 }
1076
1077 QString saveFilename = filenameFromMetadata(m_metadata);
1078 QString fullFilename;
1079
1080 QUrl url(m_musicStorageDir);
1081 fullFilename = MythCoreContext::GenMythURL(url.host(), 0, saveFilename, "Music");
1082 QString dir = fullFilename.section( '/', 0, -2);
1083
1084 QFileInfo fi(m_filelist[m_currentFile]);
1085 switch (m_typeList->GetItemCurrent()->GetData().toInt())
1086 {
1087 case IT_FRONTCOVER:
1088 saveFilename = "front." + fi.suffix();
1089 break;
1090 case IT_BACKCOVER:
1091 saveFilename = "back." + fi.suffix();
1092 break;
1093 case IT_CD:
1094 saveFilename = "cd." + fi.suffix();
1095 break;
1096 case IT_INLAY:
1097 saveFilename = "inlay." + fi.suffix();
1098 break;
1099 case IT_UNKNOWN:
1100 saveFilename = "unknown." + fi.suffix();
1101 break;
1102 default:
1103 saveFilename = fi.fileName();
1104 }
1105
1106 m_saveFilename = dir + "/" + saveFilename;
1108
1109 url.setUrl(m_saveFilename);
1110
1111 if (!RemoteFile::FindFile(url.path(), "" , "Music").isEmpty())
1112 m_statusText->SetText(tr("File Already Exists"));
1113 else
1114 m_statusText->SetText(tr("New File"));
1115 }
1116 else
1117 {
1118 if (m_currentText)
1124 }
1125}
1126
1128{
1129 if (m_filelist.empty())
1130 return;
1131
1133 QFileInfo fi(filename);
1134 filename = fi.fileName();
1135
1136 if (filename.contains("front", Qt::CaseInsensitive))
1137 m_typeList->SetValue(tr("Front Cover"));
1138 else if (filename.contains("back", Qt::CaseInsensitive))
1139 m_typeList->SetValue(tr("Back Cover"));
1140 else if (filename.contains("inlay", Qt::CaseInsensitive))
1141 m_typeList->SetValue(tr("Inlay"));
1142 else if (filename.contains("cd", Qt::CaseInsensitive))
1143 m_typeList->SetValue(tr("CD"));
1144 else
1145 m_typeList->SetValue(tr("<Unknown>"));
1146}
QString m_filename
Definition: musicmetadata.h:55
QString m_description
Definition: musicmetadata.h:58
ImageType m_imageType
Definition: musicmetadata.h:57
QString m_hostname
Definition: musicmetadata.h:56
void scanForImages(void)
void dumpToDatabase(void)
saves or updates the image details in the DB
void addImage(const AlbumArtImage *newImage)
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
void metadataChanged(void)
QString m_srcFile
Definition: importmusic.h:55
QString m_dstFile
Definition: importmusic.h:56
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: importmusic.cpp:48
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: importmusic.cpp:39
ImportMusicDialog * m_parent
Definition: importmusic.h:41
FileScannerThread(ImportMusicDialog *parent)
Definition: importmusic.cpp:34
MythUIImage * m_coverartImage
Definition: importmusic.h:209
MusicMetadata * m_metadata
Definition: importmusic.h:197
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MythUIButton * m_exitButton
Definition: importmusic.h:215
MythUIButton * m_prevButton
Definition: importmusic.h:213
void updateTypeSelector(void)
MythUIText * m_currentText
Definition: importmusic.h:205
MythUIButton * m_nextButton
Definition: importmusic.h:212
void selectorChanged(void)
bool Create(void) override
MythUIButton * m_copyButton
Definition: importmusic.h:214
MythUIText * m_filenameText
Definition: importmusic.h:204
MythUIButtonList * m_typeList
Definition: importmusic.h:210
MythUIText * m_statusText
Definition: importmusic.h:206
QStringList m_filelist
Definition: importmusic.h:194
MythUIText * m_destinationText
Definition: importmusic.h:207
void prevPressed(void)
static bool copyFile(const QString &src, const QString &dst)
void setGenre(void)
void startScan(void)
MythUIText * m_trackText
Definition: importmusic.h:137
void chooseBackend(void) const
void saveDefaults(void)
void setTitleWordCaps(void)
~ImportMusicDialog() override
Definition: importmusic.cpp:68
MythUIButton * m_locationButton
Definition: importmusic.h:126
MythUIText * m_currentText
Definition: importmusic.h:142
MythUIButton * m_addButton
Definition: importmusic.h:146
MythUIText * m_genreText
Definition: importmusic.h:135
void importFinished(void)
QString m_musicStorageDir
Definition: importmusic.h:117
MythUIButton * m_prevButton
Definition: importmusic.h:140
QStringList m_sourceFiles
Definition: importmusic.h:120
void addAllNewPressed(void)
MythUIText * m_titleText
Definition: importmusic.h:134
void nextPressed(void)
void showImportCoverArtDialog()
void setRating(void)
MythUIText * m_statusText
Definition: importmusic.h:143
void scanDirectory(QString &directory, std::vector< TrackInfo * > *tracks)
MythUIButton * m_addallnewButton
Definition: importmusic.h:147
MythUIButton * m_playButton
Definition: importmusic.h:145
ImportMusicDialog(MythScreenStack *parent)
Definition: importmusic.cpp:58
MythUIButton * m_nextButton
Definition: importmusic.h:139
void metadataChanged(void)
QString m_defaultCompArtist
Definition: importmusic.h:154
bool m_somethingWasImported
Definition: importmusic.h:118
MythUIText * m_compartistText
Definition: importmusic.h:131
void setArtist(void)
void doExit(bool ok)
MythUIButton * m_nextnewButton
Definition: importmusic.h:148
MythUIButton * m_scanButton
Definition: importmusic.h:127
void playPressed(void)
MusicMetadata * m_playingMetaData
Definition: importmusic.h:122
void showEditMetadataDialog(void)
std::vector< TrackInfo * > * m_tracks
Definition: importmusic.h:119
MythUITextEdit * m_locationEdit
Definition: importmusic.h:125
void addPressed(void)
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
void locationPressed(void)
void setYear(void)
MythUIButton * m_coverartButton
Definition: importmusic.h:128
MythUIText * m_artistText
Definition: importmusic.h:132
void nextNewPressed(void)
QString m_defaultGenre
Definition: importmusic.h:157
void coverArtPressed(void)
MythUICheckBox * m_compilationCheck
Definition: importmusic.h:150
void customEvent(QEvent *event) override
QString m_defaultAlbum
Definition: importmusic.h:156
void setCompilationArtist(void)
void ShowMenu(void) override
void setTrack(void)
void setSaveHost(const QString &host)
MythUIText * m_albumText
Definition: importmusic.h:133
MythUIText * m_filenameText
Definition: importmusic.h:130
bool Create(void) override
MythUIText * m_yearText
Definition: importmusic.h:136
void setTitleInitialCap(void)
void setAlbum(void)
QString m_defaultArtist
Definition: importmusic.h:155
void setCompilation(void)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
Definition: metaio.h:18
virtual bool write(const QString &filename, MusicMetadata *mdata)=0
Writes all metadata back to a file.
virtual MusicMetadata * read(const QString &filename)=0
Reads MusicMetadata from a file.
static MetaIO * createTagger(const QString &filename)
Finds an appropriate tagger for the given file.
Definition: metaio.cpp:31
int Year() const
void setYear(int lyear)
void setHostname(const QString &host)
void setCompilationArtist(const QString &lcompilation_artist, const QString &lcompilation_artist_sort=nullptr)
void setGenre(const QString &lgenre)
QString Hostname(void)
QString CompilationArtist() const
void setCompilation(bool state)
QString Title() const
void setTitle(const QString &ltitle, const QString &ltitle_sort=nullptr)
void setFilename(const QString &lfilename)
int Track() const
QString Filename(bool find=true)
QString Artist() const
void setRating(int lrating)
int Rating() const
void setAlbum(const QString &lalbum, const QString &lalbum_sort=nullptr)
bool Compilation() const
void setTrack(int ltrack)
QString Genre() const
AlbumArtImages * getAlbumArtImages(void)
QString Album() const
void setArtist(const QString &lartist, const QString &lartist_sort=nullptr)
void setFileSize(uint64_t lfilesize)
void dumpToDatabase(void)
MusicMetadata * getCurrentMetadata(void)
get the metadata for the current track in the playlist
void stop(bool stopAll=false)
bool isPlaying(void) const
Definition: musicplayer.h:109
void playFile(const MusicMetadata &mdata)
void SaveSetting(const QString &key, int newValue)
QLocale GetQLocale(void)
QString GetSetting(const QString &key, const QString &defaultval="")
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
QString GetMasterHostName(void)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
Basic menu dialog, message and a list of options.
MythScreenStack * GetMainStack()
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Screen in which all other widgets are contained and rendered.
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
virtual void Close()
bool Create(void) override
MythUIButtonListItem * GetItemCurrent() const
virtual void SetValue(int value)
void itemSelected(MythUIButtonListItem *item)
void Push(bool lock=false)
void Clicked()
void SetCheckState(MythUIStateType::StateType state)
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
void Reset(void) override
Reset the image back to the default defined in the theme.
Provide a dialog to quickly find an entry in a list.
void haveResult(QString)
QString GetText(void) const
void SetText(const QString &text, bool moveCursor=true)
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:65
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
virtual void SetVisible(bool visible)
static bool CopyFile(const QString &src, const QString &dst, bool overwrite=false, bool verify=false)
Definition: remotefile.cpp:587
static QString FindFile(const QString &filename, const QString &host, const QString &storageGroup, bool useRegex=false, bool allowFallback=false)
Search all BE's for a file in the give storage group.
static QStringList getGroupDirs(const QString &groupname, const QString &host)
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
unsigned int uint
Definition: freesurround.h:24
static const iso6937table * d
ImageType
Definition: musicmetadata.h:35
@ IT_INLAY
Definition: musicmetadata.h:40
@ IT_BACKCOVER
Definition: musicmetadata.h:38
@ IT_UNKNOWN
Definition: musicmetadata.h:36
@ IT_FRONTCOVER
Definition: musicmetadata.h:37
@ IT_CD
Definition: musicmetadata.h:39
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
bool isNewTune(const QString &artist, const QString &album, const QString &title)
try to find a track in the db using the given artist, album and title
Definition: musicutils.cpp:126
QString filenameFromMetadata(MusicMetadata *track)
create a filename using the template in the settings and a MusicMetadata object
Definition: musicutils.cpp:78
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
static MythThemedMenu * menu
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
STL namespace.
MusicMetadata * metadata
Definition: importmusic.h:29
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27