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() == OutputEvent::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() == OutputEvent::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() == OutputEvent::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 LOG(VB_GENERAL, LOG_ERR, QString("StreamView: failed to download radio icon from '%1'").arg(url));
237 else
238 {
239 for (int x = 0; x < m_streamList->GetCount(); x++)
240 {
242 auto *mdata = item->GetData().value<MusicMetadata *>();
243 if (mdata && mdata->LogoUrl() == url)
244 item->SetImage(filename);
245 }
246 }
247 }
248 }
249 }
250 else if (event->type() == DecoderHandlerEvent::kOperationStart)
251 {
252 auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
253 if (!dhe)
254 return;
255 if (dhe->getMessage() && m_bufferStatus)
256 {
257 m_bufferStatus->SetText(*dhe->getMessage());
258 }
259 }
260 else if (event->type() == DecoderHandlerEvent::kBufferStatus)
261 {
262 auto *dhe = dynamic_cast<DecoderHandlerEvent*>(event);
263 if (!dhe)
264 return;
265
266 int available = 0;
267 int maxSize = 0;
268 dhe->getBufferStatus(&available, &maxSize);
269
270 if (m_bufferStatus)
271 {
272 QString status = QString("%1%").arg((int)(100.0 / ((double)maxSize / (double)available)));
273 m_bufferStatus->SetText(status);
274 }
275
277 {
278 m_bufferProgress->SetTotal(maxSize);
279 m_bufferProgress->SetUsed(available);
280 }
281 }
282 else if (event->type() == DecoderHandlerEvent::kOperationStop)
283 {
284 if (m_bufferStatus)
286 }
287 else if (event->type() == DialogCompletionEvent::kEventType)
288 {
289 auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
290
291 // make sure the user didn't ESCAPE out of the menu
292 if ((dce == nullptr) || (dce->GetResult() < 0))
293 return;
294
295 QString resultid = dce->GetId();
296 QString resulttext = dce->GetResultText();
297
298 if (resultid == "mainmenu")
299 {
300 if (resulttext == tr("Add Stream"))
301 {
303 MythScreenType *screen = new EditStreamMetadata(mainStack, this, nullptr);
304
305 if (screen->Create())
306 mainStack->AddScreen(screen);
307 else
308 delete screen;
309 }
310 else if (resulttext == tr("Remove Stream"))
311 {
312 removeStream();
313 }
314 else if (resulttext == tr("Edit Stream"))
315 {
316 editStream();
317 }
318 else
319 {
320 handled = false;
321 }
322 }
323 else
324 {
325 handled = false;
326 }
327 }
328 else
329 {
330 handled = false;
331 }
332
333
334 if (!handled)
336}
337
338bool StreamView::keyPressEvent(QKeyEvent *event)
339{
341 return true;
342
343 QStringList actions;
344 bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions);
345
346 for (int i = 0; i < actions.size() && !handled; i++)
347 {
348 const QString& action = actions[i];
349 handled = true;
350
351 if (action == "EDIT")
352 {
353 editStream();
354 }
355 else if (action == "DELETE")
356 {
357 removeStream();
358 }
359 else if (action == "TOGGLELAST")
360 {
362 {
363 m_streamList->SetValueByData(QVariant::fromValue(m_lastStream));
364
366 if (item)
367 streamItemClicked(item);
368 }
369 }
370 else
371 {
372 handled = false;
373 }
374 }
375
376 if (!handled && MusicCommon::keyPressEvent(event))
377 handled = true;
378
379 return handled;
380}
381
383{
385 if (item)
386 {
387 auto *mdata = item->GetData().value<MusicMetadata *>();
389 MythScreenType *screen = new EditStreamMetadata(mainStack, this, mdata);
390
391 if (screen->Create())
392 mainStack->AddScreen(screen);
393 else
394 delete screen;
395 }
396}
397
399{
401 if (item)
402 {
403 auto *mdata = item->GetData().value<MusicMetadata *>();
404
405 if (mdata)
406 {
407 ShowOkPopup(tr("Are you sure you want to delete this Stream?\n"
408 "Broadcaster: %1 - Channel: %2")
409 .arg(mdata->Broadcaster(), mdata->Channel()),
410 this, &StreamView::doRemoveStream, true);
411 }
412 }
413}
414
416{
417 if (!ok)
418 return;
419
421 if (item)
422 {
423 auto *mdata = item->GetData().value<MusicMetadata *>();
424
425 if (mdata)
426 deleteStream(mdata);
427 }
428}
429
431{
432 Playlist *playlist = gPlayer->getCurrentPlaylist();
433 if (nullptr == playlist)
434 return;
435
437
438 bool foundActiveStream = false;
439
440 for (int x = 0; x < playlist->getTrackCount(); x++)
441 {
442 MusicMetadata *mdata = playlist->getSongAt(x);
443 auto *item = new MythUIButtonListItem(m_streamList, "",
444 QVariant::fromValue(mdata));
445 InfoMap metadataMap;
446 if (mdata)
447 mdata->toMap(metadataMap);
448 item->SetTextFromMap(metadataMap);
449 item->SetText("", "imageloaded");
450 item->SetFontState("normal");
451 item->DisplayState("default", "playstate");
452
453 // if this is the current radio stream update its play state to match the player
454 if (gPlayer->getCurrentMetadata() && mdata &&
455 mdata->ID() == gPlayer->getCurrentMetadata()->ID())
456 {
457 if (gPlayer->isPlaying())
458 {
459 item->SetFontState("running");
460 item->DisplayState("playing", "playstate");
461 }
462 else if (gPlayer->isPaused())
463 {
464 item->SetFontState("idle");
465 item->DisplayState("paused", "playstate");
466 }
467 else
468 {
469 item->SetFontState("normal");
470 item->DisplayState("stopped", "playstate");
471 }
472
474
476
477 foundActiveStream = true;
478 }
479 }
480
481 if (m_streamList->GetCount() > 0 && !foundActiveStream)
482 {
484 gPlayer->stop(true);
485 }
486
487 if (m_noStreams)
489
490 if (m_streamList->GetCount() == 0)
491 LOG(VB_GENERAL, LOG_ERR, "StreamView hasn't found any streams!");
492}
493
495{
496 if (!item)
497 return;
498
500}
501
503{
504 if (!item)
505 return;
506
507 if (!item->GetText("imageloaded").isEmpty())
508 return;
509
510 auto *mdata = item->GetData().value<MusicMetadata *>();
511 if (mdata)
512 {
513 if (!mdata->LogoUrl().isEmpty())
514 item->SetImage(mdata->getAlbumArtFile());
515 else
516 item->SetImage("");
517 }
518
519 item->SetText(" ", "imageloaded");
520}
521
523{
524 // sanity check this is a radio stream
525 int repo = ID_TO_REPO(mdata->ID());
526 if (repo != RT_Radio)
527 {
528 LOG(VB_GENERAL, LOG_ERR, "StreamView asked to add a stream but it isn't a radio stream!");
529 return;
530 }
531
532 QString url = mdata->Url();
533
535
537
539
540 // find the new stream and make it the active item
541 for (int x = 0; x < m_streamList->GetCount(); x++)
542 {
544 auto *itemsdata = item->GetData().value<MusicMetadata *>();
545 if (itemsdata)
546 {
547 if (url == itemsdata->Url())
548 {
550 break;
551 }
552 }
553 }
554}
555
557{
558 // sanity check this is a radio stream
559 int repo = ID_TO_REPO(mdata->ID());
560 if (repo != RT_Radio)
561 {
562 LOG(VB_GENERAL, LOG_ERR, "StreamView asked to update a stream but it isn't a radio stream!");
563 return;
564 }
565
566 MusicMetadata::IdType id = mdata->ID();
567
569
571
572 // update mdata to point to the new item
574
575 if (!mdata)
576 return;
577
578 // force the icon to reload incase it changed
579 QFile::remove(mdata->getAlbumArtFile());
580 mdata->reloadAlbumArtImages();
581
583
584 // if we just edited the currently playing stream update the current metadata to match
585 MusicMetadata *currentMetadata = gPlayer->getCurrentMetadata();
586 if (id == currentMetadata->ID())
587 {
588 currentMetadata->setBroadcaster(mdata->Broadcaster());
589 currentMetadata->setChannel(mdata->Channel());
590 }
591
592 // update the played tracks list to match the new metadata
594 {
595 for (int x = 0; x < m_playedTracksList->GetCount(); x++)
596 {
598 auto *playedmdata = item->GetData().value<MusicMetadata *>();
599
600 if (playedmdata && playedmdata->ID() == id)
601 {
602 playedmdata->setBroadcaster(mdata->Broadcaster());
603 playedmdata->setChannel(mdata->Channel());
604
605 InfoMap metadataMap;
606 playedmdata->toMap(metadataMap);
607 item->SetTextFromMap(metadataMap);
608 }
609 }
610 }
611
612 // find the stream and make it the active item
613 for (int x = 0; x < m_streamList->GetCount(); x++)
614 {
616 auto *itemsdata = item->GetData().value<MusicMetadata *>();
617 if (itemsdata)
618 {
619 if (mdata->ID() == itemsdata->ID())
620 {
622 break;
623 }
624 }
625 }
626}
627
629{
630 // sanity check this is a radio stream
631 int repo = ID_TO_REPO(mdata->ID());
632 if (repo != RT_Radio)
633 {
634 LOG(VB_GENERAL, LOG_ERR, "StreamView asked to delete a stream but it isn't a radio stream!");
635 return;
636 }
637
638 int currPos = m_streamList->GetCurrentPos();
639 int topPos = m_streamList->GetTopItemPos();
640
641 // if we are playing this radio stream stop playing
642 if (gPlayer->getCurrentMetadata() == mdata)
643 gPlayer->stop(true);
644
646
648
650
651 m_streamList->SetItemCurrent(currPos, topPos);
652}
653
655
657{
658 if (!LoadWindowFromXML("stream-ui.xml", "editstreammetadata", this))
659 return false;
660
661 bool err = false;
662 UIUtilE::Assign(this, m_broadcasterEdit, "broadcasteredit", &err);
663 UIUtilE::Assign(this, m_channelEdit, "channeledit", &err);
664 UIUtilE::Assign(this, m_descEdit, "descriptionedit", &err);
665 UIUtilE::Assign(this, m_url1Edit, "url1edit", &err);
666 UIUtilE::Assign(this, m_url2Edit, "url2edit", &err);
667 UIUtilE::Assign(this, m_url3Edit, "url3edit", &err);
668 UIUtilE::Assign(this, m_url4Edit, "url4edit", &err);
669 UIUtilE::Assign(this, m_url5Edit, "url5edit", &err);
670 UIUtilE::Assign(this, m_logourlEdit, "logourledit" , &err);
671 UIUtilE::Assign(this, m_genreEdit, "genreedit", &err);
672 UIUtilE::Assign(this, m_languageEdit, "languageedit", &err);
673 UIUtilE::Assign(this, m_countryEdit, "countryedit", &err);
674 UIUtilE::Assign(this, m_formatEdit, "formatedit", &err);
675 UIUtilE::Assign(this, m_saveButton, "savebutton", &err);
676 UIUtilE::Assign(this, m_cancelButton, "cancelbutton", &err);
677 UIUtilE::Assign(this, m_searchButton, "searchbutton", &err);
678
679 if (err)
680 {
681 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'editstreampopup'");
682 return false;
683 }
684
685 if (m_streamMeta)
686 {
700 }
701 else
702 {
703 m_formatEdit->SetText("%a - %t");
704 }
705
709
711
712 return true;
713}
714
716{
718 MythScreenType *screen = new SearchStream(mainStack, this);
719
720 if (screen->Create())
721 mainStack->AddScreen(screen);
722 else
723 delete screen;
724
725}
726
728{
729 bool doUpdate = true;
730
731 if (!m_streamMeta)
732 {
735 doUpdate = false;
736 }
737
745 m_streamMeta->setFormat("cast");
752
753 if (doUpdate)
755 else
757
758 Close();
759}
760
762{
763 if (mdata)
764 {
766 m_channelEdit->SetText(mdata->Channel());
767 m_url1Edit->SetText(mdata->Url(0));
768 m_url2Edit->SetText(mdata->Url(1));
769 m_url3Edit->SetText(mdata->Url(2));
770 m_url4Edit->SetText(mdata->Url(3));
771 m_url5Edit->SetText(mdata->Url(4));
772 m_logourlEdit->SetText(mdata->LogoUrl());
773 m_genreEdit->SetText(mdata->Genre());
775 m_descEdit->SetText(mdata->Description());
776 m_countryEdit->SetText(mdata->Country());
778 }
779}
780
782
784{
785 if (!LoadWindowFromXML("stream-ui.xml", "searchstream", this))
786 return false;
787
788 bool err = false;
789 UIUtilE::Assign(this, m_broadcasterList, "broadcasterlist", &err);
790 UIUtilE::Assign(this, m_genreList, "genrelist", &err);
791 UIUtilW::Assign(this, m_languageList, "languagelist", &err);
792 UIUtilW::Assign(this, m_countryList, "countrylist", &err);
793 UIUtilE::Assign(this, m_streamList, "streamlist", &err);
794 UIUtilE::Assign(this, m_channelEdit, "channeledit", &err);
795 UIUtilE::Assign(this, m_matchesText, "matchestext", &err);
796
797 if (err)
798 {
799 LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'searchstream'");
800 return false;
801 }
802
806
815
816
817 if (m_countryList)
818 {
821
825 }
826
827 if (m_languageList)
828 {
832 }
833
835
836 LoadInBackground("Loading Streams...");
837
839
840 return true;
841}
842
844{
845 loadStreams();
846 QTimer::singleShot(0, this, &SearchStream::doneLoading);
847}
848
850{
852 updateGenres();
856}
857
859{
860 if (!item)
861 return;
862
863 auto mdata = item->GetData().value<MusicMetadata>();
865
866 Close();
867}
868
870{
871 if (!item)
872 return;
873
874 auto mdata = item->GetData().value<MusicMetadata>();
875 if (!mdata.LogoUrl().isEmpty() && mdata.LogoUrl() != "-")
876 {
877 if (item->GetText("dummy") == " ")
878 {
879 item->SetImage(mdata.LogoUrl());
880 item->SetText("", "dummy");
881 }
882 }
883}
884
886{
888}
889
891{
893
894 new MythUIButtonListItem(m_broadcasterList, tr("<All Broadcasters>"));
895
897
898 query.prepare("SELECT DISTINCT broadcaster FROM music_streams ORDER BY broadcaster;");
899
900 if (!query.exec() || !query.isActive())
901 {
902 MythDB::DBError("get broadcaster", query);
903 return;
904 }
905
906 while (query.next())
907 {
908 new MythUIButtonListItem(m_broadcasterList, query.value(0).toString());
909 }
910
911 m_broadcasterList->SetValue(tr("<All Broadcasters>"));
912}
913
915{
917
918 new MythUIButtonListItem(m_genreList, tr("<All Genres>"));
919
921
922 query.prepare("SELECT DISTINCT genre FROM music_streams ORDER BY genre;");
923
924 if (!query.exec() || !query.isActive())
925 {
926 MythDB::DBError("get genres", query);
927 return;
928 }
929
930 while (query.next())
931 {
932 new MythUIButtonListItem(m_genreList, query.value(0).toString());
933 }
934
935 m_genreList->SetValue(tr("<All Genres>"));
936}
937
939{
940 if (m_countryList)
941 {
943
944 new MythUIButtonListItem(m_countryList, tr("<All Countries>"));
945
947
948 query.prepare("SELECT DISTINCT country FROM music_streams ORDER BY country;");
949
950 if (!query.exec() || !query.isActive())
951 {
952 MythDB::DBError("get countries", query);
953 return;
954 }
955
956 while (query.next())
957 {
958 new MythUIButtonListItem(m_countryList, query.value(0).toString());
959 }
960
961 m_countryList->SetValue(tr("<All Countries>"));
962 }
963}
964
966{
967 if (m_languageList)
968 {
970
971 new MythUIButtonListItem(m_languageList, tr("<All Languages>"));
972
974
975 query.prepare("SELECT DISTINCT language FROM music_streams ORDER BY language;");
976
977 if (!query.exec() || !query.isActive())
978 {
979 MythDB::DBError("get languages", query);
980 return;
981 }
982
983 while (query.next())
984 {
985 new MythUIButtonListItem(m_languageList, query.value(0).toString());
986 }
987
988 m_languageList->SetValue(tr("<All Languages>"));
989 }
990}
991
993{
994 if (m_updateTimer.isActive())
995 m_updateTimer.stop();
996
997 m_updateTimer.start(500ms);
998}
999
1001{
1002 if (m_updating)
1003 return;
1004
1005 QString broadcaster = m_broadcasterList->GetValue();
1006 QString genre = m_genreList->GetValue();
1007 QString language = m_languageList ? m_languageList->GetValue() : tr("<All Languages>");
1008 QString country = m_countryList ? m_countryList->GetValue() : tr("<All Countries>");
1009 QString channel = m_channelEdit->GetText();
1010
1011 // only update the buttonlist if something changed
1012 if (m_oldBroadcaster == broadcaster && m_oldGenre == genre && m_oldChannel == channel &&
1013 m_oldLanguage == language && m_oldCountry == country)
1014 return;
1015
1016 m_oldBroadcaster = broadcaster;
1017 m_oldGenre = genre;
1018 m_oldChannel = channel;
1019 m_oldLanguage = language;
1020 m_oldCountry = country;
1021
1022 bool searchBroadcaster = (broadcaster != tr("<All Broadcasters>"));
1023 bool searchGenre = (genre != tr("<All Genres>"));
1024 bool searchLanguage = (language != tr("<All Languages>"));
1025 bool searchCountry = (country != tr("<All Countries>"));
1026 bool searchChannel = !channel.isEmpty();
1027
1028 m_streams.clear();
1030
1032
1033 QString sql = "SELECT broadcaster, channel, description, genre, url1, url2, url3, url4, url5, "
1034 "logourl, metaformat, country, language "
1035 "FROM music_streams ";
1036 bool doneWhere = false;
1037
1038 if (searchBroadcaster)
1039 {
1040 sql += "WHERE broadcaster = :BROADCASTER ";
1041 doneWhere = true;
1042 }
1043
1044 if (searchGenre)
1045 {
1046 if (!doneWhere)
1047 {
1048 sql += "WHERE genre = :GENRE ";
1049 doneWhere = true;
1050 }
1051 else
1052 {
1053 sql += "AND genre = :GENRE ";
1054 }
1055 }
1056
1057 if (searchLanguage)
1058 {
1059 if (!doneWhere)
1060 {
1061 sql += "WHERE language = :LANGUAGE ";
1062 doneWhere = true;
1063 }
1064 else
1065 {
1066 sql += "AND language = :LANGUAGE ";
1067 }
1068 }
1069
1070 if (searchCountry)
1071 {
1072 if (!doneWhere)
1073 {
1074 sql += "WHERE country = :COUNTRY ";
1075 doneWhere = true;
1076 }
1077 else
1078 {
1079 sql += "AND country = :COUNTRY ";
1080 }
1081 }
1082
1083 if (searchChannel)
1084 {
1085 if (!doneWhere)
1086 {
1087 sql += "WHERE channel LIKE " + QString("'%%1%'").arg(channel);
1088 // doneWhere = true;
1089 }
1090 else
1091 {
1092 sql += "AND channel LIKE " + QString("'%%1%' ").arg(channel);
1093 }
1094 }
1095
1096 sql += "ORDER BY broadcaster, channel;";
1097
1098 query.prepare(sql);
1099
1100 if (searchBroadcaster)
1101 query.bindValue(":BROADCASTER", broadcaster);
1102
1103 if (searchGenre)
1104 query.bindValue(":GENRE", genre);
1105
1106 if (searchLanguage)
1107 query.bindValue(":LANGUAGE", language);
1108
1109 if (searchCountry)
1110 query.bindValue(":COUNTRY", country);
1111
1112 if (!query.exec() || !query.isActive())
1113 {
1114 MythDB::DBError("search streams", query);
1115 return;
1116 }
1117
1118 if (query.size() > 500)
1119 {
1120 QString message = tr("Updating stream list. Please Wait ...");
1121 OpenBusyPopup(message);
1122 }
1123
1124 int count = 0;
1125 while (query.next())
1126 {
1127 MusicMetadata mdata;
1128 mdata.setBroadcaster(query.value(0).toString());
1129 mdata.setChannel(query.value(1).toString());
1130 mdata.setDescription(query.value(2).toString());
1131 mdata.setGenre(query.value(3).toString());
1132
1133 for (size_t x = 0; x < STREAMURLCOUNT; x++)
1134 mdata.setUrl(query.value(4 + x).toString(), x);
1135
1136 mdata.setLogoUrl(query.value(9).toString());
1137 mdata.setMetadataFormat(query.value(10).toString());
1138 mdata.setCountry(query.value(11).toString());
1139 mdata.setLanguage(query.value(12).toString());
1140
1141 auto *item = new MythUIButtonListItem(m_streamList, "",
1142 QVariant::fromValue(mdata));
1143 InfoMap metadataMap;
1144 mdata.toMap(metadataMap);
1145
1146 item->SetTextFromMap(metadataMap);
1147
1148 item->SetText(" ", "dummy");
1149 count++;
1150
1151 if ((count % 500) == 0)
1152 {
1153 qApp->processEvents();
1154 }
1155 }
1156
1157 m_matchesText->SetText(QString("%1").arg(m_streamList->GetCount()));
1158
1159 if (query.size() > 500)
1161
1162 m_updating = false;
1163}
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:41
static const Type kEventType
Definition: mythdialogbox.h:56
MythUITextEdit * m_formatEdit
Definition: streamview.h:87
void searchClicked(void)
Definition: streamview.cpp:715
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:761
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:727
MusicMetadata * m_streamMeta
Definition: streamview.h:76
bool Create() override
Definition: streamview.cpp:656
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:837
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:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
MusicView m_currentView
Definition: musiccommon.h:141
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:206
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:91
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:226
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)
static const Type kPlaying
Definition: output.h:63
static const Type kStopped
Definition: output.h:67
static const Type kBuffering
Definition: output.h:64
int getTrackCount(void)
Definition: playlist.h:82
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1096
static void loadStreams(void)
Definition: streamview.cpp:885
static void streamVisible(MythUIButtonListItem *item)
Definition: streamview.cpp:869
QList< MusicMetadata > m_streams
Definition: streamview.h:123
QString m_oldBroadcaster
Definition: streamview.h:127
void updateGenres(void)
Definition: streamview.cpp:914
bool Create() override
Definition: streamview.cpp:783
void updateBroadcasters(void)
Definition: streamview.cpp:890
void updateCountries(void)
Definition: streamview.cpp:938
MythUITextEdit * m_channelEdit
Definition: streamview.h:137
void doneLoading(void)
Definition: streamview.cpp:849
QString m_oldLanguage
Definition: streamview.h:131
void updateStreams(void)
Definition: streamview.cpp:992
QString m_oldChannel
Definition: streamview.h:129
MythUIButtonList * m_broadcasterList
Definition: streamview.h:133
QString m_oldGenre
Definition: streamview.h:128
MythUIButtonList * m_streamList
Definition: streamview.h:138
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:843
MythUIText * m_matchesText
Definition: streamview.h:139
QTimer m_updateTimer
Definition: streamview.h:141
QString m_oldCountry
Definition: streamview.h:130
void doUpdateStreams(void)
EditStreamMetadata * m_parent
Definition: streamview.h:122
bool m_updating
Definition: streamview.h:142
void updateLanguages(void)
Definition: streamview.cpp:965
MythUIButtonList * m_countryList
Definition: streamview.h:135
void streamClicked(MythUIButtonListItem *item)
Definition: streamview.cpp:858
MythUIButtonList * m_languageList
Definition: streamview.h:136
MythUIButtonList * m_genreList
Definition: streamview.h:134
void addStream(MusicMetadata *mdata)
Definition: streamview.cpp:522
static void streamItemVisible(MythUIButtonListItem *item)
Definition: streamview.cpp:502
bool Create(void) override
Definition: streamview.cpp:39
void streamItemClicked(MythUIButtonListItem *item)
Definition: streamview.cpp:494
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:556
void deleteStream(MusicMetadata *mdata)
Definition: streamview.cpp:628
MythUIProgressBar * m_bufferProgress
Definition: streamview.h:50
void doRemoveStream(bool ok)
Definition: streamview.cpp:415
void ShowMenu(void) override
Definition: streamview.cpp:77
StreamView(MythScreenStack *parent, MythScreenType *parentScreen)
Definition: streamview.cpp:33
void updateStreamList(void)
Definition: streamview.cpp:430
void removeStream(void)
Definition: streamview.cpp:398
void editStream(void)
Definition: streamview.cpp:382
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: streamview.cpp:338
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:68
static constexpr size_t STREAMURLCOUNT
Definition: musicmetadata.h:81
static constexpr uint32_t ID_TO_REPO(uint32_t x)
Definition: musicmetadata.h:77
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