00001
00002 #include <cstdio>
00003 #include <cstring>
00004
00005
00006 #include <sys/types.h>
00007 #include <fcntl.h>
00008
00009 #include "config.h"
00010 #ifdef HAVE_CDIO
00011 # include <cdio/cdda.h>
00012 # include <cdio/paranoia.h>
00013 #endif //def HAVE_CDIO
00014
00015
00016 #include <iostream>
00017 #include <memory>
00018 using namespace std;
00019
00020
00021 #include <QApplication>
00022 #include <QDir>
00023 #include <QRegExp>
00024 #include <QKeyEvent>
00025 #include <QEvent>
00026 #include <QFile>
00027
00028
00029 #include <mythcontext.h>
00030 #include <mythdb.h>
00031 #include <lcddevice.h>
00032 #include <mythmediamonitor.h>
00033
00034
00035 #include <mythdialogbox.h>
00036 #include <mythuitext.h>
00037 #include <mythuicheckbox.h>
00038 #include <mythuitextedit.h>
00039 #include <mythuibutton.h>
00040 #include <mythuiprogressbar.h>
00041 #include <mythuibuttonlist.h>
00042 #include <mythsystem.h>
00043
00044
00045 #include <mythtv/libmythui/mythscreenstack.h>
00046 #include <mythtv/libmythui/mythprogressdialog.h>
00047
00048
00049 #include "cdrip.h"
00050 #ifdef HAVE_CDIO
00051 #include "cddecoder.h"
00052 #endif
00053 #include "encoder.h"
00054 #include "vorbisencoder.h"
00055 #include "lameencoder.h"
00056 #include "flacencoder.h"
00057 #include "genres.h"
00058 #include "editmetadata.h"
00059 #include "mythlogging.h"
00060 #include "musicutils.h"
00061
00062 #ifdef HAVE_CDIO
00063
00064 #ifndef cdrom_paranoia
00065 #define cdrom_paranoia cdrom_paranoia_t
00066 #endif
00067
00068 #ifndef CD_FRAMESIZE_RAW
00069 # define CD_FRAMESIZE_RAW CDIO_CD_FRAMESIZE_RAW
00070 #endif
00071 #endif
00072
00073 QEvent::Type RipStatusEvent::kTrackTextEvent =
00074 (QEvent::Type) QEvent::registerEventType();
00075 QEvent::Type RipStatusEvent::kOverallTextEvent =
00076 (QEvent::Type) QEvent::registerEventType();
00077 QEvent::Type RipStatusEvent::kStatusTextEvent =
00078 (QEvent::Type) QEvent::registerEventType();
00079 QEvent::Type RipStatusEvent::kTrackProgressEvent =
00080 (QEvent::Type) QEvent::registerEventType();
00081 QEvent::Type RipStatusEvent::kTrackPercentEvent =
00082 (QEvent::Type) QEvent::registerEventType();
00083 QEvent::Type RipStatusEvent::kTrackStartEvent =
00084 (QEvent::Type) QEvent::registerEventType();
00085 QEvent::Type RipStatusEvent::kOverallProgressEvent =
00086 (QEvent::Type) QEvent::registerEventType();
00087 QEvent::Type RipStatusEvent::kOverallPercentEvent =
00088 (QEvent::Type) QEvent::registerEventType();
00089 QEvent::Type RipStatusEvent::kOverallStartEvent =
00090 (QEvent::Type) QEvent::registerEventType();
00091 QEvent::Type RipStatusEvent::kFinishedEvent =
00092 (QEvent::Type) QEvent::registerEventType();
00093 QEvent::Type RipStatusEvent::kEncoderErrorEvent =
00094 (QEvent::Type) QEvent::registerEventType();
00095
00096 CDScannerThread::CDScannerThread(Ripper *ripper) :
00097 MThread("CDScanner"), m_parent(ripper)
00098 {
00099 }
00100
00101 void CDScannerThread::run()
00102 {
00103 RunProlog();
00104 m_parent->scanCD();
00105 RunEpilog();
00106 }
00107
00109
00110 CDEjectorThread::CDEjectorThread(Ripper *ripper) :
00111 MThread("CDEjector"), m_parent(ripper)
00112 {
00113 }
00114
00115 void CDEjectorThread::run()
00116 {
00117 RunProlog();
00118 m_parent->ejectCD();
00119 RunEpilog();
00120 }
00121
00123
00124 static long int getSectorCount (QString &cddevice, int tracknum)
00125 {
00126 #if defined HAVE_CDIO
00127 QByteArray devname = cddevice.toAscii();
00128 cdrom_drive *device = cdda_identify(devname.constData(), 0, NULL);
00129
00130 if (!device)
00131 {
00132 LOG(VB_GENERAL, LOG_ERR,
00133 QString("Error: %1('%2',track=%3) failed at cdda_identify()").
00134 arg(__func__).arg(cddevice).arg(tracknum));
00135 return -1;
00136 }
00137
00138 if (cdda_open(device))
00139 {
00140 LOG(VB_GENERAL, LOG_ERR,
00141 QString("Error: %1('%2',track=%3) failed at cdda_open() - cdda not supported").
00142 arg(__func__).arg(cddevice).arg(tracknum));
00143 cdda_close(device);
00144 return -1;
00145 }
00146
00147
00148 if (cdda_track_audiop (device, tracknum))
00149 {
00150 cdda_verbose_set(device, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
00151 long int start = cdda_track_firstsector(device, tracknum);
00152 long int end = cdda_track_lastsector( device, tracknum);
00153 cdda_close(device);
00154 return end - start + 1;
00155 }
00156 LOG(VB_GENERAL, LOG_ERR,
00157 QString("Error: cdrip - cdda_track_audiop(%1) returned 0").arg(cddevice));
00158
00159 cdda_close(device);
00160 #else
00161 (void)cddevice; (void)tracknum;
00162 #endif
00163 return 0;
00164 }
00165
00166 #ifdef HAVE_CDIO
00167 static void paranoia_cb(long, paranoia_cb_mode_t)
00168 {
00169 }
00170 #endif
00171
00172 CDRipperThread::CDRipperThread(RipStatus *parent, QString device,
00173 QVector<RipTrack*> *tracks, int quality) :
00174 MThread("CDRipper"),
00175 m_parent(parent), m_quit(false),
00176 m_CDdevice(device), m_quality(quality),
00177 m_tracks(tracks), m_totalSectors(0),
00178 m_totalSectorsDone(0), m_lastTrackPct(0),
00179 m_lastOverallPct(0)
00180 {
00181 #ifdef WIN32 // libcdio needs the drive letter with no path
00182 if (m_CDdevice.endsWith('\\'))
00183 m_CDdevice.chop(1);
00184 #endif
00185 }
00186
00187 CDRipperThread::~CDRipperThread(void)
00188 {
00189 cancel();
00190 wait();
00191 }
00192
00193 void CDRipperThread::cancel(void)
00194 {
00195 m_quit = true;
00196 }
00197
00198 bool CDRipperThread::isCancelled(void)
00199 {
00200 return m_quit;
00201 }
00202
00203 void CDRipperThread::run(void)
00204 {
00205 RunProlog();
00206 if (!m_tracks->size() > 0)
00207 {
00208 RunEpilog();
00209 return;
00210 }
00211
00212 Metadata *track = m_tracks->at(0)->metadata;
00213 QString tots;
00214
00215 if (track->Compilation())
00216 {
00217 tots = track->CompilationArtist() + " ~ " + track->Album();
00218 }
00219 else
00220 {
00221 tots = track->Artist() + " ~ " + track->Album();
00222 }
00223
00224 QApplication::postEvent(
00225 m_parent,
00226 new RipStatusEvent(RipStatusEvent::kOverallTextEvent, tots));
00227 QApplication::postEvent(
00228 m_parent,
00229 new RipStatusEvent(RipStatusEvent::kOverallProgressEvent, 0));
00230 QApplication::postEvent(
00231 m_parent,
00232 new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0));
00233
00234 QString textstatus;
00235 QString encodertype = gCoreContext->GetSetting("EncoderType");
00236 bool mp3usevbr = gCoreContext->GetNumSetting("Mp3UseVBR", 0);
00237
00238 m_totalSectors = 0;
00239 m_totalSectorsDone = 0;
00240 for (int trackno = 0; trackno < m_tracks->size(); trackno++)
00241 {
00242 m_totalSectors += getSectorCount(m_CDdevice, trackno + 1);
00243 }
00244
00245 QApplication::postEvent(m_parent,
00246 new RipStatusEvent(RipStatusEvent::kOverallStartEvent, m_totalSectors));
00247
00248 if (LCD *lcd = LCD::Get())
00249 {
00250 QString lcd_tots = QObject::tr("Importing ") + tots;
00251 QList<LCDTextItem> textItems;
00252 textItems.append(LCDTextItem(1, ALIGN_CENTERED,
00253 lcd_tots, "Generic", false));
00254 lcd->switchToGeneric(textItems);
00255 }
00256
00257 Metadata *titleTrack = NULL;
00258 QString outfile;
00259
00260 std::auto_ptr<Encoder> encoder;
00261
00262 for (int trackno = 0; trackno < m_tracks->size(); trackno++)
00263 {
00264 if (isCancelled())
00265 break;
00266
00267 QApplication::postEvent(
00268 m_parent,
00269 new RipStatusEvent(RipStatusEvent::kStatusTextEvent,
00270 QString("Track %1 of %2")
00271 .arg(trackno + 1).arg(m_tracks->size())));
00272
00273 QApplication::postEvent(
00274 m_parent,
00275 new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0));
00276
00277 track = m_tracks->at(trackno)->metadata;
00278
00279 if (track)
00280 {
00281 textstatus = track->Title();
00282 QApplication::postEvent(
00283 m_parent,
00284 new RipStatusEvent(
00285 RipStatusEvent::kTrackTextEvent, textstatus));
00286 QApplication::postEvent(
00287 m_parent,
00288 new RipStatusEvent(RipStatusEvent::kTrackProgressEvent, 0));
00289 QApplication::postEvent(
00290 m_parent,
00291 new RipStatusEvent(RipStatusEvent::kTrackPercentEvent, 0));
00292
00293
00294 if (m_tracks->at(trackno)->active)
00295 {
00296 titleTrack = track;
00297 titleTrack->setLength(m_tracks->at(trackno)->length);
00298
00299 outfile = filenameFromMetadata(track);
00300
00301 if (m_quality < 3)
00302 {
00303 if (encodertype == "mp3")
00304 {
00305 outfile += ".mp3";
00306 encoder.reset(new LameEncoder(gMusicData->musicDir + outfile, m_quality,
00307 titleTrack, mp3usevbr));
00308 }
00309 else
00310 {
00311 outfile += ".ogg";
00312 encoder.reset(new VorbisEncoder(gMusicData->musicDir + outfile, m_quality,
00313 titleTrack));
00314 }
00315 }
00316 else
00317 {
00318 outfile += ".flac";
00319 encoder.reset(new FlacEncoder(gMusicData->musicDir + outfile, m_quality,
00320 titleTrack));
00321 }
00322
00323 if (!encoder->isValid())
00324 {
00325 QApplication::postEvent(
00326 m_parent,
00327 new RipStatusEvent(
00328 RipStatusEvent::kEncoderErrorEvent,
00329 "Encoder failed to open file for writing"));
00330 LOG(VB_GENERAL, LOG_ERR, "MythMusic: Encoder failed"
00331 " to open file for writing");
00332
00333 RunEpilog();
00334 return;
00335 }
00336 }
00337
00338 if (!encoder.get())
00339 {
00340
00341 QApplication::postEvent(
00342 m_parent,
00343 new RipStatusEvent(RipStatusEvent::kEncoderErrorEvent,
00344 "Failed to create encoder"));
00345 LOG(VB_GENERAL, LOG_ERR, "MythMusic: No encoder, failing");
00346 RunEpilog();
00347 return;
00348 }
00349 ripTrack(m_CDdevice, encoder.get(), trackno + 1);
00350
00351 if (isCancelled())
00352 {
00353 RunEpilog();
00354 return;
00355 }
00356
00357
00358 if (m_tracks->at(trackno)->active)
00359 {
00360 titleTrack->setFilename(outfile);
00361 titleTrack->dumpToDatabase();
00362 }
00363 }
00364 }
00365
00366 QString PostRipCDScript = gCoreContext->GetSetting("PostCDRipScript");
00367
00368 if (!PostRipCDScript.isEmpty())
00369 myth_system(PostRipCDScript);
00370
00371 QApplication::postEvent(
00372 m_parent, new RipStatusEvent(RipStatusEvent::kFinishedEvent, ""));
00373
00374 RunEpilog();
00375 }
00376
00377 int CDRipperThread::ripTrack(QString &cddevice, Encoder *encoder, int tracknum)
00378 {
00379 #if defined HAVE_CDIO
00380 QByteArray devname = cddevice.toAscii();
00381 cdrom_drive *device = cdda_identify(devname.constData(), 0, NULL);
00382
00383 if (!device)
00384 {
00385 LOG(VB_GENERAL, LOG_ERR,
00386 QString("cdda_identify failed for device '%1', "
00387 "CDRipperThread::ripTrack(tracknum = %2) exiting.")
00388 .arg(cddevice).arg(tracknum));
00389 return -1;
00390 }
00391
00392 if (cdda_open(device))
00393 {
00394 LOG(VB_MEDIA, LOG_INFO,
00395 QString("Error: %1('%2',track=%3) failed at cdda_open() - cdda not supported")
00396 .arg(__func__).arg(cddevice).arg(tracknum));
00397 cdda_close(device);
00398 return -1;
00399 }
00400
00401 cdda_verbose_set(device, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
00402 long int start = cdda_track_firstsector(device, tracknum);
00403 long int end = cdda_track_lastsector(device, tracknum);
00404 LOG(VB_MEDIA, LOG_INFO, QString("%1(%2,track=%3) start=%4 end=%5")
00405 .arg(__func__).arg(cddevice).arg(tracknum).arg(start).arg(end));
00406
00407 cdrom_paranoia *paranoia = paranoia_init(device);
00408 if (gCoreContext->GetSetting("ParanoiaLevel") == "full")
00409 paranoia_modeset(paranoia, PARANOIA_MODE_FULL |
00410 PARANOIA_MODE_NEVERSKIP);
00411 else
00412 paranoia_modeset(paranoia, PARANOIA_MODE_OVERLAP);
00413
00414 paranoia_seek(paranoia, start, SEEK_SET);
00415
00416 long int curpos = start;
00417 int16_t *buffer;
00418
00419 QApplication::postEvent(
00420 m_parent,
00421 new RipStatusEvent(RipStatusEvent::kTrackStartEvent, end - start + 1));
00422 m_lastTrackPct = -1;
00423 m_lastOverallPct = -1;
00424
00425 int every15 = 15;
00426 while (curpos < end)
00427 {
00428 buffer = paranoia_read(paranoia, paranoia_cb);
00429
00430 if (encoder->addSamples(buffer, CD_FRAMESIZE_RAW))
00431 break;
00432
00433 curpos++;
00434
00435 every15--;
00436
00437 if (every15 <= 0)
00438 {
00439 every15 = 15;
00440
00441
00442 int newOverallPct = (int) (100.0 / (double) ((double) m_totalSectors /
00443 (double) (m_totalSectorsDone + curpos - start)));
00444 if (newOverallPct != m_lastOverallPct)
00445 {
00446 m_lastOverallPct = newOverallPct;
00447 QApplication::postEvent(
00448 m_parent,
00449 new RipStatusEvent(RipStatusEvent::kOverallPercentEvent,
00450 newOverallPct));
00451 QApplication::postEvent(
00452 m_parent,
00453 new RipStatusEvent(RipStatusEvent::kOverallProgressEvent,
00454 m_totalSectorsDone + curpos - start));
00455 }
00456
00457 int newTrackPct = (int) (100.0 / (double) ((double) (end - start + 1) /
00458 (double) (curpos - start)));
00459 if (newTrackPct != m_lastTrackPct)
00460 {
00461 m_lastTrackPct = newTrackPct;
00462 QApplication::postEvent(
00463 m_parent,
00464 new RipStatusEvent(RipStatusEvent::kTrackPercentEvent,
00465 newTrackPct));
00466 QApplication::postEvent(
00467 m_parent,
00468 new RipStatusEvent(RipStatusEvent::kTrackProgressEvent,
00469 curpos - start));
00470 }
00471
00472 if (LCD *lcd = LCD::Get())
00473 {
00474 float fProgress = (float)(m_totalSectorsDone + (curpos - start))
00475 / m_totalSectors;
00476 lcd->setGenericProgress(fProgress);
00477 }
00478 }
00479
00480 if (isCancelled())
00481 {
00482 break;
00483 }
00484 }
00485
00486 m_totalSectorsDone += end - start + 1;
00487
00488 paranoia_free(paranoia);
00489 cdda_close(device);
00490
00491 return (curpos - start + 1) * CD_FRAMESIZE_RAW;
00492 #else
00493 (void)cddevice; (void)encoder; (void)tracknum;
00494 return 0;
00495 #endif
00496 }
00497
00499
00500 Ripper::Ripper(MythScreenStack *parent, QString device) :
00501 MythScreenType(parent, "ripcd"),
00502 m_decoder(NULL),
00503
00504 m_artistEdit(NULL),
00505 m_albumEdit(NULL),
00506 m_genreEdit(NULL),
00507 m_yearEdit(NULL),
00508
00509 m_compilationCheck(NULL),
00510
00511 m_trackList(NULL),
00512 m_qualityList(NULL),
00513
00514 m_switchTitleArtist(NULL),
00515 m_scanButton(NULL),
00516 m_ripButton(NULL),
00517 m_searchArtistButton(NULL),
00518 m_searchAlbumButton(NULL),
00519 m_searchGenreButton(NULL),
00520
00521 m_tracks(new QVector<RipTrack*>),
00522
00523 m_somethingwasripped(false),
00524 m_mediaMonitorActive(false),
00525
00526 m_CDdevice(device),
00527
00528 m_ejectThread(NULL), m_scanThread(NULL)
00529 {
00530 #ifndef _WIN32
00531
00532 m_mediaMonitorActive = false;
00533 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
00534 if (mon && mon->IsActive())
00535 {
00536 m_mediaMonitorActive = true;
00537 mon->StopMonitoring();
00538 }
00539 #endif
00540 }
00541
00542 Ripper::~Ripper(void)
00543 {
00544 if (m_decoder)
00545 delete m_decoder;
00546
00547 #ifndef _WIN32
00548
00549 if (m_mediaMonitorActive)
00550 {
00551 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
00552 if (mon)
00553 mon->StartMonitoring();
00554 }
00555 #endif
00556
00557 if (m_somethingwasripped)
00558 emit ripFinished();
00559 }
00560
00561 bool Ripper::Create(void)
00562 {
00563 if (!LoadWindowFromXML("music-ui.xml", "cdripper", this))
00564 return false;
00565
00566 m_qualityList = dynamic_cast<MythUIButtonList *>(GetChild("quality"));
00567 m_artistEdit = dynamic_cast<MythUITextEdit *>(GetChild("artist"));
00568 m_searchArtistButton = dynamic_cast<MythUIButton *>(GetChild("searchartist"));
00569 m_albumEdit = dynamic_cast<MythUITextEdit *>(GetChild("album"));
00570 m_searchAlbumButton = dynamic_cast<MythUIButton *>(GetChild("searchalbum"));
00571 m_genreEdit = dynamic_cast<MythUITextEdit *>(GetChild("genre"));
00572 m_yearEdit = dynamic_cast<MythUITextEdit *>(GetChild("year"));
00573 m_searchGenreButton = dynamic_cast<MythUIButton *>(GetChild("searchgenre"));
00574 m_compilationCheck = dynamic_cast<MythUICheckBox *>(GetChild("compilation"));
00575 m_switchTitleArtist = dynamic_cast<MythUIButton *>(GetChild("switch"));
00576 m_scanButton = dynamic_cast<MythUIButton *>(GetChild("scan"));
00577 m_ripButton = dynamic_cast<MythUIButton *>(GetChild("rip"));
00578 m_trackList = dynamic_cast<MythUIButtonList *>(GetChild("tracks"));
00579
00580 BuildFocusList();
00581
00582 if (!m_artistEdit || !m_scanButton || !m_ripButton || !m_switchTitleArtist
00583 || !m_trackList || !m_compilationCheck || !m_searchGenreButton
00584 || !m_yearEdit || !m_genreEdit || !m_searchArtistButton
00585 || !m_albumEdit || !m_searchAlbumButton || !m_qualityList)
00586 {
00587 LOG(VB_GENERAL, LOG_ERR,
00588 "Missing theme elements for screen 'cdripper'");
00589 return false;
00590 }
00591
00592 connect(m_trackList, SIGNAL(itemClicked(MythUIButtonListItem *)),
00593 SLOT(toggleTrackActive(MythUIButtonListItem *)));
00594 connect(m_ripButton, SIGNAL(Clicked()), SLOT(startRipper()));
00595 connect(m_scanButton, SIGNAL(Clicked()), SLOT(startScanCD()));
00596 connect(m_switchTitleArtist, SIGNAL(Clicked()),
00597 SLOT(switchTitlesAndArtists()));
00598 connect(m_compilationCheck, SIGNAL(toggled(bool)),
00599 SLOT(compilationChanged(bool)));
00600 connect(m_searchGenreButton, SIGNAL(Clicked()), SLOT(searchGenre()));
00601 connect(m_genreEdit, SIGNAL(valueChanged()), SLOT(genreChanged()));
00602 m_yearEdit->SetFilter((InputFilter)(FilterAlpha | FilterSymbols | FilterPunct));
00603 m_yearEdit->SetMaxLength(4);
00604 connect(m_yearEdit, SIGNAL(valueChanged()), SLOT(yearChanged()));
00605 connect(m_artistEdit, SIGNAL(valueChanged()), SLOT(artistChanged()));
00606 connect(m_searchArtistButton, SIGNAL(Clicked()), SLOT(searchArtist()));
00607 connect(m_albumEdit, SIGNAL(valueChanged()), SLOT(albumChanged()));
00608 connect(m_searchAlbumButton, SIGNAL(Clicked()), SLOT(searchAlbum()));
00609
00610
00611 new MythUIButtonListItem(m_qualityList, tr("Low"), qVariantFromValue(0));
00612 new MythUIButtonListItem(m_qualityList, tr("Medium"), qVariantFromValue(1));
00613 new MythUIButtonListItem(m_qualityList, tr("High"), qVariantFromValue(2));
00614 new MythUIButtonListItem(m_qualityList, tr("Perfect"), qVariantFromValue(3));
00615 m_qualityList->SetValueByData(qVariantFromValue(
00616 gCoreContext->GetNumSetting("DefaultRipQuality", 1)));
00617
00618 QTimer::singleShot(500, this, SLOT(startScanCD()));
00619
00620 return true;
00621 }
00622
00623 bool Ripper::keyPressEvent(QKeyEvent *event)
00624 {
00625 if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
00626 return true;
00627
00628 bool handled = false;
00629 QStringList actions;
00630 handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
00631
00632 for (int i = 0; i < actions.size() && !handled; i++)
00633 {
00634 QString action = actions[i];
00635 handled = true;
00636
00637 if (action == "INFO")
00638 {
00639 showEditMetadataDialog(m_trackList->GetItemCurrent());
00640 }
00641 else
00642 handled = false;
00643 }
00644
00645 if (!handled && MythScreenType::keyPressEvent(event))
00646 handled = true;
00647
00648 return handled;
00649 }
00650
00651 void Ripper::startScanCD(void)
00652 {
00653 if (m_scanThread)
00654 return;
00655
00656 QString message = QObject::tr("Scanning CD. Please Wait ...");
00657 OpenBusyPopup(message);
00658
00659 m_scanThread = new CDScannerThread(this);
00660 connect(m_scanThread->qthread(), SIGNAL(finished()), SLOT(ScanFinished()));
00661 m_scanThread->start();
00662 }
00663
00664 void Ripper::ScanFinished()
00665 {
00666 delete m_scanThread;
00667 m_scanThread = NULL;
00668
00669 m_tracks->clear();
00670
00671 bool isCompilation = false;
00672 if (m_decoder)
00673 {
00674 QString label;
00675 Metadata *metadata;
00676
00677 m_artistName.clear();
00678 m_albumName.clear();
00679 m_genreName.clear();
00680 m_year.clear();
00681
00682 for (int trackno = 0; trackno < m_decoder->getNumTracks(); trackno++)
00683 {
00684 RipTrack *ripTrack = new RipTrack;
00685
00686 metadata = m_decoder->getMetadata(trackno + 1);
00687 if (metadata)
00688 {
00689 ripTrack->metadata = metadata;
00690 ripTrack->length = metadata->Length();
00691
00692 if (metadata->Compilation())
00693 {
00694 isCompilation = true;
00695 m_artistName = metadata->CompilationArtist();
00696 }
00697 else if (m_artistName.isEmpty())
00698 {
00699 m_artistName = metadata->Artist();
00700 }
00701
00702 if (m_albumName.isEmpty())
00703 m_albumName = metadata->Album();
00704
00705 if (m_genreName.isEmpty() && !metadata->Genre().isEmpty())
00706 m_genreName = metadata->Genre();
00707
00708 if (m_year.isEmpty() && metadata->Year() > 0)
00709 m_year = QString::number(metadata->Year());
00710
00711 QString title = metadata->Title();
00712 ripTrack->isNew = isNewTune(m_artistName, m_albumName, title);
00713
00714 ripTrack->active = ripTrack->isNew;
00715
00716 m_tracks->push_back(ripTrack);
00717
00718 }
00719 else
00720 delete ripTrack;
00721 }
00722
00723 m_artistEdit->SetText(m_artistName);
00724 m_albumEdit->SetText(m_albumName);
00725 m_genreEdit->SetText(m_genreName);
00726 m_yearEdit->SetText(m_year);
00727 m_compilationCheck->SetCheckState(isCompilation);
00728
00729 if (!isCompilation)
00730 m_switchTitleArtist->SetVisible(false);
00731 else
00732 m_switchTitleArtist->SetVisible(true);
00733 }
00734
00735 BuildFocusList();
00736 updateTrackList();
00737
00738 CloseBusyPopup();
00739 }
00740
00741 void Ripper::scanCD(void)
00742 {
00743 #ifdef HAVE_CDIO
00744 {
00745 LOG(VB_MEDIA, LOG_INFO, QString("Ripper::%1 CD='%2'").
00746 arg(__func__).arg(m_CDdevice));
00747 (void)cdio_close_tray(m_CDdevice.toAscii().constData(), NULL);
00748 }
00749 #endif
00750
00751 if (m_decoder)
00752 delete m_decoder;
00753
00754 m_decoder = new CdDecoder("cda", NULL, NULL, NULL);
00755 if (m_decoder)
00756 m_decoder->setDevice(m_CDdevice);
00757 }
00758
00759 void Ripper::deleteAllExistingTracks(void)
00760 {
00761 QVector<RipTrack*>::iterator it;
00762 for (it = m_tracks->begin(); it < m_tracks->end(); ++it)
00763 {
00764 RipTrack *track = (*it);
00765 if (track && !track->isNew)
00766 {
00767 if (deleteExistingTrack(track))
00768 {
00769 track->isNew = true;
00770 toggleTrackActive(track);
00771 }
00772 }
00773 }
00774 }
00775
00776 bool Ripper::deleteExistingTrack(RipTrack *track)
00777 {
00778 if (!track)
00779 return false;
00780
00781 Metadata *metadata = track->metadata;
00782
00783 if (!metadata)
00784 return false;
00785
00786 QString artist = metadata->Artist();
00787 QString album = metadata->Album();
00788 QString title = metadata->Title();
00789
00790 MSqlQuery query(MSqlQuery::InitCon());
00791 QString queryString("SELECT song_id, "
00792 "CONCAT_WS('/', music_directories.path, music_songs.filename) AS filename "
00793 "FROM music_songs "
00794 "LEFT JOIN music_artists"
00795 " ON music_songs.artist_id=music_artists.artist_id "
00796 "LEFT JOIN music_albums"
00797 " ON music_songs.album_id=music_albums.album_id "
00798 "LEFT JOIN music_directories "
00799 " ON music_songs.directory_id=music_directories.directory_id "
00800 "WHERE artist_name REGEXP \'");
00801 QString token = artist;
00802 token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"),
00803 QString("."));
00804
00805 queryString += token + "\' AND " + "album_name REGEXP \'";
00806 token = album;
00807 token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"),
00808 QString("."));
00809 queryString += token + "\' AND " + "name REGEXP \'";
00810 token = title;
00811 token.replace(QRegExp("(/|\\\\|:|\'|\\,|\\!|\\(|\\)|\"|\\?|\\|)"),
00812 QString("."));
00813 queryString += token + "\' ORDER BY artist_name, album_name,"
00814 " name, song_id, filename LIMIT 1";
00815 query.prepare(queryString);
00816
00817 if (!query.exec() || !query.isActive())
00818 {
00819 MythDB::DBError("Search music database", query);
00820 return false;
00821 }
00822
00823 if (query.next())
00824 {
00825 int trackID = query.value(0).toInt();
00826 QString filename = gMusicData->musicDir + query.value(1).toString();
00827
00828
00829 if (!QFile::remove(filename))
00830 {
00831 LOG(VB_GENERAL, LOG_NOTICE, QString("Ripper::deleteExistingTrack() "
00832 "Could not delete %1")
00833 .arg(filename));
00834 return false;
00835 }
00836
00837
00838 MSqlQuery deleteQuery(MSqlQuery::InitCon());
00839 deleteQuery.prepare("DELETE FROM music_songs"
00840 " WHERE song_id = :SONG_ID");
00841 deleteQuery.bindValue(":SONG_ID", trackID);
00842 if (!deleteQuery.exec())
00843 {
00844 MythDB::DBError("Delete Track", deleteQuery);
00845 return false;
00846 }
00847 return true;
00848 }
00849
00850 return false;
00851 }
00852
00853 bool Ripper::somethingWasRipped()
00854 {
00855 return m_somethingwasripped;
00856 }
00857
00858 void Ripper::artistChanged()
00859 {
00860 QString newartist = m_artistEdit->GetText();
00861 Metadata *data;
00862
00863 if (m_tracks->size() > 0)
00864 {
00865 for (int trackno = 0; trackno < m_tracks->size(); ++trackno)
00866 {
00867 data = m_tracks->at(trackno)->metadata;
00868
00869 if (data)
00870 {
00871 if (m_compilationCheck->GetBooleanCheckState())
00872 {
00873 data->setCompilationArtist(newartist);
00874 }
00875 else
00876 {
00877 data->setArtist(newartist);
00878 data->setCompilationArtist("");
00879 }
00880 }
00881 }
00882
00883 updateTrackList();
00884 }
00885
00886 m_artistName = newartist;
00887 }
00888
00889 void Ripper::albumChanged()
00890 {
00891 QString newalbum = m_albumEdit->GetText();
00892 Metadata *data;
00893
00894 if (m_tracks->size() > 0)
00895 {
00896 for (int trackno = 0; trackno < m_tracks->size(); ++trackno)
00897 {
00898 data = m_tracks->at(trackno)->metadata;
00899
00900 if (data)
00901 data->setAlbum(newalbum);
00902 }
00903 }
00904
00905 m_albumName = newalbum;
00906 }
00907
00908 void Ripper::genreChanged()
00909 {
00910 QString newgenre = m_genreEdit->GetText();
00911 Metadata *data;
00912
00913 if (m_tracks->size() > 0)
00914 {
00915 for (int trackno = 0; trackno < m_tracks->size(); ++trackno)
00916 {
00917 data = m_tracks->at(trackno)->metadata;
00918
00919 if (data)
00920 data->setGenre(newgenre);
00921 }
00922 }
00923
00924 m_genreName = newgenre;
00925 }
00926
00927 void Ripper::yearChanged()
00928 {
00929 QString newyear = m_yearEdit->GetText();
00930
00931 Metadata *data;
00932
00933 if (m_tracks->size() > 0)
00934 {
00935 for (int trackno = 0; trackno < m_tracks->size(); ++trackno)
00936 {
00937 data = m_tracks->at(trackno)->metadata;
00938
00939 if (data)
00940 data->setYear(newyear.toInt());
00941 }
00942 }
00943
00944 m_year = newyear;
00945 }
00946
00947 void Ripper::compilationChanged(bool state)
00948 {
00949 if (!state)
00950 {
00951 Metadata *data;
00952 if (m_tracks->size() > 0)
00953 {
00954
00955 for (int trackno = 0; trackno < m_tracks->size(); ++trackno)
00956 {
00957 data = m_tracks->at(trackno)->metadata;
00958
00959 if (data)
00960 {
00961 data->setCompilationArtist("");
00962 data->setArtist(m_artistName);
00963 data->setCompilation(false);
00964 }
00965 }
00966 }
00967
00968 m_switchTitleArtist->SetVisible(false);
00969 }
00970 else
00971 {
00972 if (m_tracks->size() > 0)
00973 {
00974
00975 for (int trackno = 0; trackno < m_tracks->size(); ++trackno)
00976 {
00977 Metadata *data;
00978 data = m_tracks->at(trackno)->metadata;
00979
00980 if (data)
00981 {
00982 data->setCompilationArtist(m_artistName);
00983 data->setCompilation(true);
00984 }
00985 }
00986 }
00987
00988 m_switchTitleArtist->SetVisible(true);
00989 }
00990
00991 BuildFocusList();
00992 updateTrackList();
00993 }
00994
00995 void Ripper::switchTitlesAndArtists()
00996 {
00997 if (!m_compilationCheck->GetBooleanCheckState())
00998 return;
00999
01000 Metadata *data;
01001
01002
01003 QString tmp;
01004 if (m_tracks->size() > 0)
01005 {
01006 for (int track = 0; track < m_tracks->size(); ++track)
01007 {
01008 data = m_tracks->at(track)->metadata;
01009
01010 if (data)
01011 {
01012 tmp = data->Artist();
01013 data->setArtist(data->Title());
01014 data->setTitle(tmp);
01015 }
01016 }
01017
01018 updateTrackList();
01019 }
01020 }
01021
01022 void Ripper::startRipper(void)
01023 {
01024 if (m_tracks->isEmpty())
01025 {
01026 ShowOkPopup(tr("There are no tracks to rip?"));
01027 return;
01028 }
01029
01030 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
01031
01032 int quality = m_qualityList->GetItemCurrent()->GetData().toInt();
01033
01034 RipStatus *statusDialog = new RipStatus(mainStack, m_CDdevice, m_tracks,
01035 quality);
01036
01037 if (statusDialog->Create())
01038 {
01039 connect(statusDialog, SIGNAL(Result(bool)), SLOT(RipComplete(bool)));
01040 mainStack->AddScreen(statusDialog);
01041 }
01042 else
01043 delete statusDialog;
01044 }
01045
01046 void Ripper::RipComplete(bool result)
01047 {
01048 if (result == true)
01049 {
01050 bool EjectCD = gCoreContext->GetNumSetting("EjectCDAfterRipping", 1);
01051 if (EjectCD)
01052 startEjectCD();
01053
01054 ShowOkPopup(tr("Rip completed successfully."));
01055
01056 m_somethingwasripped = true;
01057 }
01058
01059 if (LCD *lcd = LCD::Get())
01060 lcd->switchToTime();
01061 }
01062
01063
01064 void Ripper::startEjectCD()
01065 {
01066 if (m_ejectThread)
01067 return;
01068
01069 QString message = tr("Ejecting CD. Please Wait ...");
01070
01071 OpenBusyPopup(message);
01072
01073 m_ejectThread = new CDEjectorThread(this);
01074 connect(m_ejectThread->qthread(),
01075 SIGNAL(finished()), SLOT(EjectFinished()));
01076 m_ejectThread->start();
01077 }
01078
01079 void Ripper::EjectFinished()
01080 {
01081 delete m_ejectThread;
01082 m_ejectThread = NULL;
01083
01084 CloseBusyPopup();
01085 }
01086
01087 void Ripper::ejectCD()
01088 {
01089 LOG(VB_MEDIA, LOG_INFO, __PRETTY_FUNCTION__);
01090 bool bEjectCD = gCoreContext->GetNumSetting("EjectCDAfterRipping",1);
01091 if (bEjectCD)
01092 {
01093 #ifdef HAVE_CDIO
01094 LOG(VB_MEDIA, LOG_INFO, QString("Ripper::%1 '%2'").
01095 arg(__func__).arg(m_CDdevice));
01096 (void)cdio_eject_media_drive(m_CDdevice.toAscii().constData());
01097 #else
01098 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
01099 if (mon)
01100 {
01101 QByteArray devname = m_CDdevice.toAscii();
01102 MythMediaDevice *pMedia = mon->GetMedia(devname.constData());
01103 if (pMedia && mon->ValidateAndLock(pMedia))
01104 {
01105 pMedia->eject();
01106 mon->Unlock(pMedia);
01107 }
01108 }
01109 #endif
01110 }
01111 }
01112
01113 void Ripper::updateTrackList(void)
01114 {
01115 if (m_tracks->isEmpty())
01116 return;
01117
01118 QString tmptitle;
01119 if (m_trackList)
01120 {
01121 m_trackList->Reset();
01122
01123 int i;
01124 for (i = 0; i < (int)m_tracks->size(); i++)
01125 {
01126 if (i >= m_tracks->size())
01127 break;
01128
01129 RipTrack *track = m_tracks->at(i);
01130 Metadata *metadata = track->metadata;
01131
01132 MythUIButtonListItem *item = new MythUIButtonListItem(m_trackList,"");
01133
01134 item->setCheckable(true);
01135
01136 item->SetData(qVariantFromValue(track));
01137
01138 if (track->isNew)
01139 item->DisplayState("new", "yes");
01140 else
01141 item->DisplayState("new", "no");
01142
01143 if (track->active)
01144 item->setChecked(MythUIButtonListItem::FullChecked);
01145 else
01146 item->setChecked(MythUIButtonListItem::NotChecked);
01147
01148 item->SetText(QString::number(metadata->Track()), "track");
01149 item->SetText(metadata->Title(), "title");
01150 item->SetText(metadata->Artist(), "artist");
01151
01152 int length = track->length / 1000;
01153 if (length > 0)
01154 {
01155 int min, sec;
01156 min = length / 60;
01157 sec = length % 60;
01158 QString s;
01159 s.sprintf("%02d:%02d", min, sec);
01160 item->SetText(s, "length");
01161 }
01162 else
01163 item->SetText("", "length");
01164
01165
01166
01167 }
01168 }
01169 }
01170
01171 void Ripper::searchArtist()
01172 {
01173 QString msg = tr("Select an Artist");
01174 QStringList searchList = Metadata::fillFieldList("artist");
01175
01176 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
01177 MythUISearchDialog *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, "");
01178
01179 if (!searchDlg->Create())
01180 {
01181 delete searchDlg;
01182 return;
01183 }
01184
01185 connect(searchDlg, SIGNAL(haveResult(QString)), SLOT(setArtist(QString)));
01186
01187 popupStack->AddScreen(searchDlg);
01188 }
01189
01190 void Ripper::setArtist(QString artist)
01191 {
01192 m_artistEdit->SetText(artist);
01193 }
01194
01195 void Ripper::searchAlbum()
01196 {
01197 QString msg = tr("Select an Album");
01198 QStringList searchList = Metadata::fillFieldList("album");
01199
01200 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
01201 MythUISearchDialog *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, "");
01202
01203 if (!searchDlg->Create())
01204 {
01205 delete searchDlg;
01206 return;
01207 }
01208
01209 connect(searchDlg, SIGNAL(haveResult(QString)), SLOT(setAlbum(QString)));
01210
01211 popupStack->AddScreen(searchDlg);
01212 }
01213
01214 void Ripper::setAlbum(QString album)
01215 {
01216 m_albumEdit->SetText(album);
01217 }
01218
01219 void Ripper::searchGenre()
01220 {
01221 QString msg = tr("Select a Genre");
01222 QStringList searchList = Metadata::fillFieldList("genre");
01223
01224 m_searchList.clear();
01225 for (int x = 0; x < genre_table_size; x++)
01226 m_searchList.push_back(QString(genre_table[x]));
01227 m_searchList.sort();
01228
01229 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
01230 MythUISearchDialog *searchDlg = new MythUISearchDialog(popupStack, msg, searchList, false, "");
01231
01232 if (!searchDlg->Create())
01233 {
01234 delete searchDlg;
01235 return;
01236 }
01237
01238 connect(searchDlg, SIGNAL(haveResult(QString)), SLOT(setGenre(QString)));
01239
01240 popupStack->AddScreen(searchDlg);
01241 }
01242
01243 void Ripper::setGenre(QString genre)
01244 {
01245 m_genreEdit->SetText(genre);
01246 }
01247
01248 void Ripper::showEditMetadataDialog(MythUIButtonListItem *item)
01249 {
01250 if (!item || m_tracks->isEmpty())
01251 return;
01252
01253 RipTrack *track = qVariantValue<RipTrack *>(item->GetData());
01254
01255 if (!track)
01256 return;
01257
01258 Metadata *editMeta = track->metadata;
01259
01260 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
01261
01262 EditMetadataDialog *editDialog = new EditMetadataDialog(mainStack, editMeta);
01263 editDialog->setSaveMetadataOnly();
01264
01265 if (!editDialog->Create())
01266 {
01267 delete editDialog;
01268 return;
01269 }
01270
01271 connect(editDialog, SIGNAL(metadataChanged()), this, SLOT(metadataChanged()));
01272
01273 mainStack->AddScreen(editDialog);
01274 }
01275
01276 void Ripper::metadataChanged(void)
01277 {
01278 updateTrackList();
01279 }
01280
01281 void Ripper::toggleTrackActive(RipTrack* track)
01282 {
01283 QVariant data = QVariant::fromValue(track);
01284 MythUIButtonListItem *item = m_trackList->GetItemByData(data);
01285 if (item)
01286 {
01287 toggleTrackActive(item);
01288 }
01289 }
01290
01291 void Ripper::toggleTrackActive(MythUIButtonListItem *item)
01292 {
01293 if (m_tracks->isEmpty() || !item)
01294 return;
01295
01296 RipTrack *track = m_tracks->at(m_trackList->GetItemPos(item));
01297
01298 if (!track->active && !track->isNew)
01299 {
01300 ShowConflictMenu(track);
01301 return;
01302 }
01303
01304 track->active = !track->active;
01305
01306 if (track->active)
01307 item->setChecked(MythUIButtonListItem::FullChecked);
01308 else
01309 item->setChecked(MythUIButtonListItem::NotChecked);
01310
01311 updateTrackLengths();
01312 }
01313
01314 void Ripper::ShowConflictMenu(RipTrack* track)
01315 {
01316 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
01317
01318 QString msg = tr("This track has been disabled because it is already "
01319 "present in the database.\n"
01320 "Do you want to permanently delete the existing "
01321 "file(s)?");
01322 MythDialogBox *menu = new MythDialogBox(msg, popupStack, "conflictmenu",
01323 true);
01324
01325 if (menu->Create())
01326 popupStack->AddScreen(menu);
01327 else
01328 {
01329 delete menu;
01330 return;
01331 }
01332
01333 menu->SetReturnEvent(this, "conflictmenu");
01334 menu->AddButton(tr("No, Cancel"));
01335 menu->AddButton(tr("Yes, Delete"), QVariant::fromValue(track));
01336 menu->AddButton(tr("Yes, Delete All"));
01337 }
01338
01339 void Ripper::updateTrackLengths()
01340 {
01341 QVector<RipTrack*>::iterator it;
01342 RipTrack *track;
01343 int length = 0;
01344
01345 for (it = m_tracks->end() - 1; it == m_tracks->begin(); --it)
01346 {
01347 track = *it;
01348 if (track->active)
01349 {
01350 track->length = length + track->metadata->Length();
01351 length = 0;
01352 }
01353 else
01354 {
01355 track->length = 0;
01356 length += track->metadata->Length();
01357 }
01358 }
01359 }
01360
01361 void Ripper::customEvent(QEvent* event)
01362 {
01363 if (event->type() == DialogCompletionEvent::kEventType)
01364 {
01365 DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(event);
01366
01367 if (dce->GetId() == "conflictmenu")
01368 {
01369 int buttonNum = dce->GetResult();
01370 RipTrack *track = qVariantValue<RipTrack *>(dce->GetData());
01371
01372 switch (buttonNum)
01373 {
01374 case 0:
01375
01376 break;
01377 case 1:
01378 if (deleteExistingTrack(track))
01379 {
01380 track->isNew = true;
01381 toggleTrackActive(track);
01382 }
01383 break;
01384 case 2:
01385 deleteAllExistingTracks();
01386 break;
01387 default:
01388 break;
01389 }
01390 }
01391
01392 return;
01393 }
01394
01395 MythUIType::customEvent(event);
01396 }
01397
01398
01400
01401 RipStatus::RipStatus(MythScreenStack *parent, const QString &device,
01402 QVector<RipTrack*> *tracks, int quality)
01403 : MythScreenType(parent, "ripstatus")
01404 {
01405 m_CDdevice = device;
01406 m_tracks = tracks;
01407 m_quality = quality;
01408 m_ripperThread = NULL;
01409
01410 m_overallText = m_trackText = m_statusText = m_trackPctText =
01411 m_overallPctText = NULL;
01412
01413 m_overallProgress = m_trackProgress = NULL;
01414 }
01415
01416 RipStatus::~RipStatus(void)
01417 {
01418 if (m_ripperThread)
01419 delete m_ripperThread;
01420
01421 if (LCD *lcd = LCD::Get())
01422 lcd->switchToTime();
01423 }
01424
01425 bool RipStatus::Create(void)
01426 {
01427 if (!LoadWindowFromXML("music-ui.xml", "ripstatus", this))
01428 return false;
01429
01430 m_overallText = dynamic_cast<MythUIText *>(GetChild("overall"));
01431 m_trackText = dynamic_cast<MythUIText *>(GetChild("track"));
01432 m_statusText = dynamic_cast<MythUIText *>(GetChild("status"));
01433 m_trackPctText = dynamic_cast<MythUIText *>(GetChild("trackpct"));
01434 m_overallPctText = dynamic_cast<MythUIText *>(GetChild("overallpct"));
01435
01436 m_overallProgress = dynamic_cast<MythUIProgressBar *>(GetChild("overall_progress"));
01437 m_trackProgress = dynamic_cast<MythUIProgressBar *>(GetChild("track_progress"));
01438
01439 BuildFocusList();
01440
01441 startRip();
01442
01443 return true;
01444 }
01445
01446 bool RipStatus::keyPressEvent(QKeyEvent *event)
01447 {
01448 if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
01449 return true;
01450
01451 bool handled = false;
01452 QStringList actions;
01453 handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
01454
01455 for (int i = 0; i < actions.size() && !handled; i++)
01456 {
01457 QString action = actions[i];
01458 handled = true;
01459
01460
01461 if (action == "ESCAPE" &&
01462 m_ripperThread && m_ripperThread->isRunning())
01463 {
01464 MythConfirmationDialog *dialog =
01465 ShowOkPopup(tr("Cancel ripping the CD?"), this, NULL, true);
01466 if (dialog)
01467 dialog->SetReturnEvent(this, "stop_ripping");
01468 }
01469 else
01470 handled = false;
01471 }
01472
01473 if (!handled && MythScreenType::keyPressEvent(event))
01474 handled = true;
01475
01476 return handled;
01477 }
01478
01479 void RipStatus::customEvent(QEvent *event)
01480 {
01481 if (event->type() == DialogCompletionEvent::kEventType)
01482 {
01483 DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(event);
01484
01485 if (dce->GetId() == "stop_ripping" && dce->GetResult())
01486 {
01487 m_ripperThread->cancel();
01488 m_ripperThread->wait();
01489 Close();
01490 }
01491
01492 return;
01493 }
01494
01495 RipStatusEvent *rse = dynamic_cast<RipStatusEvent *> (event);
01496
01497 if (!rse)
01498 return;
01499
01500 if (event->type() == RipStatusEvent::kTrackTextEvent)
01501 {
01502 if (m_trackText)
01503 m_trackText->SetText(rse->text);
01504 }
01505 else if (event->type() == RipStatusEvent::kOverallTextEvent)
01506 {
01507 if (m_overallText)
01508 m_overallText->SetText(rse->text);
01509 }
01510 else if (event->type() == RipStatusEvent::kStatusTextEvent)
01511 {
01512 if (m_statusText)
01513 m_statusText->SetText(rse->text);
01514 }
01515 else if (event->type() == RipStatusEvent::kTrackProgressEvent)
01516 {
01517 if (m_trackProgress)
01518 m_trackProgress->SetUsed(rse->value);
01519 }
01520 else if (event->type() == RipStatusEvent::kTrackPercentEvent)
01521 {
01522 if (m_trackPctText)
01523 m_trackPctText->SetText(QString("%1%").arg(rse->value));
01524 }
01525 else if (event->type() == RipStatusEvent::kTrackStartEvent)
01526 {
01527 if (m_trackProgress)
01528 m_trackProgress->SetTotal(rse->value);
01529 }
01530 else if (event->type() == RipStatusEvent::kOverallProgressEvent)
01531 {
01532 if (m_overallProgress)
01533 m_overallProgress->SetUsed(rse->value);
01534 }
01535 else if (event->type() == RipStatusEvent::kOverallStartEvent)
01536 {
01537 if (m_overallProgress)
01538 m_overallProgress->SetTotal(rse->value);
01539 }
01540 else if (event->type() == RipStatusEvent::kOverallPercentEvent)
01541 {
01542 if (m_overallPctText)
01543 m_overallPctText->SetText(QString("%1%").arg(rse->value));
01544 }
01545 else if (event->type() == RipStatusEvent::kFinishedEvent)
01546 {
01547 emit Result(true);
01548 Close();
01549 }
01550 else if (event->type() == RipStatusEvent::kEncoderErrorEvent)
01551 {
01552 ShowOkPopup(tr("The encoder failed to create the file.\n"
01553 "Do you have write permissions"
01554 " for the music directory?"));
01555 Close();
01556 }
01557 else
01558 {
01559 LOG(VB_GENERAL, LOG_ERR, "Received an unknown event type!");
01560 }
01561 }
01562
01563 void RipStatus::startRip(void)
01564 {
01565 if (m_ripperThread)
01566 delete m_ripperThread;
01567
01568 m_ripperThread = new CDRipperThread(this, m_CDdevice, m_tracks, m_quality);
01569 m_ripperThread->start();
01570 }