File indexing completed on 2024-05-12 04:51:10

0001 /*
0002     SPDX-FileCopyrightText: 2003-2004 Christian Kvasny <chris@k3b.org>
0003     SPDX-FileCopyrightText: 2007-2009 Sebastian Trueg <trueg@k3b.org>
0004     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "k3bvcdjob.h"
0010 #include "k3bvcddoc.h"
0011 #include "k3bvcdtrack.h"
0012 #include "k3bvcdxmlview.h"
0013 #include "k3bcore.h"
0014 #include "k3bdoc.h"
0015 #include "k3bprocess.h"
0016 #include "k3bdevice.h"
0017 #include "k3bexternalbinmanager.h"
0018 #include "k3bglobals.h"
0019 #include "k3bcdrecordwriter.h"
0020 #include "k3bcdrdaowriter.h"
0021 #include "k3bglobalsettings.h"
0022 #include "k3bdevicehandler.h"
0023 #include "k3b_i18n.h"
0024 
0025 #include <KConfig>
0026 #include <KIO/Global>
0027 
0028 #include <QString>
0029 #include <QDateTime>
0030 #include <QFile>
0031 #include <QTemporaryFile>
0032 #include <QTimer>
0033 #include <QDebug>
0034 #include <QRegularExpression>
0035 #include <QUrl>
0036 #include <QDomDocument>
0037 
0038 
0039 class K3b::VcdJob::Private
0040 {
0041 public:
0042     QTemporaryFile* xmlFile;
0043 };
0044 
0045 
0046 K3b::VcdJob::VcdJob( K3b::VcdDoc* doc, K3b::JobHandler* jh, QObject* parent )
0047     : K3b::BurnJob( jh, parent ),
0048       d( new Private )
0049 {
0050     d->xmlFile = 0;
0051 
0052     m_doc = doc;
0053     m_doc->setCopies( m_doc->dummy() || m_doc->onlyCreateImages() ? 1 : m_doc->copies() );
0054     m_process = 0;
0055     m_currentWrittenTrackNumber = 0;
0056     m_bytesFinishedTracks = 0;
0057     m_writerJob = 0;
0058     // m_createimageonlypercent = 33.3;
0059     m_createimageonlypercent = 100 / ( m_doc->copies() + 2 );
0060     m_currentcopy = 1;
0061     m_imageFinished = false;
0062 }
0063 
0064 
0065 K3b::VcdJob::~VcdJob()
0066 {
0067     delete d->xmlFile;
0068     delete d;
0069 
0070     delete m_process;
0071 
0072     delete m_writerJob;
0073 }
0074 
0075 
0076 K3b::Doc* K3b::VcdJob::doc() const
0077 {
0078     return m_doc;
0079 }
0080 
0081 
0082 K3b::Device::Device* K3b::VcdJob::writer() const
0083 {
0084     if( doc()->onlyCreateImages() )
0085         return 0;
0086     else
0087         return doc() ->burner();
0088 }
0089 
0090 void K3b::VcdJob::cancel()
0091 {
0092     cancelAll();
0093 
0094     emit canceled();
0095     jobFinished( false );
0096 }
0097 
0098 
0099 void K3b::VcdJob::cancelAll()
0100 {
0101     m_canceled = true;
0102 
0103     if ( m_writerJob )
0104         m_writerJob->cancel();
0105 
0106     if ( m_process->isRunning() ) {
0107         m_process->disconnect( this );
0108         m_process->terminate();
0109     }
0110 
0111     // remove bin-file if it is unfinished or the user selected to remove image
0112     if ( QFile::exists( m_doc->vcdImage() ) ) {
0113         if ( (!m_doc->onTheFly() && m_doc->removeImages()) || !m_imageFinished ) {
0114             emit infoMessage( i18n( "Removing Binary file %1" , m_doc->vcdImage() ), K3b::Job::MessageSuccess );
0115             QFile::remove
0116                 ( m_doc->vcdImage() );
0117             m_doc->setVcdImage( "" );
0118         }
0119     }
0120 
0121     // remove cue-file if it is unfinished or the user selected to remove image
0122     if ( QFile::exists( m_cueFile ) ) {
0123         if ( (!m_doc->onTheFly() && m_doc->removeImages()) || !m_imageFinished ) {
0124             emit infoMessage( i18n( "Removing Cue file %1" , m_cueFile ), K3b::Job::MessageSuccess );
0125             QFile::remove
0126                 ( m_cueFile );
0127             m_cueFile = "";
0128         }
0129     }
0130 }
0131 
0132 
0133 void K3b::VcdJob::start()
0134 {
0135     qDebug() << "(K3b::VcdJob) starting job";
0136 
0137     jobStarted();
0138     emit burning( false );
0139     m_canceled = false;
0140 
0141     int pos = QString( m_doc->vcdImage() ).indexOf( ".bin", QString( m_doc->vcdImage() ).length() - 4 );
0142     if ( pos > 0 ) {
0143         m_cueFile = m_doc->vcdImage().left( pos ) + ".cue";
0144     } else {
0145         m_cueFile = m_doc->vcdImage() + ".cue";
0146         m_doc->setVcdImage( m_doc->vcdImage() + ".bin" );
0147     }
0148 
0149     if ( vcdDoc() ->onlyCreateImages() )
0150         m_createimageonlypercent = 50.0;
0151 
0152     // vcdxGen();
0153     xmlGen();
0154 }
0155 
0156 void K3b::VcdJob::xmlGen()
0157 {
0158     delete d->xmlFile;
0159     d->xmlFile = new QTemporaryFile;
0160 
0161     if( d->xmlFile->open() ) {
0162         qDebug() << "(K3b::VcdJob) writing XML data to" << d->xmlFile->fileName();
0163 
0164         K3b::VcdXmlView xmlView( m_doc );
0165         xmlView.write( *d->xmlFile );
0166 
0167         //    emit infoMessage( i18n( "XML-file successfully created" ), K3b::Job::MessageSuccess );
0168         emit debuggingOutput( "K3b::VcdXml:", xmlView.xmlString() );
0169 
0170         vcdxBuild();
0171     }
0172     else {
0173         qDebug() << "(K3b::VcdJob) could not write xmlfile.";
0174         emit infoMessage( i18n( "Could not write correct XML file." ), K3b::Job::MessageError );
0175         cancelAll();
0176         jobFinished( false );
0177     }
0178 }
0179 
0180 void K3b::VcdJob::vcdxBuild()
0181 {
0182     emit newTask( i18n( "Creating image files" ) );
0183 
0184     m_stage = stageUnknown;
0185     firstTrack = true;
0186     delete m_process;
0187     m_process = new K3b::Process();
0188     m_process->setSplitStdout( true );
0189 
0190     emit infoMessage( i18n( "Creating Cue/Bin files..." ), K3b::Job::MessageInfo );
0191     const K3b::ExternalBin* bin = k3bcore ->externalBinManager() ->binObject( "vcdxbuild" );
0192     if ( !bin ) {
0193         qDebug() << "(K3b::VcdJob) could not find vcdxbuild executable";
0194         emit infoMessage( i18n( "Could not find %1 executable." , QString("vcdxbuild") ), K3b::Job::MessageError );
0195         emit infoMessage( i18n( "To create Video CDs you have to install VcdImager version %1." ,QString( ">= 0.7.12") ), K3b::Job::MessageInfo );
0196         emit infoMessage( i18n( "You can find this on your distribution disks or download it from https://www.gnu.org/software/vcdimager" ), K3b::Job::MessageInfo );
0197         cancelAll();
0198         jobFinished( false );
0199         return ;
0200     }
0201 
0202     if ( bin->version() < K3b::Version( "0.7.12" ) ) {
0203         qDebug() << "(K3b::VcdJob) vcdxbuild executable too old!";
0204         emit infoMessage( i18n( "%1 executable too old: need version %2 or greater." ,QString( "Vcdxbuild" ),QString( "0.7.12" )), K3b::Job::MessageError );
0205         emit infoMessage( i18n( "You can find this on your distribution disks or download it from https://www.gnu.org/software/vcdimager" ), K3b::Job::MessageInfo );
0206         cancelAll();
0207         jobFinished( false );
0208         return ;
0209     }
0210 
0211     if ( !bin->copyright().isEmpty() )
0212         emit infoMessage( i18n( "Using %1 %2 – Copyright © %3" , bin->name() , bin->version() ,bin->copyright() ), MessageInfo );
0213 
0214     *m_process << bin;
0215 
0216     // additional user parameters from config
0217     const QStringList& params = k3bcore->externalBinManager() ->program( "vcdxbuild" ) ->userParameters();
0218     for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it )
0219         *m_process << *it;
0220 
0221 
0222     if ( vcdDoc() ->vcdOptions() ->Sector2336() ) {
0223         qDebug() << "(K3b::VcdJob) Write 2336 Sectors = on";
0224         *m_process << "--sector-2336";
0225     }
0226 
0227     *m_process << "--progress" << "--gui";
0228 
0229     *m_process << QString( "--cue-file=%1" ).arg( m_cueFile );
0230 
0231     *m_process << QString( "--bin-file=%1" ).arg( m_doc->vcdImage() );
0232 
0233     *m_process << d->xmlFile->fileName();
0234 
0235     connect( m_process, SIGNAL(stdoutLine(QString)),
0236              this, SLOT(slotParseVcdxBuildOutput(QString)) );
0237     connect( m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
0238              this, SLOT(slotVcdxBuildFinished(int,QProcess::ExitStatus)) );
0239 
0240     // vcdxbuild commandline parameters
0241     qDebug() << "***** vcdxbuild parameters:";
0242     QString s = m_process->joinedArgs();
0243     qDebug() << s << Qt::flush;
0244     emit debuggingOutput( "vcdxbuild command:", s );
0245 
0246     if ( !m_process->start( KProcess::MergedChannels ) ) {
0247         qDebug() << "(K3b::VcdJob) could not start vcdxbuild";
0248         emit infoMessage( i18n( "Could not start %1." , QString("vcdxbuild") ), K3b::Job::MessageError );
0249         cancelAll();
0250         jobFinished( false );
0251     }
0252 }
0253 
0254 void K3b::VcdJob::slotParseVcdxBuildOutput( const QString& line )
0255 {
0256     QDomDocument xml_doc;
0257     QDomElement xml_root;
0258 
0259     QString str = line.trimmed();
0260 
0261     emit debuggingOutput( "vcdxbuild", str );
0262 
0263     xml_doc.setContent( QString( "<?xml version='1.0'?><vcdxbuild>" ) + str + "</vcdxbuild>" );
0264 
0265     xml_root = xml_doc.documentElement();
0266 
0267     // There should be only one... but ...
0268     for ( QDomNode node = xml_root.firstChild(); !node.isNull(); node = node.nextSibling() ) {
0269         QDomElement el = node.toElement();
0270         if ( el.isNull() )
0271             continue;
0272 
0273         const QString tagName = el.tagName().toLower();
0274 
0275         if ( tagName == "progress" ) {
0276             const QString oper = el.attribute( "operation" ).toLower();
0277             const unsigned long long pos = el.attribute( "position" ).toLong();
0278             const long long size = el.attribute( "size" ).toLong();
0279 
0280             if ( oper == "scan" ) {
0281                 // Scan Video Files
0282                 if ( m_stage == stageUnknown || pos < m_bytesFinished ) {
0283                     static const QRegularExpression rx( "sequence-" );
0284                     const uint index = el.attribute( "id" ).remove( rx ).toUInt();
0285 
0286                     m_currentWrittenTrack = m_doc->at( m_currentWrittenTrackNumber );
0287                     emit newSubTask( i18n( "Scanning video file %1 of %2 (%3)" , index + 1 , doc() ->numOfTracks() , m_currentWrittenTrack->fileName() ) );
0288                     m_bytesFinished = 0;
0289 
0290                     if ( !firstTrack ) {
0291                         m_bytesFinishedTracks += m_doc->at( m_currentWrittenTrackNumber ) ->size();
0292                         m_currentWrittenTrackNumber++;
0293                     } else
0294                         firstTrack = false;
0295                 }
0296                 emit subPercent( ( int ) ( 100.0 * ( double ) pos / ( double ) size ) );
0297                 emit processedSubSize( pos / 1024 / 1024, size / 1024 / 1024 );
0298 
0299                 // this is the first of three processes.
0300                 double relOverallWritten = ( ( double ) m_bytesFinishedTracks + ( double ) pos ) / ( double ) doc() ->size();
0301                 emit percent( ( int ) ( m_createimageonlypercent * relOverallWritten ) );
0302 
0303                 m_bytesFinished = pos;
0304                 m_stage = stageScan;
0305 
0306             } else if ( oper == "write" ) {
0307                 emit subPercent( ( int ) ( 100.0 * ( double ) pos / ( double ) size ) );
0308                 emit processedSubSize( ( pos * 2048 ) / 1024 / 1024, ( size * 2048 ) / 1024 / 1024 );
0309                 emit percent( ( int ) ( m_createimageonlypercent + ( m_createimageonlypercent * ( double ) pos / ( double ) size ) ) );
0310 
0311                 m_stage = stageWrite;
0312             } else {
0313                 return ;
0314             }
0315         } else if ( tagName == "log" ) {
0316             QDomText tel = el.firstChild().toText();
0317             const QString level = el.attribute( "level" ).toLower();
0318             if ( tel.isText() ) {
0319                 const QString text = tel.data();
0320                 if ( m_stage == stageWrite && level == "information" )
0321                     qDebug() << QString( "(K3b::VcdJob) VcdxBuild information, %1" ).arg( text );
0322                 if ( ( text ).startsWith( "writing track" ) )
0323                     emit newSubTask( i18n( "Creating Image for track %1" , ( text ).mid( 14 ) ) );
0324                 else {
0325                     if ( level != "error" ) {
0326                         qDebug() << QString( "(K3b::VcdJob) vcdxbuild warning, %1" ).arg( text );
0327                         parseInformation( text );
0328                     } else {
0329                         qDebug() << QString( "(K3b::VcdJob) vcdxbuild error, %1" ).arg( text );
0330                         emit infoMessage( text, K3b::Job::MessageError );
0331                     }
0332                 }
0333             }
0334         }
0335     }
0336 }
0337 
0338 
0339 void K3b::VcdJob::slotVcdxBuildFinished( int exitCode, QProcess::ExitStatus exitStatus )
0340 {
0341     if ( exitStatus == QProcess::NormalExit ) {
0342         // TODO: check the process' exitStatus()
0343         switch ( exitCode ) {
0344         case 0:
0345             emit infoMessage( i18n( "Cue/Bin files successfully created." ), K3b::Job::MessageSuccess );
0346             m_imageFinished = true;
0347             break;
0348         default:
0349             emit infoMessage( i18n( "%1 returned an unknown error (code %2)." , QString("vcdxbuild") , exitCode ),
0350                               K3b::Job::MessageError );
0351             emit infoMessage( i18n( "Please send me an email with the last output." ), K3b::Job::MessageError );
0352             cancelAll();
0353             jobFinished( false );
0354             return ;
0355         }
0356     } else {
0357         emit infoMessage( i18n( "%1 did not exit cleanly." , QString("Vcdxbuild") ), K3b::Job::MessageError );
0358         cancelAll();
0359         jobFinished( false );
0360         return ;
0361     }
0362 
0363     //remove xml-file
0364     delete d->xmlFile;
0365     d->xmlFile = 0;
0366 
0367     qDebug() << QString( "(K3b::VcdJob) create only image: %1" ).arg( vcdDoc() ->onlyCreateImages() );
0368     if ( !vcdDoc() ->onlyCreateImages() )
0369         startWriterjob();
0370     else
0371         jobFinished( true );
0372 }
0373 
0374 
0375 void K3b::VcdJob::startWriterjob()
0376 {
0377     qDebug() << QString( "(K3b::VcdJob) writing copy %1 of %2" ).arg( m_currentcopy ).arg( m_doc->copies() );
0378     if ( prepareWriterJob() ) {
0379         if ( waitForMedium( m_doc->burner() ) == Device::MEDIA_UNKNOWN ) {
0380             cancel();
0381             return ;
0382         }
0383         // just to be sure we did not get canceled during the async discWaiting
0384         if ( m_canceled )
0385             return ;
0386 
0387         if ( m_doc->copies() > 1 )
0388             emit newTask( i18n( "Writing Copy %1 of %2" , m_currentcopy , m_doc->copies() ) );
0389 
0390         emit burning( true );
0391         m_writerJob->start();
0392     }
0393 }
0394 
0395 bool K3b::VcdJob::prepareWriterJob()
0396 {
0397     if ( m_writerJob )
0398         delete m_writerJob;
0399 
0400     const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager() ->binObject( "cdrecord" );
0401     if ( writingApp() == K3b::WritingAppAuto && cdrecordBin->hasFeature( "cuefile" ) && m_doc->burner() ->dao() )
0402         setWritingApp( K3b::WritingAppCdrecord );
0403 
0404     if ( writingApp() == K3b::WritingAppCdrdao || writingApp() == K3b::WritingAppAuto ) {
0405         K3b::CdrdaoWriter * writer = new K3b::CdrdaoWriter( m_doc->burner(), this, this );
0406         // create cdrdao job
0407         writer->setCommand( K3b::CdrdaoWriter::WRITE );
0408         writer->setSimulate( m_doc->dummy() );
0409         writer->setBurnSpeed( m_doc->speed() );
0410 
0411         writer->setTocFile( m_cueFile );
0412 
0413         m_writerJob = writer;
0414 
0415     } else if ( writingApp() == K3b::WritingAppCdrecord ) {
0416         K3b::CdrecordWriter * writer = new K3b::CdrecordWriter( m_doc->burner(), this, this );
0417         // create cdrecord job
0418 
0419         writer->setSimulate( m_doc->dummy() );
0420         writer->setBurnSpeed( m_doc->speed() );
0421         writer->setDao( true );
0422         writer->setCueFile( m_cueFile );
0423 
0424         m_writerJob = writer;
0425 
0426     }
0427 
0428     connect( m_writerJob, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) );
0429     connect( m_writerJob, SIGNAL(percent(int)), this, SLOT(slotWriterJobPercent(int)) );
0430     connect( m_writerJob, SIGNAL(processedSize(int,int)), this, SLOT(slotProcessedSize(int,int)) );
0431     connect( m_writerJob, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) );
0432     connect( m_writerJob, SIGNAL(processedSubSize(int,int)), this, SIGNAL(processedSubSize(int,int)) );
0433     connect( m_writerJob, SIGNAL(nextTrack(int,int)), this, SLOT(slotWriterNextTrack(int,int)) );
0434     connect( m_writerJob, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) );
0435     connect( m_writerJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) );
0436     connect( m_writerJob, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)), this, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)) );
0437     connect( m_writerJob, SIGNAL(finished(bool)), this, SLOT(slotWriterJobFinished(bool)) );
0438     connect( m_writerJob, SIGNAL(newTask(QString)), this, SIGNAL(newTask(QString)) );
0439     connect( m_writerJob, SIGNAL(newSubTask(QString)), this, SIGNAL(newSubTask(QString)) );
0440     connect( m_writerJob, SIGNAL(debuggingOutput(QString,QString)), this, SIGNAL(debuggingOutput(QString,QString)) );
0441 
0442     return true;
0443 }
0444 
0445 void K3b::VcdJob::slotWriterJobPercent( int p )
0446 {
0447     emit percent( ( int ) ( ( m_createimageonlypercent * ( m_currentcopy + 1 ) ) + p / ( m_doc->copies() + 2 ) ) );
0448 }
0449 
0450 void K3b::VcdJob::slotProcessedSize( int cs, int ts )
0451 {
0452     emit processedSize( cs + ( ts * ( m_currentcopy - 1 ) ) , ts * m_doc->copies() );
0453 }
0454 
0455 void K3b::VcdJob::slotWriterNextTrack( int t, int tt )
0456 {
0457     emit newSubTask( i18n( "Writing Track %1 of %2" , t , tt ) );
0458 }
0459 
0460 void K3b::VcdJob::slotWriterJobFinished( bool success )
0461 {
0462     if ( m_canceled )
0463         return ;
0464 
0465     if ( m_currentcopy >= m_doc->copies() ) {
0466         // remove bin-file if it is unfinished or the user selected to remove image
0467         if ( QFile::exists( m_doc->vcdImage() ) ) {
0468             if ( (!m_doc->onTheFly() && m_doc->removeImages()) || !m_imageFinished ) {
0469                 emit infoMessage( i18n( "Removing Binary file %1" , m_doc->vcdImage() ), K3b::Job::MessageSuccess );
0470                 QFile::remove
0471                     ( m_doc->vcdImage() );
0472                 m_doc->setVcdImage( "" );
0473             }
0474         }
0475 
0476         // remove cue-file if it is unfinished or the user selected to remove image
0477         if ( QFile::exists( m_cueFile ) ) {
0478             if ( (!m_doc->onTheFly() && m_doc->removeImages()) || !m_imageFinished ) {
0479                 emit infoMessage( i18n( "Removing Cue file %1" , m_cueFile ), K3b::Job::MessageSuccess );
0480                 QFile::remove
0481                     ( m_cueFile );
0482                 m_cueFile = "";
0483             }
0484         }
0485     }
0486 
0487     if ( success ) {
0488         // alright
0489         // the writerJob should have emitted the "simulation/writing successful" signal
0490         if ( m_currentcopy >= m_doc->copies() ) {
0491             if ( k3bcore->globalSettings()->ejectMedia() ) {
0492                 K3b::Device::eject( m_doc->burner() );
0493             }
0494             jobFinished( true );
0495         } else {
0496             if( !K3b::eject( m_doc->burner() ) ) {
0497                 blockingInformation( i18n("K3b was unable to eject the written disk. Please do so manually.") );
0498             }
0499             m_currentcopy++;
0500             startWriterjob();
0501         }
0502     } else {
0503         cancelAll();
0504         jobFinished( false );
0505     }
0506 }
0507 
0508 void K3b::VcdJob::parseInformation( const QString &text )
0509 {
0510     // parse warning
0511     if ( text.contains( "mpeg user scan data: one or more BCD fields out of range for" ) ) {
0512         int index = text.indexOf( " for" );
0513 
0514         emit infoMessage( i18n( "One or more BCD fields out of range for %1" , text.mid( index + 4 ).trimmed() ), K3b::Job::MessageWarning );
0515 
0516     } else if ( text.contains( "mpeg user scan data: from now on, scan information data errors will not be reported anymore" ) ) {
0517         emit infoMessage( i18n( "From now on, scan information data errors will not be reported anymore" ), K3b::Job::MessageInfo );
0518         emit infoMessage( i18n( "Consider enabling the 'update scan offsets' option, if it is not enabled already." ), K3b::Job::MessageInfo );
0519 
0520     } else if ( text.contains( "APS' pts seems out of order (actual pts" ) ) {
0521         int index = text.indexOf( "(actual pts" );
0522         int index2 = text.indexOf( ", last seen pts" );
0523         int index3 = text.indexOf( ") -- ignoring this aps" );
0524 
0525         emit infoMessage( i18n( "APS' pts seems out of order (actual pts %1, last seen pts %2)" , text.mid( index + 12, index2 - index - 12 ).trimmed() , text.mid( index2 + 14, index3 - index2 - 14 ).trimmed() ), K3b::Job::MessageWarning );
0526         emit infoMessage( i18n( "Ignoring this aps" ), K3b::Job::MessageInfo );
0527 
0528     } else if ( text.contains( "bad packet at packet" ) ) {
0529         int index = text.indexOf( "at packet #" );
0530         int index2 = text.indexOf( "(stream byte offset" );
0531         int index3 = text.indexOf( ") -- remaining " );
0532         int index4 = text.indexOf( "bytes of stream will be ignored" );
0533 
0534         emit infoMessage( i18n( "Bad packet at packet #%1 (stream byte offset %2)" , text.mid( index + 11, index2 - index - 11 ).trimmed() , text.mid( index2 + 19, index3 - index2 - 19 ).trimmed() ), K3b::Job::MessageWarning );
0535 
0536         const QString ignoredString = text.mid( index3 + 15, index4 - index3 - 15 ).trimmed();
0537         bool okay = true;
0538         const int ignoredBytes = ignoredString.toInt(&okay);
0539 
0540         if (okay) {
0541             emit infoMessage( i18np( "The remaining byte of the stream will be ignored.", "The remaining %1 bytes of the stream will be ignored." , ignoredBytes ), K3b::Job::MessageWarning );
0542         } else {
0543             emit infoMessage( i18n( "An unknown number of remaining stream bytes will be ignored." ), K3b::Job::MessageWarning );
0544         }
0545     }
0546 }
0547 
0548 QString K3b::VcdJob::jobDescription() const
0549 {
0550     switch ( m_doc->vcdType() ) {
0551     case K3b::VcdDoc::VCD11:
0552         return i18n( "Writing Video CD (Version 1.1)" );
0553     case K3b::VcdDoc::VCD20:
0554         return i18n( "Writing Video CD (Version 2.0)" );
0555     case K3b::VcdDoc::SVCD10:
0556         return i18n( "Writing Super Video CD" );
0557     case K3b::VcdDoc::HQVCD:
0558         return i18n( "Writing High-Quality Video CD" );
0559     default:
0560         return i18n( "Writing Video CD" );
0561     }
0562 }
0563 
0564 
0565 QString K3b::VcdJob::jobDetails() const
0566 {
0567     return ( i18np( "1 MPEG (%2)",
0568                     "%1 MPEGs (%2)",
0569                     m_doc->tracks() ->count(), KIO::convertSize( m_doc->size() ) )
0570              + ( m_doc->copies() > 1
0571                  ? i18np( " - %1 copy", " - %1 copies", m_doc->copies() )
0572                  : QString() ) );
0573 }
0574 
0575 #include "moc_k3bvcdjob.cpp"