diff --git a/autotests/taglibwritertest.cpp b/autotests/taglibwritertest.cpp index 3373da4..82291b0 100644 --- a/autotests/taglibwritertest.cpp +++ b/autotests/taglibwritertest.cpp @@ -1,243 +1,346 @@ /* * Copyright (C) 2016 Varun Joshi * Copyright (C) 2018 Alexander Stippich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "taglibwritertest.h" #include "indexerextractortestsconfig.h" #include "writers/taglibwriter.h" #include "writedata.h" #include #include #include #include "taglib.h" #include "fileref.h" #include #include #include #include using namespace KFileMetaData; QString TagLibWriterTest::testFilePath(const QString& fileName) const { return QLatin1String(INDEXER_TESTS_SAMPLE_FILES_PATH) + QLatin1Char('/') + fileName; } void TagLibWriterTest::testCommonData() { QFETCH(QString, fileType); QFETCH(QString, mimeType); QFETCH(QString, stringSuffix); QString temporaryFileName = QStringLiteral("writertest.") + fileType; QFile::copy(testFilePath("test." + fileType), testFilePath(temporaryFileName)); TagLibWriter writerPlugin{this}; QCOMPARE(writerPlugin.writeMimetypes().contains(mimeType),true); WriteData data(testFilePath(temporaryFileName), mimeType); data.add(Property::Title, QString(QStringLiteral("Title1") + stringSuffix)); data.add(Property::Artist, QString(QStringLiteral("Artist1") + stringSuffix)); data.add(Property::Album, QString(QStringLiteral("Album1") + stringSuffix)); + data.add(Property::AlbumArtist, QString(QStringLiteral("AlbumArtist1") + stringSuffix)); + data.add(Property::Composer, QString(QStringLiteral("Composer1") + stringSuffix)); data.add(Property::TrackNumber, 10); + data.add(Property::DiscNumber, 2); data.add(Property::ReleaseYear, 1999); data.add(Property::Genre, QString(QStringLiteral("Genre1") + stringSuffix)); data.add(Property::Comment, QString(QStringLiteral("Comment1") + stringSuffix)); + data.add(Property::Copyright, QString(QStringLiteral("Copyright1") + stringSuffix)); + writerPlugin.write(data); KFileMetaData::ExtractorCollection extractors; QList extractorList = extractors.fetchExtractors(mimeType); if (extractorList.isEmpty()) QFAIL("This mime type is not supported by the extractor. Likely a newer KDE Frameworks version is required."); KFileMetaData::Extractor* ex = extractorList.first(); KFileMetaData::SimpleExtractionResult result(testFilePath(temporaryFileName), mimeType, KFileMetaData::ExtractionResult::ExtractMetaData); ex->extract(&result); QCOMPARE(result.properties().value(Property::Title), QVariant(QStringLiteral("Title1") + stringSuffix)); QCOMPARE(result.properties().value(Property::Artist), QVariant(QStringLiteral("Artist1") + stringSuffix)); QCOMPARE(result.properties().value(Property::Album), QVariant(QStringLiteral("Album1") + stringSuffix)); + QCOMPARE(result.properties().value(Property::AlbumArtist), QVariant(QStringLiteral("AlbumArtist1") + stringSuffix)); + QCOMPARE(result.properties().value(Property::Composer), QVariant(QStringLiteral("Composer1") + stringSuffix)); QCOMPARE(result.properties().value(Property::TrackNumber).toInt(), 10); + QCOMPARE(result.properties().value(Property::DiscNumber).toInt(), 2); QCOMPARE(result.properties().value(Property::ReleaseYear).toInt(), 1999); QCOMPARE(result.properties().value(Property::Genre), QVariant(QStringLiteral("Genre1") + stringSuffix)); QCOMPARE(result.properties().value(Property::Comment), QVariant(QStringLiteral("Comment1") + stringSuffix)); + QCOMPARE(result.properties().value(Property::Copyright), QVariant(QStringLiteral("Copyright1") + stringSuffix)); QFile::remove(testFilePath(temporaryFileName)); } void TagLibWriterTest::testCommonData_data() { // Add some unicode characters, use codepoints to avoid any issues with // source encoding: "€µ" static const QChar data[2] = { 0x20ac, 0xb5 }; QString unicodeTestStringSuffix(data, 2); QTest::addColumn("fileType"); QTest::addColumn("mimeType"); QTest::addColumn("stringSuffix"); QTest::addRow("aiff") << QStringLiteral("aif") << QStringLiteral("audio/x-aiff") << QString() ; QTest::addRow("aiff_unicode") << QStringLiteral("aif") << QStringLiteral("audio/x-aiff") << unicodeTestStringSuffix ; QTest::addRow("ape") << QStringLiteral("ape") << QStringLiteral("audio/x-ape") << QString() ; QTest::addRow("ape_unicode") << QStringLiteral("ape") << QStringLiteral("audio/x-ape") << unicodeTestStringSuffix ; QTest::addRow("flac") << QStringLiteral("flac") << QStringLiteral("audio/flac") << QString() ; QTest::addRow("flac_unicode") << QStringLiteral("flac") << QStringLiteral("audio/flac") << unicodeTestStringSuffix ; QTest::addRow("m4a") << QStringLiteral("m4a") << QStringLiteral("audio/mp4") << QString() ; QTest::addRow("m4a_unicode") << QStringLiteral("m4a") << QStringLiteral("audio/mp4") << unicodeTestStringSuffix ; QTest::addRow("mp3") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << QString() ; QTest::addRow("mp3_unicode") << QStringLiteral("mp3") << QStringLiteral("audio/mpeg3") << unicodeTestStringSuffix ; QTest::addRow("mpc") << QStringLiteral("mpc") << QStringLiteral("audio/x-musepack") << QString() ; QTest::addRow("mpc_unicode") << QStringLiteral("mpc") << QStringLiteral("audio/x-musepack") << unicodeTestStringSuffix ; QTest::addRow("ogg") << QStringLiteral("ogg") << QStringLiteral("audio/ogg") << QString() ; QTest::addRow("ogg_unicode") << QStringLiteral("ogg") << QStringLiteral("audio/ogg") << unicodeTestStringSuffix ; QTest::addRow("opus") << QStringLiteral("opus") << QStringLiteral("audio/opus") << QString() ; QTest::addRow("opus_unicode") << QStringLiteral("opus") << QStringLiteral("audio/opus") << unicodeTestStringSuffix ; QTest::addRow("speex") << QStringLiteral("spx") << QStringLiteral("audio/speex") << QString() ; QTest::addRow("speex_unicode") << QStringLiteral("spx") << QStringLiteral("audio/speex") << unicodeTestStringSuffix ; QTest::addRow("wav") << QStringLiteral("wav") << QStringLiteral("audio/wav") << QString() ; QTest::addRow("wav_unicode") << QStringLiteral("wav") << QStringLiteral("audio/wav") << unicodeTestStringSuffix ; QTest::addRow("wavpack") << QStringLiteral("wv") << QStringLiteral("audio/x-wavpack") << QString() ; QTest::addRow("wavpack_unicode") << QStringLiteral("wv") << QStringLiteral("audio/x-wavpack") << unicodeTestStringSuffix ; QTest::addRow("wma") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << QString() ; QTest::addRow("wma_unicode") << QStringLiteral("wma") << QStringLiteral("audio/x-ms-wma") << unicodeTestStringSuffix ; } +void TagLibWriterTest::testExtendedData() +{ + QFETCH(QString, fileType); + QFETCH(QString, mimeType); + + QString temporaryFileName = QStringLiteral("writertest.") + fileType; + + QFile::copy(testFilePath("test." + fileType), testFilePath(temporaryFileName)); + TagLibWriter writerPlugin{this}; + + WriteData data(testFilePath(temporaryFileName), mimeType); + + data.add(Property::Composer, QStringLiteral("Composer1")); + data.add(Property::Lyricist, QStringLiteral("Lyricist1")); + data.add(Property::Conductor, QStringLiteral("Conductor1")); + data.add(Property::Lyrics, QStringLiteral("Lyrics1")); + data.add(Property::Language, QStringLiteral("Language1")); + + writerPlugin.write(data); + + KFileMetaData::ExtractorCollection extractors; + QList extractorList = extractors.fetchExtractors(mimeType); + if (extractorList.isEmpty()) + QFAIL("This mime type is not supported by the extractor. Likely a newer KDE Frameworks version is required."); + KFileMetaData::Extractor* ex = extractorList.first(); + KFileMetaData::SimpleExtractionResult result(testFilePath(temporaryFileName), mimeType, + KFileMetaData::ExtractionResult::ExtractMetaData); + + ex->extract(&result); + QCOMPARE(result.properties().value(Property::Composer), QVariant(QStringLiteral("Composer1"))); + QCOMPARE(result.properties().value(Property::Lyricist), QVariant(QStringLiteral("Lyricist1"))); + QCOMPARE(result.properties().value(Property::Conductor), QVariant(QStringLiteral("Conductor1"))); + QCOMPARE(result.properties().value(Property::Lyrics), QVariant(QStringLiteral("Lyrics1"))); + QCOMPARE(result.properties().value(Property::Language), QVariant(QStringLiteral("Language1"))); + + QFile::remove(testFilePath(temporaryFileName)); +} + +void TagLibWriterTest::testExtendedData_data() +{ + QTest::addColumn("fileType"); + QTest::addColumn("mimeType"); + + QTest::addRow("aiff") + << QStringLiteral("aif") + << QStringLiteral("audio/x-aiff") + ; + + QTest::addRow("ape") + << QStringLiteral("ape") + << QStringLiteral("audio/x-ape") + ; + + QTest::addRow("flac") + << QStringLiteral("flac") + << QStringLiteral("audio/flac") + ; + + QTest::addRow("mp3") + << QStringLiteral("mp3") + << QStringLiteral("audio/mpeg3") + ; + + QTest::addRow("mpc") + << QStringLiteral("mpc") + << QStringLiteral("audio/x-musepack") + ; + + QTest::addRow("ogg") + << QStringLiteral("ogg") + << QStringLiteral("audio/ogg") + ; + + QTest::addRow("opus") + << QStringLiteral("opus") + << QStringLiteral("audio/opus") + ; + + QTest::addRow("speex") + << QStringLiteral("spx") + << QStringLiteral("audio/speex") + ; + + QTest::addRow("wav") + << QStringLiteral("wav") + << QStringLiteral("audio/wav") + ; + + QTest::addRow("wavpack") + << QStringLiteral("wv") + << QStringLiteral("audio/x-wavpack") + ; +} + QTEST_GUILESS_MAIN(TagLibWriterTest) diff --git a/autotests/taglibwritertest.h b/autotests/taglibwritertest.h index 1f42599..6f15aa6 100644 --- a/autotests/taglibwritertest.h +++ b/autotests/taglibwritertest.h @@ -1,37 +1,39 @@ /* * Copyright (C) 2016 Varun Joshi * Copyright (C) 2018 Alexander Stippich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef TAGLIBWRITERTEST_H #define TAGLIBWRITERTEST_H #include class TagLibWriterTest : public QObject { Q_OBJECT private: QString testFilePath(const QString& fileName) const; private Q_SLOTS: void testCommonData(); void testCommonData_data(); + void testExtendedData(); + void testExtendedData_data(); }; #endif // TAGLIBWRITERTEST_H diff --git a/src/writers/taglibwriter.cpp b/src/writers/taglibwriter.cpp index e0e2dbd..aa9e455 100644 --- a/src/writers/taglibwriter.cpp +++ b/src/writers/taglibwriter.cpp @@ -1,229 +1,265 @@ /* * Copyright (C) 2016 Varun Joshi * Copyright (C) 2018 Alexander Stippich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "taglibwriter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { const QStringList supportedMimeTypes = { QStringLiteral("audio/flac"), QStringLiteral("audio/mp4"), QStringLiteral("audio/mpeg"), QStringLiteral("audio/mpeg3"), QStringLiteral("audio/ogg"), QStringLiteral("audio/opus"), QStringLiteral("audio/speex"), QStringLiteral("audio/wav"), QStringLiteral("audio/x-aiff"), QStringLiteral("audio/x-ape"), QStringLiteral("audio/x-mpeg"), QStringLiteral("audio/x-ms-wma"), QStringLiteral("audio/x-musepack"), QStringLiteral("audio/x-opus+ogg"), QStringLiteral("audio/x-speex+ogg"), QStringLiteral("audio/x-vorbis+ogg"), QStringLiteral("audio/x-wav"), QStringLiteral("audio/x-wavpack"), }; } using namespace KFileMetaData; void writeGenericProperties(TagLib::PropertyMap &oldProperties, const PropertyMap &newProperties) { if (newProperties.contains(Property::Title)) { oldProperties.replace("TITLE", QStringToTString(newProperties.value(Property::Title).toString())); } if (newProperties.contains(Property::Artist)) { oldProperties.replace("ARTIST", QStringToTString(newProperties.value(Property::Artist).toString())); } + if (newProperties.contains(Property::AlbumArtist)) { + oldProperties.replace("ALBUMARTIST", QStringToTString(newProperties.value(Property::AlbumArtist).toString())); + } + if (newProperties.contains(Property::Album)) { oldProperties.replace("ALBUM", QStringToTString(newProperties.value(Property::Album).toString())); } if (newProperties.contains(Property::TrackNumber)) { int trackNumber = newProperties.value(Property::TrackNumber).toInt(); //taglib requires uint if (trackNumber >= 0) { oldProperties.replace("TRACKNUMBER", QStringToTString(newProperties.value(Property::TrackNumber).toString())); } } + if (newProperties.contains(Property::DiscNumber)) { + int discNumber = newProperties.value(Property::DiscNumber).toInt(); + //taglib requires uint + if (discNumber >= 0) { + oldProperties.replace("DISCNUMBER", QStringToTString(newProperties.value(Property::DiscNumber).toString())); + } + } + if (newProperties.contains(Property::ReleaseYear)) { int year = newProperties.value(Property::ReleaseYear).toInt(); //taglib requires uint if (year >= 0) { oldProperties.replace("DATE", QStringToTString(newProperties.value(Property::ReleaseYear).toString())); } } if (newProperties.contains(Property::Genre)) { oldProperties.replace("GENRE", QStringToTString(newProperties.value(Property::Genre).toString())); } if (newProperties.contains(Property::Comment)) { oldProperties.replace("COMMENT", QStringToTString(newProperties.value(Property::Comment).toString())); } + + if (newProperties.contains(Property::Composer)) { + oldProperties.replace("COMPOSER", QStringToTString(newProperties.value(Property::Composer).toString())); + } + + if (newProperties.contains(Property::Lyricist)) { + oldProperties.replace("LYRICIST", QStringToTString(newProperties.value(Property::Lyricist).toString())); + } + + if (newProperties.contains(Property::Conductor)) { + oldProperties.replace("CONDUCTOR", QStringToTString(newProperties.value(Property::Conductor).toString())); + } + + if (newProperties.contains(Property::Copyright)) { + oldProperties.replace("COPYRIGHT", QStringToTString(newProperties.value(Property::Copyright).toString())); + } + + if (newProperties.contains(Property::Lyrics)) { + oldProperties.replace("LYRICS", QStringToTString(newProperties.value(Property::Lyrics).toString())); + } + + if (newProperties.contains(Property::Language)) { + oldProperties.replace("LANGUAGE", QStringToTString(newProperties.value(Property::Language).toString())); + } } TagLibWriter::TagLibWriter(QObject* parent) : WriterPlugin(parent) { } QStringList TagLibWriter::writeMimetypes() const { return supportedMimeTypes; } void TagLibWriter::write(const WriteData& data) { const QString fileUrl = data.inputUrl(); const PropertyMap properties = data.getAllProperties(); const QString mimeType = data.inputMimetype(); TagLib::FileStream stream(fileUrl.toUtf8().constData(), false); if (!stream.isOpen()) { qWarning() << "Unable to open file in write mode: " << fileUrl; return; } if ((mimeType == QLatin1String("audio/mpeg")) || (mimeType == QLatin1String("audio/mpeg3")) || (mimeType == QLatin1String("audio/x-mpeg"))) { TagLib::MPEG::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/x-aiff")) { TagLib::RIFF::AIFF::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if ((mimeType == QLatin1String("audio/wav")) || (mimeType == QLatin1String("audio/x-wav"))) { TagLib::RIFF::WAV::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/x-musepack")) { TagLib::MPC::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/x-ape")) { TagLib::APE::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/x-wavpack")) { TagLib::WavPack::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/mp4")) { TagLib::MP4::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/flac")) { TagLib::FLAC::File file(&stream, TagLib::ID3v2::FrameFactory::instance(), false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/ogg") || mimeType == QLatin1String("audio/x-vorbis+ogg")) { TagLib::Ogg::Vorbis::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/opus") || mimeType == QLatin1String("audio/x-opus+ogg")) { TagLib::Ogg::Opus::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/speex") || mimeType == QLatin1String("audio/x-speex+ogg")) { TagLib::Ogg::Speex::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } else if (mimeType == QLatin1String("audio/x-ms-wma")) { TagLib::ASF::File file(&stream, false); if (file.isValid()) { auto savedProperties = file.properties(); writeGenericProperties(savedProperties, properties); file.setProperties(savedProperties); file.save(); } } }