MythTV master
mythmusic.cpp
Go to the documentation of this file.
1// C++ headers
2#include <cstdlib>
3#include <thread>
4#include <sys/stat.h>
5#include <sys/types.h>
6
7// Qt headers
8#include <QApplication>
9#include <QDir>
10#include <QScopedPointer>
11
12// MythTV headers
13#include <libmythbase/compat.h>
16#include <libmythbase/mythdb.h>
21#include <libmythbase/mythversion.h>
30
31// MythMusic headers
32#include "cddecoder.h"
33#include "config.h"
34#include "decoder.h"
35#include "generalsettings.h"
36#include "importmusic.h"
37#include "importsettings.h"
38#include "mainvisual.h"
39#include "musicdata.h"
40#include "musicdbcheck.h"
41#include "musicplayer.h"
42#include "playersettings.h"
43#include "playlistcontainer.h"
44#include "playlisteditorview.h"
45#include "playlistview.h"
46#include "ratingsettings.h"
47#include "streamview.h"
49
50#ifdef HAVE_CDIO
51#include "cdrip.h"
52#endif
53
54#ifdef HAVE_CDIO
58static QString chooseCD(void)
59{
60 if (!gCDdevice.isEmpty())
61 return gCDdevice;
62
63#ifdef Q_OS_DARWIN
65#endif
66
68}
69#endif
70
72static bool checkStorageGroup(void)
73{
74 // get a list of hosts with a directory defined for the 'Music' storage group
75 QStringList hostList;
77 QString sql = "SELECT DISTINCT hostname "
78 "FROM storagegroup "
79 "WHERE groupname = 'Music'";
80 if (!query.exec(sql) || !query.isActive())
81 {
82 MythDB::DBError("checkStorageGroup get host list", query);
83 }
84 else
85 {
86 while(query.next())
87 {
88 hostList.append(query.value(0).toString());
89 }
90 }
91
92 if (hostList.isEmpty())
93 {
94 ShowOkPopup(QCoreApplication::translate("(MythMusicMain)",
95 "No directories found in the 'Music' storage group. "
96 "Please run mythtv-setup on the backend machine to add one."));
97 return false;
98 }
99
100 // get a list of hosts with a directory defined for the 'MusicArt' storage group
101 hostList.clear();
102 sql = "SELECT DISTINCT hostname "
103 "FROM storagegroup "
104 "WHERE groupname = 'MusicArt'";
105 if (!query.exec(sql) || !query.isActive())
106 {
107 MythDB::DBError("checkStorageGroup get host list", query);
108 }
109 else
110 {
111 while(query.next())
112 {
113 hostList.append(query.value(0).toString());
114 }
115 }
116
117 if (hostList.isEmpty())
118 {
119 ShowOkPopup(QCoreApplication::translate("(MythMusicMain)",
120 "No directories found in the 'MusicArt' storage group. "
121 "Please run mythtv-setup on the backend machine to add one."));
122 return false;
123 }
124
125 return true;
126}
127
129static bool checkMusicAvailable(void)
130{
131 MSqlQuery count_query(MSqlQuery::InitCon());
132 bool foundMusic = false;
133 if (count_query.exec("SELECT COUNT(*) FROM music_songs;"))
134 {
135 if(count_query.next() &&
136 0 != count_query.value(0).toInt())
137 {
138 foundMusic = true;
139 }
140 }
141
142 if (!foundMusic)
143 {
144 ShowOkPopup(QCoreApplication::translate("(MythMusicMain)",
145 "No music has been found.\n"
146 "Please select 'Scan For New Music' "
147 "to perform a scan for music."));
148 }
149
150 return foundMusic;
151}
152
153static void startPlayback(void)
154{
156 return;
157
159
161
162 auto *view = new PlaylistView(mainStack, nullptr);
163
164 if (view->Create())
165 mainStack->AddScreen(view);
166 else
167 delete view;
168}
169
170static void startStreamPlayback(void)
171{
173
175
176 auto *view = new StreamView(mainStack, nullptr);
177
178 if (view->Create())
179 mainStack->AddScreen(view);
180 else
181 delete view;
182}
183
184static void startDatabaseTree(void)
185{
187 return;
188
190
192
193 QString lastView = gCoreContext->GetSetting("MusicPlaylistEditorView", "tree");
194 auto *view = new PlaylistEditorView(mainStack, nullptr, lastView);
195
196 if (view->Create())
197 mainStack->AddScreen(view);
198 else
199 delete view;
200}
201
202static void startRipper(void)
203{
204#ifdef HAVE_CDIO
205 if (!checkStorageGroup())
206 return;
207
209
211
212 auto *rip = new Ripper(mainStack, chooseCD());
213
214 if (rip->Create())
215 {
216 mainStack->AddScreen(rip);
217 QObject::connect(rip, &Ripper::ripFinished,
219 Qt::QueuedConnection);
220 }
221 else
222 {
223 delete rip;
224 }
225
226#else
227 ShowOkPopup(QCoreApplication::translate("(MythMusicMain)",
228 "MythMusic hasn't been built with libcdio "
229 "support so ripping CDs is not possible"));
230#endif
231}
232
233static void runScan(void)
234{
235 if (!checkStorageGroup())
236 return;
237
238 LOG(VB_GENERAL, LOG_INFO, "Scanning for music files");
239
241}
242
243static void startImport(void)
244{
245 if (!checkStorageGroup())
246 return;
247
249
251
252 auto *import = new ImportMusicDialog(mainStack);
253
254 if (import->Create())
255 {
256 mainStack->AddScreen(import);
257 QObject::connect(import, &ImportMusicDialog::importFinished,
259 Qt::QueuedConnection);
260 }
261 else
262 {
263 delete import;
264 }
265}
266
267// these point to the the mainmenu callback if found
268static void (*m_callback)(void *, QString &) = nullptr;
269static void *m_callbackdata = nullptr;
270
271static void MusicCallback([[maybe_unused]] void *data, QString &selection)
272{
273 QString sel = selection.toLower();
274 if (sel == "music_create_playlist")
275 {
277 }
278 else if (sel == "music_play")
279 {
281 }
282 else if (sel == "stream_play")
283 {
285 }
286 else if (sel == "music_rip")
287 {
288 startRipper();
289 }
290 else if (sel == "music_import")
291 {
292 startImport();
293 }
294 else if (sel == "settings_scan")
295 {
296 runScan();
297 }
298 else if (sel == "settings_general")
299 {
301 auto *gs = new GeneralSettings(mainStack, "general settings");
302
303 if (gs->Create())
304 mainStack->AddScreen(gs);
305 else
306 delete gs;
307 }
308 else if (sel == "settings_player")
309 {
311 auto *ps = new PlayerSettings(mainStack, "player settings");
312
313 if (ps->Create())
314 mainStack->AddScreen(ps);
315 else
316 delete ps;
317 }
318 else if (sel == "settings_rating")
319 {
321 auto *rs = new RatingSettings(mainStack, "rating settings");
322
323 if (rs->Create())
324 mainStack->AddScreen(rs);
325 else
326 delete rs;
327 }
328 else if (sel == "settings_visualization")
329 {
330
332 auto *vs = new VisualizationSettings(mainStack, "visualization settings");
333
334 if (vs->Create())
335 mainStack->AddScreen(vs);
336 else
337 delete vs;
338 }
339 else if (sel == "settings_import")
340 {
342 auto *is = new ImportSettings(mainStack, "import settings");
343
344 if (is->Create())
345 mainStack->AddScreen(is);
346 else
347 delete is;
348 }
349 else
350 {
351 // if we have found the mainmenu callback
352 // pass the selection on to it
354 m_callback(m_callbackdata, selection);
355 }
356}
357
358static int runMenu(const QString& which_menu)
359{
360 QString themedir = GetMythUI()->GetThemeDir();
361
362 // find the 'mainmenu' MythThemedMenu so we can use the callback from it
363 MythThemedMenu *mainMenu = nullptr;
364 QObject *parentObject = GetMythMainWindow()->GetMainStack()->GetTopScreen();
365
366 while (parentObject)
367 {
368 auto *menu = qobject_cast<MythThemedMenu *>(parentObject);
369
370 if (menu && menu->objectName() == "mainmenu")
371 {
372 mainMenu = menu;
373 break;
374 }
375
376 parentObject = parentObject->parent();
377 }
378
379 auto *diag = new MythThemedMenu(themedir, which_menu,
380 GetMythMainWindow()->GetMainStack(),
381 "music menu");
382
383 // save the callback from the main menu
384 if (mainMenu)
386
387 diag->setCallback(MusicCallback, nullptr);
388 diag->setKillable();
389
390 if (diag->foundTheme())
391 {
392 if (LCD *lcd = LCD::Get())
393 {
394 lcd->switchToTime();
395 }
397 return 0;
398 }
399 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find menu %1 or theme %2")
400 .arg(which_menu, themedir));
401 delete diag;
402 return -1;
403}
404
405static void runMusicPlayback(void)
406{
407 GetMythUI()->AddCurrentLocation("playmusic");
410}
411
412static void runMusicStreamPlayback(void)
413{
414 GetMythUI()->AddCurrentLocation("streammusic");
417}
418
419static void runMusicSelection(void)
420{
421 GetMythUI()->AddCurrentLocation("musicplaylists");
424}
425
426static void runRipCD(void)
427{
429
430#ifdef HAVE_CDIO
432
433 auto *rip = new Ripper(mainStack, chooseCD());
434
435 if (rip->Create())
436 {
437 mainStack->AddScreen(rip);
438 }
439 else
440 {
441 delete rip;
442 return;
443 }
444
445 QObject::connect(rip, &Ripper::ripFinished,
447 Qt::QueuedConnection);
448#endif
449}
450
451static void showMiniPlayer(void)
452{
454 return;
455
456 // only show the miniplayer if there isn't already a client attached
457 if (!gPlayer->hasClient())
459}
460
461static QStringList GetMusicFilter()
462{
463 QString filt = MetaIO::kValidFileExtensions;
464 filt.replace(".", "*.");
465 return filt.split('|');
466}
467
468static QStringList BuildFileList(const QString &dir, const QStringList &filters)
469{
470 QStringList ret;
471
472 QDir d(dir);
473 if (!d.exists())
474 return ret;
475
476 d.setNameFilters(filters);
477 d.setFilter(QDir::Files | QDir::AllDirs |
478 QDir::NoSymLinks | QDir::Readable |
479 QDir::NoDotAndDotDot);
480 d.setSorting(QDir::Name | QDir::DirsLast);
481
482 QFileInfoList list = d.entryInfoList();
483 if (list.isEmpty())
484 return ret;
485
486 for (const auto & fi : std::as_const(list))
487 {
488 if (fi.isDir())
489 {
490 ret += BuildFileList(fi.absoluteFilePath(), filters);
491 QCoreApplication::processEvents();
492 }
493 else
494 {
495 ret << fi.absoluteFilePath();
496 }
497 }
498 return ret;
499}
500
501static void handleMedia(MythMediaDevice *cd, bool forcePlayback)
502{
503 static QString s_mountPath;
504
505 if (!cd)
506 return;
507
508 if (MEDIASTAT_MOUNTED != cd->getStatus())
509 {
510 if (s_mountPath != cd->getMountPath())
511 return;
512
513 LOG(VB_MEDIA, LOG_INFO, QString(
514 "MythMusic: '%1' unmounted, clearing data").arg(cd->getVolumeID()));
515
518 {
519 // Now playing a track which is no longer available so stop playback
520 gPlayer->stop(true);
521 }
522
523 // device is not usable so remove any existing CD tracks
525 {
528 }
529
530 gPlayer->activePlaylistChanged(-1, false);
532
533 return;
534 }
535
536 LOG(VB_MEDIA, LOG_NOTICE, QString("MythMusic: '%1' mounted on '%2'")
537 .arg(cd->getVolumeID(), cd->getMountPath()) );
538
539 s_mountPath.clear();
540
541 // don't show the music screen if AutoPlayCD is off
542 if (!forcePlayback && !gCoreContext->GetBoolSetting("AutoPlayCD", false))
543 return;
544
547
548 // remove any existing CD tracks
551
553
554 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
555
556 QString message = QCoreApplication::translate("(MythMusicMain)",
557 "Searching for music files...");
558 auto *busy = new MythUIBusyDialog( message, popupStack, "musicscanbusydialog");
559 if (busy->Create())
560 {
561 popupStack->AddScreen(busy, false);
562 }
563 else
564 {
565 delete busy;
566 busy = nullptr;
567 }
568
569 // Search for music files
570 QStringList trackList = BuildFileList(cd->getMountPath(), GetMusicFilter());
571 LOG(VB_MEDIA, LOG_INFO, QString("MythMusic: %1 music files found")
572 .arg(trackList.count()));
573
574 if (busy)
575 busy->Close();
576
577 if (trackList.isEmpty())
578 return;
579
580 message = QCoreApplication::translate("(MythMusicMain)", "Loading music tracks");
581 auto *progress = new MythUIProgressDialog( message, popupStack,
582 "scalingprogressdialog");
583 if (progress->Create())
584 {
585 popupStack->AddScreen(progress, false);
586 progress->SetTotal(trackList.count());
587 }
588 else
589 {
590 delete progress;
591 progress = nullptr;
592 }
593
594 // Read track metadata and add to all_music
595 int track = 0;
596 for (const auto & file : std::as_const(trackList))
597 {
598 QScopedPointer<MusicMetadata> meta(MetaIO::readMetadata(file));
599 if (meta)
600 {
601 meta->setTrack(++track);
603 }
604 if (progress)
605 {
606 progress->SetProgress(track);
607 QCoreApplication::processEvents();
608 }
609 }
610 LOG(VB_MEDIA, LOG_INFO, QString("MythMusic: %1 tracks scanned").arg(track));
611
612 if (progress)
613 progress->Close();
614
615 // Remove all tracks from the playlist
617
618 // Create list of new tracks
619 QList<int> songList;
620 const int tracks = gMusicData->m_all_music->getCDTrackCount();
621 songList.reserve(tracks);
622 for (track = 1; track <= tracks; track++)
623 {
625 if (mdata)
626 songList.append(mdata->ID());
627 }
628 if (songList.isEmpty())
629 return;
630
631 s_mountPath = cd->getMountPath();
632
633 // Add new tracks to playlist
635 songList, true, PL_REPLACE, 0);
637
638 // if there is no music screen showing then show the Playlist view
639 if (!gPlayer->hasClient())
640 {
641 // make sure we start playing from the first track
642 gCoreContext->SaveSetting("MusicBookmark", 0);
643 gCoreContext->SaveSetting("MusicBookmarkPosition", 0);
644
646 }
647}
648
649#ifdef HAVE_CDIO
650static void handleCDMedia(MythMediaDevice *cd, bool forcePlayback)
651{
652
653 if (!cd)
654 return;
655
656 LOG(VB_MEDIA, LOG_NOTICE, "Got a CD media changed event");
657
658 QString newDevice;
659
660 // save the device if valid
661 if (cd->isUsable())
662 {
663#ifdef Q_OS_DARWIN
664 newDevice = cd->getMountPath();
665#else
666 newDevice = cd->getDevicePath();
667#endif
668
669 gCDdevice = newDevice;
670 LOG(VB_MEDIA, LOG_INFO, "MythMusic: Storing CD device " + gCDdevice);
671 }
672 else
673 {
674 LOG(VB_MEDIA, LOG_INFO, "Device is not usable clearing cd data");
675
678 {
679 // we was playing a cd track which is no longer available so stop playback
680 // TODO should check the playing track is from the ejected drive if more than one is available
681 gPlayer->stop(true);
682 }
683
684 // device is not usable so remove any existing CD tracks
686 {
689 }
690
691 gPlayer->activePlaylistChanged(-1, false);
693
694 return;
695 }
696
699
700 // wait for the music and playlists to load
703 {
704 QCoreApplication::processEvents();
705 std::this_thread::sleep_for(50ms);
706 }
707
708 // remove any existing CD tracks
711
712 // find any new cd tracks
713 auto *decoder = new CdDecoder("cda", nullptr, nullptr);
714 decoder->setDevice(newDevice);
715
716 int tracks = decoder->getNumTracks();
717 bool setTitle = false;
718
719 for (int trackNo = 1; trackNo <= tracks; trackNo++)
720 {
721 MusicMetadata *track = decoder->getMetadata(trackNo);
722 if (track)
723 {
725
726 if (!setTitle)
727 {
728
729 QString parenttitle = " ";
730 if (track->FormatArtist().length() > 0)
731 {
732 parenttitle += track->FormatArtist();
733 parenttitle += " ~ ";
734 }
735
736 if (track->Album().length() > 0)
737 {
738 parenttitle += track->Album();
739 }
740 else
741 {
742 parenttitle = " " + QCoreApplication::translate("(MythMusicMain)",
743 "Unknown");
744 LOG(VB_GENERAL, LOG_INFO, "Couldn't find your "
745 " CD. It may not be in the freedb database.\n"
746 " More likely, however, is that you need to delete\n"
747 " ~/.cddb and ~/.cdserverrc and restart MythMusic.");
748 }
749
750 gMusicData->m_all_music->setCDTitle(parenttitle);
751 setTitle = true;
752 }
753
754 delete track;
755 }
756 }
757
759
760 delete decoder;
761
762 // if the AutoPlayCD setting is set we remove all the existing tracks
763 // from the playlist and replace them with the new CD tracks found
764 if (forcePlayback || gCoreContext->GetBoolSetting("AutoPlayCD", false))
765 {
767
768 QList<int> songList;
769
770 songList.reserve(gMusicData->m_all_music->getCDTrackCount());
771 for (int x = 1; x <= gMusicData->m_all_music->getCDTrackCount(); x++)
772 {
774 if (mdata)
775 songList.append(mdata->ID());
776 }
777
778 if (!songList.isEmpty())
779 {
781 songList, true, PL_REPLACE, 0);
783 }
784 }
785 else
786 {
787 // don't show the music screen if AutoPlayCD is off
788 return;
789 }
790
791 // if there is no music screen showing show the Playlist view
792 if (!gPlayer->hasClient())
793 {
794 // make sure we start playing from the first track
795 gCoreContext->SaveSetting("MusicBookmark", 0);
796 gCoreContext->SaveSetting("MusicBookmarkPosition", 0);
797
799 }
800}
801#else
802static void handleCDMedia([[maybe_unused]] MythMediaDevice *cd, [[maybe_unused]] bool forcePlayback)
803{
804 LOG(VB_GENERAL, LOG_NOTICE, "MythMusic got a media changed event"
805 "but cdio support is not compiled in");
806}
807#endif
808
809static void setupKeys(void)
810{
811 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Play music"),
812 "", "", runMusicPlayback);
813 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Select music playlists"),
814 "", "", runMusicSelection);
815 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Play radio stream"),
816 "", "", runMusicStreamPlayback);
817 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Rip CD"),
818 "", "", runRipCD);
819 REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Scan music"),
820 "", "", runScan);
821 REG_JUMPEX(QT_TRANSLATE_NOOP("MythControls", "Show Music Miniplayer"),
822 "", "", showMiniPlayer, false);
823
824 REG_KEY("Music", "NEXTTRACK", QT_TRANSLATE_NOOP("MythControls",
825 "Move to the next track"), ">,.,Z,End,Media Next");
826 REG_KEY("Music", "PREVTRACK", QT_TRANSLATE_NOOP("MythControls",
827 "Move to the previous track"), ",,<,Q,Home,Media Previous");
828 REG_KEY("Music", "FFWD", QT_TRANSLATE_NOOP("MythControls",
829 "Fast forward"), "PgDown,Ctrl+F,Media Fast Forward");
830 REG_KEY("Music", "RWND", QT_TRANSLATE_NOOP("MythControls",
831 "Rewind"), "PgUp,Ctrl+B,Media Rewind");
832 REG_KEY("Music", "PAUSE", QT_TRANSLATE_NOOP("MythControls",
833 "Pause/Start playback"), "P,Media Play");
834 REG_KEY("Music", "PLAY", QT_TRANSLATE_NOOP("MythControls",
835 "Start playback"), "");
836 REG_KEY("Music", "STOP", QT_TRANSLATE_NOOP("MythControls",
837 "Stop playback"), "O,Media Stop");
838 REG_KEY("Music", "VOLUMEDOWN", QT_TRANSLATE_NOOP("MythControls",
839 "Volume down"), "[,{,F10,Volume Down");
840 REG_KEY("Music", "VOLUMEUP", QT_TRANSLATE_NOOP("MythControls",
841 "Volume up"), "],},F11,Volume Up");
842 REG_KEY("Music", "MUTE", QT_TRANSLATE_NOOP("MythControls",
843 "Mute"), "|,\\,F9,Volume Mute");
844 REG_KEY("Music", "TOGGLEUPMIX",QT_TRANSLATE_NOOP("MythControls",
845 "Toggle audio upmixer"), "Ctrl+U");
846 REG_KEY("Music", "CYCLEVIS", QT_TRANSLATE_NOOP("MythControls",
847 "Cycle visualizer mode"), "6");
848 REG_KEY("Music", "BLANKSCR", QT_TRANSLATE_NOOP("MythControls",
849 "Blank screen"), "5");
850 REG_KEY("Music", "THMBUP", QT_TRANSLATE_NOOP("MythControls",
851 "Increase rating"), "9");
852 REG_KEY("Music", "THMBDOWN", QT_TRANSLATE_NOOP("MythControls",
853 "Decrease rating"), "7");
854 REG_KEY("Music", "REFRESH", QT_TRANSLATE_NOOP("MythControls",
855 "Refresh music tree"), "8");
856 REG_KEY("Music", "SPEEDUP", QT_TRANSLATE_NOOP("MythControls",
857 "Increase Play Speed"), "W,3");
858 REG_KEY("Music", "SPEEDDOWN", QT_TRANSLATE_NOOP("MythControls",
859 "Decrease Play Speed"), "X,1");
860 REG_KEY("Music", "MARK", QT_TRANSLATE_NOOP("MythControls",
861 "Toggle track selection"), "T");
862 REG_KEY("Music", "TOGGLESHUFFLE", QT_TRANSLATE_NOOP("MythControls",
863 "Toggle shuffle mode"), "");
864 REG_KEY("Music", "TOGGLEREPEAT", QT_TRANSLATE_NOOP("MythControls",
865 "Toggle repeat mode"), "");
866 REG_KEY("Music", "TOGGLELAST", QT_TRANSLATE_NOOP("MythControls",
867 "Switch to previous radio stream"), "");
868
869 // switch to view key bindings
870 REG_KEY("Music", "SWITCHTOPLAYLIST", QT_TRANSLATE_NOOP("MythControls",
871 "Switch to the current playlist view"), "");
872 REG_KEY("Music", "SWITCHTOPLAYLISTEDITORTREE", QT_TRANSLATE_NOOP("MythControls",
873 "Switch to the playlist editor tree view"), "");
874 REG_KEY("Music", "SWITCHTOPLAYLISTEDITORGALLERY", QT_TRANSLATE_NOOP("MythControls",
875 "Switch to the playlist editor gallery view"), "");
876 REG_KEY("Music", "SWITCHTOSEARCH", QT_TRANSLATE_NOOP("MythControls",
877 "Switch to the search view"), "");
878 REG_KEY("Music", "SWITCHTOVISUALISER", QT_TRANSLATE_NOOP("MythControls",
879 "Switch to the fullscreen visualiser view"), "");
880 REG_KEY("Music", "SWITCHTORADIO", QT_TRANSLATE_NOOP("MythControls",
881 "Switch to the radio stream view"), "");
882
883 REG_MEDIA_HANDLER(QT_TRANSLATE_NOOP("MythControls",
884 "MythMusic Media Handler 1/2"), "", handleCDMedia,
885 MEDIATYPE_AUDIO | MEDIATYPE_MIXED, QString());
886 QString filt = MetaIO::kValidFileExtensions;
887 filt.replace('|',',');
888 filt.remove('.');
889 REG_MEDIA_HANDLER(QT_TRANSLATE_NOOP("MythControls",
890 "MythMusic Media Handler 2/2"), "", handleMedia,
891 MEDIATYPE_MMUSIC, filt);
892}
893
894int mythplugin_init(const char *libversion)
895{
896 if (!MythCoreContext::TestPluginVersion("mythmusic", libversion,
897 MYTH_BINARY_VERSION))
898 return -1;
899
901 bool upgraded = UpgradeMusicDatabaseSchema();
903
904 if (!upgraded)
905 {
906 LOG(VB_GENERAL, LOG_ERR,
907 "Couldn't upgrade music database schema, exiting.");
908 return -1;
909 }
910
911 setupKeys();
912
913 gPlayer = new MusicPlayer(nullptr);
914 gMusicData = new MusicData();
915
916 return 0;
917}
918
919
921{
922 return runMenu("musicmenu.xml");
923}
924
926{
927 return runMenu("music_settings.xml");
928}
929
931{
932 gPlayer->stop(true);
933
934 // TODO these should be saved when they are changed
935 // Automagically save all playlists and metadata (ratings) that have changed
937 {
939 }
940
942 {
944 }
945
946 delete gPlayer;
947
948 delete gMusicData;
949}
MusicMetadata * getCDMetadata(int m_the_track)
void addCDTrack(const MusicMetadata &the_track)
int getCDTrackCount(void) const
void clearCDData(void)
bool cleanOutThreads()
void save()
Check each MusicMetadata entry and save those that have changed (ratings, etc.)
void setCDTitle(const QString &a_title)
bool doneLoading() const
void importFinished(void)
Definition: lcddevice.h:170
static LCD * Get(void)
Definition: lcddevice.cpp:68
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:129
QVariant value(int i) const
Definition: mythdbcon.h:205
bool isActive(void) const
Definition: mythdbcon.h:216
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
static QString defaultCDdevice()
CDDevice, user-selected drive, or /dev/cdrom.
static QString GetMountPath(const QString &devPath)
If the device is being monitored, return its mountpoint.
static const QString kValidFileExtensions
Definition: metaio.h:160
static MusicMetadata * readMetadata(const QString &filename)
Read the metadata from filename directly.
Definition: metaio.cpp:65
static void scanMusic(void)
Definition: musicdata.cpp:51
bool m_initialized
Definition: musicdata.h:54
void reloadMusic(void) const
reload music after a scan, rip or import
Definition: musicdata.cpp:61
AllMusic * m_all_music
Definition: musicdata.h:52
void loadMusic(void) const
Definition: musicdata.cpp:102
PlaylistContainer * m_all_playlists
Definition: musicdata.h:51
bool isCDTrack(void) const
QString FormatArtist()
IdType ID() const
QString Album() const
MusicMetadata * getCurrentMetadata(void)
get the metadata for the current track in the playlist
void showMiniPlayer(void) const
void stop(bool stopAll=false)
void activePlaylistChanged(int trackID, bool deleted)
void sendCDChangedEvent(void)
bool isPlaying(void) const
Definition: musicplayer.h:109
bool setCurrentTrackPos(int pos)
bool hasClient(void)
Definition: musicplayer.h:112
void ActivateSettingsCache(bool activate=true)
void SaveSetting(const QString &key, int newValue)
QString GetSetting(const QString &key, const QString &defaultval="")
static bool TestPluginVersion(const QString &name, const QString &libversion, const QString &pluginversion)
bool GetBoolSetting(const QString &key, bool defaultval=false)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
MythScreenStack * GetMainStack()
MythScreenStack * GetStack(const QString &Stackname)
const QString & getMountPath() const
Definition: mythmedia.h:58
MythMediaStatus getStatus() const
Definition: mythmedia.h:70
bool isUsable() const
Is this device "ready", for a plugin to access?
Definition: mythmedia.h:84
const QString & getDevicePath() const
Definition: mythmedia.h:61
const QString & getVolumeID() const
Definition: mythmedia.h:72
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
virtual MythScreenType * GetTopScreen(void) const
Themed menu class, used for main menus in MythTV frontend.
void getCallback(void(**lcallback)(void *, QString &), void **data)
Get the themed menus callback function and data for that function.
QString RemoveCurrentLocation()
void AddCurrentLocation(const QString &Location)
bool doneLoading() const
Playlist * getActive(void)
void removeAllCDTracks(void)
Definition: playlist.cpp:98
void removeAllTracks(void)
Definition: playlist.cpp:90
int fillSonglistFromList(const QList< int > &songList, bool removeDuplicates, InsertPLOption insertOption, int currentTrackID)
Definition: playlist.cpp:779
Definition: cdrip.h:102
void ripFinished(void)
static const iso6937table * d
static void REG_MEDIA_HANDLER(const QString &destination, const QString &description, MediaCallback callback, int mediaType, const QString &extensions)
Definition: mediamonitor.h:143
MusicData * gMusicData
Definition: musicdata.cpp:23
bool UpgradeMusicDatabaseSchema(void)
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
QString gCDdevice
Definition: musicplayer.cpp:39
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()
static QString themedir
Definition: mythdirs.cpp:27
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
static void REG_JUMPEX(const QString &Destination, const QString &Description, const QString &Key, void(*Callback)(void), bool ExitToMain)
static void REG_JUMP(const QString &Destination, const QString &Description, const QString &Key, void(*Callback)(void))
static void REG_KEY(const QString &Context, const QString &Action, const QString &Description, const QString &Key)
@ MEDIATYPE_MIXED
Definition: mythmedia.h:27
@ MEDIATYPE_AUDIO
Definition: mythmedia.h:28
@ MEDIATYPE_MMUSIC
Definition: mythmedia.h:31
@ MEDIASTAT_MOUNTED
Definition: mythmedia.h:21
static void handleMedia(MythMediaDevice *cd, bool forcePlayback)
Definition: mythmusic.cpp:501
static void startStreamPlayback(void)
Definition: mythmusic.cpp:170
static void showMiniPlayer(void)
Definition: mythmusic.cpp:451
int mythplugin_config(void)
Definition: mythmusic.cpp:925
static QStringList BuildFileList(const QString &dir, const QStringList &filters)
Definition: mythmusic.cpp:468
static void runScan(void)
Definition: mythmusic.cpp:233
static void(* m_callback)(void *, QString &)
Definition: mythmusic.cpp:268
static void runMusicStreamPlayback(void)
Definition: mythmusic.cpp:412
void mythplugin_destroy(void)
Definition: mythmusic.cpp:930
static void startPlayback(void)
Definition: mythmusic.cpp:153
static void startRipper(void)
Definition: mythmusic.cpp:202
static void startImport(void)
Definition: mythmusic.cpp:243
static void startDatabaseTree(void)
Definition: mythmusic.cpp:184
static void runRipCD(void)
Definition: mythmusic.cpp:426
static void handleCDMedia(MythMediaDevice *cd, bool forcePlayback)
Definition: mythmusic.cpp:802
static void runMusicPlayback(void)
Definition: mythmusic.cpp:405
static void setupKeys(void)
Definition: mythmusic.cpp:809
static int runMenu(const QString &which_menu)
Definition: mythmusic.cpp:358
static void MusicCallback(void *data, QString &selection)
Definition: mythmusic.cpp:271
static bool checkStorageGroup(void)
checks we have at least one music directory in the 'Music' storage group
Definition: mythmusic.cpp:72
static void runMusicSelection(void)
Definition: mythmusic.cpp:419
int mythplugin_run(void)
Definition: mythmusic.cpp:920
static bool checkMusicAvailable(void)
checks we have some tracks available
Definition: mythmusic.cpp:129
static QStringList GetMusicFilter()
Definition: mythmusic.cpp:461
int mythplugin_init(const char *libversion)
Definition: mythmusic.cpp:894
static void * m_callbackdata
Definition: mythmusic.cpp:269
static MythThemedMenu * menu
MythUIHelper * GetMythUI()
@ PL_REPLACE
Definition: playlist.h:24