File indexing completed on 2024-12-01 07:32:18
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"