1
2 #include "config.h"
3 #include "logger.h"
4 #include "global.h"
5
6 #include <KConfigGroup>
7 #include <QDir>
8 #include <QDomElement>
9 #include <QTime>
10 #include <solid/device.h>
11 #include <KStandardDirs>
12
13
Config(Logger * _logger,QObject * parent)14 Config::Config( Logger *_logger, QObject *parent )
15 : QObject( parent ),
16 logger( _logger )
17 {
18 connect( this, SIGNAL(updateWriteLogFilesSetting(bool)), logger, SLOT(updateWriteSetting(bool)) );
19
20 pPluginLoader = new PluginLoader( logger, this );
21 pTagEngine = new TagEngine( this );
22 pConversionOptionsManager = new ConversionOptionsManager( pPluginLoader, this );
23 }
24
~Config()25 Config::~Config()
26 {
27 save();
28 qDeleteAll(data.profiles);
29 }
30
load()31 void Config::load()
32 {
33 QTime time;
34 time.start();
35
36 QStringList formats;
37
38 KSharedConfig::Ptr conf = KGlobal::config();
39 KConfigGroup group;
40
41 group = conf->group( "General" );
42 data.app.configVersion = group.readEntry( "configVersion", 0 );
43 data.general.startTab = group.readEntry( "startTab", 0 );
44 data.general.lastTab = group.readEntry( "lastTab", 0 );
45 data.general.defaultProfile = group.readEntry( "defaultProfile", i18n("Last used") );
46 data.general.lastProfile = group.readEntry( "lastProfile", i18n("High") );
47 data.general.defaultFormat = group.readEntry( "defaultFormat", i18n("Last used") );
48 data.general.lastFormat = group.readEntry( "lastFormat", "ogg vorbis" );
49 data.general.lastOutputDirectoryMode = group.readEntry( "lastOutputDirectoryMode", 0 );
50 data.general.specifyOutputDirectory = group.readEntry( "specifyOutputDirectory", QDir::homePath() + "/soundKonverter" );
51 data.general.metaDataOutputDirectory = group.readEntry( "metaDataOutputDirectory", QDir::homePath() + "/soundKonverter/%b/%d - %n - %a - %t" );
52 data.general.copyStructureOutputDirectory = group.readEntry( "copyStructureOutputDirectory", QDir::homePath() + "/soundKonverter" );
53 data.general.lastMetaDataOutputDirectoryPaths = group.readEntry( "lastMetaDataOutputDirectoryPaths", QStringList() );
54 data.general.lastNormalOutputDirectoryPaths = group.readEntry( "lastNormalOutputDirectoryPaths", QStringList() );
55 data.general.waitForAlbumGain = group.readEntry( "waitForAlbumGain", true );
56 data.general.useVFATNames = group.readEntry( "useVFATNames", false );
57 data.general.copyIfSameCodec = group.readEntry( "copyIfSameCodec", false );
58 data.general.writeLogFiles = group.readEntry( "writeLogFiles", false );
59 data.general.conflictHandling = (Config::Data::General::ConflictHandling)group.readEntry( "conflictHandling", 0 );
60 // data.general.priority = group.readEntry( "priority", 10 );
61 data.general.numFiles = group.readEntry( "numFiles", 0 );
62 data.general.numReplayGainFiles = group.readEntry( "numReplayGainFiles", 0 );
63 if( data.general.numFiles == 0 || data.general.numReplayGainFiles == 0 )
64 {
65 QList<Solid::Device> processors = Solid::Device::listFromType(Solid::DeviceInterface::Processor, QString());
66 const int num = processors.count() > 0 ? processors.count() : 1;
67 if( data.general.numFiles == 0 )
68 data.general.numFiles = num;
69 if( data.general.numReplayGainFiles == 0 )
70 data.general.numReplayGainFiles = num;
71 }
72 // data.general.executeUserScript = group.readEntry( "executeUserScript", false );
73 // data.general.showToolBar = group.readEntry( "showToolBar", false );
74 // data.general.outputFilePermissions = group.readEntry( "outputFilePermissions", 644 );
75 data.general.actionMenuConvertMimeTypes = group.readEntry( "actionMenuConvertMimeTypes", QStringList() );
76 data.general.actionMenuReplayGainMimeTypes = group.readEntry( "actionMenuReplayGainMimeTypes", QStringList() );
77 data.general.replayGainGrouping = (Config::Data::General::ReplayGainGrouping)group.readEntry( "replayGainGrouping", 0 );
78 data.general.preferredOggVorbisExtension = group.readEntry( "preferredOggVorbisExtension", "ogg" );
79 data.general.preferredVorbisCommentCommentTag = group.readEntry( "preferredVorbisCommentCommentTag", "DESCRIPTION" );
80 data.general.preferredVorbisCommentTrackTotalTag = group.readEntry( "preferredVorbisCommentTrackTotalTag", "TRACKTOTAL" );
81 data.general.preferredVorbisCommentDiscTotalTag = group.readEntry( "preferredVorbisCommentDiscTotalTag", "DISCTOTAL" );
82
83 // due to a bug lastNormalOutputDirectoryPaths could have more than 5 items
84 while( data.general.lastNormalOutputDirectoryPaths.count() > 5 )
85 data.general.lastNormalOutputDirectoryPaths.takeLast();
86
87 group = conf->group( "Advanced" );
88 data.advanced.useSharedMemoryForTempFiles = group.readEntry( "useSharedMemoryForTempFiles", false );
89 data.advanced.sharedMemorySize = 0;
90 if( QFile::exists("/dev/shm") )
91 {
92 system("df -B 1M /dev/shm | tail -1 > /dev/shm/soundkonverter_shm_size");
93 QFile chkdf("/dev/shm/soundkonverter_shm_size");
94 if( chkdf.open(QIODevice::ReadOnly|QIODevice::Text) )
95 {
96 QTextStream t( &chkdf );
97 QString s = t.readLine();
98 QRegExp rxlen( "^(?:\\S+)(?:\\s+)(?:\\s+)(\\d+)(?:\\s+)(\\d+)(?:\\s+)(\\d+)(?:\\s+)(\\d+)" );
99 if( s.contains(rxlen) )
100 {
101 data.advanced.sharedMemorySize = rxlen.cap(1).toInt();
102 }
103 chkdf.close();
104 }
105 chkdf.remove();
106 }
107 data.advanced.maxSizeForSharedMemoryTempFiles = group.readEntry( "maxSizeForSharedMemoryTempFiles", data.advanced.sharedMemorySize / 4 );
108 data.advanced.usePipes = group.readEntry( "usePipes", false );
109 data.advanced.ejectCdAfterRip = group.readEntry( "ejectCdAfterRip", true );
110
111 group = conf->group( "CoverArt" );
112 data.coverArt.writeCovers = group.readEntry( "writeCovers", 1 );
113 data.coverArt.writeCoverName = group.readEntry( "writeCoverName", 0 );
114 data.coverArt.writeCoverDefaultName = group.readEntry( "writeCoverDefaultName", i18nc("cover file name","cover") );
115
116 group = conf->group( "Backends" );
117 formats = group.readEntry( "formats", QStringList() );
118 foreach( const QString& format, formats )
119 {
120 CodecData codecData;
121 codecData.codecName = format;
122 codecData.encoders = group.readEntry( format + "_encoders", QStringList() );
123 codecData.decoders = group.readEntry( format + "_decoders", QStringList() );
124 codecData.replaygain = group.readEntry( format + "_replaygain", QStringList() );
125 data.backends.codecs += codecData;
126 }
127 data.backends.filters = group.readEntry( "filters", QStringList() );
128 data.backends.enabledFilters = group.readEntry( "enabledFilters", QStringList() );
129
130 pPluginLoader->load();
131
132 QString pluginName;
133 QStringList enabledPlugins;
134 QStringList newPlugins;
135 int codecIndex;
136
137 formats = pPluginLoader->formatList( PluginLoader::Possibilities(PluginLoader::Encode|PluginLoader::Decode|PluginLoader::ReplayGain), PluginLoader::CompressionType(PluginLoader::InferiorQuality|PluginLoader::Lossy|PluginLoader::Lossless|PluginLoader::Hybrid) );
138
139 // build default backend priority list
140
141 foreach( const QString& format, formats )
142 {
143 if( format == "wav" )
144 continue;
145
146 // get the index of the format in the data.backends.codecs list for direct access
147 codecIndex = -1;
148 for( int i=0; i<data.backends.codecs.count(); i++ )
149 {
150 if( data.backends.codecs.at(i).codecName == format )
151 {
152 codecIndex = i;
153 break;
154 }
155 }
156 // add format to the data.backends.codecs list if it isn't already in it
157 if( codecIndex == -1 )
158 {
159 CodecData codecData;
160 codecData.codecName = format;
161 data.backends.codecs += codecData;
162 codecIndex = data.backends.codecs.count() - 1;
163 }
164
165 // encoders
166 enabledPlugins.clear();
167 newPlugins.clear();
168 // register existing enabled plugins as such and list new enabled plugins
169 foreach( const ConversionPipeTrunk& trunk, pPluginLoader->conversionFilterPipeTrunks )
170 {
171 if( trunk.codecTo == format && trunk.enabled )
172 {
173 pluginName = trunk.plugin->name();
174 enabledPlugins += pluginName;
175 if( !data.backends.codecs.at(codecIndex).encoders.contains(pluginName) && newPlugins.filter(QRegExp("[0-9]{8,8}"+pluginName)).count()==0 )
176 {
177 newPlugins += QString::number(trunk.rating).rightJustified(8,'0') + pluginName;
178 }
179 }
180 }
181 // remove plugins from the encoder list if they aren't enabled any more
182 for( int i=0; i<data.backends.codecs.at(codecIndex).encoders.count(); i++ )
183 {
184 if( !enabledPlugins.contains(data.backends.codecs.at(codecIndex).encoders.at(i)) )
185 {
186 data.backends.codecs[codecIndex].encoders.removeAt(i);
187 i--;
188 }
189 }
190 // sort new enabled plugins and append them to the encoder list
191 newPlugins.sort();
192 for( int i=newPlugins.count()-1; i>=0; i-- ) // QStringList doesn't support sorting in descending order
193 {
194 data.backends.codecs[codecIndex].encoders += newPlugins.at(i).right(newPlugins.at(i).length()-8);
195 }
196
197 // decoders
198 enabledPlugins.clear();
199 newPlugins.clear();
200 // register existing enabled plugins as such and list new enabled plugins
201 foreach( const ConversionPipeTrunk& trunk, pPluginLoader->conversionFilterPipeTrunks )
202 {
203 if( trunk.codecFrom == format && trunk.enabled )
204 {
205 pluginName = trunk.plugin->name();
206 enabledPlugins += pluginName;
207 if( !data.backends.codecs.at(codecIndex).decoders.contains(pluginName) && newPlugins.filter(QRegExp("[0-9]{8,8}"+pluginName)).count()==0 )
208 {
209 newPlugins += QString::number(trunk.rating).rightJustified(8,'0') + pluginName;
210 }
211 }
212 }
213 // remove plugins from the decoder list if they aren't enabled any more
214 for( int i=0; i<data.backends.codecs.at(codecIndex).decoders.count(); i++ )
215 {
216 if( !enabledPlugins.contains(data.backends.codecs.at(codecIndex).decoders.at(i)) )
217 {
218 data.backends.codecs[codecIndex].decoders.removeAt(i);
219 i--;
220 }
221 }
222 // sort new enabled plugins and append them to the decoder list
223 newPlugins.sort();
224 for( int i=newPlugins.count()-1; i>=0; i-- ) // QStringList doesn't support sorting in descending order
225 {
226 data.backends.codecs[codecIndex].decoders += newPlugins.at(i).right(newPlugins.at(i).length()-8);
227 }
228
229 // replaygain
230 enabledPlugins.clear();
231 const bool internalReplayGainEnabled = pPluginLoader->hasCodecInternalReplayGain(format);
232 if( internalReplayGainEnabled )
233 {
234 enabledPlugins += i18n("Try internal");
235 }
236 newPlugins.clear();
237 // register existing enabled plugins as such and list new enabled plugins
238 foreach( const ReplayGainPipe& pipe, pPluginLoader->replaygainPipes )
239 {
240 if( pipe.codecName == format && pipe.enabled )
241 {
242 pluginName = pipe.plugin->name();
243 enabledPlugins += pluginName;
244 if( !data.backends.codecs.at(codecIndex).replaygain.contains(pluginName) && newPlugins.filter(QRegExp("[0-9]{8,8}"+pluginName)).count()==0 )
245 {
246 newPlugins += QString::number(pipe.rating).rightJustified(8,'0') + pluginName;
247 }
248 }
249 }
250 // remove plugins from the replay gain list if they aren't enabled any more
251 for( int i=0; i<data.backends.codecs.at(codecIndex).replaygain.count(); i++ )
252 {
253 if( !enabledPlugins.contains(data.backends.codecs.at(codecIndex).replaygain.at(i)) )
254 {
255 data.backends.codecs[codecIndex].replaygain.removeAt(i);
256 i--;
257 }
258 }
259 // append internal replay gain if it is enabled
260 if( internalReplayGainEnabled && !data.backends.codecs.at(codecIndex).replaygain.contains(i18n("Try internal")) )
261 {
262 data.backends.codecs[codecIndex].replaygain += i18n("Try internal");
263 }
264 // sort new enabled plugins and append them to the replay gain list
265 newPlugins.sort();
266 for( int i=newPlugins.count()-1; i>=0; i-- ) // QStringList doesn't support sorting in descending order
267 {
268 data.backends.codecs[codecIndex].replaygain += newPlugins.at(i).right(newPlugins.at(i).length()-8);
269 }
270 }
271
272 // filters
273 enabledPlugins.clear();
274 newPlugins.clear();
275 // register existing enabled plugins as such and list new enabled plugins
276 foreach( FilterPlugin *plugin, pPluginLoader->getAllFilterPlugins() )
277 {
278 pluginName = plugin->name();
279 foreach( const ConversionPipeTrunk& trunk, plugin->codecTable() )
280 {
281 if( trunk.enabled && trunk.codecFrom == "wav" && trunk.codecTo == "wav" )
282 {
283 enabledPlugins += pluginName;
284 if( !data.backends.filters.contains(pluginName) && newPlugins.filter(QRegExp("[0-9]{8,8}"+pluginName)).count()==0 )
285 {
286 newPlugins += QString::number(trunk.rating).rightJustified(8,'0') + pluginName;
287 break;
288 }
289 }
290 }
291 }
292 // remove plugins from the filter list if they aren't enabled any more
293 for( int i=0; i<data.backends.filters.count(); i++ )
294 {
295 if( !enabledPlugins.contains(data.backends.filters.at(i)) )
296 {
297 data.backends.filters.removeAt(i);
298 i--;
299 }
300 }
301 // sort new enabled plugins and append them to the filter list
302 newPlugins.sort();
303 for( int i=newPlugins.count()-1; i>=0; i-- ) // QStringList doesn't support sorting in descending order
304 {
305 data.backends.filters += newPlugins.at(i).right(newPlugins.at(i).length()-8);
306 }
307 // since filters can be completely disabled we have to keep track of data.backends.enabledFilters as well
308 // remove plugins from the enabledFilters list if they aren't enabled any more
309 for( int i=0; i<data.backends.enabledFilters.count(); i++ )
310 {
311 if( !data.backends.filters.contains(data.backends.enabledFilters.at(i)) )
312 {
313 data.backends.enabledFilters.removeAt(i);
314 i--;
315 }
316 }
317 // always enable the first filter
318 if( data.app.configVersion < 1005 && data.backends.enabledFilters.isEmpty() && data.backends.filters.count() > 0 )
319 {
320 data.backends.enabledFilters.append( data.backends.filters.first() );
321 }
322
323 // import KDE4 profiles - paths are hard-coded because I don't know how to properly get the KDE4 data path
324 if( data.app.configVersion < 1006 )
325 {
326 const QString src = QDir::homePath() + "/.kde4/share/apps/soundkonverter/profiles.xml";
327 const QString dest = KStandardDirs::locateLocal("data","soundkonverter/profiles.xml");
328 if( QFile::exists(src) && !QFile::exists(dest) )
329 {
330 QFile::copy(src, dest);
331 logger->log( 1000, i18n("Importing old profiles from: %1").arg(src) );
332 }
333 }
334
335 logger->log( 1000, "\nloading profiles ..." );
336 QFile listFile( KStandardDirs::locateLocal("data","soundkonverter/profiles.xml") );
337 if( listFile.open( QIODevice::ReadOnly ) )
338 {
339 QDomDocument list("soundkonverter_profilelist");
340 if( list.setContent( &listFile ) )
341 {
342 QDomElement root = list.documentElement();
343 if( root.nodeName() == "soundkonverter" && root.attribute("type") == "profilelist" )
344 {
345 QDomNodeList conversionOptionsElements = root.elementsByTagName("conversionOptions");
346 for( int i=0; i<conversionOptionsElements.count(); i++ )
347 {
348 const QString profileName = conversionOptionsElements.at(i).toElement().attribute("profileName");
349 const QString pluginName = conversionOptionsElements.at(i).toElement().attribute("pluginName");
350 CodecPlugin *plugin = qobject_cast<CodecPlugin*>(pPluginLoader->backendPluginByName( pluginName ));
351 if( plugin )
352 {
353 QList<QDomElement> filterOptionsElements;
354 ConversionOptions *conversionOptions = plugin->conversionOptionsFromXml( conversionOptionsElements.at(i).toElement(), &filterOptionsElements );
355 if( conversionOptions )
356 {
357 foreach( const QDomElement& filterOptionsElement, filterOptionsElements )
358 {
359 FilterOptions *filterOptions = 0;
360 const QString filterPluginName = filterOptionsElement.attribute("pluginName");
361 FilterPlugin *filterPlugin = qobject_cast<FilterPlugin*>(pPluginLoader->backendPluginByName( filterPluginName ));
362 if( filterPlugin )
363 {
364 filterOptions = filterPlugin->filterOptionsFromXml( filterOptionsElement );
365 }
366 else
367 {
368 logger->log( 1000, "\tcannot load filter for profile: " + profileName );
369 continue;
370 }
371 conversionOptions->filterOptions.append( filterOptions );
372 }
373
374 pConversionOptionsManager->addConversionOptions( conversionOptions );
375
376 data.profiles[profileName] = conversionOptions->copy();
377 if( profileName != "soundkonverter_last_used" )
378 logger->log( 1000, "\tname: " + profileName + ", plugin: " + pluginName );
379 }
380 }
381 else
382 {
383 logger->log( 1000, "\tname: " + profileName + ", plugin: " + pluginName );
384 logger->log( 1000, "\t\tcannot be loaded beacause the plugin cannot be found" );
385 continue;
386 }
387 }
388 }
389 }
390 listFile.close();
391 }
392 logger->log( 1000, "... all profiles loaded\n" );
393
394 QString profile;
395 QStringList sFormat;
396 QStringList sProfile;
397 sProfile += i18n("Last used");
398 sProfile += i18n("Very low");
399 sProfile += i18n("Low");
400 sProfile += i18n("Medium");
401 sProfile += i18n("High");
402 sProfile += i18n("Very high");
403 sProfile += i18n("Lossless");
404 sProfile += i18n("Hybrid");
405 sProfile += customProfiles();
406 if( sProfile.indexOf(data.general.defaultProfile) == -1 )
407 {
408 data.general.defaultProfile = i18n("High");
409 }
410 else
411 {
412 profile = data.general.defaultProfile;
413
414 if( profile == i18n("Very low") || profile == i18n("Low") || profile == i18n("Medium") || profile == i18n("High") || profile == i18n("Very high") )
415 {
416 sFormat = pPluginLoader->formatList(PluginLoader::Encode,PluginLoader::Lossy);
417 }
418 else if( profile == i18n("Lossless") )
419 {
420 sFormat = pPluginLoader->formatList(PluginLoader::Encode,PluginLoader::Lossless);
421 }
422 else if( profile == i18n("Hybrid") )
423 {
424 sFormat = pPluginLoader->formatList(PluginLoader::Encode,PluginLoader::Hybrid);
425 }
426 else if( profile == i18n("User defined") )
427 {
428 sFormat = pPluginLoader->formatList(PluginLoader::Encode,PluginLoader::CompressionType(PluginLoader::InferiorQuality|PluginLoader::Lossy|PluginLoader::Lossless|PluginLoader::Hybrid));
429 }
430 else
431 {
432 const ConversionOptions *conversionOptions = data.profiles.value( profile );
433 if( conversionOptions )
434 sFormat += conversionOptions->codecName;
435 }
436 if( sFormat.indexOf(data.general.defaultFormat) == -1 )
437 {
438 data.general.defaultFormat = i18n("Last used");
439 }
440 }
441
442 group = conf->group( "BackendOptimizationsIgnoreList" );
443 const int backendOptimizationsIgnoreListCount = group.readEntry( "count", 0 );
444
445 CodecOptimizations::Optimization optimization;
446 for( int i=0; i<backendOptimizationsIgnoreListCount; i++ )
447 {
448 const QStringList backendOptimization = group.readEntry( QString("ignore_%1").arg(i), QStringList() );
449 optimization.codecName = backendOptimization.at(0);
450 const QString mode = backendOptimization.at(1);
451 if( mode == "Encode" )
452 {
453 optimization.mode = CodecOptimizations::Optimization::Encode;
454 }
455 else if( mode == "Decode" )
456 {
457 optimization.mode = CodecOptimizations::Optimization::Decode;
458 }
459 else if( mode == "ReplayGain" )
460 {
461 optimization.mode = CodecOptimizations::Optimization::ReplayGain;
462 }
463 optimization.currentBackend = backendOptimization.at(2);
464 optimization.betterBackend = backendOptimization.at(3);
465 optimization.solution = CodecOptimizations::Optimization::Ignore;
466 data.backendOptimizationsIgnoreList.optimizationList.append(optimization);
467 }
468
469 writeServiceMenu();
470
471 logger->log( 1000, QString("loading of the configuration took %1 ms").arg(time.elapsed()) );
472 }
473
save()474 void Config::save()
475 {
476 writeServiceMenu();
477
478 KSharedConfig::Ptr conf = KGlobal::config();
479 KConfigGroup group;
480
481 group = conf->group( "General" );
482 group.writeEntry( "configVersion", SOUNDKONVERTER_VERSION_NUMBER );
483 group.writeEntry( "startTab", data.general.startTab );
484 group.writeEntry( "lastTab", data.general.lastTab );
485 group.writeEntry( "defaultProfile", data.general.defaultProfile );
486 group.writeEntry( "lastProfile", data.general.lastProfile );
487 group.writeEntry( "defaultFormat", data.general.defaultFormat );
488 group.writeEntry( "lastFormat", data.general.lastFormat );
489 group.writeEntry( "lastOutputDirectoryMode", data.general.lastOutputDirectoryMode );
490 group.writeEntry( "specifyOutputDirectory", data.general.specifyOutputDirectory );
491 group.writeEntry( "metaDataOutputDirectory", data.general.metaDataOutputDirectory );
492 group.writeEntry( "copyStructureOutputDirectory", data.general.copyStructureOutputDirectory );
493 group.writeEntry( "lastMetaDataOutputDirectoryPaths", data.general.lastMetaDataOutputDirectoryPaths );
494 group.writeEntry( "lastNormalOutputDirectoryPaths", data.general.lastNormalOutputDirectoryPaths );
495 group.writeEntry( "waitForAlbumGain", data.general.waitForAlbumGain );
496 group.writeEntry( "useVFATNames", data.general.useVFATNames );
497 group.writeEntry( "copyIfSameCodec", data.general.copyIfSameCodec );
498 group.writeEntry( "writeLogFiles", data.general.writeLogFiles );
499 group.writeEntry( "conflictHandling", (int)data.general.conflictHandling );
500 // group.writeEntry( "priority", data.general.priority );
501 group.writeEntry( "numFiles", data.general.numFiles );
502 group.writeEntry( "numReplayGainFiles", data.general.numReplayGainFiles );
503 // group.writeEntry( "executeUserScript", data.general.executeUserScript );
504 // group.writeEntry( "showToolBar", data.general.showToolBar );
505 // group.writeEntry( "outputFilePermissions", data.general.outputFilePermissions );
506 group.writeEntry( "actionMenuConvertMimeTypes", data.general.actionMenuConvertMimeTypes );
507 group.writeEntry( "actionMenuReplayGainMimeTypes", data.general.actionMenuReplayGainMimeTypes );
508 group.writeEntry( "replayGainGrouping", (int)data.general.replayGainGrouping );
509 group.writeEntry( "preferredOggVorbisExtension", data.general.preferredOggVorbisExtension );
510 group.writeEntry( "preferredVorbisCommentCommentTag", data.general.preferredVorbisCommentCommentTag );
511 group.writeEntry( "preferredVorbisCommentTrackTotalTag", data.general.preferredVorbisCommentTrackTotalTag );
512 group.writeEntry( "preferredVorbisCommentDiscTotalTag", data.general.preferredVorbisCommentDiscTotalTag );
513
514 group = conf->group( "Advanced" );
515 group.writeEntry( "useSharedMemoryForTempFiles", data.advanced.useSharedMemoryForTempFiles );
516 group.writeEntry( "maxSizeForSharedMemoryTempFiles", data.advanced.maxSizeForSharedMemoryTempFiles );
517 group.writeEntry( "usePipes", data.advanced.usePipes );
518 group.writeEntry( "ejectCdAfterRip", data.advanced.ejectCdAfterRip );
519
520 group = conf->group( "CoverArt" );
521 group.writeEntry( "writeCovers", data.coverArt.writeCovers );
522 group.writeEntry( "writeCoverName", data.coverArt.writeCoverName );
523 group.writeEntry( "writeCoverDefaultName", data.coverArt.writeCoverDefaultName );
524
525 group = conf->group( "Backends" );
526 group.deleteEntry( "rippers" );
527 QStringList formats;
528 foreach( const CodecData& codec, data.backends.codecs )
529 {
530 const QString format = codec.codecName;
531 group.writeEntry( format + "_encoders", codec.encoders );
532 group.writeEntry( format + "_decoders", codec.decoders );
533 group.writeEntry( format + "_replaygain", codec.replaygain );
534 formats += format;
535 }
536 group.writeEntry( "formats", formats );
537 group.writeEntry( "filters", data.backends.filters );
538 group.writeEntry( "enabledFilters", data.backends.enabledFilters );
539
540 group = conf->group( "BackendOptimizationsIgnoreList" );
541 group.writeEntry( "count", data.backendOptimizationsIgnoreList.optimizationList.count() );
542
543 for( int i=0; i<data.backendOptimizationsIgnoreList.optimizationList.count(); i++ )
544 {
545 QStringList backendOptimization;
546 backendOptimization << data.backendOptimizationsIgnoreList.optimizationList.at(i).codecName;
547 if( data.backendOptimizationsIgnoreList.optimizationList.at(i).mode == CodecOptimizations::Optimization::Encode )
548 {
549 backendOptimization << "Encode";
550 }
551 else if( data.backendOptimizationsIgnoreList.optimizationList.at(i).mode == CodecOptimizations::Optimization::Decode )
552 {
553 backendOptimization << "Decode";
554 }
555 else if( data.backendOptimizationsIgnoreList.optimizationList.at(i).mode == CodecOptimizations::Optimization::ReplayGain )
556 {
557 backendOptimization << "ReplayGain";
558 }
559 backendOptimization << data.backendOptimizationsIgnoreList.optimizationList.at(i).currentBackend;
560 backendOptimization << data.backendOptimizationsIgnoreList.optimizationList.at(i).betterBackend;
561 group.writeEntry( QString("ignore_%1").arg(i), backendOptimization );
562 }
563
564 emit updateWriteLogFilesSetting( data.general.writeLogFiles );
565 }
566
writeServiceMenu()567 void Config::writeServiceMenu()
568 {
569 QString content;
570 QStringList mimeTypes;
571
572 content = "";
573 content += "[Desktop Entry]\n";
574 content += "Type=Service\n";
575 content += "Encoding=UTF-8\n";
576
577 const QStringList convertFormats = pPluginLoader->formatList( PluginLoader::Decode, PluginLoader::CompressionType(PluginLoader::InferiorQuality|PluginLoader::Lossy|PluginLoader::Lossless|PluginLoader::Hybrid) );
578
579 mimeTypes.clear();
580 foreach( const QString& format, convertFormats )
581 {
582 mimeTypes += pPluginLoader->codecMimeTypes( format );
583 }
584
585 content += "ServiceTypes=KonqPopupMenu/Plugin," + mimeTypes.join(",") + "\n";
586
587 content += "Icon=soundkonverter\n";
588 content += "Actions=ConvertWithSoundkonverter;\n\n";
589
590 content += "[Desktop Action ConvertWithSoundkonverter]\n";
591 content += "Name="+i18n("Convert with soundKonverter")+"\n";
592 content += "Icon=soundkonverter\n";
593 content += "Exec=soundkonverter %F\n";
594
595 const QString convertActionFileName = KStandardDirs::locateLocal( "services", "ServiceMenus/convert_with_soundkonverter.desktop" );
596 if( ( data.general.actionMenuConvertMimeTypes != mimeTypes || !QFile::exists(convertActionFileName) ) && mimeTypes.count() > 0 )
597 {
598 QFile convertActionFile( convertActionFileName );
599 if( convertActionFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
600 {
601 QTextStream convertActionStream( &convertActionFile );
602 convertActionStream << content;
603 convertActionFile.close();
604 }
605 data.general.actionMenuConvertMimeTypes = mimeTypes;
606 }
607
608 content = "";
609 content += "[Desktop Entry]\n";
610 content += "Type=Service\n";
611 content += "Encoding=UTF-8\n";
612
613 const QStringList replaygainFormats = pPluginLoader->formatList( PluginLoader::ReplayGain, PluginLoader::CompressionType(PluginLoader::InferiorQuality|PluginLoader::Lossy|PluginLoader::Lossless|PluginLoader::Hybrid) );
614
615 mimeTypes.clear();
616 foreach( const QString& format, replaygainFormats )
617 {
618 mimeTypes += pPluginLoader->codecMimeTypes( format );
619 }
620
621 content += "ServiceTypes=KonqPopupMenu/Plugin," + mimeTypes.join(",") + "\n";
622
623 content += "Icon=soundkonverter_replaygain\n";
624 content += "Actions=AddReplayGainWithSoundkonverter;\n\n";
625
626 content += "[Desktop Action AddReplayGainWithSoundkonverter]\n";
627 content += "Name="+i18n("Add Replay Gain with soundKonverter")+"\n";
628 content += "Icon=soundkonverter-replaygain\n";
629 content += "Exec=soundkonverter --replaygain %F\n";
630
631 const QString replaygainActionFileName = KStandardDirs::locateLocal( "services", "ServiceMenus/add_replaygain_with_soundkonverter.desktop" );
632 if( ( data.general.actionMenuReplayGainMimeTypes != mimeTypes || !QFile::exists(replaygainActionFileName) ) && mimeTypes.count() > 0 )
633 {
634 QFile replaygainActionFile( replaygainActionFileName );
635 if( replaygainActionFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
636 {
637 QTextStream replaygainActionStream( &replaygainActionFile );
638 replaygainActionStream << content;
639 replaygainActionFile.close();
640 }
641 data.general.actionMenuReplayGainMimeTypes = mimeTypes;
642 }
643 }
644
customProfiles()645 QStringList Config::customProfiles()
646 {
647 QStringList profiles;
648
649 foreach( const QString& profileName, data.profiles.keys() )
650 {
651 if( profileName == "soundkonverter_last_used" )
652 continue;
653
654 const ConversionOptions* profileConversionOptions = data.profiles.value(profileName);
655
656 QList<CodecPlugin*> plugins = pPluginLoader->encodersForCodec( profileConversionOptions->codecName );
657 foreach( const CodecPlugin *plugin, plugins )
658 {
659 if( plugin->name() == profileConversionOptions->pluginName )
660 {
661 profiles.append( profileName );
662 break;
663 }
664 }
665 }
666
667 return profiles;
668 }
669
getOptimizations(bool includeIgnored)670 QList<CodecOptimizations::Optimization> Config::getOptimizations( bool includeIgnored )
671 {
672 QTime time;
673 time.start();
674
675 QList<CodecOptimizations::Optimization> optimizationList;
676 CodecOptimizations::Optimization optimization;
677
678 QStringList tempPluginList;
679 QStringList optimizedPluginList;
680 int currentBackendRating = 0;
681 int betterBackendRating = 0;
682 int codecIndex;
683 bool ignore;
684
685 const QStringList formats = pPluginLoader->formatList( PluginLoader::Possibilities(PluginLoader::Encode|PluginLoader::Decode|PluginLoader::ReplayGain), PluginLoader::CompressionType(PluginLoader::InferiorQuality|PluginLoader::Lossy|PluginLoader::Lossless|PluginLoader::Hybrid) );
686 foreach( const QString& format, formats )
687 {
688 if( format == "wav" )
689 continue;
690
691 codecIndex = -1;
692 for( int j=0; j<data.backends.codecs.count(); j++ )
693 {
694 if( data.backends.codecs.at(j).codecName == format )
695 {
696 codecIndex = j;
697 break;
698 }
699 }
700 if( codecIndex == -1 )
701 continue;
702
703 // encoders
704 tempPluginList.clear();
705 for( int j=0; j<pPluginLoader->conversionPipeTrunks.count(); j++ )
706 {
707 if( pPluginLoader->conversionPipeTrunks.at(j).codecTo == format && pPluginLoader->conversionPipeTrunks.at(j).enabled && pPluginLoader->conversionPipeTrunks.at(j).plugin->type() == "codec" )
708 {
709 const QString pluginName = pPluginLoader->conversionPipeTrunks.at(j).plugin->name();
710 if( tempPluginList.filter(QRegExp("[0-9]{8,8}"+pluginName)).count() == 0 )
711 {
712 tempPluginList += QString::number(pPluginLoader->conversionPipeTrunks.at(j).rating).rightJustified(8,'0') + pluginName;
713 }
714 }
715 }
716 for( int j=0; j<pPluginLoader->filterPipeTrunks.count(); j++ )
717 {
718 if( pPluginLoader->filterPipeTrunks.at(j).codecTo == format && pPluginLoader->filterPipeTrunks.at(j).enabled && pPluginLoader->filterPipeTrunks.at(j).plugin->type() == "filter" )
719 {
720 const QString pluginName = pPluginLoader->filterPipeTrunks.at(j).plugin->name();
721 if( tempPluginList.filter(QRegExp("[0-9]{8,8}"+pluginName)).count() == 0 )
722 {
723 tempPluginList += QString::number(pPluginLoader->filterPipeTrunks.at(j).rating).rightJustified(8,'0') + pluginName;
724 }
725 }
726 }
727 tempPluginList.sort();
728 optimizedPluginList.clear();
729 for( int j=tempPluginList.count()-1; j>=0; j-- )
730 {
731 const QString pluginName = tempPluginList.at(j).right(tempPluginList.at(j).length()-8);
732 const int pluginRating = tempPluginList.at(j).left(8).toInt();
733 optimizedPluginList += pluginName;
734 if( data.backends.codecs.at(codecIndex).encoders.count() > 0 && pluginName == data.backends.codecs.at(codecIndex).encoders.first() )
735 {
736 currentBackendRating = pluginRating;
737 }
738 if( j == tempPluginList.count()-1 )
739 {
740 betterBackendRating = pluginRating;
741 }
742 }
743 if( optimizedPluginList.count() != 0 && data.backends.codecs.at(codecIndex).encoders.count() != 0 )
744 {
745 ignore = false;
746 for( int j=0; j<data.backendOptimizationsIgnoreList.optimizationList.count(); j++ )
747 {
748 if( data.backendOptimizationsIgnoreList.optimizationList.at(j).codecName == format &&
749 data.backendOptimizationsIgnoreList.optimizationList.at(j).mode == CodecOptimizations::Optimization::Encode &&
750 data.backendOptimizationsIgnoreList.optimizationList.at(j).currentBackend == data.backends.codecs.at(codecIndex).encoders.first() &&
751 data.backendOptimizationsIgnoreList.optimizationList.at(j).betterBackend == optimizedPluginList.first()
752 )
753 {
754 ignore = true;
755 }
756 }
757
758 // is there a better plugin available and has the better plugin really a higher rating or was it just sorted alphabetically at the top
759 if( optimizedPluginList.first() != data.backends.codecs.at(codecIndex).encoders.first() && betterBackendRating > currentBackendRating )
760 {
761 if( ignore && includeIgnored )
762 {
763 optimization.codecName = format;
764 optimization.mode = CodecOptimizations::Optimization::Encode;
765 optimization.currentBackend = data.backends.codecs.at(codecIndex).encoders.first();
766 optimization.betterBackend = optimizedPluginList.first();
767 optimization.solution = CodecOptimizations::Optimization::Ignore;
768 optimizationList.append(optimization);
769 }
770 else if( !ignore )
771 {
772 optimization.codecName = format;
773 optimization.mode = CodecOptimizations::Optimization::Encode;
774 optimization.currentBackend = data.backends.codecs.at(codecIndex).encoders.first();
775 optimization.betterBackend = optimizedPluginList.first();
776 optimization.solution = CodecOptimizations::Optimization::Undecided;
777 optimizationList.append(optimization);
778 }
779 }
780 }
781
782 // decoders
783 tempPluginList.clear();
784 for( int j=0; j<pPluginLoader->conversionPipeTrunks.count(); j++ )
785 {
786 if( pPluginLoader->conversionPipeTrunks.at(j).codecFrom == format && pPluginLoader->conversionPipeTrunks.at(j).enabled && pPluginLoader->conversionPipeTrunks.at(j).plugin->type() == "codec" )
787 {
788 const QString pluginName = pPluginLoader->conversionPipeTrunks.at(j).plugin->name();
789 if( tempPluginList.filter(QRegExp("[0-9]{8,8}"+pluginName)).count() == 0 )
790 {
791 tempPluginList += QString::number(pPluginLoader->conversionPipeTrunks.at(j).rating).rightJustified(8,'0') + pluginName;
792 }
793 }
794 }
795 for( int j=0; j<pPluginLoader->filterPipeTrunks.count(); j++ )
796 {
797 if( pPluginLoader->filterPipeTrunks.at(j).codecFrom == format && pPluginLoader->filterPipeTrunks.at(j).enabled && pPluginLoader->filterPipeTrunks.at(j).plugin->type() == "filter" )
798 {
799 const QString pluginName = pPluginLoader->filterPipeTrunks.at(j).plugin->name();
800 if( tempPluginList.filter(QRegExp("[0-9]{8,8}"+pluginName)).count() == 0 )
801 {
802 tempPluginList += QString::number(pPluginLoader->filterPipeTrunks.at(j).rating).rightJustified(8,'0') + pluginName;
803 }
804 }
805 }
806 tempPluginList.sort();
807 optimizedPluginList.clear();
808 for( int j=tempPluginList.count()-1; j>=0; j-- )
809 {
810 const QString pluginName = tempPluginList.at(j).right(tempPluginList.at(j).length()-8);
811 const int pluginRating = tempPluginList.at(j).left(8).toInt();
812 optimizedPluginList += pluginName;
813 if( data.backends.codecs.at(codecIndex).decoders.count() > 0 && pluginName == data.backends.codecs.at(codecIndex).decoders.first() )
814 {
815 currentBackendRating = pluginRating;
816 }
817 if( j == tempPluginList.count()-1 )
818 {
819 betterBackendRating = pluginRating;
820 }
821 }
822 if( optimizedPluginList.count() != 0 && data.backends.codecs.at(codecIndex).decoders.count() != 0 )
823 {
824 ignore = false;
825 for( int j=0; j<data.backendOptimizationsIgnoreList.optimizationList.count(); j++ )
826 {
827 if( data.backendOptimizationsIgnoreList.optimizationList.at(j).codecName == format &&
828 data.backendOptimizationsIgnoreList.optimizationList.at(j).mode == CodecOptimizations::Optimization::Decode &&
829 data.backendOptimizationsIgnoreList.optimizationList.at(j).currentBackend == data.backends.codecs.at(codecIndex).decoders.first() &&
830 data.backendOptimizationsIgnoreList.optimizationList.at(j).betterBackend == optimizedPluginList.first()
831 )
832 {
833 ignore = true;
834 }
835 }
836
837 // is there a better plugin available and has the better plugin really a higher rating or was it just sorted alphabetically at the top
838 if( optimizedPluginList.first() != data.backends.codecs.at(codecIndex).decoders.first() && betterBackendRating > currentBackendRating )
839 {
840 if( ignore && includeIgnored )
841 {
842 optimization.codecName = format;
843 optimization.mode = CodecOptimizations::Optimization::Decode;
844 optimization.currentBackend = data.backends.codecs.at(codecIndex).decoders.first();
845 optimization.betterBackend = optimizedPluginList.first();
846 optimization.solution = CodecOptimizations::Optimization::Ignore;
847 optimizationList.append(optimization);
848 }
849 else if( !ignore )
850 {
851 optimization.codecName = format;
852 optimization.mode = CodecOptimizations::Optimization::Decode;
853 optimization.currentBackend = data.backends.codecs.at(codecIndex).decoders.first();
854 optimization.betterBackend = optimizedPluginList.first();
855 optimization.solution = CodecOptimizations::Optimization::Undecided;
856 optimizationList.append(optimization);
857 }
858 }
859 }
860
861 // replaygain
862 tempPluginList.clear();
863 for( int j=0; j<pPluginLoader->replaygainPipes.count(); j++ )
864 {
865 if( pPluginLoader->replaygainPipes.at(j).codecName == format && pPluginLoader->replaygainPipes.at(j).enabled )
866 {
867 const QString pluginName = pPluginLoader->replaygainPipes.at(j).plugin->name();
868 if( tempPluginList.filter(QRegExp("[0-9]{8,8}"+pluginName)).count() == 0 )
869 {
870 tempPluginList += QString::number(pPluginLoader->replaygainPipes.at(j).rating).rightJustified(8,'0') + pluginName;
871 }
872 }
873 }
874 tempPluginList.sort();
875 optimizedPluginList.clear();
876 for( int j=tempPluginList.count()-1; j>=0; j-- )
877 {
878 const QString pluginName = tempPluginList.at(j).right(tempPluginList.at(j).length()-8);
879 const int pluginRating = tempPluginList.at(j).left(8).toInt();
880 optimizedPluginList += pluginName;
881 if( data.backends.codecs.at(codecIndex).replaygain.count() > 0 && pluginName == data.backends.codecs.at(codecIndex).replaygain.first() )
882 {
883 currentBackendRating = pluginRating;
884 }
885 if( j == tempPluginList.count()-1 )
886 {
887 betterBackendRating = pluginRating;
888 }
889 }
890 if( optimizedPluginList.count() != 0 && data.backends.codecs.at(codecIndex).replaygain.count() != 0 )
891 {
892 ignore = false;
893 for( int j=0; j<data.backendOptimizationsIgnoreList.optimizationList.count(); j++ )
894 {
895 if( data.backendOptimizationsIgnoreList.optimizationList.at(j).codecName == format &&
896 data.backendOptimizationsIgnoreList.optimizationList.at(j).mode == CodecOptimizations::Optimization::ReplayGain &&
897 data.backendOptimizationsIgnoreList.optimizationList.at(j).currentBackend == data.backends.codecs.at(codecIndex).replaygain.first() &&
898 data.backendOptimizationsIgnoreList.optimizationList.at(j).betterBackend == optimizedPluginList.first()
899 )
900 {
901 ignore = true;
902 break;
903 }
904 }
905
906 // is there a better plugin available and has the better plugin really a higher rating or was it just sorted alphabetically at the top
907 if( optimizedPluginList.first() != data.backends.codecs.at(codecIndex).replaygain.first() && betterBackendRating > currentBackendRating )
908 {
909 if( ignore && includeIgnored )
910 {
911 optimization.codecName = format;
912 optimization.mode = CodecOptimizations::Optimization::ReplayGain;
913 optimization.currentBackend = data.backends.codecs.at(codecIndex).replaygain.first();
914 optimization.betterBackend = optimizedPluginList.first();
915 optimization.solution = CodecOptimizations::Optimization::Ignore;
916 optimizationList.append(optimization);
917 }
918 else if( !ignore )
919 {
920 optimization.codecName = format;
921 optimization.mode = CodecOptimizations::Optimization::ReplayGain;
922 optimization.currentBackend = data.backends.codecs.at(codecIndex).replaygain.first();
923 optimization.betterBackend = optimizedPluginList.first();
924 optimization.solution = CodecOptimizations::Optimization::Undecided;
925 optimizationList.append(optimization);
926 }
927 }
928 }
929 }
930
931 logger->log( 1000, QString("generation of the optimization list took %1 ms").arg(time.elapsed()) );
932
933 return optimizationList;
934 }
935
doOptimizations(const QList<CodecOptimizations::Optimization> & optimizationList)936 void Config::doOptimizations( const QList<CodecOptimizations::Optimization>& optimizationList )
937 {
938 int codecIndex;
939
940 for( int i=0; i<optimizationList.count(); i++ )
941 {
942 if( optimizationList.at(i).solution == CodecOptimizations::Optimization::Fix )
943 {
944 codecIndex = -1;
945 for( int j=0; j<data.backends.codecs.count(); j++ )
946 {
947 if( data.backends.codecs.at(j).codecName == optimizationList.at(i).codecName )
948 {
949 codecIndex = j;
950 break;
951 }
952 }
953 if( codecIndex == -1 )
954 continue;
955
956 for( int j=0; j<data.backendOptimizationsIgnoreList.optimizationList.count(); j++ )
957 {
958 if( data.backendOptimizationsIgnoreList.optimizationList.at(j).codecName == optimizationList.at(i).codecName &&
959 data.backendOptimizationsIgnoreList.optimizationList.at(j).mode == optimizationList.at(i).mode &&
960 data.backendOptimizationsIgnoreList.optimizationList.at(j).currentBackend == optimizationList.at(i).currentBackend &&
961 data.backendOptimizationsIgnoreList.optimizationList.at(j).betterBackend == optimizationList.at(i).betterBackend
962 )
963 {
964 data.backendOptimizationsIgnoreList.optimizationList.removeAt( j );
965 break;
966 }
967 }
968
969 if( optimizationList.at(i).mode == CodecOptimizations::Optimization::Encode )
970 {
971 data.backends.codecs[codecIndex].encoders.removeAll( optimizationList.at(i).betterBackend );
972 data.backends.codecs[codecIndex].encoders.prepend( optimizationList.at(i).betterBackend );
973 }
974 else if( optimizationList.at(i).mode == CodecOptimizations::Optimization::Decode )
975 {
976 data.backends.codecs[codecIndex].decoders.removeAll( optimizationList.at(i).betterBackend );
977 data.backends.codecs[codecIndex].decoders.prepend( optimizationList.at(i).betterBackend );
978 }
979 else if( optimizationList.at(i).mode == CodecOptimizations::Optimization::ReplayGain )
980 {
981 data.backends.codecs[codecIndex].replaygain.removeAll( optimizationList.at(i).betterBackend );
982 data.backends.codecs[codecIndex].replaygain.prepend( optimizationList.at(i).betterBackend );
983 }
984 }
985 else if( optimizationList.at(i).solution == CodecOptimizations::Optimization::Ignore )
986 {
987 bool found = false;
988
989 for( int j=0; j<data.backendOptimizationsIgnoreList.optimizationList.count(); j++ )
990 {
991 if( data.backendOptimizationsIgnoreList.optimizationList.at(j).codecName == optimizationList.at(i).codecName &&
992 data.backendOptimizationsIgnoreList.optimizationList.at(j).mode == optimizationList.at(i).mode &&
993 data.backendOptimizationsIgnoreList.optimizationList.at(j).currentBackend == optimizationList.at(i).currentBackend &&
994 data.backendOptimizationsIgnoreList.optimizationList.at(j).betterBackend == optimizationList.at(i).betterBackend
995 )
996 {
997 found = true;
998 break;
999 }
1000 }
1001
1002 if( !found )
1003 data.backendOptimizationsIgnoreList.optimizationList.append(optimizationList.at(i));
1004 }
1005 }
1006 }
1007
1008