MythTV  master
cdrip.cpp
Go to the documentation of this file.
1 // ANSI C includes
2 #include <cstdio>
3 #include <cstring>
4 
5 // Unix C includes
6 #include <sys/types.h>
7 #include <fcntl.h>
8 
9 #include "config.h"
10 
11 // C++ includes
12 #include <chrono>
13 #include <iostream>
14 #include <memory>
15 
16 // Qt includes
17 #include <QApplication>
18 #include <QDir>
19 #include <QEvent>
20 #include <QFile>
21 #include <QKeyEvent>
22 #include <QRegExp>
23 #include <QTimer>
24 #include <QUrl>
25 #include <utility>
26 
27 // MythTV plugin includes
28 #include <mythcontext.h>
29 #include <mythdb.h>
30 #include <lcddevice.h>
31 #include <mythmediamonitor.h>
32 #include <mythdirs.h>
33 #include <mythmiscutil.h>
34 
35 // MythUI
36 #include <mythdialogbox.h>
37 #include <mythuitext.h>
38 #include <mythuicheckbox.h>
39 #include <mythuitextedit.h>
40 #include <mythuibutton.h>
41 #include <mythuiprogressbar.h>
42 #include <mythuibuttonlist.h>
43 #include <mythsystemlegacy.h>
44 #include <storagegroup.h>
45 #include <remotefile.h>
46 
47 // MythUI headers
48 #include <mythtv/libmythui/mythscreenstack.h>
49 #include <mythtv/libmythui/mythprogressdialog.h>
50 
51 // MythMusic includes
52 #include "cdrip.h"
53 #ifdef HAVE_CDIO
54 #include "cddecoder.h"
55 #endif // HAVE_CDIO
56 #include "editmetadata.h"
57 #include "encoder.h"
58 #include "flacencoder.h"
59 #include "genres.h"
60 #include "lameencoder.h"
61 #include "musicutils.h"
62 #include "mythlogging.h"
63 #include "vorbisencoder.h"
64 
65 using namespace std::chrono_literals;
66 
67 #ifdef HAVE_CDIO
68 // libparanoia compatibility
69 #ifndef cdrom_paranoia
70 #define cdrom_paranoia cdrom_paranoia_t
71 #endif // cdrom_paranoia
72 
73 #ifndef CD_FRAMESIZE_RAW
74 # define CD_FRAMESIZE_RAW CDIO_CD_FRAMESIZE_RAW
75 #endif // CD_FRAMESIZE_RAW
76 #endif // HAVE_CDIO
77 
79  (QEvent::Type) QEvent::registerEventType();
81  (QEvent::Type) QEvent::registerEventType();
83  (QEvent::Type) QEvent::registerEventType();
85  (QEvent::Type) QEvent::registerEventType();
87  (QEvent::Type) QEvent::registerEventType();
89  (QEvent::Type) QEvent::registerEventType();
91  (QEvent::Type) QEvent::registerEventType();
93  (QEvent::Type) QEvent::registerEventType();
95  (QEvent::Type) QEvent::registerEventType();
97  (QEvent::Type) QEvent::registerEventType();
98 QEvent::Type RipStatusEvent::kCopyEndEvent =
99  (QEvent::Type) QEvent::registerEventType();
100 QEvent::Type RipStatusEvent::kFinishedEvent =
101  (QEvent::Type) QEvent::registerEventType();
103  (QEvent::Type) QEvent::registerEventType();
104 
106 {
107  RunProlog();
108  m_parent->scanCD();
109  RunEpilog();
110 }
111 
113 
115 {
116  RunProlog();
117  m_parent->ejectCD();
118  RunEpilog();
119 }
120 
122 
123 static long int getSectorCount (QString &cddevice, int tracknum)
124 {
125 #ifdef HAVE_CDIO
126  QByteArray devname = cddevice.toLatin1();
127  cdrom_drive *device = cdda_identify(devname.constData(), 0, nullptr);
128 
129  if (!device)
130  {
131  LOG(VB_GENERAL, LOG_ERR,
132  QString("Error: %1('%2',track=%3) failed at cdda_identify()").
133  arg(__func__).arg(cddevice).arg(tracknum));
134  return -1;
135  }
136 
137  if (cdda_open(device))
138  {
139  LOG(VB_GENERAL, LOG_ERR,
140  QString("Error: %1('%2',track=%3) failed at cdda_open() - cdda not supported").
141  arg(__func__).arg(cddevice).arg(tracknum));
142  cdda_close(device);
143  return -1;
144  }
145 
146  // we only care about audio tracks
147  if (cdda_track_audiop (device, tracknum))
148  {
149  cdda_verbose_set(device, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
150  long int start = cdda_track_firstsector(device, tracknum);
151  long int end = cdda_track_lastsector( device, tracknum);
152  cdda_close(device);
153  return end - start + 1;
154  }
155  LOG(VB_GENERAL, LOG_ERR,
156  QString("Error: cdrip - cdda_track_audiop(%1) returned 0").arg(cddevice));
157 
158  cdda_close(device);
159 #else
160  (void)cddevice; (void)tracknum;
161 #endif // HAVE_CDIO
162  return 0;
163 }
164 
165 #ifdef HAVE_CDIO
166 static void paranoia_cb(long /*status*/, paranoia_cb_mode_t /*mode*/)
167 {
168 }
169 #endif // HAVE_CDIO
170 
172  QVector<RipTrack*> *tracks, int quality) :
173  MThread("CDRipper"),
174  m_parent(parent),
175  m_cdDevice(std::move(device)), m_quality(quality),
176  m_tracks(tracks)
177 {
178 #ifdef WIN32 // libcdio needs the drive letter with no path
179  if (m_cdDevice.endsWith('\\'))
180  m_cdDevice.chop(1);
181 #endif // WIN32
182 
183  QString lastHost = gCoreContext->GetSetting("MythMusicLastRipHost", gCoreContext->GetMasterHostName());
184  QStringList dirs = StorageGroup::getGroupDirs("Music", lastHost);
185  if (dirs.count() > 0)
186  m_musicStorageDir = StorageGroup::getGroupDirs("Music", lastHost).at(0);
187 }
188 
190 {
191  cancel();
192  wait();
193 }
194 
196 {
197  m_quit = true;
198 }
199 
201 {
202  return m_quit;
203 }
204 
206 {
207  RunProlog();
208 
209  if (m_tracks->empty())
210  {
211  RunEpilog();
212  return;
213  }
214 
215  m_totalSectors = 0;
216  m_totalSectorsDone = 0;
217  for (int trackno = 0; trackno < m_tracks->size(); trackno++)
218  {
219  m_totalSectors += getSectorCount(m_cdDevice, trackno + 1);
220  }
221 
222  if (!m_totalSectors)
223  {
224  RunEpilog();
225  return;
226  }
227 
228  MusicMetadata *track = m_tracks->at(0)->metadata;
229  QString tots;
230 
231  if (track->Compilation())
232  {
233  tots = track->CompilationArtist() + " ~ " + track->Album();
234  }
235  else
236  {
237  tots = track->Artist() + " ~ " + track->Album();
238  }
239 
240  QApplication::postEvent(
241  m_parent,
243  QApplication::postEvent(
244  m_parent,
246  QApplication::postEvent(
247  m_parent,
249 
250  QString textstatus;
251  QString encodertype = gCoreContext->GetSetting("EncoderType");
252  bool mp3usevbr = gCoreContext->GetBoolSetting("Mp3UseVBR", false);
253 
254  QApplication::postEvent(m_parent,
256 
257  if (LCD *lcd = LCD::Get())
258  {
259  QString lcd_tots = tr("Importing %1").arg(tots);
260  QList<LCDTextItem> textItems;
261  textItems.append(LCDTextItem(1, ALIGN_CENTERED,
262  lcd_tots, "Generic", false));
263  lcd->switchToGeneric(textItems);
264  }
265 
266  MusicMetadata *titleTrack = nullptr;
267  QString saveDir = GetConfDir() + "/tmp/RipTemp/";
268  QString outfile;
269 
270  std::unique_ptr<Encoder> encoder;
271 
272  for (int trackno = 0; trackno < m_tracks->size(); trackno++)
273  {
274  if (isCancelled())
275  break;
276 
277  QApplication::postEvent(
278  m_parent,
280  QString("Track %1 of %2")
281  .arg(trackno + 1).arg(m_tracks->size())));
282 
283  QApplication::postEvent(
284  m_parent,
286 
287  track = m_tracks->at(trackno)->metadata;
288 
289  if (track)
290  {
291  textstatus = track->Title();
292  QApplication::postEvent(
293  m_parent,
294  new RipStatusEvent(
295  RipStatusEvent::kTrackTextEvent, textstatus));
296  QApplication::postEvent(
297  m_parent,
299  QApplication::postEvent(
300  m_parent,
302 
303  // do we need to start a new file?
304  if (m_tracks->at(trackno)->active)
305  {
306  titleTrack = track;
307  titleTrack->setLength(m_tracks->at(trackno)->length);
308 
309  if (m_quality < 3)
310  {
311  if (encodertype == "mp3")
312  {
313  outfile = QString("track%1.mp3").arg(trackno);
314  encoder = std::make_unique<LameEncoder>(saveDir + outfile, m_quality,
315  titleTrack, mp3usevbr);
316  }
317  else // ogg
318  {
319  outfile = QString("track%1.ogg").arg(trackno);
320  encoder = std::make_unique<VorbisEncoder>(saveDir + outfile, m_quality,
321  titleTrack);
322  }
323  }
324  else
325  {
326  outfile = QString("track%1.flac").arg(trackno);
327  encoder = std::make_unique<FlacEncoder>(saveDir + outfile, m_quality,
328  titleTrack);
329  }
330 
331  if (!encoder->isValid())
332  {
333  QApplication::postEvent(
334  m_parent,
335  new RipStatusEvent(
337  "Encoder failed to open file for writing"));
338  LOG(VB_GENERAL, LOG_ERR, "MythMusic: Encoder failed"
339  " to open file for writing");
340 
341  RunEpilog();
342  return;
343  }
344  }
345 
346  if (!encoder)
347  {
348  // This should never happen.
349  QApplication::postEvent(
350  m_parent,
352  "Failed to create encoder"));
353  LOG(VB_GENERAL, LOG_ERR, "MythMusic: No encoder, failing");
354  RunEpilog();
355  return;
356  }
357  ripTrack(m_cdDevice, encoder.get(), trackno + 1);
358 
359  if (isCancelled())
360  {
361  RunEpilog();
362  return;
363  }
364 
365  if (m_tracks->at(trackno)->active)
366  {
367  QString ext = QFileInfo(outfile).suffix();
368  QString destFile = filenameFromMetadata(titleTrack) + '.' + ext;
369  QUrl url(m_musicStorageDir);
370 
371  // save the metadata to the DB
372  titleTrack->setFilename(destFile);
373  titleTrack->setHostname(url.host());
374  titleTrack->setFileSize((quint64)QFileInfo(outfile).size());
375  titleTrack->dumpToDatabase();
376 
377  // this will delete the encoder which will write the metadata in it's dtor
378  encoder.reset();
379 
380  // copy track to the BE
381  destFile = MythCoreContext::GenMythURL(url.host(), 0, destFile, "Music");
382 
383  QApplication::postEvent(m_parent, new RipStatusEvent(RipStatusEvent::kCopyStartEvent, 0));
384  RemoteFile::CopyFile(saveDir + outfile, destFile, true);
385  QApplication::postEvent(m_parent, new RipStatusEvent(RipStatusEvent::kCopyEndEvent, 0));
386  }
387  }
388  }
389 
390  QString PostRipCDScript = gCoreContext->GetSetting("PostCDRipScript");
391 
392  if (!PostRipCDScript.isEmpty())
393  myth_system(PostRipCDScript);
394 
395  QApplication::postEvent(
397 
398  RunEpilog();
399 }
400 
401 int CDRipperThread::ripTrack(QString &cddevice, Encoder *encoder, int tracknum)
402 {
403 #ifdef HAVE_CDIO
404  QByteArray devname = cddevice.toLatin1();
405  cdrom_drive *device = cdda_identify(devname.constData(), 0, nullptr);
406 
407  if (!device)
408  {
409  LOG(VB_GENERAL, LOG_ERR,
410  QString("cdda_identify failed for device '%1', "
411  "CDRipperThread::ripTrack(tracknum = %2) exiting.")
412  .arg(cddevice).arg(tracknum));
413  return -1;
414  }
415 
416  if (cdda_open(device))
417  {
418  LOG(VB_MEDIA, LOG_INFO,
419  QString("Error: %1('%2',track=%3) failed at cdda_open() - cdda not supported")
420  .arg(__func__).arg(cddevice).arg(tracknum));
421  cdda_close(device);
422  return -1;
423  }
424 
425  cdda_verbose_set(device, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
426  long int start = cdda_track_firstsector(device, tracknum);
427  long int end = cdda_track_lastsector(device, tracknum);
428  LOG(VB_MEDIA, LOG_INFO, QString("%1(%2,track=%3) start=%4 end=%5")
429  .arg(__func__).arg(cddevice).arg(tracknum).arg(start).arg(end));
430 
431  cdrom_paranoia *paranoia = paranoia_init(device);
432  if (gCoreContext->GetSetting("ParanoiaLevel") == "full")
433  {
434  paranoia_modeset(paranoia, PARANOIA_MODE_FULL |
435  PARANOIA_MODE_NEVERSKIP);
436  }
437  else
438  {
439  paranoia_modeset(paranoia, PARANOIA_MODE_OVERLAP);
440  }
441 
442  paranoia_seek(paranoia, start, SEEK_SET);
443 
444  long int curpos = start;
445 
446  QApplication::postEvent(
447  m_parent,
449  m_lastTrackPct = -1;
450  m_lastOverallPct = -1;
451 
452  int every15 = 15;
453  while (curpos < end)
454  {
455  int16_t *buffer = paranoia_read(paranoia, paranoia_cb);
456 
457  if (encoder->addSamples(buffer, CD_FRAMESIZE_RAW))
458  break;
459 
460  curpos++;
461 
462  every15--;
463 
464  if (every15 <= 0)
465  {
466  every15 = 15;
467 
468  // updating the UITypes can be slow - only update if we need to:
469  int newOverallPct = (int) (100.0 / ((double) m_totalSectors /
470  (m_totalSectorsDone + curpos - start)));
471  if (newOverallPct != m_lastOverallPct)
472  {
473  m_lastOverallPct = newOverallPct;
474  QApplication::postEvent(
475  m_parent,
477  newOverallPct));
478  QApplication::postEvent(
479  m_parent,
481  m_totalSectorsDone + curpos - start));
482  }
483 
484  int newTrackPct = (int) (100.0 / ((double) (end - start + 1) / (curpos - start)));
485  if (newTrackPct != m_lastTrackPct)
486  {
487  m_lastTrackPct = newTrackPct;
488  QApplication::postEvent(
489  m_parent,
491  newTrackPct));
492  QApplication::postEvent(
493  m_parent,
495  curpos - start));
496  }
497 
498  if (LCD *lcd = LCD::Get())
499  {
500  float fProgress = (float)(m_totalSectorsDone + (curpos - start))
501  / m_totalSectors;
502  lcd->setGenericProgress(fProgress);
503  }
504  }
505 
506  if (isCancelled())
507  {
508  break;
509  }
510  }
511 
512  m_totalSectorsDone += end - start + 1;
513 
514  paranoia_free(paranoia);
515  cdda_close(device);
516 
517  return (curpos - start + 1) * CD_FRAMESIZE_RAW;
518 #else
519  (void)cddevice; (void)encoder; (void)tracknum;
520  return 0;
521 #endif // HAVE_CDIO
522 }
523 
525 
526 Ripper::Ripper(MythScreenStack *parent, QString device) :
527  MythScreenType(parent, "ripcd"),
528  m_tracks(new QVector<RipTrack*>),
529  m_cdDevice(std::move(device))
530 {
531 #ifndef _WIN32
532  // if the MediaMonitor is running stop it
533  m_mediaMonitorActive = false;
535  if (mon && mon->IsActive())
536  {
537  m_mediaMonitorActive = true;
538  mon->StopMonitoring();
539  }
540 #endif // _WIN32
541 
542  // make sure the directory where we temporarily save the rips is present
543  QDir dir;
544  dir.mkpath(GetConfDir() + "/tmp/RipTemp/");
545 
546  // remove any ripped tracks from the temp rip directory
547  QString command = "rm -f " + GetConfDir() + "/tmp/RipTemp/*";
548  myth_system(command);
549 
550  // get last host and directory we ripped to
551  QString lastHost = gCoreContext->GetSetting("MythMusicLastRipHost", gCoreContext->GetMasterHostName());
552  QStringList dirs = StorageGroup::getGroupDirs("Music", lastHost);
553  if (dirs.count() > 0)
554  m_musicStorageDir = StorageGroup::getGroupDirs("Music", lastHost).at(0);
555 }
556 
558 {
559  // remove any ripped tracks from the temp rip directory
560  QString command = "rm -f " + GetConfDir() + "/tmp/RipTemp/*";
561  myth_system(command);
562 
563  delete m_decoder;
564 
565 #ifndef _WIN32
566  // if the MediaMonitor was active when we started then restart it
568  {
570  if (mon)
571  mon->StartMonitoring();
572  }
573 #endif // _WIN32
574 
576  emit ripFinished();
577 }
578 
579 bool Ripper::Create(void)
580 {
581  if (!LoadWindowFromXML("music-ui.xml", "cdripper", this))
582  return false;
583 
584  m_qualityList = dynamic_cast<MythUIButtonList *>(GetChild("quality"));
585  m_artistEdit = dynamic_cast<MythUITextEdit *>(GetChild("artist"));
586  m_searchArtistButton = dynamic_cast<MythUIButton *>(GetChild("searchartist"));
587  m_albumEdit = dynamic_cast<MythUITextEdit *>(GetChild("album"));
588  m_searchAlbumButton = dynamic_cast<MythUIButton *>(GetChild("searchalbum"));
589  m_genreEdit = dynamic_cast<MythUITextEdit *>(GetChild("genre"));
590  m_yearEdit = dynamic_cast<MythUITextEdit *>(GetChild("year"));
591  m_searchGenreButton = dynamic_cast<MythUIButton *>(GetChild("searchgenre"));
592  m_compilationCheck = dynamic_cast<MythUICheckBox *>(GetChild("compilation"));
593  m_switchTitleArtist = dynamic_cast<MythUIButton *>(GetChild("switch"));
594  m_scanButton = dynamic_cast<MythUIButton *>(GetChild("scan"));
595  m_ripButton = dynamic_cast<MythUIButton *>(GetChild("rip"));
596  m_trackList = dynamic_cast<MythUIButtonList *>(GetChild("tracks"));
597 
598  BuildFocusList();
599 
604  {
605  LOG(VB_GENERAL, LOG_ERR,
606  "Missing theme elements for screen 'cdripper'");
607  return false;
608  }
609 
611  this, qOverload<MythUIButtonListItem *>(&Ripper::toggleTrackActive));
627 
628  // Populate Quality List
629  new MythUIButtonListItem(m_qualityList, tr("Low"), QVariant::fromValue(0));
630  new MythUIButtonListItem(m_qualityList, tr("Medium"), QVariant::fromValue(1));
631  new MythUIButtonListItem(m_qualityList, tr("High"), QVariant::fromValue(2));
632  new MythUIButtonListItem(m_qualityList, tr("Perfect"), QVariant::fromValue(3));
633  m_qualityList->SetValueByData(QVariant::fromValue(
634  gCoreContext->GetNumSetting("DefaultRipQuality", 1)));
635 
636  QTimer::singleShot(500ms, this, &Ripper::startScanCD);
637 
638  return true;
639 }
640 
641 bool Ripper::keyPressEvent(QKeyEvent *event)
642 {
643  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
644  return true;
645 
646  QStringList actions;
647  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
648 
649  for (int i = 0; i < actions.size() && !handled; i++)
650  {
651  QString action = actions[i];
652  handled = true;
653 
654  if (action == "EDIT" || action == "INFO") // INFO purely for historical reasons
656  else if (action == "MENU")
657  ShowMenu();
658  else
659  handled = false;
660  }
661 
662  if (!handled && MythScreenType::keyPressEvent(event))
663  handled = true;
664 
665  return handled;
666 }
667 
669 {
670  if (m_tracks->empty())
671  return;
672 
673  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
674 
675  auto *menu = new MythDialogBox("", popupStack, "ripmusicmenu");
676 
677  if (menu->Create())
678  popupStack->AddScreen(menu);
679  else
680  {
681  delete menu;
682  return;
683  }
684 
685  menu->SetReturnEvent(this, "menu");
686  menu->AddButton(tr("Select Where To Save Tracks"), &Ripper::chooseBackend);
687  menu->AddButton(tr("Edit Track Metadata"),
688  qOverload<>(&Ripper::showEditMetadataDialog));
689 }
690 
692 {
694 }
695 
696 void Ripper::chooseBackend(void) const
697 {
698  QStringList hostList;
699 
700  // get a list of hosts with a directory defined for the 'Music' storage group
702  QString sql = "SELECT DISTINCT hostname "
703  "FROM storagegroup "
704  "WHERE groupname = 'Music'";
705  if (!query.exec(sql) || !query.isActive())
706  MythDB::DBError("Ripper::chooseBackend get host list", query);
707  else
708  {
709  while(query.next())
710  {
711  hostList.append(query.value(0).toString());
712  }
713  }
714 
715  if (hostList.isEmpty())
716  {
717  LOG(VB_GENERAL, LOG_ERR, "Ripper::chooseBackend: No backends found");
718  return;
719  }
720 
721  QString msg = tr("Select where to save tracks");
722 
723  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
724  auto *searchDlg = new MythUISearchDialog(popupStack, msg, hostList, false, "");
725 
726  if (!searchDlg->Create())
727  {
728  delete searchDlg;
729  return;
730  }
731 
732  connect(searchDlg, &MythUISearchDialog::haveResult, this, &Ripper::setSaveHost);
733 
734  popupStack->AddScreen(searchDlg);
735 }
736 
737 void Ripper::setSaveHost(const QString& host)
738 {
739  gCoreContext->SaveSetting("MythMusicLastRipHost", host);
740 
741  QStringList dirs = StorageGroup::getGroupDirs("Music", host);
742  if (dirs.count() > 0)
743  m_musicStorageDir = StorageGroup::getGroupDirs("Music", host).at(0);
744 }
745 
747 {
748  if (m_scanThread)
749  return;
750 
751  QString message = tr("Scanning CD. Please Wait ...");
752  OpenBusyPopup(message);
753 
754  m_scanThread = new CDScannerThread(this);
755  connect(m_scanThread->qthread(), &QThread::finished, this, &Ripper::ScanFinished);
756  m_scanThread->start();
757 }
758 
760 {
761  delete m_scanThread;
762  m_scanThread = nullptr;
763 
764  m_tracks->clear();
765 
766  if (m_decoder)
767  {
768  bool isCompilation = false;
769 
770  m_artistName.clear();
771  m_albumName.clear();
772  m_genreName.clear();
773  m_year.clear();
774 
775  for (int trackno = 0; trackno < m_decoder->getNumTracks(); trackno++)
776  {
777  auto *ripTrack = new RipTrack;
778 
779  MusicMetadata *metadata = m_decoder->getMetadata(trackno + 1);
780  if (metadata)
781  {
782  ripTrack->metadata = metadata;
783  ripTrack->length = metadata->Length();
784 
785  if (metadata->Compilation())
786  {
787  isCompilation = true;
788  m_artistName = metadata->CompilationArtist();
789  }
790  else if (m_artistName.isEmpty())
791  {
792  m_artistName = metadata->Artist();
793  }
794 
795  if (m_albumName.isEmpty())
796  m_albumName = metadata->Album();
797 
798  if (m_genreName.isEmpty() && !metadata->Genre().isEmpty())
799  m_genreName = metadata->Genre();
800 
801  if (m_year.isEmpty() && metadata->Year() > 0)
802  m_year = QString::number(metadata->Year());
803 
804  QString title = metadata->Title();
805  ripTrack->isNew = isNewTune(m_artistName, m_albumName, title);
806 
807  ripTrack->active = ripTrack->isNew;
808 
809  m_tracks->push_back(ripTrack);
810 
811  }
812  else
813  delete ripTrack;
814  }
815 
820  m_compilationCheck->SetCheckState(isCompilation);
821 
822  if (!isCompilation)
824  else
826  }
827 
828  BuildFocusList();
829  updateTrackList();
830 
831  CloseBusyPopup();
832 }
833 
834 void Ripper::scanCD(void)
835 {
836 #ifdef HAVE_CDIO
837  {
838  LOG(VB_MEDIA, LOG_INFO, QString("Ripper::%1 CD='%2'").
839  arg(__func__).arg(m_cdDevice));
840  (void)cdio_close_tray(m_cdDevice.toLatin1().constData(), nullptr);
841  }
842 #endif // HAVE_CDIO
843 
844  delete m_decoder;
845  m_decoder = new CdDecoder("cda", nullptr, nullptr);
846  if (m_decoder)
848 }
849 
851 {
852  for (auto *it = m_tracks->begin(); it < m_tracks->end(); ++it)
853  {
854  RipTrack *track = (*it);
855  if (track && !track->isNew)
856  {
857  if (deleteExistingTrack(track))
858  {
859  track->isNew = true;
860  toggleTrackActive(track);
861  }
862  }
863  }
864 }
865 
867 {
868  if (!track)
869  return false;
870 
871  MusicMetadata *metadata = track->metadata;
872 
873  if (!metadata)
874  return false;
875 
876  QString artist = metadata->Artist();
877  QString album = metadata->Album();
878  QString title = metadata->Title();
879 
881  QString queryString("SELECT song_id, "
882  "CONCAT_WS('/', music_directories.path, music_songs.filename) AS filename "
883  "FROM music_songs "
884  "LEFT JOIN music_artists"
885  " ON music_songs.artist_id=music_artists.artist_id "
886  "LEFT JOIN music_albums"
887  " ON music_songs.album_id=music_albums.album_id "
888  "LEFT JOIN music_directories "
889  " ON music_songs.directory_id=music_directories.directory_id "
890  "WHERE artist_name REGEXP \'");
891  QString token = artist;
892  token.replace(QRegExp(R"((/|\\|:|'|\,|\!|\(|\)|"|\?|\|))"),
893  QString("."));
894 
895  queryString += token + "\' AND " + "album_name REGEXP \'";
896  token = album;
897  token.replace(QRegExp(R"((/|\\|:|'|\,|\!|\(|\)|"|\?|\|))"),
898  QString("."));
899  queryString += token + "\' AND " + "name REGEXP \'";
900  token = title;
901  token.replace(QRegExp(R"((/|\\|:|'|\,|\!|\(|\)|"|\?|\|))"),
902  QString("."));
903  queryString += token + "\' ORDER BY artist_name, album_name,"
904  " name, song_id, filename LIMIT 1";
905  query.prepare(queryString);
906 
907  if (!query.exec() || !query.isActive())
908  {
909  MythDB::DBError("Search music database", query);
910  return false;
911  }
912 
913  if (query.next())
914  {
915  int trackID = query.value(0).toInt();
916  QString filename = query.value(1).toString();
917  QUrl url(m_musicStorageDir);
918  filename = MythCoreContext::GenMythURL(url.host(), 0, filename, "Music");
919 
920  // delete file
921  // FIXME: RemoteFile::DeleteFile will only work with files on the master BE
923  {
924  LOG(VB_GENERAL, LOG_NOTICE, QString("Ripper::deleteExistingTrack() "
925  "Could not delete %1")
926  .arg(filename));
927  return false;
928  }
929 
930  // remove database entry
931  MSqlQuery deleteQuery(MSqlQuery::InitCon());
932  deleteQuery.prepare("DELETE FROM music_songs"
933  " WHERE song_id = :SONG_ID");
934  deleteQuery.bindValue(":SONG_ID", trackID);
935  if (!deleteQuery.exec())
936  {
937  MythDB::DBError("Delete Track", deleteQuery);
938  return false;
939  }
940  return true;
941  }
942 
943  return false;
944 }
945 
946 bool Ripper::somethingWasRipped() const
947 {
948  return m_somethingwasripped;
949 }
950 
952 {
953  QString newartist = m_artistEdit->GetText();
954 
955  if (!m_tracks->empty())
956  {
957  for (const auto *track : qAsConst(*m_tracks))
958  {
959  MusicMetadata *data = track->metadata;
960  if (data)
961  {
963  {
964  data->setCompilationArtist(newartist);
965  }
966  else
967  {
968  data->setArtist(newartist);
969  data->setCompilationArtist("");
970  }
971  }
972  }
973 
974  updateTrackList();
975  }
976 
977  m_artistName = newartist;
978 }
979 
981 {
982  QString newalbum = m_albumEdit->GetText();
983 
984  if (!m_tracks->empty())
985  {
986  for (const auto *track : qAsConst(*m_tracks))
987  {
988  MusicMetadata *data = track->metadata;
989  if (data)
990  data->setAlbum(newalbum);
991  }
992  }
993 
994  m_albumName = newalbum;
995 }
996 
998 {
999  QString newgenre = m_genreEdit->GetText();
1000 
1001  if (!m_tracks->empty())
1002  {
1003  for (const auto *track : qAsConst(*m_tracks))
1004  {
1005  MusicMetadata *data = track->metadata;
1006  if (data)
1007  data->setGenre(newgenre);
1008  }
1009  }
1010 
1011  m_genreName = newgenre;
1012 }
1013 
1014 void Ripper::yearChanged()
1015 {
1016  QString newyear = m_yearEdit->GetText();
1017 
1018  if (!m_tracks->empty())
1019  {
1020  for (const auto *track : qAsConst(*m_tracks))
1021  {
1022  MusicMetadata *data = track->metadata;
1023  if (data)
1024  data->setYear(newyear.toInt());
1025  }
1026  }
1027 
1028  m_year = newyear;
1029 }
1030 
1031 void Ripper::compilationChanged(bool state)
1032 {
1033  if (!state)
1034  {
1035  if (!m_tracks->empty())
1036  {
1037  // Update artist MetaData of each track on the ablum...
1038  for (const auto *track : qAsConst(*m_tracks))
1039  {
1040  MusicMetadata *data = track->metadata;
1041  if (data)
1042  {
1043  data->setCompilationArtist("");
1044  data->setArtist(m_artistName);
1045  data->setCompilation(false);
1046  }
1047  }
1048  }
1049 
1051  }
1052  else
1053  {
1054  if (!m_tracks->empty())
1055  {
1056  // Update artist MetaData of each track on the album...
1057  for (const auto *track : qAsConst(*m_tracks))
1058  {
1059  MusicMetadata *data = track->metadata;
1060 
1061  if (data)
1062  {
1064  data->setCompilation(true);
1065  }
1066  }
1067  }
1068 
1070  }
1071 
1072  BuildFocusList();
1073  updateTrackList();
1074 }
1075 
1077 {
1079  return;
1080 
1081  // Switch title and artist for each track
1082  QString tmp;
1083  if (!m_tracks->empty())
1084  {
1085  for (const auto *track : qAsConst(*m_tracks))
1086  {
1087  MusicMetadata *data = track->metadata;
1088 
1089  if (data)
1090  {
1091  tmp = data->Artist();
1092  data->setArtist(data->Title());
1093  data->setTitle(tmp);
1094  }
1095  }
1096 
1097  updateTrackList();
1098  }
1099 }
1100 
1101 void Ripper::startRipper(void)
1102 {
1103  if (m_tracks->isEmpty())
1104  {
1105  ShowOkPopup(tr("There are no tracks to rip?"));
1106  return;
1107  }
1108 
1110 
1111  int quality = m_qualityList->GetItemCurrent()->GetData().toInt();
1112 
1113  auto *statusDialog = new RipStatus(mainStack, m_cdDevice, m_tracks, quality);
1114 
1115  if (statusDialog->Create())
1116  {
1117  connect(statusDialog, &RipStatus::Result, this, &Ripper::RipComplete);
1118  mainStack->AddScreen(statusDialog);
1119  }
1120  else
1121  delete statusDialog;
1122 }
1123 
1124 void Ripper::RipComplete(bool result)
1125 {
1126  if (result)
1127  {
1128  bool EjectCD = gCoreContext->GetBoolSetting("EjectCDAfterRipping", true);
1129  if (EjectCD)
1130  startEjectCD();
1131 
1132  ShowOkPopup(tr("Rip completed successfully."));
1133 
1134  m_somethingwasripped = true;
1135  }
1136 
1137  if (LCD *lcd = LCD::Get())
1138  lcd->switchToTime();
1139 }
1140 
1141 
1142 void Ripper::startEjectCD()
1143 {
1144  if (m_ejectThread)
1145  return;
1146 
1147  QString message = tr("Ejecting CD. Please Wait ...");
1148 
1149  OpenBusyPopup(message);
1150 
1151  m_ejectThread = new CDEjectorThread(this);
1152  connect(m_ejectThread->qthread(),
1153  &QThread::finished, this, &Ripper::EjectFinished);
1154  m_ejectThread->start();
1155 }
1156 
1157 void Ripper::EjectFinished()
1158 {
1159  delete m_ejectThread;
1160  m_ejectThread = nullptr;
1161 
1162  CloseBusyPopup();
1163 }
1164 
1165 void Ripper::ejectCD()
1166 {
1167  LOG(VB_MEDIA, LOG_INFO, __PRETTY_FUNCTION__);
1168  bool bEjectCD = gCoreContext->GetBoolSetting("EjectCDAfterRipping",true);
1169  if (bEjectCD)
1170  {
1171 #ifdef HAVE_CDIO
1172  LOG(VB_MEDIA, LOG_INFO, QString("Ripper::%1 '%2'").
1173  arg(__func__).arg(m_cdDevice));
1174  (void)cdio_eject_media_drive(m_cdDevice.toLatin1().constData());
1175 #else
1177  if (mon)
1178  {
1179  QByteArray devname = m_cdDevice.toLatin1();
1180  MythMediaDevice *pMedia = mon->GetMedia(devname.constData());
1181  if (pMedia && mon->ValidateAndLock(pMedia))
1182  {
1183  pMedia->eject();
1184  mon->Unlock(pMedia);
1185  }
1186  }
1187 #endif // HAVE_CDIO
1188  }
1189 }
1190 
1191 void Ripper::updateTrackList(void)
1192 {
1193  if (m_tracks->isEmpty())
1194  return;
1195 
1196  if (m_trackList)
1197  {
1198  m_trackList->Reset();
1199 
1200  for (int i = 0; i < m_tracks->size(); i++)
1201  {
1202  if (i >= m_tracks->size())
1203  break;
1204 
1205  RipTrack *track = m_tracks->at(i);
1206  MusicMetadata *metadata = track->metadata;
1207 
1208  auto *item = new MythUIButtonListItem(m_trackList,"");
1209 
1210  item->setCheckable(true);
1211 
1212  item->SetData(QVariant::fromValue(track));
1213 
1214  if (track->isNew)
1215  item->DisplayState("new", "yes");
1216  else
1217  item->DisplayState("new", "no");
1218 
1219  if (track->active)
1220  item->setChecked(MythUIButtonListItem::FullChecked);
1221  else
1222  item->setChecked(MythUIButtonListItem::NotChecked);
1223 
1224  item->SetText(QString::number(metadata->Track()), "track");
1225  item->SetText(metadata->Title(), "title");
1226  item->SetText(metadata->Artist(), "artist");
1227 
1228  if (track->length >= ONESECINMS)
1229  {
1230  item->SetText(MythFormatTimeMs(track->length, "mm:ss"), "length");
1231  }
1232  else
1233  item->SetText("", "length");
1234 
1235 // if (i == m_currentTrack)
1236 // m_trackList->SetItemCurrent(i);
1237  }
1238  }
1239 }
1240 
1241 void Ripper::searchArtist() const
1242 {
1243  QString msg = tr("Select an Artist");
1244  QStringList searchList = MusicMetadata::fillFieldList("artist");
1245 
1246  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1247  auto *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, "");
1248 
1249  if (!searchDlg->Create())
1250  {
1251  delete searchDlg;
1252  return;
1253  }
1254 
1255  connect(searchDlg, &MythUISearchDialog::haveResult, this, &Ripper::setArtist);
1256 
1257  popupStack->AddScreen(searchDlg);
1258 }
1259 
1260 void Ripper::setArtist(const QString& artist)
1261 {
1262  m_artistEdit->SetText(artist);
1263 }
1264 
1265 void Ripper::searchAlbum() const
1266 {
1267  QString msg = tr("Select an Album");
1268  QStringList searchList = MusicMetadata::fillFieldList("album");
1269 
1270  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1271  auto *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, "");
1272 
1273  if (!searchDlg->Create())
1274  {
1275  delete searchDlg;
1276  return;
1277  }
1278 
1279  connect(searchDlg, &MythUISearchDialog::haveResult, this, &Ripper::setAlbum);
1280 
1281  popupStack->AddScreen(searchDlg);
1282 }
1283 
1284 void Ripper::setAlbum(const QString& album)
1285 {
1286  m_albumEdit->SetText(album);
1287 }
1288 
1289 void Ripper::searchGenre()
1290 {
1291  QString msg = tr("Select a Genre");
1292  QStringList searchList = MusicMetadata::fillFieldList("genre");
1293  // load genre list
1294  m_searchList.clear();
1295  for (const auto & genre : genre_table)
1296  m_searchList.push_back(QString::fromStdString(genre));
1297  m_searchList.sort();
1298 
1299  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1300  auto *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, "");
1301 
1302  if (!searchDlg->Create())
1303  {
1304  delete searchDlg;
1305  return;
1306  }
1307 
1308  connect(searchDlg, &MythUISearchDialog::haveResult, this, &Ripper::setGenre);
1309 
1310  popupStack->AddScreen(searchDlg);
1311 }
1312 
1313 void Ripper::setGenre(const QString& genre)
1314 {
1315  m_genreEdit->SetText(genre);
1316 }
1317 
1319 {
1320  if (!item || m_tracks->isEmpty())
1321  return;
1322 
1323  auto *track = item->GetData().value<RipTrack *>();
1324 
1325  if (!track)
1326  return;
1327 
1328  MusicMetadata *editMeta = track->metadata;
1329 
1331 
1332  auto *editDialog = new EditMetadataDialog(mainStack, editMeta);
1333  editDialog->setSaveMetadataOnly();
1334 
1335  if (!editDialog->Create())
1336  {
1337  delete editDialog;
1338  return;
1339  }
1340 
1341  connect(editDialog, &EditMetadataCommon::metadataChanged, this, &Ripper::metadataChanged);
1342 
1343  mainStack->AddScreen(editDialog);
1344 }
1345 
1346 void Ripper::metadataChanged(void)
1347 {
1348  updateTrackList();
1349 }
1350 
1352 {
1353  QVariant data = QVariant::fromValue(track);
1355  if (item)
1356  {
1357  toggleTrackActive(item);
1358  }
1359 }
1360 
1362 {
1363  if (m_tracks->isEmpty() || !item)
1364  return;
1365 
1366  int pos = m_trackList->GetItemPos(item);
1367 
1368  // sanity check item position
1369  if (pos < 0 || pos > m_tracks->count() - 1)
1370  return;
1371 
1372  RipTrack *track = m_tracks->at(pos);
1373 
1374  if (!track->active && !track->isNew)
1375  {
1376  ShowConflictMenu(track);
1377  return;
1378  }
1379 
1380  track->active = !track->active;
1381 
1382  if (track->active)
1384  else
1386 
1388 }
1389 
1391 {
1392  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1393 
1394  QString msg = tr("This track has been disabled because it is already "
1395  "present in the database.\n"
1396  "Do you want to permanently delete the existing "
1397  "file(s)?");
1398  auto *menu = new MythDialogBox(msg, popupStack, "conflictmenu", true);
1399 
1400  if (menu->Create())
1401  popupStack->AddScreen(menu);
1402  else
1403  {
1404  delete menu;
1405  return;
1406  }
1407 
1408  menu->SetReturnEvent(this, "conflictmenu");
1409  menu->AddButton(tr("No, Cancel"));
1410  menu->AddButtonV(tr("Yes, Delete"), QVariant::fromValue(track));
1411  menu->AddButton(tr("Yes, Delete All"));
1412 }
1413 
1415 {
1416  int length = 0;
1417 
1418  for (auto *it = m_tracks->end() - 1; it == m_tracks->begin(); --it)
1419  {
1420  RipTrack *track = *it;
1421  if (track->active)
1422  {
1423  track->length = length + track->metadata->Length();
1424  length = 0;
1425  }
1426  else
1427  {
1428  track->length = 0;
1429  length += track->metadata->Length();
1430  }
1431  }
1432 }
1433 
1434 void Ripper::customEvent(QEvent* event)
1435 {
1436  if (event->type() == DialogCompletionEvent::kEventType)
1437  {
1438  auto *dce = dynamic_cast<DialogCompletionEvent *>(event);
1439  if (dce == nullptr)
1440  return;
1441  if (dce->GetId() == "conflictmenu")
1442  {
1443  int buttonNum = dce->GetResult();
1444  auto *track = dce->GetData().value<RipTrack *>();
1445 
1446  switch (buttonNum)
1447  {
1448  case 0:
1449  // Do nothing
1450  break;
1451  case 1:
1452  if (deleteExistingTrack(track))
1453  {
1454  track->isNew = true;
1455  toggleTrackActive(track);
1456  }
1457  break;
1458  case 2:
1460  break;
1461  default:
1462  break;
1463  }
1464  }
1465 
1466  return;
1467  }
1468 
1469  MythUIType::customEvent(event);
1470 }
1471 
1472 
1474 
1476 {
1477  delete m_ripperThread;
1478  if (LCD *lcd = LCD::Get())
1479  lcd->switchToTime();
1480 }
1481 
1482 bool RipStatus::Create(void)
1483 {
1484  if (!LoadWindowFromXML("music-ui.xml", "ripstatus", this))
1485  return false;
1486 
1487  m_overallText = dynamic_cast<MythUIText *>(GetChild("overall"));
1488  m_trackText = dynamic_cast<MythUIText *>(GetChild("track"));
1489  m_statusText = dynamic_cast<MythUIText *>(GetChild("status"));
1490  m_trackPctText = dynamic_cast<MythUIText *>(GetChild("trackpct"));
1491  m_overallPctText = dynamic_cast<MythUIText *>(GetChild("overallpct"));
1492 
1493  m_overallProgress = dynamic_cast<MythUIProgressBar *>(GetChild("overall_progress"));
1494  m_trackProgress = dynamic_cast<MythUIProgressBar *>(GetChild("track_progress"));
1495 
1496  BuildFocusList();
1497 
1498  startRip();
1499 
1500  return true;
1501 }
1502 
1503 bool RipStatus::keyPressEvent(QKeyEvent *event)
1504 {
1505  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
1506  return true;
1507 
1508  QStringList actions;
1509  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
1510 
1511  for (int i = 0; i < actions.size() && !handled; i++)
1512  {
1513  QString action = actions[i];
1514  handled = true;
1515 
1516 
1517  if (action == "ESCAPE" &&
1519  {
1520  MythConfirmationDialog *dialog =
1521  ShowOkPopup(tr("Cancel ripping the CD?"), true);
1522  if (dialog)
1523  dialog->SetReturnEvent(this, "stop_ripping");
1524  }
1525  else
1526  handled = false;
1527  }
1528 
1529  if (!handled && MythScreenType::keyPressEvent(event))
1530  handled = true;
1531 
1532  return handled;
1533 }
1534 
1535 void RipStatus::customEvent(QEvent *event)
1536 {
1537  if (event->type() == DialogCompletionEvent::kEventType)
1538  {
1539  auto *dce = dynamic_cast<DialogCompletionEvent *>(event);
1540  if (dce == nullptr)
1541  return;
1542  if ((dce->GetId() == "stop_ripping") && (dce->GetResult() != 0))
1543  {
1545  m_ripperThread->wait();
1546  Close();
1547  }
1548 
1549  return;
1550  }
1551 
1552  auto *rse = dynamic_cast<RipStatusEvent *> (event);
1553  if (!rse)
1554  return;
1555 
1556  if (event->type() == RipStatusEvent::kTrackTextEvent)
1557  {
1558  if (m_trackText)
1559  m_trackText->SetText(rse->m_text);
1560  }
1561  else if (event->type() == RipStatusEvent::kOverallTextEvent)
1562  {
1563  if (m_overallText)
1564  m_overallText->SetText(rse->m_text);
1565  }
1566  else if (event->type() == RipStatusEvent::kStatusTextEvent)
1567  {
1568  if (m_statusText)
1569  m_statusText->SetText(rse->m_text);
1570  }
1571  else if (event->type() == RipStatusEvent::kTrackProgressEvent)
1572  {
1573  if (m_trackProgress)
1574  m_trackProgress->SetUsed(rse->m_value);
1575  }
1576  else if (event->type() == RipStatusEvent::kTrackPercentEvent)
1577  {
1578  if (m_trackPctText)
1579  m_trackPctText->SetText(QString("%1%").arg(rse->m_value));
1580  }
1581  else if (event->type() == RipStatusEvent::kTrackStartEvent)
1582  {
1583  if (m_trackProgress)
1584  m_trackProgress->SetTotal(rse->m_value);
1585  }
1586  else if (event->type() == RipStatusEvent::kCopyStartEvent)
1587  {
1588  if (m_trackPctText)
1589  m_trackPctText->SetText(tr("Copying Track ..."));
1590  }
1591  else if (event->type() == RipStatusEvent::kCopyEndEvent)
1592  {
1593  if (m_trackPctText)
1594  m_trackPctText->SetText("");
1595  }
1596  else if (event->type() == RipStatusEvent::kOverallProgressEvent)
1597  {
1598  if (m_overallProgress)
1599  m_overallProgress->SetUsed(rse->m_value);
1600  }
1601  else if (event->type() == RipStatusEvent::kOverallStartEvent)
1602  {
1603  if (m_overallProgress)
1604  m_overallProgress->SetTotal(rse->m_value);
1605  }
1606  else if (event->type() == RipStatusEvent::kOverallPercentEvent)
1607  {
1608  if (m_overallPctText)
1609  m_overallPctText->SetText(QString("%1%").arg(rse->m_value));
1610  }
1611  else if (event->type() == RipStatusEvent::kFinishedEvent)
1612  {
1613  emit Result(true);
1614  Close();
1615  }
1616  else if (event->type() == RipStatusEvent::kEncoderErrorEvent)
1617  {
1618  ShowOkPopup(tr("The encoder failed to create the file.\n"
1619  "Do you have write permissions"
1620  " for the music directory?"));
1621  Close();
1622  }
1623  else
1624  {
1625  LOG(VB_GENERAL, LOG_ERR, "Received an unknown event type!");
1626  }
1627 }
1628 
1629 void RipStatus::startRip(void)
1630 {
1631  delete m_ripperThread;
1633  m_ripperThread->start();
1634 }
MythFormatTimeMs
QString MythFormatTimeMs(int msecs, const QString &fmt)
Format a milliseconds time value.
Definition: mythmiscutil.cpp:1233
CdDecoder::getMetadata
MusicMetadata * getMetadata(void)
Definition: cddecoder.cpp:501
Ripper::EjectFinished
void EjectFinished(void)
MythUIButton::Clicked
void Clicked()
FilterAlpha
@ FilterAlpha
Definition: mythuitextedit.h:20
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:204
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
ONESECINMS
#define ONESECINMS
Definition: mythmiscutil.h:107
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:315
Ripper::m_artistEdit
MythUITextEdit * m_artistEdit
Definition: cdrip.h:153
MythUITextEdit::SetMaxLength
void SetMaxLength(int length)
Definition: mythuitextedit.cpp:211
MythUISearchDialog
Provide a dialog to quickly find an entry in a list.
Definition: mythdialogbox.h:398
MusicMetadata::Title
QString Title() const
Definition: musicmetadata.h:162
Ripper::m_genreName
QString m_genreName
Definition: cdrip.h:174
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1590
RipTrack::metadata
MusicMetadata * metadata
Definition: cdrip.h:52
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:288
myth_system
uint myth_system(const QString &command, uint flags, uint timeout)
Definition: mythsystemlegacy.cpp:501
Ripper::m_somethingwasripped
bool m_somethingwasripped
Definition: cdrip.h:177
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:828
RipStatusEvent::kTrackPercentEvent
static Type kTrackPercentEvent
Definition: cdrip.h:203
MythUIButtonList::SetValueByData
void SetValueByData(const QVariant &data)
Definition: mythuibuttonlist.cpp:1542
mythuitext.h
mythuiprogressbar.h
Ripper::m_cdDevice
QString m_cdDevice
Definition: cdrip.h:180
CDRipperThread::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: cdrip.cpp:205
CDEjectorThread::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: cdrip.cpp:114
Ripper::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: cdrip.cpp:641
MusicMetadata::Genre
QString Genre() const
Definition: musicmetadata.h:175
Ripper::m_qualityList
MythUIButtonList * m_qualityList
Definition: cdrip.h:161
editmetadata.h
CDEjectorThread
Definition: cdrip.h:39
Ripper::m_year
QString m_year
Definition: cdrip.h:175
Ripper::m_tracks
QVector< RipTrack * > * m_tracks
Definition: cdrip.h:170
RipStatus::Create
bool Create(void) override
mythdb.h
Ripper::m_searchGenreButton
MythUIButton * m_searchGenreButton
Definition: cdrip.h:168
CDRipperThread::isCancelled
bool isCancelled(void) const
Definition: cdrip.cpp:200
Ripper::setGenre
void setGenre(const QString &genre)
Ripper::m_searchArtistButton
MythUIButton * m_searchArtistButton
Definition: cdrip.h:166
Ripper::deleteExistingTrack
bool deleteExistingTrack(RipTrack *track)
Definition: cdrip.cpp:866
MusicMetadata::setLength
void setLength(int llength)
Definition: musicmetadata.h:206
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:402
MediaMonitor::GetMediaMonitor
static MediaMonitor * GetMediaMonitor(void)
Definition: mythmediamonitor.cpp:83
RipStatusEvent::kCopyEndEvent
static Type kCopyEndEvent
Definition: cdrip.h:209
RipStatus::m_trackText
MythUIText * m_trackText
Definition: cdrip.h:241
MusicMetadata::CompilationArtist
QString CompilationArtist() const
Definition: musicmetadata.h:138
MusicMetadata::fillFieldList
static QStringList fillFieldList(const QString &field)
Definition: musicmetadata.cpp:1220
title
QString title
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:636
CDRipperThread::m_lastOverallPct
int m_lastOverallPct
Definition: cdrip.h:89
getSectorCount
static long int getSectorCount(QString &cddevice, int tracknum)
Definition: cdrip.cpp:123
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:131
MythConfirmationDialog::SetReturnEvent
void SetReturnEvent(QObject *retobject, const QString &resultid)
Definition: mythdialogbox.cpp:519
RipStatusEvent::kOverallTextEvent
static Type kOverallTextEvent
Definition: cdrip.h:200
flacencoder.h
MythUISearchDialog::haveResult
void haveResult(QString)
DialogCompletionEvent::kEventType
static Type kEventType
Definition: mythdialogbox.h:57
Ripper::ejectCD
void ejectCD(void)
Ripper::yearChanged
void yearChanged(void)
MediaMonitor::StartMonitoring
virtual void StartMonitoring(void)
Start the monitoring thread if needed.
Definition: mythmediamonitor.cpp:457
Ripper::toggleTrackActive
void toggleTrackActive(MythUIButtonListItem *item)
MythUICheckBox::GetBooleanCheckState
bool GetBooleanCheckState(void) const
Definition: mythuicheckbox.cpp:103
RipStatus
Definition: cdrip.h:214
CDRipperThread::m_cdDevice
QString m_cdDevice
Definition: cdrip.h:81
Ripper::scanCD
void scanCD(void)
Definition: cdrip.cpp:834
MythUIProgressBar::SetUsed
void SetUsed(int value)
Definition: mythuiprogressbar.cpp:59
genre_table
const genre_table_array genre_table
Definition: genres.cpp:4
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:198
MythScreenStack
Definition: mythscreenstack.h:15
arg
arg(title).arg(filename).arg(doDelete))
RipStatus::m_trackProgress
MythUIProgressBar * m_trackProgress
Definition: cdrip.h:246
mythmediamonitor.h
MythUIButtonListItem::FullChecked
@ FullChecked
Definition: mythuibuttonlist.h:34
Ripper::deleteAllExistingTracks
void deleteAllExistingTracks(void)
Definition: cdrip.cpp:850
vorbisencoder.h
MythUIType::customEvent
void customEvent(QEvent *event) override
Definition: mythuitype.cpp:984
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
Ripper::compilationChanged
void compilationChanged(bool state)
MythUITextEdit
A text entry and edit widget.
Definition: mythuitextedit.h:32
RipStatus::m_ripperThread
CDRipperThread * m_ripperThread
Definition: cdrip.h:248
MusicMetadata::setAlbum
void setAlbum(const QString &lalbum, const QString &lalbum_sort=nullptr)
Definition: musicmetadata.h:152
MusicMetadata::Track
int Track() const
Definition: musicmetadata.h:199
Encoder
Definition: mythplugins/mythmusic/mythmusic/encoder.h:13
Ripper::m_decoder
CdDecoder * m_decoder
Definition: cdrip.h:151
genres.h
MythScreenType::OpenBusyPopup
void OpenBusyPopup(const QString &message="")
Definition: mythscreentype.cpp:336
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:198
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:44
InputFilter
InputFilter
Definition: mythuitextedit.h:17
RipStatus::m_trackPctText
MythUIText * m_trackPctText
Definition: cdrip.h:244
Ripper::m_scanButton
MythUIButton * m_scanButton
Definition: cdrip.h:164
MusicMetadata
Definition: musicmetadata.h:80
MediaMonitor::GetMedia
MythMediaDevice * GetMedia(const QString &path)
Get media device by pathname. Must be locked with ValidateAndLock().
Definition: mythmediamonitor.cpp:543
CDRipperThread::m_musicStorageDir
QString m_musicStorageDir
Definition: cdrip.h:91
MythUITextEdit::GetText
QString GetText(void) const
Definition: mythuitextedit.h:47
mythdirs.h
CDRipperThread::CDRipperThread
CDRipperThread(RipStatus *parent, QString device, QVector< RipTrack * > *tracks, int quality)
Definition: cdrip.cpp:171
RipStatus::m_overallText
MythUIText * m_overallText
Definition: cdrip.h:240
MusicMetadata::Artist
QString Artist() const
Definition: musicmetadata.h:126
menu
static MythThemedMenu * menu
Definition: mythtv/programs/mythtv-setup/main.cpp:53
mythuibuttonlist.h
Ripper::chooseBackend
void chooseBackend(void) const
Definition: cdrip.cpp:696
Ripper::m_trackList
MythUIButtonList * m_trackList
Definition: cdrip.h:160
LCD::Get
static LCD * Get(void)
Definition: lcddevice.cpp:67
RipStatusEvent::kCopyStartEvent
static Type kCopyStartEvent
Definition: cdrip.h:208
musicutils.h
Ripper::ripFinished
void ripFinished(void)
MythUIButtonList::GetItemByData
MythUIButtonListItem * GetItemByData(const QVariant &data)
Definition: mythuibuttonlist.cpp:1684
RipStatus::~RipStatus
~RipStatus(void) override
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:112
RipTrack::length
int length
Definition: cdrip.h:54
mythsystemlegacy.h
RipStatus::startRip
void startRip(void)
Ripper::m_mediaMonitorActive
bool m_mediaMonitorActive
Definition: cdrip.h:178
MythUICheckBox::toggled
void toggled(bool)
cddecoder.h
isNewTune
bool isNewTune(const QString &artist, const QString &album, const QString &title)
try to find a track in the db using the given artist, album and title
Definition: musicutils.cpp:139
MythUIButtonList::GetItemPos
int GetItemPos(MythUIButtonListItem *item) const
Definition: mythuibuttonlist.cpp:1698
Ripper::m_searchList
QStringList m_searchList
Definition: cdrip.h:176
MythUIButtonListItem
Definition: mythuibuttonlist.h:27
RipStatusEvent::kTrackTextEvent
static Type kTrackTextEvent
Definition: cdrip.h:199
MythUITextEdit::SetText
void SetText(const QString &text, bool moveCursor=true)
Definition: mythuitextedit.cpp:216
CDRipperThread::m_totalSectors
long int m_totalSectors
Definition: cdrip.h:85
MythUIProgressBar::SetTotal
void SetTotal(int value)
Definition: mythuiprogressbar.cpp:71
mythlogging.h
Ripper::searchArtist
void searchArtist(void) const
MusicMetadata::setHostname
void setHostname(const QString &host)
Definition: musicmetadata.h:230
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:781
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
CdDecoder
Definition: cddecoder.h:26
Ripper::genreChanged
void genreChanged(void)
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1114
Ripper::startScanCD
void startScanCD(void)
Definition: cdrip.cpp:746
RipStatus::Result
void Result(bool)
remotefile.h
Ripper::m_searchAlbumButton
MythUIButton * m_searchAlbumButton
Definition: cdrip.h:167
MediaMonitor::StopMonitoring
void StopMonitoring(void)
Stop the monitoring thread if needed.
Definition: mythmediamonitor.cpp:480
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:12
CDRipperThread::m_tracks
QVector< RipTrack * > * m_tracks
Definition: cdrip.h:83
CDRipperThread::m_totalSectorsDone
long int m_totalSectorsDone
Definition: cdrip.h:86
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:166
cdrip.h
filenameFromMetadata
QString filenameFromMetadata(MusicMetadata *track)
create a filename using the template in the settings and a MusicMetadata object
Definition: musicutils.cpp:77
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
RipStatus::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Ripper::m_scanThread
CDScannerThread * m_scanThread
Definition: cdrip.h:183
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:178
CDRipperThread::m_parent
RipStatus * m_parent
Definition: cdrip.h:79
FilterPunct
@ FilterPunct
Definition: mythuitextedit.h:24
MusicMetadata::setGenre
void setGenre(const QString &lgenre)
Definition: musicmetadata.h:176
CDScannerThread::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: cdrip.cpp:105
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:222
RipStatusEvent::kEncoderErrorEvent
static Type kEncoderErrorEvent
Definition: cdrip.h:211
CDRipperThread::m_quit
bool m_quit
Definition: cdrip.h:80
MusicMetadata::setTitle
void setTitle(const QString &ltitle, const QString &ltitle_sort=nullptr)
Definition: musicmetadata.h:164
MythUIButton
A single button widget.
Definition: mythuibutton.h:21
MusicMetadata::setFileSize
void setFileSize(uint64_t lfilesize)
Definition: musicmetadata.h:233
EditMetadataDialog
Definition: editvideometadata.h:19
FilterSymbols
@ FilterSymbols
Definition: mythuitextedit.h:23
StorageGroup::getGroupDirs
static QStringList getGroupDirs(const QString &groupname, const QString &host)
Definition: storagegroup.cpp:817
Ripper::Ripper
Ripper(MythScreenStack *parent, QString device)
Definition: cdrip.cpp:526
MThread::qthread
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:238
Ripper::albumChanged
void albumChanged(void)
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:637
Ripper::setArtist
void setArtist(const QString &artist)
Ripper::m_artistName
QString m_artistName
Definition: cdrip.h:173
MediaMonitor::Unlock
void Unlock(MythMediaDevice *pMedia)
decrements the MythMediaDevices reference count
Definition: mythmediamonitor.cpp:520
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:211
ALIGN_CENTERED
@ ALIGN_CENTERED
Definition: lcddevice.h:57
RipStatusEvent::kTrackStartEvent
static Type kTrackStartEvent
Definition: cdrip.h:204
storagegroup.h
MusicMetadata::setFilename
void setFilename(const QString &lfilename)
Definition: musicmetadata.cpp:960
RipTrack::active
bool active
Definition: cdrip.h:53
Ripper::searchGenre
void searchGenre(void)
RemoteFile::DeleteFile
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:418
MythUITextEdit::SetFilter
void SetFilter(InputFilter filter)
Definition: mythuitextedit.h:49
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3580
Ripper::ShowMenu
void ShowMenu(void) override
Definition: cdrip.cpp:668
RipStatusEvent
Definition: cdrip.h:187
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
token
return token
Definition: musicutils.cpp:74
MythUICheckBox
A checkbox widget supporting three check states - on,off,half and two conditions - selected and unsel...
Definition: mythuicheckbox.h:15
CdDecoder::setDevice
void setDevice(const QString &dev)
Definition: cddecoder.cpp:106
RemoteFile::CopyFile
static bool CopyFile(const QString &src, const QString &dst, bool overwrite=false, bool verify=false)
Definition: remotefile.cpp:587
MediaMonitor
Definition: mythmediamonitor.h:43
Ripper::updateTrackLengths
void updateTrackLengths(void)
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:933
CDRipperThread::m_lastTrackPct
int m_lastTrackPct
Definition: cdrip.h:88
Ripper::m_musicStorageDir
QString m_musicStorageDir
Definition: cdrip.h:149
CDRipperThread::~CDRipperThread
~CDRipperThread() override
Definition: cdrip.cpp:189
Ripper::m_switchTitleArtist
MythUIButton * m_switchTitleArtist
Definition: cdrip.h:163
MusicMetadata::Album
QString Album() const
Definition: musicmetadata.h:150
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:927
CdDecoder::getNumTracks
int getNumTracks()
Definition: cddecoder.cpp:448
RipStatus::customEvent
void customEvent(QEvent *event) override
Ripper::updateTrackList
void updateTrackList(void)
RipStatus::m_overallPctText
MythUIText * m_overallPctText
Definition: cdrip.h:243
MusicMetadata::setCompilationArtist
void setCompilationArtist(const QString &lcompilation_artist, const QString &lcompilation_artist_sort=nullptr)
Definition: musicmetadata.h:140
CDScannerThread
Definition: cdrip.h:28
RipStatusEvent::kFinishedEvent
static Type kFinishedEvent
Definition: cdrip.h:210
RipStatusEvent::kOverallProgressEvent
static Type kOverallProgressEvent
Definition: cdrip.h:205
MythMediaDevice::eject
virtual MythMediaError eject(bool open_close=true)
Definition: mythmedia.cpp:307
Ripper::Create
bool Create(void) override
Definition: cdrip.cpp:579
RipStatusEvent::kTrackProgressEvent
static Type kTrackProgressEvent
Definition: cdrip.h:202
Ripper::RipComplete
void RipComplete(bool result)
MusicMetadata::dumpToDatabase
void dumpToDatabase(void)
Definition: musicmetadata.cpp:672
MythUIText
All purpose text widget, displays a text string.
Definition: mythuitext.h:30
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:414
MusicMetadata::setArtist
void setArtist(const QString &lartist, const QString &lartist_sort=nullptr)
Definition: musicmetadata.h:128
mythmiscutil.h
Ripper::customEvent
void customEvent(QEvent *event) override
Ripper::startEjectCD
void startEjectCD(void)
encoder.h
RipStatus::m_cdDevice
QString m_cdDevice
Definition: cdrip.h:238
MythConfirmationDialog
Dialog asking for user confirmation. Ok and optional Cancel button.
Definition: mythdialogbox.h:271
mythuitextedit.h
MythUICheckBox::SetCheckState
void SetCheckState(MythUIStateType::StateType state)
Definition: mythuicheckbox.cpp:66
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:692
dir
QDir dir
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1174
RipStatus::m_overallProgress
MythUIProgressBar * m_overallProgress
Definition: cdrip.h:245
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
RipStatus::m_statusText
MythUIText * m_statusText
Definition: cdrip.h:242
MediaMonitor::IsActive
bool IsActive(void) const
Definition: mythmediamonitor.h:51
DialogCompletionEvent
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
Ripper::m_genreEdit
MythUITextEdit * m_genreEdit
Definition: cdrip.h:155
MusicMetadata::Compilation
bool Compilation() const
Definition: musicmetadata.h:251
Ripper::showEditMetadataDialog
void showEditMetadataDialog(void)
Definition: cdrip.cpp:691
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:133
Ripper::m_yearEdit
MythUITextEdit * m_yearEdit
Definition: cdrip.h:156
MythUIType::SetVisible
virtual void SetVisible(bool visible)
Definition: mythuitype.cpp:1086
mythcontext.h
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
LCDTextItem
Definition: lcddevice.h:59
lameencoder.h
RipStatus::m_tracks
QVector< RipTrack * > * m_tracks
Definition: cdrip.h:236
MythUIButtonList::Reset
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuibuttonlist.cpp:114
Ripper::ShowConflictMenu
void ShowConflictMenu(RipTrack *track)
Ripper::searchAlbum
void searchAlbum(void) const
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:268
RipStatusEvent::kStatusTextEvent
static Type kStatusTextEvent
Definition: cdrip.h:201
build_compdb.action
action
Definition: build_compdb.py:9
CDRipperThread::m_quality
int m_quality
Definition: cdrip.h:82
CDRipperThread::cancel
void cancel(void)
Definition: cdrip.cpp:195
Ripper::setSaveHost
void setSaveHost(const QString &host)
Definition: cdrip.cpp:737
Ripper::startRipper
void startRipper(void)
mythuibutton.h
Ripper::m_albumEdit
MythUITextEdit * m_albumEdit
Definition: cdrip.h:154
MediaMonitor::ValidateAndLock
bool ValidateAndLock(MythMediaDevice *pMedia)
Validates the MythMediaDevice and increments its reference count.
Definition: mythmediamonitor.cpp:503
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:320
MusicMetadata::setYear
void setYear(int lyear)
Definition: musicmetadata.h:197
MythUITextEdit::valueChanged
void valueChanged()
Ripper::switchTitlesAndArtists
void switchTitlesAndArtists()
DialogCompletionEvent::GetResult
int GetResult() const
Definition: mythdialogbox.h:53
MythMediaDevice
Definition: mythmedia.h:48
CDRipperThread::ripTrack
int ripTrack(QString &cddevice, Encoder *encoder, int tracknum)
Definition: cdrip.cpp:401
MythThemedMenuState::Create
bool Create(void) override
Definition: myththemedmenu.cpp:36
Ripper::artistChanged
void artistChanged(void)
MusicMetadata::setCompilation
void setCompilation(bool state)
Definition: musicmetadata.h:252
EditMetadataCommon::metadataChanged
void metadataChanged(void)
Ripper::setAlbum
void setAlbum(const QString &album)
Ripper::m_ejectThread
CDEjectorThread * m_ejectThread
Definition: cdrip.h:182
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:902
MThread::wait
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:305
Ripper::m_ripButton
MythUIButton * m_ripButton
Definition: cdrip.h:165
lcddevice.h
mythuicheckbox.h
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:151
CDRipperThread
Definition: cdrip.h:62
RipTrack
Definition: cdrip.h:50
Ripper::metadataChanged
void metadataChanged(void)
RipTrack::isNew
bool isNew
Definition: cdrip.h:55
MythUIButtonListItem::setChecked
void setChecked(CheckState state)
Definition: mythuibuttonlist.cpp:3544
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
RipStatus::m_quality
int m_quality
Definition: cdrip.h:237
query
MSqlQuery query(MSqlQuery::InitCon())
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:557
MusicMetadata::Length
int Length() const
Definition: musicmetadata.h:205
RipStatusEvent::kOverallStartEvent
static Type kOverallStartEvent
Definition: cdrip.h:207
LCD
Definition: lcddevice.h:169
MythScreenType::CloseBusyPopup
void CloseBusyPopup(void)
Definition: mythscreentype.cpp:354
MusicMetadata::Year
int Year() const
Definition: musicmetadata.h:196
Ripper::~Ripper
~Ripper(void) override
Definition: cdrip.cpp:557
Ripper::ScanFinished
void ScanFinished(void)
Definition: cdrip.cpp:759
Encoder::addSamples
virtual int addSamples(int16_t *bytes, unsigned int len)=0
RipStatusEvent::kOverallPercentEvent
static Type kOverallPercentEvent
Definition: cdrip.h:206
Ripper::somethingWasRipped
bool somethingWasRipped() const
Ripper::m_albumName
QString m_albumName
Definition: cdrip.h:172
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:919
MythUIButtonListItem::NotChecked
@ NotChecked
Definition: mythuibuttonlist.h:32
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
Ripper::m_compilationCheck
MythUICheckBox * m_compilationCheck
Definition: cdrip.h:158