MythTV master
importmusic.cpp
Go to the documentation of this file.
1#include <thread>
2
3// qt
4#include <QApplication>
5#include <QDir>
6#include <QFontMetrics>
7
8// MythTV
26
27// mythmusic
28#include "editmetadata.h"
29#include "genres.h"
30#include "importmusic.h"
31#include "musicplayer.h"
32
33
35
37 MThread("FileScanner"), m_parent(parent)
38{
39}
40
42{
43 RunProlog();
45 RunEpilog();
46}
47
49
51{
52 RunProlog();
54 RunEpilog();
55}
56
58
59
61 MythScreenType(parent, "musicimportfiles"),
62 m_tracks(new std::vector<TrackInfo*>)
63{
64 QString lastHost = gCoreContext->GetSetting("MythMusicLastImportHost", gCoreContext->GetMasterHostName());
65 QStringList dirs = StorageGroup::getGroupDirs("Music", lastHost);
66 if (dirs.count() > 0)
67 m_musicStorageDir = StorageGroup::getGroupDirs("Music", lastHost).at(0);
68}
69
71{
73 {
75 gPlayer->stop(true);
76 }
77
79 gCoreContext->SaveSetting("MythMusicLastImportDir", m_locationEdit->GetText());
80
81 delete m_tracks;
82
84 emit importFinished();
85}
86
88{
89 if (!m_tracks->empty())
90 {
91 // update current
92 //: %1 is the current track,
93 //: %2 is the number of tracks
94 m_currentText->SetText(tr("%1 of %2", "Current track position")
95 .arg(m_currentTrack + 1).arg(m_tracks->size()));
96
97 MusicMetadata *meta = m_tracks->at(m_currentTrack)->metadata;
101 m_artistText->SetText(meta->Artist());
102 m_albumText->SetText(meta->Album());
103 m_titleText->SetText(meta->Title());
104 m_genreText->SetText(meta->Genre());
105 m_yearText->SetText(QString::number(meta->Year()));
106 m_trackText->SetText(QString::number(meta->Track()));
107 if (m_tracks->at(m_currentTrack)->isNewTune)
108 {
110 m_statusText->SetText(tr("New File"));
111 }
112 else
113 {
115 m_statusText->SetText(tr("Already in Database"));
116 }
117 }
118 else
119 {
120 // update current
121 m_currentText->SetText(tr("Not found"));
129 m_yearText->Reset();
133 }
134}
135
137{
139 return true;
140
141 QStringList actions;
142 bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
143
144 for (int i = 0; i < actions.size() && !handled; i++)
145 {
146 const QString& action = actions[i];
147 handled = true;
148
149 if (action == "LEFT")
150 {
152 }
153 else if (action == "RIGHT")
154 {
156 }
157 else if (action == "EDIT")
158 {
160 }
161 else if (action == "MENU")
162 {
163 ShowMenu();
164 }
165 else if (action == "ESCAPE" && !GetMythMainWindow()->IsExitingToMain())
166 {
167 bool found = false;
168 if (!m_tracks->empty())
169 {
170 uint track = 0;
171 while (track < m_tracks->size())
172 {
173 if (m_tracks->at(track)->isNewTune)
174 {
175 found = true;
176 break;
177 }
178 track++;
179 }
180
181 if (found)
182 {
183 QString msg = tr("You might have unsaved changes.\nAre you sure you want to exit this screen?");
184 ShowOkPopup(msg, this, &ImportMusicDialog::doExit, true);
185 }
186 }
187
188 handled = found;
189 }
190 else if (action == "1")
191 {
193 }
194 else if (action == "2")
195 {
197 }
198 else if (action == "3")
199 {
200 setArtist();
201 }
202 else if (action == "4")
203 {
204 setAlbum();
205 }
206 else if (action == "5")
207 {
208 setGenre();
209 }
210 else if (action == "6")
211 {
212 setYear();
213 }
214 else if (action == "7")
215 {
216 setRating();
217 }
218 else if (action == "8")
219 {
221 }
222 else if (action == "9")
223 {
225 }
226 else if (action == "0")
227 {
228 setTrack();
229 }
230 else
231 {
232 handled = false;
233 }
234 }
235
236 if (!handled && MythScreenType::keyPressEvent(event))
237 handled = true;
238
239 return handled;
240}
241
243{
244 if (!LoadWindowFromXML("music-ui.xml", "import_music", this))
245 return false;
246
247 bool err = false;
248 UIUtilE::Assign(this, m_locationEdit, "location", &err);
249 UIUtilE::Assign(this, m_locationButton, "directoryfinder", &err);
250 UIUtilE::Assign(this, m_scanButton, "scan", &err);
251 UIUtilE::Assign(this, m_coverartButton, "coverart", &err);
252 UIUtilE::Assign(this, m_filenameText, "filename", &err);
253 UIUtilE::Assign(this, m_compartistText, "compartist", &err);
254 UIUtilE::Assign(this, m_artistText, "artist", &err);
255 UIUtilE::Assign(this, m_albumText, "album", &err);
256 UIUtilE::Assign(this, m_titleText, "title", &err);
257 UIUtilE::Assign(this, m_genreText, "genre", &err);
258 UIUtilE::Assign(this, m_yearText, "year", &err);
259 UIUtilE::Assign(this, m_trackText, "track", &err);
260 UIUtilE::Assign(this, m_currentText, "position", &err);
261 UIUtilE::Assign(this, m_statusText, "status", &err);
262 UIUtilE::Assign(this, m_compilationCheck,"compilation", &err);
263 UIUtilE::Assign(this, m_playButton, "play", &err);
264 UIUtilE::Assign(this, m_nextnewButton, "nextnew", &err);
265 UIUtilE::Assign(this, m_addButton, "add", &err);
266 UIUtilE::Assign(this, m_addallnewButton, "addallnew", &err);
267 UIUtilE::Assign(this, m_nextButton, "next", &err);
268 UIUtilE::Assign(this, m_prevButton, "prev", &err);
269
270 if (err)
271 {
272 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'import_music'");
273 return false;
274 }
275
285
286 fillWidgets();
287
289
290 m_locationEdit->SetText(gCoreContext->GetSetting("MythMusicLastImportDir", "/"));
291
292 return true;
293}
294
296{
297 if (ok)
298 Close();
299}
300
302{
303 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
304 auto *fb = new MythUIFileBrowser(popupStack, m_locationEdit->GetText());
305 // TODO Install a name filter on supported music formats
306 fb->SetTypeFilter(QDir::AllDirs | QDir::Readable);
307 if (fb->Create())
308 {
309 fb->SetReturnEvent(this, "locationchange");
310 popupStack->AddScreen(fb);
311 }
312 else
313 {
314 delete fb;
315 }
316}
317
319{
321}
322
324{
325 if (m_tracks->empty())
326 return;
327
329
331}
332
334{
335 if (m_currentTrack > 0)
336 {
338 fillWidgets();
339 }
340}
341
343{
344 if (m_currentTrack < (int) m_tracks->size() - 1)
345 {
347 fillWidgets();
348 }
349}
350
352{
353 if (m_tracks->empty())
354 return;
355
356 MusicMetadata *meta = m_tracks->at(m_currentTrack)->metadata;
357
358 // is the current track a new file?
359 if (m_tracks->at(m_currentTrack)->isNewTune)
360 {
361 // do we need to update the tags?
362 if (m_tracks->at(m_currentTrack)->metadataHasChanged)
363 {
364 MetaIO *tagger = MetaIO::createTagger(meta->Filename());
365 if (tagger)
366 {
367 tagger->write(meta->Filename(), meta);
368 delete tagger;
369 }
370 }
371
372 // get the save filename
373 QString origFilename = meta->Filename();
374 QString saveFilename = filenameFromMetadata(meta);
375 QString fullFilename;
376
377 QUrl url(m_musicStorageDir);
378 fullFilename = MythCoreContext::GenMythURL(url.host(), 0, saveFilename, "Music");
379
380
381 // we need to manually copy the file extension
382 QFileInfo fi(origFilename);
383 saveFilename += "." + fi.suffix();
384 fullFilename += "." + fi.suffix();
385
386 LOG(VB_FILE, LOG_INFO, QString("Copying file from: %1").arg(origFilename));
387 LOG(VB_FILE, LOG_INFO, QString("to: ").arg(fullFilename));
388
389 // copy the file to the new location
390 if (!copyFile(origFilename, fullFilename))
391 {
392 ShowOkPopup(tr("Copy Failed\nCould not copy file to: %1").arg(fullFilename));
393 return;
394 }
395
396 meta->setFilename(saveFilename);
397 meta->setHostname(url.host());
398 meta->setFileSize((quint64)QFileInfo(origFilename).size());
399
400 // update the database
401 meta->dumpToDatabase();
402
403 // find any albumart for this track
406
408
409 m_tracks->at(m_currentTrack)->isNewTune =
410 isNewTune(meta->Artist(), meta->Album(), meta->Title());
411
412 // update the UI
413 fillWidgets();
414 }
415 else
416 {
417 ShowOkPopup(tr("This track is already in the database"));
418 }
419}
420
422{
423 if (m_tracks->empty())
424 return;
425
426 m_currentTrack = 0;
427 int newCount = 0;
428
429 while (m_currentTrack < (int) m_tracks->size())
430 {
431 fillWidgets();
432 QCoreApplication::processEvents();
433
434 if (m_tracks->at(m_currentTrack)->isNewTune)
435 {
436 addPressed();
437 newCount++;
438 }
439
440 QCoreApplication::processEvents();
441
443 }
444
446
447 ShowOkPopup(tr("%1 new tracks were added to the database").arg(newCount));
448}
449
451{
452 if (m_tracks->empty())
453 return;
454
455 uint track = m_currentTrack + 1;
456 while (track < m_tracks->size())
457 {
458 if (m_tracks->at(track)->isNewTune)
459 {
460 m_currentTrack = track;
461 fillWidgets();
462 break;
463 }
464 track++;
465 }
466}
467
468bool ImportMusicDialog::copyFile(const QString &src, const QString &dst)
469{
470 bool res = false;
471 QString host = QUrl(dst).host();
472
473 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
474 auto *busy =
475 new MythUIBusyDialog(tr("Copying music file to the 'Music' storage group on %1").arg(host),
476 popupStack,
477 "scanbusydialog");
478
479 if (busy->Create())
480 {
481 popupStack->AddScreen(busy, false);
482 }
483 else
484 {
485 delete busy;
486 busy = nullptr;
487 }
488
489 auto *copy = new FileCopyThread(src, dst);
490 copy->start();
491
492 while (!copy->isFinished())
493 {
494 std::this_thread::sleep_for(500us);
495 QCoreApplication::processEvents();
496 }
497
498 res = copy->GetResult();
499
500 delete copy;
501
502 if (busy)
503 busy->Close();
504
505 return res;
506}
507
509{
510 // sanity check - make sure the user isn't trying to import tracks from the music directory
511 QString location = m_locationEdit->GetText();
512 if (!location.endsWith('/'))
513 location.append('/');
514
515 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
516 auto *busy = new MythUIBusyDialog(tr("Searching for music files"),
517 popupStack, "scanbusydialog");
518
519 if (busy->Create())
520 {
521 popupStack->AddScreen(busy, false);
522 }
523 else
524 {
525 delete busy;
526 busy = nullptr;
527 }
528 auto *scanner = new FileScannerThread(this);
529 scanner->start();
530
531 while (!scanner->isFinished())
532 {
533 std::this_thread::sleep_for(500us);
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 {
574 scanDirectory(filename, tracks);
575 }
576 else
577 {
579 if (tagger)
580 {
581 MusicMetadata *metadata = tagger->read(filename);
582 if (metadata)
583 {
584 auto * track = new TrackInfo;
585 track->metadata = metadata;
586 track->isNewTune = isNewTune(metadata->Artist(), metadata->Album(),
587 metadata->Title());
588 track->metadataHasChanged = false;
589 tracks->push_back(track);
590 m_sourceFiles.append(filename);
591 }
592
593 delete tagger;
594 }
595 }
596 }
597}
598
600{
601 if (m_tracks->empty())
602 return;
603
604 MusicMetadata *editMeta = m_tracks->at(m_currentTrack)->metadata;
605
607
608 auto *editDialog = new EditMetadataDialog(mainStack, editMeta);
609
610 if (!editDialog->Create())
611 {
612 delete editDialog;
613 return;
614 }
615
616 editDialog->setSaveMetadataOnly();
617
619
620 mainStack->AddScreen(editDialog);
621}
622
624{
625 MusicMetadata *editMeta = m_tracks->at(m_currentTrack)->metadata;
626 m_tracks->at(m_currentTrack)->metadataHasChanged = true;
627 m_tracks->at(m_currentTrack)->isNewTune =
628 isNewTune(editMeta->Artist(), editMeta->Album(), editMeta->Title());
629 fillWidgets();
630}
631
633{
634 if (m_tracks->empty())
635 return;
636
637 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
638
639 auto *menu = new MythDialogBox("", popupStack, "importmusicmenu");
640
641 if (menu->Create())
642 {
643 popupStack->AddScreen(menu);
644 }
645 else
646 {
647 delete menu;
648 return;
649 }
650
651 menu->SetReturnEvent(this, "menu");
652 menu->AddButton(tr("Select Where To Save Tracks"), &ImportMusicDialog::chooseBackend);
653 menu->AddButton(tr("Save Defaults"), &ImportMusicDialog::saveDefaults);
654
655 if (m_haveDefaults)
656 {
657 menu->AddButton(tr("Change Compilation Flag"), &ImportMusicDialog::setCompilation);
658 menu->AddButton(tr("Change Compilation Artist"),
660 menu->AddButton(tr("Change Artist"), &ImportMusicDialog::setArtist);
661 menu->AddButton(tr("Change Album"), &ImportMusicDialog::setAlbum);
662 menu->AddButton(tr("Change Genre"), &ImportMusicDialog::setGenre);
663 menu->AddButton(tr("Change Year"), &ImportMusicDialog::setYear);
664 menu->AddButton(tr("Change Rating"), &ImportMusicDialog::setRating);
665 }
666}
667
669{
670 QStringList hostList;
671
672 // get a list of hosts with a directory defined for the 'Music' storage group
674 QString sql = "SELECT DISTINCT hostname "
675 "FROM storagegroup "
676 "WHERE groupname = 'Music'";
677 if (!query.exec(sql) || !query.isActive())
678 {
679 MythDB::DBError("ImportMusicDialog::chooseBackend get host list", query);
680 }
681 else
682 {
683 while(query.next())
684 {
685 hostList.append(query.value(0).toString());
686 }
687 }
688
689 if (hostList.isEmpty())
690 {
691 LOG(VB_GENERAL, LOG_ERR, "ImportMusicDialog::chooseBackend: No backends found");
692 return;
693 }
694
695 QString msg = tr("Select where to save tracks");
696
697 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
698 auto *searchDlg = new MythUISearchDialog(popupStack, msg, hostList, false, "");
699
700 if (!searchDlg->Create())
701 {
702 delete searchDlg;
703 return;
704 }
705
707
708 popupStack->AddScreen(searchDlg);
709}
710
711void ImportMusicDialog::setSaveHost(const QString& host)
712{
713 gCoreContext->SaveSetting("MythMusicLastImportHost", host);
714
715 QStringList dirs = StorageGroup::getGroupDirs("Music", host);
716 if (dirs.count() > 0)
717 m_musicStorageDir = StorageGroup::getGroupDirs("Music", host).at(0);
718
719}
720
722{
723 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
726 m_defaultArtist = data->Artist();
727 m_defaultAlbum = data->Album();
728 m_defaultGenre = data->Genre();
729 m_defaultYear = data->Year();
730 m_defaultRating = data->Rating();
731
732 m_haveDefaults = true;
733}
734
736{
737 if (!m_haveDefaults)
738 return;
739
740 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
741
743 {
746 }
747 else
748 {
751 }
752
753 fillWidgets();
754}
755
757{
758 if (!m_haveDefaults)
759 return;
760
761 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
763
764 fillWidgets();
765}
766
768{
769 if (!m_haveDefaults)
770 return;
771
772 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
774
775 m_tracks->at(m_currentTrack)->isNewTune =
776 isNewTune(data->Artist(), data->Album(), data->Title());
777
778 fillWidgets();
779}
780
782{
783 if (!m_haveDefaults)
784 return;
785
786 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
788
789 m_tracks->at(m_currentTrack)->isNewTune =
790 isNewTune(data->Artist(), data->Album(), data->Title());
791
792 fillWidgets();
793}
794
796{
797 if (!m_haveDefaults)
798 return;
799
800 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
801 data->setYear(m_defaultYear);
802
803 fillWidgets();
804}
805
807{
808 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
809 data->setTrack(data->Track() + 100);
810
811 fillWidgets();
812}
813
815{
816 if (!m_haveDefaults)
817 return;
818
819 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
821
822 fillWidgets();
823}
824
826{
827 if (!m_haveDefaults)
828 return;
829
830 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
832}
833
835{
836 QLocale locale = gCoreContext->GetQLocale();
837 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
838 QString title = locale.toLower(data->Title().simplified());
839 title[0] = title[0].toUpper();
840 data->setTitle(title);
841 fillWidgets();
842}
843
845{
846 QLocale locale = gCoreContext->GetQLocale();
847 MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
848 QString title = locale.toLower(data->Title().simplified());
849 QStringList title_words = title.split(' ');
850
851 // NOLINTNEXTLINE(modernize-loop-convert)
852 for (int x = 0; x < title_words.size(); ++x)
853 title_words[x][0] = title_words[x][0].toUpper();
854
855 data->setTitle(title_words.join(' '));
856 fillWidgets();
857}
858
860{
861 if (m_tracks->empty())
862 return;
863
864 QFileInfo fi(m_sourceFiles.at(m_currentTrack));
865
867
868 auto *import = new ImportCoverArtDialog(mainStack,
869 fi.absolutePath(),
870 m_tracks->at(m_currentTrack)->metadata,
872
873 if (import->Create())
874 mainStack->AddScreen(import);
875 else
876 delete import;
877}
878
880{
881 if (auto *dce = dynamic_cast<DialogCompletionEvent*>(event))
882 {
883 if (dce->GetId() == "locationchange")
884 {
885 m_locationEdit->SetText(dce->GetResultText());
886 startScan();
887 }
888 }
889}
890
892
894{
896 return true;
897
898 QStringList actions;
899 bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
900
901 for (int i = 0; i < actions.size() && !handled; i++)
902 {
903 const QString& action = actions[i];
904 handled = true;
905
906 if (action == "LEFT")
907 {
909 }
910 else if (action == "RIGHT")
911 {
913 }
914 else
915 {
916 handled = false;
917 }
918 }
919
920 if (!handled && MythScreenType::keyPressEvent(event))
921 handled = true;
922
923 return handled;
924}
925
927{
928 if (!LoadWindowFromXML("music-ui.xml", "import_coverart", this))
929 return false;
930
931 bool err = false;
932 UIUtilE::Assign(this, m_filenameText, "file", &err);
933 UIUtilE::Assign(this, m_currentText, "position", &err);
934 UIUtilE::Assign(this, m_statusText, "status", &err);
935 UIUtilE::Assign(this, m_destinationText, "destination", &err);
936 UIUtilE::Assign(this, m_coverartImage, "coverart", &err);
937 UIUtilE::Assign(this, m_copyButton, "copy", &err);
938 UIUtilE::Assign(this, m_exitButton, "exit", &err);
939 UIUtilE::Assign(this, m_prevButton, "prev", &err);
940 UIUtilE::Assign(this, m_nextButton, "next", &err);
941 UIUtilE::Assign(this, m_typeList, "type", &err);
942
943 if (err)
944 {
945 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'import_coverart'");
946 return false;
947 }
948
949 if (m_typeList)
950 {
951 new MythUIButtonListItem(m_typeList, tr("Front Cover"),
952 QVariant::fromValue((int)IT_FRONTCOVER));
953 new MythUIButtonListItem(m_typeList, tr("Back Cover"),
954 QVariant::fromValue((int)IT_BACKCOVER));
955 new MythUIButtonListItem(m_typeList, tr("CD"),
956 QVariant::fromValue((int)IT_CD));
957 new MythUIButtonListItem(m_typeList, tr("Inlay"),
958 QVariant::fromValue((int)IT_INLAY));
959 new MythUIButtonListItem(m_typeList, tr("<Unknown>"),
960 QVariant::fromValue((int)IT_UNKNOWN));
961
964 }
965
966 if (m_copyButton)
968
969 if (m_exitButton)
971
972 if (m_prevButton)
974
975 if (m_nextButton)
977
979
981
982 return true;
983}
984
986{
987 updateStatus();
988}
989
991{
992 if (!m_filelist.empty())
993 {
995 {
996 //: %1 is the filename
997 ShowOkPopup(tr("Copy CoverArt Failed.\nCopying to %1").arg(m_saveFilename));
998 return;
999 }
1000
1001 // add the file to the database
1002 QString filename = m_saveFilename.section( '/', -1, -1);
1003 AlbumArtImage image;
1004 image.m_description = "";
1005 image.m_embedded = false;
1006 image.m_filename = filename;
1007 image.m_hostname = m_metadata->Hostname();
1008 image.m_imageType = (ImageType)m_typeList->GetItemCurrent()->GetData().toInt();
1009
1012
1013 updateStatus();
1014 }
1015}
1016
1018{
1019 if (m_currentFile > 0)
1020 {
1021 m_currentFile--;
1023 updateStatus();
1024 }
1025}
1026
1028{
1029 if (m_currentFile < m_filelist.size() - 1)
1030 {
1031 m_currentFile++;
1033 updateStatus();
1034 }
1035}
1036
1038{
1039 QDir d(m_sourceDir);
1040
1041 if (!d.exists())
1042 return;
1043
1044 QString nameFilter = gCoreContext->GetSetting("AlbumArtFilter",
1045 "*.png;*.jpg;*.jpeg;*.gif;*.bmp");
1046
1047 QFileInfoList list = d.entryInfoList(nameFilter.split(";"),
1048 QDir::Files | QDir::Dirs |
1049 QDir::NoDotAndDotDot);
1050 if (list.isEmpty())
1051 return;
1052
1053 for (const auto & fi : std::as_const(list))
1054 {
1055 QString filename = fi.absoluteFilePath();
1056 if (!fi.isDir())
1057 {
1058 m_filelist.append(filename);
1059 }
1060 }
1061
1062 m_currentFile = 0;
1064 updateStatus();
1065}
1066
1068{
1069 if (!m_filelist.empty())
1070 {
1071 if (m_currentText)
1072 {
1073 //: %1 is the current position of the file being copied,
1074 //: %2 is the total number of files
1075 m_currentText->SetText(tr("%1 of %2", "Current file copied")
1076 .arg(m_currentFile + 1)
1077 .arg(m_filelist.size()));
1078 }
1082
1083 QString saveFilename = filenameFromMetadata(m_metadata);
1084 QString fullFilename;
1085
1086 QUrl url(m_musicStorageDir);
1087 fullFilename = MythCoreContext::GenMythURL(url.host(), 0, saveFilename, "Music");
1088 QString dir = fullFilename.section( '/', 0, -2);
1089
1090 QFileInfo fi(m_filelist[m_currentFile]);
1091 switch (m_typeList->GetItemCurrent()->GetData().toInt())
1092 {
1093 case IT_FRONTCOVER:
1094 saveFilename = "front." + fi.suffix();
1095 break;
1096 case IT_BACKCOVER:
1097 saveFilename = "back." + fi.suffix();
1098 break;
1099 case IT_CD:
1100 saveFilename = "cd." + fi.suffix();
1101 break;
1102 case IT_INLAY:
1103 saveFilename = "inlay." + fi.suffix();
1104 break;
1105 case IT_UNKNOWN:
1106 saveFilename = "unknown." + fi.suffix();
1107 break;
1108 default:
1109 saveFilename = fi.fileName();
1110 }
1111
1112 m_saveFilename = dir + "/" + saveFilename;
1114
1115 url.setUrl(m_saveFilename);
1116
1117 if (!RemoteFile::FindFile(url.path(), "" , "Music").isEmpty())
1118 m_statusText->SetText(tr("File Already Exists"));
1119 else
1120 m_statusText->SetText(tr("New File"));
1121 }
1122 else
1123 {
1124 if (m_currentText)
1130 }
1131}
1132
1134{
1135 if (m_filelist.empty())
1136 return;
1137
1139 QFileInfo fi(filename);
1140 filename = fi.fileName();
1141
1142 if (filename.contains("front", Qt::CaseInsensitive))
1143 m_typeList->SetValue(tr("Front Cover"));
1144 else if (filename.contains("back", Qt::CaseInsensitive))
1145 m_typeList->SetValue(tr("Back Cover"));
1146 else if (filename.contains("inlay", Qt::CaseInsensitive))
1147 m_typeList->SetValue(tr("Inlay"));
1148 else if (filename.contains("cd", Qt::CaseInsensitive))
1149 m_typeList->SetValue(tr("CD"));
1150 else
1151 m_typeList->SetValue(tr("<Unknown>"));
1152}
1153
1154#include "moc_importmusic.cpp"
QString m_filename
Definition: musicmetadata.h:51
QString m_description
Definition: musicmetadata.h:54
ImageType m_imageType
Definition: musicmetadata.h:53
QString m_hostname
Definition: musicmetadata.h:52
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:40
void metadataChanged(void)
QString m_srcFile
Definition: importmusic.h:59
QString m_dstFile
Definition: importmusic.h:60
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:50
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:41
ImportMusicDialog * m_parent
Definition: importmusic.h:43
FileScannerThread(ImportMusicDialog *parent)
Definition: importmusic.cpp:36
MythUIImage * m_coverartImage
Definition: importmusic.h:215
MusicMetadata * m_metadata
Definition: importmusic.h:203
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MythUIButton * m_exitButton
Definition: importmusic.h:221
MythUIButton * m_prevButton
Definition: importmusic.h:219
void updateTypeSelector(void)
MythUIText * m_currentText
Definition: importmusic.h:211
MythUIButton * m_nextButton
Definition: importmusic.h:218
void selectorChanged(void)
bool Create(void) override
MythUIButton * m_copyButton
Definition: importmusic.h:220
MythUIText * m_filenameText
Definition: importmusic.h:210
MythUIButtonList * m_typeList
Definition: importmusic.h:216
MythUIText * m_statusText
Definition: importmusic.h:212
QStringList m_filelist
Definition: importmusic.h:200
MythUIText * m_destinationText
Definition: importmusic.h:213
void prevPressed(void)
static bool copyFile(const QString &src, const QString &dst)
void setGenre(void)
void startScan(void)
MythUIText * m_trackText
Definition: importmusic.h:143
void chooseBackend(void) const
void saveDefaults(void)
void setTitleWordCaps(void)
~ImportMusicDialog() override
Definition: importmusic.cpp:70
MythUIButton * m_locationButton
Definition: importmusic.h:132
MythUIText * m_currentText
Definition: importmusic.h:148
MythUIButton * m_addButton
Definition: importmusic.h:152
MythUIText * m_genreText
Definition: importmusic.h:141
void importFinished(void)
QString m_musicStorageDir
Definition: importmusic.h:123
MythUIButton * m_prevButton
Definition: importmusic.h:146
QStringList m_sourceFiles
Definition: importmusic.h:126
void addAllNewPressed(void)
MythUIText * m_titleText
Definition: importmusic.h:140
void nextPressed(void)
void showImportCoverArtDialog()
void setRating(void)
MythUIText * m_statusText
Definition: importmusic.h:149
void scanDirectory(QString &directory, std::vector< TrackInfo * > *tracks)
MythUIButton * m_addallnewButton
Definition: importmusic.h:153
MythUIButton * m_playButton
Definition: importmusic.h:151
ImportMusicDialog(MythScreenStack *parent)
Definition: importmusic.cpp:60
MythUIButton * m_nextButton
Definition: importmusic.h:145
void metadataChanged(void)
QString m_defaultCompArtist
Definition: importmusic.h:160
bool m_somethingWasImported
Definition: importmusic.h:124
MythUIText * m_compartistText
Definition: importmusic.h:137
void setArtist(void)
void doExit(bool ok)
MythUIButton * m_nextnewButton
Definition: importmusic.h:154
MythUIButton * m_scanButton
Definition: importmusic.h:133
void playPressed(void)
MusicMetadata * m_playingMetaData
Definition: importmusic.h:128
void showEditMetadataDialog(void)
std::vector< TrackInfo * > * m_tracks
Definition: importmusic.h:125
MythUITextEdit * m_locationEdit
Definition: importmusic.h:131
void addPressed(void)
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
void locationPressed(void)
void setYear(void)
MythUIButton * m_coverartButton
Definition: importmusic.h:134
MythUIText * m_artistText
Definition: importmusic.h:138
void nextNewPressed(void)
QString m_defaultGenre
Definition: importmusic.h:163
void coverArtPressed(void)
MythUICheckBox * m_compilationCheck
Definition: importmusic.h:156
void customEvent(QEvent *event) override
QString m_defaultAlbum
Definition: importmusic.h:162
void setCompilationArtist(void)
void ShowMenu(void) override
void setTrack(void)
void setSaveHost(const QString &host)
MythUIText * m_albumText
Definition: importmusic.h:139
MythUIText * m_filenameText
Definition: importmusic.h:136
bool Create(void) override
MythUIText * m_yearText
Definition: importmusic.h:142
void setTitleInitialCap(void)
void setAlbum(void)
QString m_defaultArtist
Definition: importmusic.h:161
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:620
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:814
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:552
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:180
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:193
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:32
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:225
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:589
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: compat.h:60
static const iso6937table * d
ImageType
Definition: musicmetadata.h:31
@ IT_INLAY
Definition: musicmetadata.h:36
@ IT_BACKCOVER
Definition: musicmetadata.h:34
@ IT_UNKNOWN
Definition: musicmetadata.h:32
@ IT_FRONTCOVER
Definition: musicmetadata.h:33
@ IT_CD
Definition: musicmetadata.h:35
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.
MusicMetadata * metadata
Definition: importmusic.h:29
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27