Commit 73d6b4d45fdc594a4d2de989d926b255d036c6fb

Finish a long-standing personal TODO item: embedding AFT tags now works with FLAC, Ogg/Vorbis, Ogg/Speex, and Ogg/FLAC files.  \m/

svn path=/trunk/extragear/multimedia/amarok/; revision=983700
utilities/afttagger/AFTTagger.cpp
(180 / 8)
  
11/*
22 * Copyright (c) 2008-2009 Jeff Mitchell <mitchell@kde.org>
3 * QStringToTString and TStringToQString macros Copyright 2002-2008 by Scott Wheeler, wheeler@kde.org, licensed under LGPL 2.1
3 * Qt4QStringToTString and TStringToQString macros Copyright 2002-2008 by Scott Wheeler, wheeler@kde.org, licensed under LGPL 2.1
44 *
55 * This program is free software; you can redistribute it and/or modify
66 * it under the terms of the GNU General Public License as published by
2222
2323//Taglib
2424#include <fileref.h>
25#include <flacfile.h>
2526#include <id3v2tag.h>
2627#include <mpegfile.h>
28#include <oggfile.h>
29#include <oggflacfile.h>
30#include <speexfile.h>
31#include <tstringlist.h>
2732#include <tfile.h>
2833#include <uniquefileidentifierframe.h>
34#include <vorbisfile.h>
35#include <xiphcomment.h>
2936
3037#include <QtDebug>
3138#include <QCryptographicHash>
4444#include <iostream>
4545
4646//QT4-happy versions
47#undef QStringToTString
48#define QStringToTString(s) TagLib::String(s.toUtf8().data(), TagLib::String::UTF8)
49#undef TStringToQString
50#define TStringToQString(s) QString::fromUtf8(s.toCString(true))
47#define Qt4QStringToTString(s) TagLib::String(s.toUtf8().data(), TagLib::String::UTF8)
5148
5249static int s_currentVersion = 1;
5350
180180 bool saveNecessary = false;
181181
182182 TagLib::FileRef tempFileRef = TagLib::FileRef( tempEncodedName, true, TagLib::AudioProperties::Fast );
183 if ( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( tempFileRef.file() ) )
183 if( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( tempFileRef.file() ) )
184184 saveNecessary = handleMPEG( file );
185 else if( TagLib::Ogg::File *file = dynamic_cast<TagLib::Ogg::File *>( tempFileRef.file() ) )
186 saveNecessary = handleOgg( file );
187 else if( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( tempFileRef.file() ) )
188 saveNecessary = handleFLAC( file );
185189 else
186190 {
187191 if( m_verbose )
188 m_textStream << qPrintable( tr( "INFO: File not able to be parsed by TagLib or wrong kind (currently this program only supports MPEG files), cleaning up temp file" ) ) << endl;
192 m_textStream << qPrintable( tr( "INFO: File not able to be parsed by TagLib or wrong kind (currently this program only supports MPEG, Ogg, and FLAC files), cleaning up temp file" ) ) << endl;
189193 if( !sfs.cleanupSave() )
190194 m_textStream << qPrintable( tr( "WARNING: file at %1 could not be cleaned up; check for strays" ).arg( filePath ) ) << endl;
191195 return;
212212bool
213213AFTTagger::handleMPEG( TagLib::MPEG::File *file )
214214{
215 if( file->readOnly() )
216 {
217 m_textStream << qPrintable( tr( "ERROR: File is read-only or could not be opened" ) ) << endl;
218 return false;
219 }
220
215221 QString uid;
216222 bool newUid = false;
217223 if( m_verbose )
313313 if( m_verbose )
314314 m_textStream << qPrintable( tr( "INFO: Adding new frame and saving file with UID: %1" ).arg( uid ) ) << endl;
315315 file->ID3v2Tag()->addFrame( new TagLib::ID3v2::UniqueFileIdentifierFrame(
316 QStringToTString( ourId ), QStringToTString( uid ).data( TagLib::String::Latin1 ) ) );
316 Qt4QStringToTString( ourId ), Qt4QStringToTString( uid ).data( TagLib::String::Latin1 ) ) );
317317 file->save();
318318 return true;
319319 }
320320 }
321321 return false;
322322}
323
324bool
325AFTTagger::handleOgg( TagLib::Ogg::File *file )
326{
327 if( file->readOnly() )
328 {
329 m_textStream << qPrintable( tr( "ERROR: File is read-only or could not be opened" ) ) << endl;
330 return false;
331 }
332
333 TagLib::Ogg::XiphComment *comment = 0;
334 if( dynamic_cast<TagLib::Ogg::FLAC::File*>(file) )
335 comment = ( dynamic_cast<TagLib::Ogg::FLAC::File*>(file) )->tag();
336 else if( dynamic_cast<TagLib::Ogg::Speex::File*>(file) )
337 comment = ( dynamic_cast<TagLib::Ogg::Speex::File*>(file) )->tag();
338 else if( dynamic_cast<TagLib::Ogg::Vorbis::File*>(file) )
339 comment = ( dynamic_cast<TagLib::Ogg::Vorbis::File*>(file) )->tag();
340
341 if( !comment )
342 return false;
343
344 if( handleXiphComment( comment, file ) )
345 {
346 file->save();
347 return true;
348 }
349
350 return false;
351}
352
353bool
354AFTTagger::handleFLAC( TagLib::FLAC::File *file )
355{
356 if( file->readOnly() )
357 {
358 m_textStream << qPrintable( tr( "ERROR: File is read-only or could not be opened" ) ) << endl;
359 return false;
360 }
361
362 TagLib::Ogg::XiphComment *comment = file->xiphComment( true );
363 if( !comment )
364 return false;
365
366 if( handleXiphComment( comment, file ) )
367 {
368 file->save();
369 return true;
370 }
371
372 return false;
373}
374
375bool
376AFTTagger::handleXiphComment( TagLib::Ogg::XiphComment *comment, TagLib::File *file )
377{
378 QString uid;
379 bool newUid = false;
380 bool nothingfound = true;
381 TagLib::StringList toRemove;
382 if( m_verbose )
383 m_textStream << qPrintable( tr( "INFO: File has a XiphComment, opening..." ) ) << endl;
384
385 if( comment->fieldListMap().isEmpty() )
386 {
387 if( m_verbose )
388 m_textStream << qPrintable( tr( "INFO: No fields found in XiphComment" ) ) << endl;
389
390 if( m_delete )
391 return false;
392 }
393 else
394 {
395 if( m_verbose )
396 m_textStream << qPrintable( tr( "INFO: Found existing XiphComment frames, parsing" ) ) << endl;
397 TagLib::Ogg::FieldListMap fieldListMap = comment->fieldListMap();
398
399 if( m_verbose )
400 m_textStream << qPrintable( tr( "INFO: fieldListMap size is %1" ).arg( fieldListMap.size() ) ) << endl;
401
402 TagLib::Ogg::FieldListMap::Iterator iter;
403 for( iter = fieldListMap.begin(); iter != fieldListMap.end(); ++iter )
404 {
405 TagLib::String key = iter->first;
406 QString qkey = TStringToQString( key ).toUpper();
407 if( qkey.startsWith( "AMAROK - REDISCOVER YOUR MUSIC" ) )
408 {
409 nothingfound = false;
410
411 if( m_verbose )
412 m_textStream << qPrintable( tr( "INFO: Removing old-style ATF identifier %1" ).arg( qkey ) ) << endl;
413
414 toRemove.append( key );
415 if( !m_delete )
416 newUid = true;
417 }
418 else if( qkey.startsWith( "AMAROK 2 AFT" ) )
419 {
420 nothingfound = false;
421
422 if( m_verbose )
423 m_textStream << qPrintable( tr( "INFO: Found an existing AFT identifier: %1" ).arg( qkey ) ) << endl;
424
425 if( m_delete )
426 {
427 toRemove.append( key );
428 if( m_verbose )
429 m_textStream << qPrintable( tr( "INFO: Removing current AFT frame" ) ) << endl;
430 }
431 else
432 {
433 int version = qkey.at( 13 ).digitValue();
434 if( m_verbose )
435 m_textStream << qPrintable( tr( "INFO: AFT identifier is version %1" ).arg( version ) ) << endl;
436 if( version < s_currentVersion )
437 {
438 if( m_verbose )
439 m_textStream << qPrintable( tr( "INFO: Upgrading AFT identifier from version %1 to version %2" ).arg( version, s_currentVersion ) ) << endl;
440 uid = upgradeUID( version, TStringToQString( fieldListMap[key].front() ) );
441 if( m_verbose )
442 m_textStream << qPrintable( tr( "INFO: Removing current AFT frame" ) ) << endl;
443 toRemove.append( key );
444 newUid = true;
445 }
446 else if( version == s_currentVersion && m_newid )
447 {
448 if( m_verbose )
449 m_textStream << qPrintable( tr( "INFO: New IDs specified to be generated, doing so" ) ) << endl;
450 toRemove.append( key );
451 newUid = true;
452 }
453 else
454 {
455 if( m_verbose )
456 m_textStream << qPrintable( tr( "INFO: ID is current" ) ) << endl;
457 return false;
458 }
459 }
460 }
461 }
462 for( TagLib::StringList::ConstIterator iter = toRemove.begin(); iter != toRemove.end(); ++iter )
463 comment->removeField( *iter );
464 }
465 if( newUid || ( nothingfound && !m_delete ) )
466 {
467 QString ourId = QString( "Amarok 2 AFTv" + QString::number( s_currentVersion ) + " - amarok.kde.org" );
468 if( uid.isEmpty() )
469 uid = createCurrentUID( file );
470 if( m_verbose )
471 m_textStream << qPrintable( tr( "INFO: Adding new field and saving file with UID: %1" ).arg( uid ) ) << endl;
472 comment->addField( Qt4QStringToTString( ourId ), Qt4QStringToTString( uid ) );
473 return true;
474 }
475 else if( toRemove.size() )
476 return true;
477
478 return false;
479}
480
323481
324482
325483QString
utilities/afttagger/AFTTagger.h
(6 / 0)
  
2020#ifndef AFTTAGGER_H
2121#define AFTTAGGER_H
2222
23#include <flacfile.h>
2324#include <mpegfile.h>
25#include <oggfile.h>
2426#include <tfile.h>
27#include <xiphcomment.h>
2528
2629#include <QCoreApplication>
2730#include <QStringList>
4646
4747 void processPath( const QString &path );
4848 bool handleMPEG( TagLib::MPEG::File *file );
49 bool handleOgg( TagLib::Ogg::File *file );
50 bool handleFLAC( TagLib::FLAC::File *file );
51 bool handleXiphComment( TagLib::Ogg::XiphComment *comment, TagLib::File *file );
4952 QString createCurrentUID( TagLib::File *file );
5053 QString createV1UID( TagLib::File *file );
5154 QString upgradeUID( int version, QString currValue );
utilities/collectionscanner/CollectionScanner.cpp
(45 / 13)
  
5252#include <mpegfile.h>
5353#include <oggfile.h>
5454#include <oggflacfile.h>
55#include <speexfile.h>
5556#include <tlist.h>
5657#include <tstring.h>
5758#include <vorbisfile.h>
7272#include <uniquefileidentifierframe.h>
7373#include <xiphcomment.h>
7474
75#define Qt4QStringToTString(s) TagLib::String(s.toUtf8().data(), TagLib::String::UTF8)
7576
7677int
7778main( int argc, char *argv[] )
483483CollectionScanner::readEmbeddedUniqueId( const TagLib::FileRef &fileref )
484484{
485485 int currentVersion = 1; //TODO: Make this more global?
486 if ( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( fileref.file() ) )
486 QString ourId = QString( "Amarok 2 AFTv" + QString::number( currentVersion ) + " - amarok.kde.org" );
487 if( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( fileref.file() ) )
487488 {
488489 if( !file->ID3v2Tag( false ) )
489490 return QString();
490 QString ourId = QString( "Amarok 2 AFTv" + QString::number( currentVersion ) + " - amarok.kde.org" );
491491 if( file->ID3v2Tag()->frameListMap()["UFID"].isEmpty() )
492492 return QString();
493493 TagLib::ID3v2::FrameList frameList = file->ID3v2Tag()->frameListMap()["UFID"];
498498 if( currFrame )
499499 {
500500 QString owner = TStringToQString( currFrame->owner() );
501 if( owner.startsWith( "Amarok 2 AFT" ) )
501 if( owner.compare( ourId, Qt::CaseInsensitive ) == 0 )
502502 {
503 int version = owner.at( 13 ).digitValue();
504 if( version == currentVersion )
505 return TStringToQString( TagLib::String( currFrame->identifier() ) );
503 qDebug() << "Found MP3 identifier: " << TStringToQString( TagLib::String( currFrame->identifier() ) ).toLower();
504 return TStringToQString( TagLib::String( currFrame->identifier() ) ).toLower();
506505 }
507506 }
508507 }
509508 }
509 //from here below assumes a file with a XiphComment; put non-conforming formats up above...
510 TagLib::Ogg::XiphComment *comment = 0;
511 if( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( fileref.file() ) )
512 {
513 comment = file->xiphComment( false );
514 if( !comment )
515 return QString();
516 }
517 else if( TagLib::Ogg::File *file = dynamic_cast<TagLib::Ogg::File *>( fileref.file() ) )
518 {
519 if( dynamic_cast<TagLib::Ogg::FLAC::File*>(file) )
520 comment = ( dynamic_cast<TagLib::Ogg::FLAC::File*>(file) )->tag();
521 else if( dynamic_cast<TagLib::Ogg::Speex::File*>(file) )
522 comment = ( dynamic_cast<TagLib::Ogg::Speex::File*>(file) )->tag();
523 else if( dynamic_cast<TagLib::Ogg::Vorbis::File*>(file) )
524 comment = ( dynamic_cast<TagLib::Ogg::Vorbis::File*>(file) )->tag();
525 if( !comment )
526 return QString();
527 }
528 if( comment->contains( Qt4QStringToTString( ourId.toUpper() ) ) )
529 {
530 QString identifier = TStringToQString( comment->fieldListMap()[Qt4QStringToTString(ourId.toUpper())].front()).toLower();
531 qDebug() << "Found Ogg or FLAC identifier: " << identifier;
532 return identifier;
533 }
534
510535 return QString();
511536}
512537
552552 if( file->tag() )
553553 return file->tag()->render();
554554 }
555 else if ( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( fileref.file() ) )
555 else if ( TagLib::Ogg::Speex::File *file = dynamic_cast<TagLib::Ogg::Speex::File *>( fileref.file() ) )
556556 {
557 if( file->ID3v2Tag() )
558 return file->ID3v2Tag()->render();
559 else if( file->ID3v1Tag() )
560 return file->ID3v1Tag()->render();
561 else if( file->xiphComment() )
562 return file->xiphComment()->render();
557 if( file->tag() )
558 return file->tag()->render();
563559 }
564560 else if ( TagLib::Ogg::FLAC::File *file = dynamic_cast<TagLib::Ogg::FLAC::File *>( fileref.file() ) )
565561 {
566562 if( file->tag() )
567563 return file->tag()->render();
564 }
565 else if ( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( fileref.file() ) )
566 {
567 if( file->xiphComment() )
568 return file->xiphComment()->render();
569 else if( file->ID3v1Tag() )
570 return file->ID3v1Tag()->render();
571 else if( file->ID3v2Tag() )
572 return file->ID3v2Tag()->render();
568573 }
569574 else if ( TagLib::MPC::File *file = dynamic_cast<TagLib::MPC::File *>( fileref.file() ) )
570575 {

Comments

Add a new comment:

Login or create an account to post a comment

Add your comment