MythTV master
streamview.cpp
Go to the documentation of this file.
1// C++ headers
2#include <chrono>
3#include <cstdlib>
4#include <iostream>
5
6// qt
7#include <QDomDocument>
8#include <QKeyEvent>
9#include <QThread>
10
11// MythTV
12#include <libmythbase/mythdb.h>
26
27// mythmusic
28#include "musiccommon.h"
29#include "musicdata.h"
30#include "musicplayer.h"
31#include "streamview.h"
32
34 : MusicCommon(parent, parentScreen, "streamview")
35{
37}
38
40{
41 // Load the theme for this screen
42 bool err = LoadWindowFromXML("stream-ui.xml", "streamview", this);
43
44 if (!err)
45 return false;
46
47 // find common widgets available on any view
48 err = CreateCommon();
49
50 // find widgets specific to this view
51 UIUtilE::Assign(this, m_streamList, "streamlist", &err);
52 UIUtilW::Assign(this, m_bufferStatus, "bufferstatus", &err);
53 UIUtilW::Assign(this, m_bufferProgress, "bufferprogress", &err);
54 UIUtilW::Assign(this, m_noStreams, "nostreams", &err);
55
56 if (err)
57 {
58 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'streamview'");
59 return false;
60 }
61
66
68
71
73
74 return true;
75}
76
78{
79 auto *menu = new MythMenu(tr("Stream Actions"), this, "mainmenu");
80 menu->AddItemV(MusicCommon::tr("Fullscreen Visualizer"), QVariant::fromValue((int)MV_VISUALIZER));
81 menu->AddItem(tr("Add Stream"));
82
84 {
85 menu->AddItem(tr("Edit Stream"));
86 menu->AddItem(tr("Remove Stream"));
87 }
88
89 menu->AddItemV(MusicCommon::tr("Lyrics"), QVariant::fromValue((int)MV_LYRICS));
90
91 menu->AddItem(tr("More Options"), nullptr, createSubMenu());
92
93 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
94
95 auto *menuPopup = new MythDialogBox(menu, popupStack, "actionmenu");
96
97 if (menuPopup->Create())
98 popupStack->AddScreen(menuPopup);
99 else
100 delete menu;
101}
102
103void StreamView::customEvent(QEvent *event)
104{
105 bool handled = true;
106
108 {
109 if (!gPlayer->getPlayedTracksList().isEmpty())
111
112 // add the new track to the list
114 {
115 MusicMetadata *mdata = gPlayer->getPlayedTracksList().last();
116
117 auto *item = new MythUIButtonListItem(m_playedTracksList, "",
118 QVariant::fromValue(mdata), 0);
119
120 InfoMap metadataMap;
121 mdata->toMap(metadataMap);
122 item->SetTextFromMap(metadataMap);
123 item->SetFontState("normal");
124 item->DisplayState("default", "playstate");
125 item->SetImage(mdata->getAlbumArtFile());
126
128 }
129 }
130 else if (event->type() == MusicPlayerEvent::kTrackChangeEvent)
131 {
132 auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
133
134 if (!mpe)
135 return;
136
137 if (m_streamList)
138 {
139 MythUIButtonListItem *item = m_streamList->GetItemByData(QVariant::fromValue(m_currStream));
140 if (item)
141 {
142 item->SetFontState("normal");
143 item->DisplayState("default", "playstate");
144 }
145
147 {
150 }
151
152 item = m_streamList->GetItemByData(QVariant::fromValue(m_currStream));
153 if (item)
154 {
155 if (gPlayer->isPlaying())
156 {
157 item->SetFontState("running");
158 item->DisplayState("playing", "playstate");
159 }
160 else if (gPlayer->isPaused())
161 {
162 item->SetFontState("idle");
163 item->DisplayState("paused", "playstate");
164 }
165 else
166 {
167 item->SetFontState("normal");
168 item->DisplayState("stopped", "playstate");
169 }
170 }
171 }
172
174 }
175 else if (event->type() == AudioOutput::Event::kPlaying)
176 {
177 if (gPlayer->isPlaying())
178 {
179 if (m_streamList)
180 {
181 MythUIButtonListItem *item = m_streamList->GetItemByData(QVariant::fromValue(m_currStream));
182 if (item)
183 {
184 item->SetFontState("running");
185 item->DisplayState("playing", "playstate");
186 }
187 }
188 }
189
190 // pass it on to the default handler in MusicCommon
191 handled = false;
192 }
193 else if (event->type() == AudioOutput::Event::kStopped)
194 {
195 if (m_streamList)
196 {
197 MythUIButtonListItem *item = m_streamList->GetItemByData(QVariant::fromValue(m_currStream));
198 if (item)
199 {
200 item->SetFontState("normal");
201 item->DisplayState("stopped", "playstate");
202 }
203 }
204
205 // pass it on to the default handler in MusicCommon
206 handled = false;
207 }
208 else if (event->type() == AudioOutput::Event::kBuffering)
209 {
210 }
211 else if (event->type() == MythEvent::kMythEventMessage)
212 {
213 auto *me = dynamic_cast<MythEvent *>(event);
214 if (me == nullptr)
215 return;
216 QStringList tokens = me->Message().split(" ", Qt::SkipEmptyParts);
217
218 if (tokens.isEmpty())
219 return;
220
221 if (tokens[0] == "DOWNLOAD_FILE")
222 {
223 QStringList args = me->ExtraDataList();
224
225 if (tokens[1] == "UPDATE")
226 {
227 }
228 else if (tokens[1] == "FINISHED")
229 {
230 const QString& url = args[0];
231 int fileSize = args[2].toInt();
232 int errorCode = args[4].toInt();
233 const QString& filename = args[1];
234
235 if ((errorCode != 0) || (fileSize == 0))
236 {
237 LOG(VB_GENERAL, LOG_ERR, QString("StreamView: failed to download radio icon from '%1'").arg(url));
238 }
239 else
240 {
241 for (int x = 0; x < m_streamList->GetCount(); x++)
242 {
244 auto *mdata = item->GetData().value<MusicMetadata *>();
245 if (mdata && mdata->LogoUrl() == url)
246 item->SetImage(filename);
247 }
248 }
249 }
250 }
251 }
252 else if (event->type() == DecoderHandlerEvent::kOperationStart)
253 {
254 auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
255 if (!dhe)
256 return;
257 if (dhe->getMessage() && m_bufferStatus)
258 {
259 m_bufferStatus->SetText(*dhe->getMessage());
260 }
261 }
262 else if (event->type() == DecoderHandlerEvent::kBufferStatus)
263 {
264 auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
265 if (!dhe)
266 return;
267
268 int available = 0;
269 int maxSize = 0;
270 dhe->getBufferStatus(&available, &maxSize);
271
272 if (m_bufferStatus)
273 {
274 QString status = QString("%1%").arg((int)(100.0 / ((double)maxSize / (double)available)));
275 m_bufferStatus->SetText(status);
276 }
277
279 {
280 m_bufferProgress->SetTotal(maxSize);
281 m_bufferProgress->SetUsed(available);
282 }
283 }
284 else if (event->type() == DecoderHandlerEvent::kOperationStop)
285 {
286 if (m_bufferStatus)
288 }
289 else if (event->type() == DialogCompletionEvent::kEventType)
290 {
291 auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
292
293 // make sure the user didn't ESCAPE out of the menu
294 if ((dce == nullptr) || (dce->GetResult() < 0))
295 return;
296
297 QString resultid = dce->GetId();
298 QString resulttext = dce->GetResultText();
299
300 if (resultid == "mainmenu")
301 {
302 if (resulttext == tr("Add Stream"))
303 {
305 MythScreenType *screen = new EditStreamMetadata(mainStack, this, nullptr);
306
307 if (screen->Create())
308 mainStack->AddScreen(screen);
309 else
310 delete screen;
311 }
312 else if (resulttext == tr("Remove Stream"))
313 {
314 removeStream();
315 }
316 else if (resulttext == tr("Edit Stream"))
317 {
318 editStream();
319 }
320 else
321 {
322 handled = false;
323 }
324 }
325 else
326 {
327 handled = false;
328 }
329 }
330 else
331 {
332 handled = false;
333 }
334
335
336 if (!handled)
338}
339
340bool StreamView::keyPressEvent(QKeyEvent *event)
341{
343 return true;
344
345 QStringList actions;
346 bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
347
348 for (int i = 0; i < actions.size() && !handled; i++)
349 {
350 const QString& action = actions[i];
351 handled = true;
352
353 if (action == "EDIT")
354 {
355 editStream();
356 }
357 else if (action == "DELETE")
358 {
359 removeStream();
360 }
361 else if (action == "TOGGLELAST")
362 {
364 {
365 m_streamList->SetValueByData(QVariant::fromValue(m_lastStream));
366
368 if (item)
369 streamItemClicked(item);
370 }
371 }
372 else
373 {
374 handled = false;
375 }
376 }
377
378 if (!handled && MusicCommon::keyPressEvent(event))
379 handled = true;
380
381 return handled;
382}
383
385{
387 if (item)
388 {
389 auto *mdata = item->GetData().value<MusicMetadata *>();
391 MythScreenType *screen = new EditStreamMetadata(mainStack, this, mdata);
392
393 if (screen->Create())
394 mainStack->AddScreen(screen);
395 else
396 delete screen;
397 }
398}
399
401{
403 if (item)
404 {
405 auto *mdata = item->GetData().value<MusicMetadata *>();
406
407 if (mdata)
408 {
409 ShowOkPopup(tr("Are you sure you want to delete this Stream?\n"
410 "Broadcaster: %1 - Channel: %2")
411 .arg(mdata->Broadcaster(), mdata->Channel()),
412 this, &StreamView::doRemoveStream, true);
413 }
414 }
415}
416
418{
419 if (!ok)
420 return;
421
423 if (item)
424 {
425 auto *mdata = item->GetData().value<MusicMetadata *>();
426
427 if (mdata)
428 deleteStream(mdata);
429 }
430}
431
433{
434 Playlist *playlist = gPlayer->getCurrentPlaylist();
435 if (nullptr == playlist)
436 return;
437
439
440 bool foundActiveStream = false;
441
442 for (int x = 0; x < playlist->getTrackCount(); x++)
443 {
444 MusicMetadata *mdata = playlist->getSongAt(x);
445 auto *item = new MythUIButtonListItem(m_streamList, "",
446 QVariant::fromValue(mdata));
447 InfoMap metadataMap;
448 if (mdata)
449 mdata->toMap(metadataMap);
450 item->SetTextFromMap(metadataMap);
451 item->SetText("", "imageloaded");
452 item->SetFontState("normal");
453 item->DisplayState("default", "playstate");
454
455 // if this is the current radio stream update its play state to match the player
456 if (gPlayer->getCurrentMetadata() && mdata &&
457 mdata->ID() == gPlayer->getCurrentMetadata()->ID())
458 {
459 if (gPlayer->isPlaying())
460 {
461 item->SetFontState("running");
462 item->DisplayState("playing", "playstate");
463 }
464 else if (gPlayer->isPaused())
465 {
466 item->SetFontState("idle");
467 item->DisplayState("paused", "playstate");
468 }
469 else
470 {
471 item->SetFontState("normal");
472 item->DisplayState("stopped", "playstate");
473 }
474
476
478
479 foundActiveStream = true;
480 }
481 }
482
483 if (m_streamList->GetCount() > 0 && !foundActiveStream)
484 {
486 gPlayer->stop(true);
487 }
488
489 if (m_noStreams)
491
492 if (m_streamList->GetCount() == 0)
493 LOG(VB_GENERAL, LOG_ERR, "StreamView hasn't found any streams!");
494}
495
497{
498 if (!item)
499 return;
500
502}
503
505{
506 if (!item)
507 return;
508
509 if (!item->GetText("imageloaded").isEmpty())
510 return;
511
512 auto *mdata = item->GetData().value<MusicMetadata *>();
513 if (mdata)
514 {
515 if (!mdata->LogoUrl().isEmpty())
516 item->SetImage(mdata->getAlbumArtFile());
517 else
518 item->SetImage("");
519 }
520
521 item->SetText(" ", "imageloaded");
522}
523
525{
526 // sanity check this is a radio stream
527 int repo = ID_TO_REPO(mdata->ID());
528 if (repo != RT_Radio)
529 {
530 LOG(VB_GENERAL, LOG_ERR, "StreamView asked to add a stream but it isn't a radio stream!");
531 return;
532 }
533
534 QString url = mdata->Url();
535
537
539
541
542 // find the new stream and make it the active item
543 for (int x = 0; x < m_streamList->GetCount(); x++)
544 {
546 auto *itemsdata = item->GetData().value<MusicMetadata *>();
547 if (itemsdata)
548 {
549 if (url == itemsdata->Url())
550 {
552 break;
553 }
554 }
555 }
556}
557
559{
560 // sanity check this is a radio stream
561 int repo = ID_TO_REPO(mdata->ID());
562 if (repo != RT_Radio)
563 {
564 LOG(VB_GENERAL, LOG_ERR, "StreamView asked to update a stream but it isn't a radio stream!");
565 return;
566 }
567
568 MusicMetadata::IdType id = mdata->ID();
569
571
573
574 // update mdata to point to the new item
576
577 if (!mdata)
578 return;
579
580 // force the icon to reload incase it changed
581 QFile::remove(mdata->getAlbumArtFile());
582 mdata->reloadAlbumArtImages();
583
585
586 // if we just edited the currently playing stream update the current metadata to match
587 MusicMetadata *currentMetadata = gPlayer->getCurrentMetadata();
588 if (id == currentMetadata->ID())
589 {
590 currentMetadata->setBroadcaster(mdata->Broadcaster());
591 currentMetadata->setChannel(mdata->Channel());
592 }
593
594 // update the played tracks list to match the new metadata
596 {
597 for (int x = 0; x < m_playedTracksList->GetCount(); x++)
598 {
600 auto *playedmdata = item->GetData().value<MusicMetadata *>();
601
602 if (playedmdata && playedmdata->ID() == id)
603 {
604 playedmdata->setBroadcaster(mdata->Broadcaster());
605 playedmdata->setChannel(mdata->Channel());
606
607 InfoMap metadataMap;
608 playedmdata->toMap(metadataMap);
609 item->SetTextFromMap(metadataMap);
610 }
611 }
612 }
613
614 // find the stream and make it the active item
615 for (int x = 0; x < m_streamList->GetCount(); x++)
616 {
618 auto *itemsdata = item->GetData().value<MusicMetadata *>();
619 if (itemsdata)
620 {
621 if (mdata->ID() == itemsdata->ID())
622 {
624 break;
625 }
626 }
627 }
628}
629
631{
632 // sanity check this is a radio stream
633 int repo = ID_TO_REPO(mdata->ID());
634 if (repo != RT_Radio)
635 {
636 LOG(VB_GENERAL, LOG_ERR, "StreamView asked to delete a stream but it isn't a radio stream!");
637 return;
638 }
639
640 int currPos = m_streamList->GetCurrentPos();
641 int topPos = m_streamList->GetTopItemPos();
642
643 // if we are playing this radio stream stop playing
644 if (gPlayer->getCurrentMetadata() == mdata)
645 gPlayer->stop(true);
646
648
650
652
653 m_streamList->SetItemCurrent(currPos, topPos);
654}
655
657
659{
660 if (!LoadWindowFromXML("stream-ui.xml", "editstreammetadata", this))
661 return false;
662
663 bool err = false;
664 UIUtilE::Assign(this, m_broadcasterEdit, "broadcasteredit", &err);
665 UIUtilE::Assign(this, m_channelEdit, "channeledit", &err);
666 UIUtilE::Assign(this, m_descEdit, "descriptionedit", &err);
667 UIUtilE::Assign(this, m_url1Edit, "url1edit", &err);
668 UIUtilE::Assign(this, m_url2Edit, "url2edit", &err);
669 UIUtilE::Assign(this, m_url3Edit, "url3edit", &err);
670 UIUtilE::Assign(this, m_url4Edit, "url4edit", &err);
671 UIUtilE::Assign(this, m_url5Edit, "url5edit", &err);
672 UIUtilE::Assign(this, m_logourlEdit, "logourledit" , &err);
673 UIUtilE::Assign(this, m_genreEdit, "genreedit", &err);
674 UIUtilE::Assign(this, m_languageEdit, "languageedit", &err);
675 UIUtilE::Assign(this, m_countryEdit, "countryedit", &err);
676 UIUtilE::Assign(this, m_formatEdit, "formatedit", &err);
677 UIUtilE::Assign(this, m_saveButton, "savebutton", &err);
678 UIUtilE::Assign(this, m_cancelButton, "cancelbutton", &err);
679 UIUtilE::Assign(this, m_searchButton, "searchbutton", &err);
680
681 if (err)
682 {
683 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'editstreampopup'");
684 return false;
685 }
686
687 if (m_streamMeta)
688 {
702 }
703 else
704 {
705 m_formatEdit->SetText("%a - %t");
706 }
707
711
713
714 return true;
715}
716
718{
720 MythScreenType *screen = new SearchStream(mainStack, this);
721
722 if (screen->Create())
723 mainStack->AddScreen(screen);
724 else
725 delete screen;
726
727}
728
730{
731 bool doUpdate = true;
732
733 if (!m_streamMeta)
734 {
737 doUpdate = false;
738 }
739
747 m_streamMeta->setFormat("cast");
754
755 if (doUpdate)
757 else
759
760 Close();
761}
762
764{
765 if (mdata)
766 {
768 m_channelEdit->SetText(mdata->Channel());
769 m_url1Edit->SetText(mdata->Url(0));
770 m_url2Edit->SetText(mdata->Url(1));
771 m_url3Edit->SetText(mdata->Url(2));
772 m_url4Edit->SetText(mdata->Url(3));
773 m_url5Edit->SetText(mdata->Url(4));
774 m_logourlEdit->SetText(mdata->LogoUrl());
775 m_genreEdit->SetText(mdata->Genre());
777 m_descEdit->SetText(mdata->Description());
778 m_countryEdit->SetText(mdata->Country());
780 }
781}
782
784
786{
787 if (!LoadWindowFromXML("stream-ui.xml", "searchstream", this))
788 return false;
789
790 bool err = false;
791 UIUtilE::Assign(this, m_broadcasterList, "broadcasterlist", &err);
792 UIUtilE::Assign(this, m_genreList, "genrelist", &err);
793 UIUtilW::Assign(this, m_languageList, "languagelist", &err);
794 UIUtilW::Assign(this, m_countryList, "countrylist", &err);
795 UIUtilE::Assign(this, m_streamList, "streamlist", &err);
796 UIUtilE::Assign(this, m_channelEdit, "channeledit", &err);
797 UIUtilE::Assign(this, m_matchesText, "matchestext", &err);
798
799 if (err)
800 {
801 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'searchstream'");
802 return false;
803 }
804
808
817
818
819 if (m_countryList)
820 {
823
827 }
828
829 if (m_languageList)
830 {
834 }
835
837
838 LoadInBackground("Loading Streams...");
839
841
842 return true;
843}
844
846{
847 loadStreams();
848 QTimer::singleShot(0, this, &SearchStream::doneLoading);
849}
850
852{
854 updateGenres();
858}
859
861{
862 if (!item)
863 return;
864
865 auto mdata = item->GetData().value<MusicMetadata>();
867
868 Close();
869}
870
872{
873 if (!item)
874 return;
875
876 auto mdata = item->GetData().value<MusicMetadata>();
877 if (!mdata.LogoUrl().isEmpty() && mdata.LogoUrl() != "-")
878 {
879 if (item->GetText("dummy") == " ")
880 {
881 item->SetImage(mdata.LogoUrl());
882 item->SetText("", "dummy");
883 }
884 }
885}
886
888{
890}
891
893{
895
896 new MythUIButtonListItem(m_broadcasterList, tr("<All Broadcasters>"));
897
899
900 query.prepare("SELECT DISTINCT broadcaster FROM music_streams ORDER BY broadcaster;");
901
902 if (!query.exec() || !query.isActive())
903 {
904 MythDB::DBError("get broadcaster", query);
905 return;
906 }
907
908 while (query.next())
909 {
910 new MythUIButtonListItem(m_broadcasterList, query.value(0).toString());
911 }
912
913 m_broadcasterList->SetValue(tr("<All Broadcasters>"));
914}
915
917{
919
920 new MythUIButtonListItem(m_genreList, tr("<All Genres>"));
921
923
924 query.prepare("SELECT DISTINCT genre FROM music_streams ORDER BY genre;");
925
926 if (!query.exec() || !query.isActive())
927 {
928 MythDB::DBError("get genres", query);
929 return;
930 }
931
932 while (query.next())
933 {
934 new MythUIButtonListItem(m_genreList, query.value(0).toString());
935 }
936
937 m_genreList->SetValue(tr("<All Genres>"));
938}
939
941{
942 if (m_countryList)
943 {
945
946 new MythUIButtonListItem(m_countryList, tr("<All Countries>"));
947
949
950 query.prepare("SELECT DISTINCT country FROM music_streams ORDER BY country;");
951
952 if (!query.exec() || !query.isActive())
953 {
954 MythDB::DBError("get countries", query);
955 return;
956 }
957
958 while (query.next())
959 {
960 new MythUIButtonListItem(m_countryList, query.value(0).toString());
961 }
962
963 m_countryList->SetValue(tr("<All Countries>"));
964 }
965}
966
968{
969 if (m_languageList)
970 {
972
973 new MythUIButtonListItem(m_languageList, tr("<All Languages>"));
974
976
977 query.prepare("SELECT DISTINCT language FROM music_streams ORDER BY language;");
978
979 if (!query.exec() || !query.isActive())
980 {
981 MythDB::DBError("get languages", query);
982 return;
983 }
984
985 while (query.next())
986 {
987 new MythUIButtonListItem(m_languageList, query.value(0).toString());
988 }
989
990 m_languageList->SetValue(tr("<All Languages>"));
991 }
992}
993
995{
996 if (m_updateTimer.isActive())
997 m_updateTimer.stop();
998
999 m_updateTimer.start(500ms);
1000}
1001
1003{
1004 if (m_updating)
1005 return;
1006
1007 QString broadcaster = m_broadcasterList->GetValue();
1008 QString genre = m_genreList->GetValue();
1009 QString language = m_languageList ? m_languageList->GetValue() : tr("<All Languages>");
1010 QString country = m_countryList ? m_countryList->GetValue() : tr("<All Countries>");
1011 QString channel = m_channelEdit->GetText();
1012
1013 // only update the buttonlist if something changed
1014 if (m_oldBroadcaster == broadcaster && m_oldGenre == genre && m_oldChannel == channel &&
1015 m_oldLanguage == language && m_oldCountry == country)
1016 return;
1017
1018 m_oldBroadcaster = broadcaster;
1019 m_oldGenre = genre;
1020 m_oldChannel = channel;
1021 m_oldLanguage = language;
1022 m_oldCountry = country;
1023
1024 bool searchBroadcaster = (broadcaster != tr("<All Broadcasters>"));
1025 bool searchGenre = (genre != tr("<All Genres>"));
1026 bool searchLanguage = (language != tr("<All Languages>"));
1027 bool searchCountry = (country != tr("<All Countries>"));
1028 bool searchChannel = !channel.isEmpty();
1029
1030 m_streams.clear();
1032
1034
1035 QString sql = "SELECT broadcaster, channel, description, genre, url1, url2, url3, url4, url5, "
1036 "logourl, metaformat, country, language "
1037 "FROM music_streams ";
1038 bool doneWhere = false;
1039
1040 if (searchBroadcaster)
1041 {
1042 sql += "WHERE broadcaster = :BROADCASTER ";
1043 doneWhere = true;
1044 }
1045
1046 if (searchGenre)
1047 {
1048 if (!doneWhere)
1049 {
1050 sql += "WHERE genre = :GENRE ";
1051 doneWhere = true;
1052 }
1053 else
1054 {
1055 sql += "AND genre = :GENRE ";
1056 }
1057 }
1058
1059 if (searchLanguage)
1060 {
1061 if (!doneWhere)
1062 {
1063 sql += "WHERE language = :LANGUAGE ";
1064 doneWhere = true;
1065 }
1066 else
1067 {
1068 sql += "AND language = :LANGUAGE ";
1069 }
1070 }
1071
1072 if (searchCountry)
1073 {
1074 if (!doneWhere)
1075 {
1076 sql += "WHERE country = :COUNTRY ";
1077 doneWhere = true;
1078 }
1079 else
1080 {
1081 sql += "AND country = :COUNTRY ";
1082 }
1083 }
1084
1085 if (searchChannel)
1086 {
1087 if (!doneWhere)
1088 {
1089 sql += "WHERE channel LIKE " + QString("'%%1%'").arg(channel);
1090 // doneWhere = true;
1091 }
1092 else
1093 {
1094 sql += "AND channel LIKE " + QString("'%%1%' ").arg(channel);
1095 }
1096 }
1097
1098 sql += "ORDER BY broadcaster, channel;";
1099
1100 query.prepare(sql);
1101
1102 if (searchBroadcaster)
1103 query.bindValue(":BROADCASTER", broadcaster);
1104
1105 if (searchGenre)
1106 query.bindValue(":GENRE", genre);
1107
1108 if (searchLanguage)
1109 query.bindValue(":LANGUAGE", language);
1110
1111 if (searchCountry)
1112 query.bindValue(":COUNTRY", country);
1113
1114 if (!query.exec() || !query.isActive())
1115 {
1116 MythDB::DBError("search streams", query);
1117 return;
1118 }
1119
1120 if (query.size() > 500)
1121 {
1122 QString message = tr("Updating stream list. Please Wait ...");
1123 OpenBusyPopup(message);
1124 }
1125
1126 int count = 0;
1127 while (query.next())
1128 {
1129 MusicMetadata mdata;
1130 mdata.setBroadcaster(query.value(0).toString());
1131 mdata.setChannel(query.value(1).toString());
1132 mdata.setDescription(query.value(2).toString());
1133 mdata.setGenre(query.value(3).toString());
1134
1135 for (size_t x = 0; x < STREAMURLCOUNT; x++)
1136 mdata.setUrl(query.value(4 + x).toString(), x);
1137
1138 mdata.setLogoUrl(query.value(9).toString());
1139 mdata.setMetadataFormat(query.value(10).toString());
1140 mdata.setCountry(query.value(11).toString());
1141 mdata.setLanguage(query.value(12).toString());
1142
1143 auto *item = new MythUIButtonListItem(m_streamList, "",
1144 QVariant::fromValue(mdata));
1145 InfoMap metadataMap;
1146 mdata.toMap(metadataMap);
1147
1148 item->SetTextFromMap(metadataMap);
1149
1150 item->SetText(" ", "dummy");
1151 count++;
1152
1153 if ((count % 500) == 0)
1154 {
1155 qApp->processEvents();
1156 }
1157 }
1158
1159 m_matchesText->SetText(QString("%1").arg(m_streamList->GetCount()));
1160
1161 if (query.size() > 500)
1163
1164 m_updating = false;
1165}
1166
1167#include "moc_streamview.cpp"
void removeStream(MusicMetadata *mdata)
void updateStream(MusicMetadata *mdata)
MusicMetadata * getMetadata(MusicMetadata::IdType an_id)
void addStream(MusicMetadata *mdata)
Events sent by the DecoderHandler and it's helper classes.
static const Type kBufferStatus
static const Type kOperationStart
void getBufferStatus(int *available, int *maxSize) const
static const Type kOperationStop
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:40
static const Type kEventType
Definition: mythdialogbox.h:55
MythUITextEdit * m_formatEdit
Definition: streamview.h:87
void searchClicked(void)
Definition: streamview.cpp:717
MythUIButton * m_saveButton
Definition: streamview.h:94
MythUITextEdit * m_url4Edit
Definition: streamview.h:84
MythUIButton * m_searchButton
Definition: streamview.h:92
void changeStreamMetadata(MusicMetadata *mdata)
Definition: streamview.cpp:763
StreamView * m_parent
Definition: streamview.h:74
MythUITextEdit * m_logourlEdit
Definition: streamview.h:86
MythUITextEdit * m_url5Edit
Definition: streamview.h:85
MythUITextEdit * m_url3Edit
Definition: streamview.h:83
MythUITextEdit * m_languageEdit
Definition: streamview.h:90
MythUITextEdit * m_broadcasterEdit
Definition: streamview.h:78
MythUITextEdit * m_url1Edit
Definition: streamview.h:81
MythUITextEdit * m_channelEdit
Definition: streamview.h:79
void saveClicked(void)
Definition: streamview.cpp:729
MusicMetadata * m_streamMeta
Definition: streamview.h:76
bool Create() override
Definition: streamview.cpp:658
MythUITextEdit * m_countryEdit
Definition: streamview.h:89
MythUITextEdit * m_url2Edit
Definition: streamview.h:82
MythUITextEdit * m_descEdit
Definition: streamview.h:80
MythUIButton * m_cancelButton
Definition: streamview.h:93
MythUITextEdit * m_genreEdit
Definition: streamview.h:88
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:839
QVariant value(int i) const
Definition: mythdbcon.h:204
int size(void) const
Definition: mythdbcon.h:214
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:620
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:890
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
MusicView m_currentView
Definition: musiccommon.h:143
void updateTrackInfo(MusicMetadata *mdata)
bool CreateCommon(void)
Definition: musiccommon.cpp:78
void updateUIPlayedList(void)
MythMenu * createSubMenu(void)
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
MythUIButtonList * m_playedTracksList
Definition: musiccommon.h:208
void customEvent(QEvent *event) override
AllStream * m_all_streams
Definition: musicdata.h:53
void setRepo(RepoType repo)
void setMetadataFormat(const QString &metaformat)
void setChannel(const QString &channel)
QString Language(void)
void setGenre(const QString &lgenre)
QString Country(void)
void setFormat(const QString &lformat)
void setLogoUrl(const QString &logourl)
void setCountry(const QString &country)
void toMap(InfoMap &metadataMap, const QString &prefix="")
QString Broadcaster(void)
void reloadAlbumArtImages(void)
QString MetadataFormat(void)
QString getAlbumArtFile(void)
void setLanguage(const QString &language)
QString Channel(void)
IdType ID() const
QString Url(size_t index=0)
QString LogoUrl(void)
uint32_t IdType
Definition: musicmetadata.h:87
QString Genre() const
void setBroadcaster(const QString &broadcaster)
QString Description(void)
void setUrl(const QString &url, size_t index=0)
static bool updateStreamList(void)
void setDescription(const QString &description)
static const Type kPlayedTracksChangedEvent
Definition: musicplayer.h:50
static const Type kTrackChangeEvent
Definition: musicplayer.h:39
MusicMetadata * getCurrentMetadata(void)
get the metadata for the current track in the playlist
void setPlayMode(PlayMode mode)
void stop(bool stopAll=false)
void loadStreamPlaylist(void)
bool isPaused(void)
Definition: musicplayer.h:110
QList< MusicMetadata * > & getPlayedTracksList(void)
Definition: musicplayer.h:141
bool isPlaying(void) const
Definition: musicplayer.h:109
bool setCurrentTrackPos(int pos)
Playlist * getCurrentPlaylist(void)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
Basic menu dialog, message and a list of options.
This class is used as a container for messages.
Definition: mythevent.h:17
const QString & Message() const
Definition: mythevent.h:65
static const Type kMythEventMessage
Definition: mythevent.h:79
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 LoadInBackground(const QString &message="")
virtual bool Create(void)
void OpenBusyPopup(const QString &message="")
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
void CloseBusyPopup(void)
virtual void Close()
void SetFontState(const QString &state, const QString &name="")
void DisplayState(const QString &state, const QString &name)
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
QString GetText(const QString &name="") const
void SetText(const QString &text, const QString &name="", const QString &state="")
virtual QString GetValue() const
MythUIButtonListItem * GetItemCurrent() const
void itemVisible(MythUIButtonListItem *item)
void SetItemCurrent(MythUIButtonListItem *item)
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
int GetTopItemPos(void) const
MythUIButtonListItem * GetItemByData(const QVariant &data)
virtual void SetValue(int value)
int GetCurrentPos() const
void itemClicked(MythUIButtonListItem *item)
MythUIButtonListItem * GetItemAt(int pos) const
void SetValueByData(const QVariant &data)
void itemSelected(MythUIButtonListItem *item)
void Clicked()
void SetUsed(int value)
void SetTotal(int value)
QString GetText(void) const
void SetText(const QString &text, bool moveCursor=true)
void valueChanged()
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)
int getTrackCount(void)
Definition: playlist.h:82
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1089
static void loadStreams(void)
Definition: streamview.cpp:887
static void streamVisible(MythUIButtonListItem *item)
Definition: streamview.cpp:871
QList< MusicMetadata > m_streams
Definition: streamview.h:125
QString m_oldBroadcaster
Definition: streamview.h:129
void updateGenres(void)
Definition: streamview.cpp:916
bool Create() override
Definition: streamview.cpp:785
void updateBroadcasters(void)
Definition: streamview.cpp:892
void updateCountries(void)
Definition: streamview.cpp:940
MythUITextEdit * m_channelEdit
Definition: streamview.h:139
void doneLoading(void)
Definition: streamview.cpp:851
QString m_oldLanguage
Definition: streamview.h:133
void updateStreams(void)
Definition: streamview.cpp:994
QString m_oldChannel
Definition: streamview.h:131
MythUIButtonList * m_broadcasterList
Definition: streamview.h:135
QString m_oldGenre
Definition: streamview.h:130
MythUIButtonList * m_streamList
Definition: streamview.h:140
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
Definition: streamview.cpp:845
MythUIText * m_matchesText
Definition: streamview.h:141
QTimer m_updateTimer
Definition: streamview.h:143
QString m_oldCountry
Definition: streamview.h:132
void doUpdateStreams(void)
EditStreamMetadata * m_parent
Definition: streamview.h:124
bool m_updating
Definition: streamview.h:144
void updateLanguages(void)
Definition: streamview.cpp:967
MythUIButtonList * m_countryList
Definition: streamview.h:137
void streamClicked(MythUIButtonListItem *item)
Definition: streamview.cpp:860
MythUIButtonList * m_languageList
Definition: streamview.h:138
MythUIButtonList * m_genreList
Definition: streamview.h:136
void addStream(MusicMetadata *mdata)
Definition: streamview.cpp:524
static void streamItemVisible(MythUIButtonListItem *item)
Definition: streamview.cpp:504
bool Create(void) override
Definition: streamview.cpp:39
void streamItemClicked(MythUIButtonListItem *item)
Definition: streamview.cpp:496
MythUIText * m_noStreams
Definition: streamview.h:48
MusicMetadata * m_lastStream
Definition: streamview.h:53
void customEvent(QEvent *event) override
Definition: streamview.cpp:103
MythUIText * m_bufferStatus
Definition: streamview.h:49
void updateStream(MusicMetadata *mdata)
Definition: streamview.cpp:558
void deleteStream(MusicMetadata *mdata)
Definition: streamview.cpp:630
MythUIProgressBar * m_bufferProgress
Definition: streamview.h:50
void doRemoveStream(bool ok)
Definition: streamview.cpp:417
void ShowMenu(void) override
Definition: streamview.cpp:77
StreamView(MythScreenStack *parent, MythScreenType *parentScreen)
Definition: streamview.cpp:33
void updateStreamList(void)
Definition: streamview.cpp:432
void removeStream(void)
Definition: streamview.cpp:400
void editStream(void)
Definition: streamview.cpp:384
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: streamview.cpp:340
MusicMetadata * m_currStream
Definition: streamview.h:52
MythUIButtonList * m_streamList
Definition: streamview.h:47
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
@ MV_LYRICS
Definition: musiccommon.h:34
@ MV_RADIO
Definition: musiccommon.h:42
@ MV_VISUALIZER
Definition: musiccommon.h:37
MusicData * gMusicData
Definition: musicdata.cpp:23
@ RT_Radio
Definition: musicmetadata.h:64
static constexpr size_t STREAMURLCOUNT
Definition: musicmetadata.h:77
static constexpr uint32_t ID_TO_REPO(uint32_t x)
Definition: musicmetadata.h:73
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
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
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27