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