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