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