File indexing completed on 2024-05-05 04:50:55

0001 /*
0002     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "k3bcdda2wavreader.h"
0008 
0009 #include "k3bexternalbinmanager.h"
0010 #include "k3bdevice.h"
0011 #include "k3bdevicemanager.h"
0012 #include "k3bcore.h"
0013 #include "k3bprocess.h"
0014 #include "k3b_i18n.h"
0015 
0016 #include <QDebug>
0017 #include <QRegExp>
0018 #include <QVector>
0019 
0020 
0021 class K3b::Cdda2wavReader::Private
0022 {
0023 public:
0024     Private()
0025         : cdda2wavBin(0),
0026           process(0),
0027           canceled(false),
0028           running(false),
0029           fdToWriteTo(-1) {
0030     }
0031 
0032     const K3b::ExternalBin* cdda2wavBin;
0033     K3b::Process* process;
0034 
0035     bool canceled;
0036     bool running;
0037 
0038     int fdToWriteTo;
0039 
0040     int currentTrack;
0041     QVector<int> trackOffsets;
0042 };
0043 
0044 
0045 K3b::Cdda2wavReader::Cdda2wavReader( QObject* parent )
0046     : K3b::Job( parent )
0047 {
0048     d = new Private();
0049 }
0050 
0051 
0052 K3b::Cdda2wavReader::~Cdda2wavReader()
0053 {
0054     delete d->process;
0055     delete d;
0056 }
0057 
0058 
0059 bool K3b::Cdda2wavReader::active() const
0060 {
0061     return d->running;
0062 }
0063 
0064 
0065 void K3b::Cdda2wavReader::writeToFd( int fd )
0066 {
0067     d->fdToWriteTo = fd;
0068 }
0069 
0070 
0071 void K3b::Cdda2wavReader::start()
0072 {
0073     start( false );
0074 }
0075 
0076 
0077 void K3b::Cdda2wavReader::start( bool onlyInfo )
0078 {
0079     d->running = true;
0080     d->canceled = false;
0081     d->currentTrack = 1;
0082     d->trackOffsets.clear();
0083 
0084     jobStarted();
0085 
0086     d->cdda2wavBin = k3bcore->externalBinManager()->binObject( "cdda2wav" );
0087     if( !d->cdda2wavBin ) {
0088         emit infoMessage( i18n("Could not find %1 executable.",QString("cdda2wav")), MessageError );
0089         jobFinished(false);
0090         d->running = false;
0091         return;
0092     }
0093 
0094     // prepare the process
0095     delete d->process;
0096     d->process = new K3b::Process();
0097     d->process->setSplitStdout(true);
0098     d->process->setSuppressEmptyLines(true);
0099     d->process->setWorkingDirectory( m_imagePath );
0100     connect( d->process, SIGNAL(stdoutLine(QString)), this, SLOT(slotProcessLine(QString)) );
0101     connect( d->process, SIGNAL(stderrLine(QString)), this, SLOT(slotProcessLine(QString)) );
0102     connect( d->process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotProcessExited(int,QProcess::ExitStatus)) );
0103 
0104     // create the command line
0105     *d->process << d->cdda2wavBin->path;
0106     *d->process << "-vall" << ( d->cdda2wavBin->hasFeature( "gui" ) ? "-gui" : "-g" );
0107     if( d->cdda2wavBin->hasFeature( "dev" ) )
0108         *d->process << QString("dev=%1").arg(K3b::Device::externalBinDeviceParameter(m_device, d->cdda2wavBin));
0109     else
0110         *d->process << "-D" << K3b::Device::externalBinDeviceParameter(m_device, d->cdda2wavBin);
0111     *d->process << ( d->cdda2wavBin->hasFeature( "bulk" ) ? "-bulk" : "-B" );
0112     if( onlyInfo )
0113         *d->process << ( d->cdda2wavBin->hasFeature( "info-only" ) ? "-info-only" : "-J" );
0114     else if( d->fdToWriteTo != -1 )
0115         *d->process << ( d->cdda2wavBin->hasFeature( "no-infofile" ) ? "-no-infofile" : "-H" );
0116 
0117     // additional user parameters from config
0118     const QStringList& params = d->cdda2wavBin->userParameters();
0119     for( QStringList::const_iterator it = params.begin(); it != params.end(); ++it )
0120         *d->process << *it;
0121 
0122     // start the thing
0123     if( !d->process->start( K3Process::All ) ) {
0124         // something went wrong when starting the program
0125         // it "should" be the executable
0126         qDebug() << "(K3b::Cdda2wavReader) could not start cdda2wav";
0127         emit infoMessage( i18n("Could not start %1.",QString("cdda2wav")), K3b::Job::MessageError );
0128         d->running = false;
0129         jobFinished(false);
0130     }
0131 }
0132 
0133 
0134 void K3b::Cdda2wavReader::cancel()
0135 {
0136     if( d->running ) {
0137         d->canceled = true;
0138         if( d->process )
0139             if( d->process->isRunning() )
0140                 d->process->kill();
0141     }
0142 }
0143 
0144 
0145 void K3b::Cdda2wavReader::slotProcessLine( const QString& line )
0146 {
0147     // Tracks:11 44:37.30
0148     // CDINDEX discid: ZvzBXv614ACgzn1bWWy107cs0nA-
0149     // CDDB discid: 0x8a0a730b
0150     // CD-Text: not detected
0151     // CD-Extra: not detected
0152     // Album title: '' from ''
0153     // T01:       0  3:39.70 audio linear copydenied stereo title '' from ''
0154     // T02:   16495  3:10.47 audio linear copydenied stereo title '' from ''
0155     // T03:   30792  3:30.00 audio linear copydenied stereo title '' from ''
0156     // T04:   46542  4:05.05 audio linear copydenied stereo title '' from ''
0157     // T05:   64922  3:44.35 audio linear copydenied stereo title '' from ''
0158     // T06:   81757  4:36.45 audio linear copydenied stereo title '' from ''
0159     // T07:  102502  3:59.30 audio linear copydenied stereo title '' from ''
0160     // T08:  120457  5:24.30 audio linear copydenied stereo title '' from ''
0161     // T09:  144787  3:26.28 audio linear copydenied stereo title '' from ''
0162     // T10:  160265  4:07.20 audio linear copydenied stereo title '' from ''
0163     // T11:  178810  4:51.20 audio linear copydenied stereo title '' from ''
0164 
0165     // percent_done:
0166     // 100%  track  1 successfully recorded
0167     // 100%  track  2 successfully recorded
0168     // 100%  track  3 successfully recorded
0169 
0170 
0171 
0172     static QRegExp rx( "T\\d\\d:" );
0173     if( rx.exactMatch( line.left(4) ) || line.startsWith( "Leadout" ) ) {
0174         int pos = line.indexOf( ' ' );
0175         int endpos = line.indexOf( QRegExp( "\\d" ), pos );
0176         endpos = line.indexOf( ' ', endpos );
0177         bool ok;
0178         int offset = line.mid( pos, endpos-pos ).toInt(&ok);
0179         if( ok )
0180             d->trackOffsets.append( offset );
0181         else
0182             qDebug() << "(K3b::Cdda2wavReader) track offset parsing error: '" << line.mid( pos, endpos-pos ) << "'";
0183     }
0184 
0185     else if( line.startsWith( "percent_done" ) ) {
0186         // the reading starts
0187         d->currentTrack = 1;
0188         emit nextTrack( d->currentTrack, d->trackOffsets.count() );
0189     }
0190 
0191     else if( line.contains("successfully recorded") ) {
0192         d->currentTrack++;
0193         emit nextTrack( d->currentTrack, d->trackOffsets.count() );
0194     }
0195 
0196     else if( line.contains("%") ) {
0197         // parse progress
0198         bool ok;
0199         int p = line.left(3).toInt(&ok);
0200         if( ok ) {
0201             emit subPercent( p );
0202 
0203             int overall = d->trackOffsets[d->currentTrack-1];
0204             int tSize = d->trackOffsets[d->currentTrack] - d->trackOffsets[d->currentTrack-1];
0205             overall += (tSize*p/100);
0206 
0207             emit percent( overall*100/d->trackOffsets[d->trackOffsets.count()-1] );
0208         }
0209         else
0210             qDebug() << "(K3b::Cdda2wavReader) track progress parsing error: '" << line.left(3) << "'";
0211     }
0212 }
0213 
0214 
0215 void K3b::Cdda2wavReader::slotProcessExited( int exitCode, QProcess::ExitStatus exitStatus )
0216 {
0217     d->running = false;
0218 
0219     if( d->canceled ) {
0220         emit canceled();
0221         jobFinished(false);
0222         return;
0223     }
0224 
0225     if( exitStatus == QProcess::NormalExit ) {
0226         // TODO: improve this
0227 
0228         if( exitCode == 0 ) {
0229             jobFinished( true );
0230         }
0231         else {
0232             emit infoMessage( i18n("%1 returned an unknown error (code %2)."
0233                                    QString("Cdda2wav"), exitCode ), MessageError );
0234             jobFinished( false );
0235         }
0236     }
0237     else {
0238         emit infoMessage( i18n("%1 did not exit cleanly.",QString("Cdda2wav")),
0239                           MessageError );
0240         jobFinished( false );
0241     }
0242 }
0243 
0244 #include "moc_k3bcdda2wavreader.cpp"