Add option to embed covers when copying songs to devices. (ID3v2, mp4, vorbis comment tag types only)
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
7. Allow editing of tags, and replaygain calculation, of files from folder view
|
||||
which do not contain tags.
|
||||
8. Merge 'External Settings' into 'Interface Settingst'
|
||||
9. Add option to embed covers when copying songs to devices. (ID3v2, mp4,
|
||||
vorbis comment tag types only)
|
||||
|
||||
0.9.1
|
||||
-----
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "device.h"
|
||||
#include "covers.h"
|
||||
#include "utils.h"
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QTemporaryFile>
|
||||
#ifndef Q_OS_WIN
|
||||
@@ -130,6 +131,7 @@ void Device::cleanDir(const QString &dir, const QString &base, const QString &co
|
||||
#include <unistd.h>
|
||||
|
||||
const QLatin1String Device::constNoCover("-");
|
||||
const QLatin1String Device::constEmbedCover("+");
|
||||
|
||||
Device * Device::create(DevicesModel *m, const QString &udi)
|
||||
{
|
||||
@@ -191,6 +193,38 @@ bool Device::fixVariousArtists(const QString &file, Song &song, bool applyFix)
|
||||
return false;
|
||||
}
|
||||
|
||||
static QByteArray save(const QImage &img) {
|
||||
QByteArray ba;
|
||||
QBuffer buffer(&ba);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
img.save(&buffer, "JPG");
|
||||
buffer.close();
|
||||
return ba;
|
||||
}
|
||||
|
||||
void Device::embedCover(const QString &file, Song &song, unsigned int coverMaxSize)
|
||||
{
|
||||
if (Tags::readImage(file).isNull()) {
|
||||
Covers::Image coverImage=Covers::self()->getImage(song);
|
||||
if (!coverImage.img.isNull()) {
|
||||
QByteArray imgData;
|
||||
if (coverImage.img.width()>(int)coverMaxSize || coverImage.img.height()>(int)coverMaxSize) {
|
||||
imgData=save(coverImage.img.scaled(QSize(coverMaxSize, coverMaxSize), Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
} else if (!coverImage.fileName.endsWith(".jpg", Qt::CaseInsensitive) || !QFile::exists(coverImage.fileName)) {
|
||||
imgData=save(coverImage.img);
|
||||
} else {
|
||||
QFile f(coverImage.fileName);
|
||||
if (f.open(QIODevice::ReadOnly)) {
|
||||
imgData=f.readAll();
|
||||
} else {
|
||||
imgData=save(coverImage.img);
|
||||
}
|
||||
}
|
||||
Tags::embedImage(file, imgData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QTemporaryFile * Device::copySongToTemp(Song &song)
|
||||
{
|
||||
QTemporaryFile *temp=new QTemporaryFile();
|
||||
|
||||
@@ -55,11 +55,13 @@ class Device : public MusicLibraryItemRoot
|
||||
public:
|
||||
static Device * create(DevicesModel *m, const QString &udi);
|
||||
static bool fixVariousArtists(const QString &file, Song &song, bool applyFix);
|
||||
static void embedCover(const QString &file, Song &song, unsigned int coverMaxSize);
|
||||
static QTemporaryFile * copySongToTemp(Song &song);
|
||||
static void moveDir(const QString &from, const QString &to, const QString &base, const QString &coverFile);
|
||||
static void cleanDir(const QString &dir, const QString &base, const QString &coverFile, int level=0);
|
||||
|
||||
static const QLatin1String constNoCover;
|
||||
static const QLatin1String constEmbedCover;
|
||||
|
||||
enum Status {
|
||||
Ok,
|
||||
|
||||
@@ -80,12 +80,13 @@ DevicePropertiesWidget::DevicePropertiesWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, schemeDlg(0)
|
||||
, noCoverText(i18n("Don't copy covers"))
|
||||
, embedCoverText(i18n("Embed cover within each file"))
|
||||
, modified(false)
|
||||
, saveable(false)
|
||||
{
|
||||
setupUi(this);
|
||||
configFilename->setIcon(Icons::configureIcon);
|
||||
albumCovers->insertItems(0, QStringList() << noCoverText << Covers::standardNames());
|
||||
albumCovers->insertItems(0, QStringList() << noCoverText << embedCoverText << Covers::standardNames());
|
||||
coverMaxSize->insertItems(0, QStringList() << i18n("No maximum size") << i18n("400 pixels") << i18n("300 pixels") << i18n("200 pixels") << i18n("100 pixels"));
|
||||
fixVariousArtists->setToolTip(i18n("<p>When copying tracks to a device, and the 'Album Artist' is set to 'Various Artists', "
|
||||
"then Cantata will set the 'Artist' tag of all tracks to 'Various Artists' and the "
|
||||
@@ -110,6 +111,7 @@ DevicePropertiesWidget::DevicePropertiesWidget(QWidget *parent)
|
||||
|
||||
void DevicePropertiesWidget::update(const QString &path, const DeviceOptions &opts, int props)
|
||||
{
|
||||
bool allowCovers=(props&Prop_CoversAll)||(props&Prop_CoversBasic);
|
||||
filenameScheme->setText(opts.scheme);
|
||||
vfatSafe->setChecked(opts.vfatSafe);
|
||||
asciiOnly->setChecked(opts.asciiOnly);
|
||||
@@ -118,10 +120,11 @@ void DevicePropertiesWidget::update(const QString &path, const DeviceOptions &op
|
||||
musicFolder->setText(path);
|
||||
musicFolder->setVisible(props&Prop_Folder);
|
||||
musicFolderLabel->setVisible(props&Prop_Folder);
|
||||
albumCovers->setVisible(props&Prop_Covers);
|
||||
albumCoversLabel->setVisible(props&Prop_Covers);
|
||||
coverMaxSize->setVisible(props&Prop_Covers);
|
||||
coverMaxSizeLabel->setVisible(props&Prop_Covers);
|
||||
albumCovers->setVisible(allowCovers);
|
||||
albumCoversLabel->setVisible(allowCovers);
|
||||
coverMaxSize->setVisible(allowCovers);
|
||||
coverMaxSizeLabel->setVisible(allowCovers);
|
||||
albumCovers->setEditable(props&Prop_CoversAll);
|
||||
fixVariousArtists->setVisible(props&Prop_Va);
|
||||
fixVariousArtistsLabel->setVisible(props&Prop_Va);
|
||||
fixVariousArtists->setChecked(opts.fixVariousArtists);
|
||||
@@ -169,14 +172,20 @@ void DevicePropertiesWidget::update(const QString &path, const DeviceOptions &op
|
||||
}
|
||||
|
||||
origOpts=opts;
|
||||
albumCovers->setCurrentIndex(0);
|
||||
if (origOpts.coverName==Device::constNoCover) {
|
||||
origOpts.coverName=noCoverText;
|
||||
albumCovers->setCurrentIndex(0);
|
||||
}
|
||||
for (int i=1; i<albumCovers->count(); ++i) {
|
||||
if (albumCovers->itemText(i)==origOpts.coverName) {
|
||||
albumCovers->setCurrentIndex(i);
|
||||
break;
|
||||
if (origOpts.coverName==Device::constEmbedCover) {
|
||||
origOpts.coverName=embedCoverText;
|
||||
albumCovers->setCurrentIndex(1);
|
||||
} else {
|
||||
albumCovers->setCurrentIndex(0);
|
||||
for (int i=1; i<albumCovers->count(); ++i) {
|
||||
if (albumCovers->itemText(i)==origOpts.coverName) {
|
||||
albumCovers->setCurrentIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +260,12 @@ void DevicePropertiesWidget::checkSaveable()
|
||||
if (!modified && checkFolder) {
|
||||
modified=musicFolder->text().trimmed()!=origMusicFolder;
|
||||
}
|
||||
saveable=!opts.scheme.isEmpty() && (!checkFolder || !musicFolder->text().trimmed().isEmpty()) && !albumCovers->currentText().isEmpty();
|
||||
saveable=!opts.scheme.isEmpty() && (!checkFolder || !musicFolder->text().trimmed().isEmpty()) && !opts.coverName.isEmpty();
|
||||
if (saveable &&
|
||||
( (-1!=opts.coverName.indexOf(noCoverText) && opts.coverName!=noCoverText) ||
|
||||
(-1!=opts.coverName.indexOf(embedCoverText) && opts.coverName!=embedCoverText) ) ) {
|
||||
saveable=false;
|
||||
}
|
||||
emit updated();
|
||||
}
|
||||
|
||||
@@ -278,7 +292,7 @@ DeviceOptions DevicePropertiesWidget::settings()
|
||||
opts.transcoderCodec=QString();
|
||||
opts.transcoderValue=0;
|
||||
opts.transcoderWhenDifferent=false;
|
||||
opts.coverName=albumCovers->currentText();
|
||||
opts.coverName=cover();
|
||||
opts.coverMaxSize=0==coverMaxSize->currentIndex() ? 0 : ((coverMaxSize->count()-coverMaxSize->currentIndex())*100);
|
||||
if (transcoderFrame->isVisible()) {
|
||||
opts.transcoderCodec=transcoderName->itemData(transcoderName->currentIndex()).toString();
|
||||
@@ -297,5 +311,10 @@ DeviceOptions DevicePropertiesWidget::settings()
|
||||
|
||||
QString DevicePropertiesWidget::cover() const
|
||||
{
|
||||
return albumCovers->currentText()==noCoverText ? Device::constNoCover : albumCovers->currentText();
|
||||
QString coverName=albumCovers->currentText().trimmed();
|
||||
return coverName==noCoverText
|
||||
? Device::constNoCover
|
||||
: coverName==embedCoverText
|
||||
? Device::constEmbedCover
|
||||
: coverName;
|
||||
}
|
||||
|
||||
@@ -34,16 +34,17 @@ class DevicePropertiesWidget : public QWidget, Ui::DevicePropertiesWidget
|
||||
|
||||
public:
|
||||
enum Properties {
|
||||
Prop_Basic = 0x00,
|
||||
Prop_Basic = 0x00,
|
||||
|
||||
Prop_Folder = 0x01,
|
||||
Prop_Covers = 0x02,
|
||||
Prop_Va = 0x04,
|
||||
Prop_Transcoder = 0x08,
|
||||
Prop_Cache = 0x10,
|
||||
Prop_AutoScan = 0x20,
|
||||
Prop_Folder = 0x01,
|
||||
Prop_CoversAll = 0x02,
|
||||
Prop_CoversBasic = 0x04,
|
||||
Prop_Va = 0x08,
|
||||
Prop_Transcoder = 0x10,
|
||||
Prop_Cache = 0x20,
|
||||
Prop_AutoScan = 0x40,
|
||||
|
||||
Prop_All = 0xFF
|
||||
Prop_All = 0xFF
|
||||
};
|
||||
DevicePropertiesWidget(QWidget *parent);
|
||||
virtual ~DevicePropertiesWidget() { }
|
||||
@@ -68,6 +69,7 @@ private:
|
||||
DeviceOptions origOpts;
|
||||
QString origMusicFolder;
|
||||
QString noCoverText;
|
||||
QString embedCoverText;
|
||||
bool modified;
|
||||
bool saveable;
|
||||
};
|
||||
|
||||
@@ -109,13 +109,20 @@ QString CopyJob::updateTagsLocal()
|
||||
{
|
||||
// First, if we are going to update tags (e.g. to fix various artists), then check if we want to do that locally, before
|
||||
// copying to device. For UMS devices, we just modify on device, but for remote (e.g. sshfs) then it'd be better to do locally :-)
|
||||
if (copyOpts&OptsFixLocal && (copyOpts&OptsApplyVaFix || copyOpts&OptsUnApplyVaFix)) {
|
||||
if (copyOpts&OptsFixLocal && (copyOpts&OptsApplyVaFix || copyOpts&OptsUnApplyVaFix || Device::constEmbedCover==deviceOpts.coverName)) {
|
||||
song.file=srcFile;
|
||||
temp=Device::copySongToTemp(song);
|
||||
if (!temp || !Device::fixVariousArtists(temp->fileName(), song, copyOpts&OptsApplyVaFix)) {
|
||||
if (!temp) {
|
||||
emit result(StatusFailed);
|
||||
return QString();
|
||||
}
|
||||
if ((copyOpts&OptsApplyVaFix || copyOpts&OptsUnApplyVaFix) && !Device::fixVariousArtists(temp->fileName(), song, copyOpts&OptsApplyVaFix)) {
|
||||
emit result(StatusFailed);
|
||||
return QString();
|
||||
}
|
||||
if (Device::constEmbedCover==deviceOpts.coverName) {
|
||||
Device::embedCover(temp->fileName(), song, deviceOpts.coverMaxSize);
|
||||
}
|
||||
return temp->fileName();
|
||||
}
|
||||
return srcFile;
|
||||
@@ -123,14 +130,19 @@ QString CopyJob::updateTagsLocal()
|
||||
|
||||
void CopyJob::updateTagsDest()
|
||||
{
|
||||
if (!stopRequested && !(copyOpts&OptsFixLocal) && (copyOpts&OptsApplyVaFix || copyOpts&OptsUnApplyVaFix)) {
|
||||
Device::fixVariousArtists(destFile, song, copyOpts&OptsApplyVaFix);
|
||||
if (!stopRequested && !(copyOpts&OptsFixLocal) && (copyOpts&OptsApplyVaFix || copyOpts&OptsUnApplyVaFix || Device::constEmbedCover==deviceOpts.coverName)) {
|
||||
if (copyOpts&OptsApplyVaFix || copyOpts&OptsUnApplyVaFix) {
|
||||
Device::fixVariousArtists(destFile, song, copyOpts&OptsApplyVaFix);
|
||||
}
|
||||
if (!stopRequested && Device::constEmbedCover==deviceOpts.coverName) {
|
||||
Device::embedCover(destFile, song, deviceOpts.coverMaxSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CopyJob::copyCover(const QString &origSrcFile)
|
||||
{
|
||||
if (!stopRequested && Device::constNoCover!=deviceOpts.coverName) {
|
||||
if (!stopRequested && Device::constNoCover!=deviceOpts.coverName && Device::constEmbedCover!=deviceOpts.coverName) {
|
||||
song.file=destFile;
|
||||
copiedCover=Covers::copyCover(song, Utils::getDir(origSrcFile), Utils::getDir(destFile), deviceOpts.coverName, deviceOpts.coverMaxSize);
|
||||
}
|
||||
|
||||
@@ -507,10 +507,11 @@ static LIBMTP_filetype_t mtpFileType(const Song &s)
|
||||
return LIBMTP_FILETYPE_UNDEF_AUDIO;
|
||||
}
|
||||
|
||||
void MtpConnection::putSong(const Song &s, bool fixVa)
|
||||
void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts)
|
||||
{
|
||||
bool added=false;
|
||||
bool fixedVa=false;
|
||||
bool embedCoverImage=Device::constEmbedCover==opts.coverName;
|
||||
LIBMTP_track_t *meta=0;
|
||||
if (device) {
|
||||
meta=LIBMTP_new_track_t();
|
||||
@@ -528,14 +529,17 @@ void MtpConnection::putSong(const Song &s, bool fixVa)
|
||||
QString fileName=song.file;
|
||||
QTemporaryFile *temp=0;
|
||||
|
||||
if (fixVa) {
|
||||
if (fixVa || embedCoverImage) {
|
||||
// Need to 'workaround' broken various artists handling, so write to a temporary file first...
|
||||
temp=Device::copySongToTemp(song);
|
||||
if (temp) {
|
||||
song.file=temp->fileName();
|
||||
if (Device::fixVariousArtists(temp->fileName(), song, true)) {
|
||||
if (embedCoverImage) {
|
||||
Device::embedCover(song.file, song, opts.coverMaxSize);
|
||||
}
|
||||
if (fixVa && Device::fixVariousArtists(temp->fileName(), song, true)) {
|
||||
fixedVa=true;
|
||||
}
|
||||
song.file=temp->fileName();
|
||||
}
|
||||
}
|
||||
meta->title=createString(song.title);
|
||||
@@ -924,6 +928,7 @@ MtpDevice::MtpDevice(DevicesModel *m, Solid::Device &dev)
|
||||
static bool registeredTypes=false;
|
||||
if (!registeredTypes) {
|
||||
qRegisterMetaType<QSet<QString> >("QSet<QString>");
|
||||
qRegisterMetaType<DeviceOptions >("DeviceOptions");
|
||||
registeredTypes=true;
|
||||
}
|
||||
|
||||
@@ -941,7 +946,7 @@ MtpDevice::MtpDevice(DevicesModel *m, Solid::Device &dev)
|
||||
connect(this, SIGNAL(updateLibrary()), connection, SLOT(updateLibrary()));
|
||||
connect(connection, SIGNAL(libraryUpdated()), this, SLOT(libraryUpdated()));
|
||||
connect(connection, SIGNAL(progress(int)), this, SLOT(emitProgress(int)));
|
||||
connect(this, SIGNAL(putSong(const Song &, bool)), connection, SLOT(putSong(const Song &, bool)));
|
||||
connect(this, SIGNAL(putSong(const Song &, bool, const DeviceOptions &)), connection, SLOT(putSong(const Song &, bool, const DeviceOptions &)));
|
||||
connect(connection, SIGNAL(putSongStatus(bool, int, const QString &, bool)), this, SLOT(putSongStatus(bool, int, const QString &, bool)));
|
||||
connect(this, SIGNAL(getSong(const Song &, const QString &)), connection, SLOT(getSong(const Song &, const QString &)));
|
||||
connect(connection, SIGNAL(getSongStatus(bool)), this, SLOT(getSongStatus(bool)));
|
||||
@@ -994,7 +999,7 @@ void MtpDevice::configure(QWidget *parent)
|
||||
if (!configured) {
|
||||
connect(dlg, SIGNAL(cancelled()), SLOT(saveProperties()));
|
||||
}
|
||||
dlg->show(QString(), opts, DevicePropertiesWidget::Prop_Va|DevicePropertiesWidget::Prop_Transcoder);
|
||||
dlg->show(QString(), opts, DevicePropertiesWidget::Prop_CoversBasic|DevicePropertiesWidget::Prop_Va|DevicePropertiesWidget::Prop_Transcoder);
|
||||
}
|
||||
|
||||
void MtpDevice::rescan(bool full)
|
||||
@@ -1092,7 +1097,7 @@ void MtpDevice::addSong(const Song &s, bool overwrite, bool copyCover)
|
||||
}
|
||||
}
|
||||
transcoding=false;
|
||||
emit putSong(currentSong, needToFixVa);
|
||||
emit putSong(currentSong, needToFixVa, opts);
|
||||
}
|
||||
|
||||
void MtpDevice::copySongTo(const Song &s, const QString &baseDir, const QString &musicPath, bool overwrite, bool copyCover)
|
||||
@@ -1203,7 +1208,7 @@ void MtpDevice::transcodeSongResult(int status)
|
||||
if (FileJob::StatusOk!=status) {
|
||||
emit actionStatus(TranscodeFailed);
|
||||
} else {
|
||||
emit putSong(currentSong, needToFixVa);
|
||||
emit putSong(currentSong, needToFixVa, DeviceOptions(Device::constNoCover));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public Q_SLOTS:
|
||||
void connectToDevice();
|
||||
void disconnectFromDevice(bool showStatus=true);
|
||||
void updateLibrary();
|
||||
void putSong(const Song &song, bool fixVa);
|
||||
void putSong(const Song &song, bool fixVa, const DeviceOptions &opts);
|
||||
void getSong(const Song &song, const QString &dest, bool fixVa, bool copyCover);
|
||||
void delSong(const Song &song);
|
||||
void cleanDirs(const QSet<QString> &dirs);
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
Q_SIGNALS:
|
||||
// These are for talking to connection thread...
|
||||
void updateLibrary();
|
||||
void putSong(const Song &song, bool fixVa);
|
||||
void putSong(const Song &song, bool fixVa, const DeviceOptions &opts);
|
||||
void getSong(const Song &song, const QString &dest, bool fixVa, bool copyCover);
|
||||
void delSong(const Song &song);
|
||||
void cleanMusicDirs(const QSet<QString> &dirs);
|
||||
|
||||
@@ -365,7 +365,7 @@ static bool updateID3v2Tag(TagLib::ID3v2::Tag *tag, const char *tagName, const Q
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool writeID3v2Tags(TagLib::ID3v2::Tag *tag, const Song &from, const Song &to, const RgTags &rg)
|
||||
static bool writeID3v2Tags(TagLib::ID3v2::Tag *tag, const Song &from, const Song &to, const RgTags &rg, const QByteArray &img)
|
||||
{
|
||||
bool changed=false;
|
||||
|
||||
@@ -396,6 +396,17 @@ static bool writeID3v2Tags(TagLib::ID3v2::Tag *tag, const Song &from, const Song
|
||||
}
|
||||
changed=true;
|
||||
}
|
||||
|
||||
if (!img.isEmpty()) {
|
||||
TagLib::ByteVector imgData(img.constData(), img.length());
|
||||
TagLib::ID3v2::AttachedPictureFrame *pic=new TagLib::ID3v2::AttachedPictureFrame;
|
||||
pic->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
|
||||
pic->setMimeType("image/jpeg");
|
||||
pic->setPicture(imgData);
|
||||
tag->addFrame(pic);
|
||||
changed=true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -548,7 +559,7 @@ static bool updateVorbisCommentTag(TagLib::Ogg::XiphComment *tag, const char *ta
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool writeVorbisCommentTags(TagLib::Ogg::XiphComment *tag, const Song &from, const Song &to, const RgTags &rg)
|
||||
static bool writeVorbisCommentTags(TagLib::Ogg::XiphComment *tag, const Song &from, const Song &to, const RgTags &rg, const QByteArray &img)
|
||||
{
|
||||
bool changed=false;
|
||||
|
||||
@@ -574,6 +585,11 @@ static bool writeVorbisCommentTags(TagLib::Ogg::XiphComment *tag, const Song &fr
|
||||
}
|
||||
changed=true;
|
||||
}
|
||||
|
||||
if (!img.isEmpty()) {
|
||||
tag->addField("COVERART", qString2TString(QString::fromAscii(img.toBase64())));
|
||||
changed=true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -632,7 +648,7 @@ static bool updateMP4Tag(TagLib::MP4::Tag *tag, const char *tagName, const QStri
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool writeMP4Tags(TagLib::MP4::Tag *tag, const Song &from, const Song &to, const RgTags &rg)
|
||||
static bool writeMP4Tags(TagLib::MP4::Tag *tag, const Song &from, const Song &to, const RgTags &rg, const QByteArray &img)
|
||||
{
|
||||
bool changed=false;
|
||||
|
||||
@@ -659,6 +675,17 @@ static bool writeMP4Tags(TagLib::MP4::Tag *tag, const Song &from, const Song &to
|
||||
}
|
||||
changed=true;
|
||||
}
|
||||
|
||||
if (!img.isEmpty()) {
|
||||
TagLib::ByteVector imgData(img.constData(), img.length());
|
||||
TagLib::MP4::CoverArt coverArt(TagLib::MP4::CoverArt::JPEG, imgData);
|
||||
TagLib::MP4::CoverArtList coverArtList;
|
||||
coverArtList.append(coverArt);
|
||||
TagLib::MP4::Item coverItem(coverArtList);
|
||||
TagLib::MP4::ItemListMap &map = tag->itemListMap();
|
||||
map.insert("covr", coverItem);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
#endif
|
||||
@@ -802,7 +829,7 @@ static void readTags(const TagLib::FileRef fileref, Song *song, ReplayGain *rg,
|
||||
}
|
||||
}
|
||||
|
||||
static bool writeTags(const TagLib::FileRef fileref, const Song &from, const Song &to, const RgTags &rg)
|
||||
static bool writeTags(const TagLib::FileRef fileref, const Song &from, const Song &to, const RgTags &rg, const QByteArray &img)
|
||||
{
|
||||
bool changed=false;
|
||||
TagLib::Tag *tag=fileref.tag();
|
||||
@@ -834,56 +861,56 @@ static bool writeTags(const TagLib::FileRef fileref, const Song &from, const Son
|
||||
}
|
||||
if (TagLib::MPEG::File *file = dynamic_cast< TagLib::MPEG::File * >(fileref.file())) {
|
||||
if (file->ID3v2Tag()) {
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg) || changed;
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg, img) || changed;
|
||||
} else if (file->APETag()) {
|
||||
changed=writeAPETags(file->APETag(), from, to, rg) || changed;
|
||||
// } else if (file->ID3v1Tag()) {
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg) || changed;
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg, img) || changed;
|
||||
} else if (file->ID3v2Tag(true)) {
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg) || changed;
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg, img) || changed;
|
||||
}
|
||||
} else if (TagLib::Ogg::Vorbis::File *file = dynamic_cast< TagLib::Ogg::Vorbis::File * >(fileref.file())) {
|
||||
if (file->tag()) {
|
||||
changed=writeVorbisCommentTags(file->tag(), from, to, rg) || changed;
|
||||
changed=writeVorbisCommentTags(file->tag(), from, to, rg, img) || changed;
|
||||
}
|
||||
} else if (TagLib::Ogg::FLAC::File *file = dynamic_cast< TagLib::Ogg::FLAC::File * >(fileref.file())) {
|
||||
if (file->tag()) {
|
||||
changed=writeVorbisCommentTags(file->tag(), from, to, rg) || changed;
|
||||
changed=writeVorbisCommentTags(file->tag(), from, to, rg, img) || changed;
|
||||
}
|
||||
} else if (TagLib::Ogg::Speex::File *file = dynamic_cast< TagLib::Ogg::Speex::File * >(fileref.file())) {
|
||||
if (file->tag()) {
|
||||
changed=writeVorbisCommentTags(file->tag(), from, to, rg) || changed;
|
||||
changed=writeVorbisCommentTags(file->tag(), from, to, rg, img) || changed;
|
||||
}
|
||||
} else if (TagLib::FLAC::File *file = dynamic_cast< TagLib::FLAC::File * >(fileref.file())) {
|
||||
if (file->xiphComment()) {
|
||||
changed=writeVorbisCommentTags(file->xiphComment(), from, to, rg) || changed;
|
||||
changed=writeVorbisCommentTags(file->xiphComment(), from, to, rg, img) || changed;
|
||||
} else if (file->ID3v2Tag()) {
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg) || changed;
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg, img) || changed;
|
||||
// } else if (file->ID3v1Tag()) {
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg) || changed;
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg, img) || changed;
|
||||
} else if (file->ID3v2Tag(true)) {
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg) || changed;
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg, img) || changed;
|
||||
}
|
||||
#ifdef TAGLIB_MP4_FOUND
|
||||
} else if (TagLib::MP4::File *file = dynamic_cast< TagLib::MP4::File * >(fileref.file())) {
|
||||
TagLib::MP4::Tag *tag = dynamic_cast<TagLib::MP4::Tag * >(file->tag());
|
||||
if (tag) {
|
||||
changed=writeMP4Tags(tag, from, to, rg) || changed;
|
||||
changed=writeMP4Tags(tag, from, to, rg, img) || changed;
|
||||
}
|
||||
#endif
|
||||
} else if (TagLib::MPC::File *file = dynamic_cast< TagLib::MPC::File * >(fileref.file())) {
|
||||
if (file->APETag(true)) {
|
||||
changed=writeAPETags(file->APETag(), from, to, rg) || changed;
|
||||
// } else if (file->ID3v1Tag()) {
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg) || changed;
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg, img) || changed;
|
||||
}
|
||||
} else if (TagLib::RIFF::AIFF::File *file = dynamic_cast< TagLib::RIFF::AIFF::File * >(fileref.file())) {
|
||||
if (file->tag()) {
|
||||
changed=writeID3v2Tags(file->tag(), from, to, rg) || changed;
|
||||
changed=writeID3v2Tags(file->tag(), from, to, rg, img) || changed;
|
||||
}
|
||||
} else if (TagLib::RIFF::WAV::File *file = dynamic_cast< TagLib::RIFF::WAV::File * >(fileref.file())) {
|
||||
if (file->tag()) {
|
||||
changed=writeID3v2Tags(file->tag(), from, to, rg) || changed;
|
||||
changed=writeID3v2Tags(file->tag(), from, to, rg, img) || changed;
|
||||
}
|
||||
#ifdef TAGLIB_ASF_FOUND
|
||||
} else if (TagLib::ASF::File *file = dynamic_cast< TagLib::ASF::File * >(fileref.file())) {
|
||||
@@ -894,15 +921,15 @@ static bool writeTags(const TagLib::FileRef fileref, const Song &from, const Son
|
||||
#endif
|
||||
} else if (TagLib::TrueAudio::File *file = dynamic_cast< TagLib::TrueAudio::File * >(fileref.file())) {
|
||||
if (file->ID3v2Tag(true)) {
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg) || changed;
|
||||
changed=writeID3v2Tags(file->ID3v2Tag(), from, to, rg, img) || changed;
|
||||
// } else if (file->ID3v1Tag()) {
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg) || changed;
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg, img) || changed;
|
||||
}
|
||||
} else if (TagLib::WavPack::File *file = dynamic_cast< TagLib::WavPack::File * >(fileref.file())) {
|
||||
if (file->APETag(true)) {
|
||||
changed=writeAPETags(file->APETag(), from, to, rg) || changed;
|
||||
// } else if (file->ID3v1Tag()) {
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg) || changed;
|
||||
// changed=writeID3v1Tags(fileref, from, to, rg, img) || changed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1000,7 +1027,7 @@ Update update(const QString &fileName, const Song &from, const Song &to)
|
||||
TagLib::ID3v1::Tag *v1=mpeg ? mpeg->ID3v1Tag(false) : 0;
|
||||
bool haveV1=v1 && (!v1->title().isEmpty() || !v1->artist().isEmpty() || !v1->album().isEmpty());
|
||||
|
||||
if (writeTags(fileref, from, to, RgTags())) {
|
||||
if (writeTags(fileref, from, to, RgTags(), QByteArray())) {
|
||||
if (mpeg && !haveV1) {
|
||||
return mpeg->save(TagLib::MPEG::File::ID3v2) ? Update_Modified : Update_Failed;
|
||||
}
|
||||
@@ -1040,7 +1067,31 @@ Update updateReplaygain(const QString &fileName, const ReplayGain &rg)
|
||||
TagLib::ID3v1::Tag *v1=mpeg ? mpeg->ID3v1Tag(false) : 0;
|
||||
bool haveV1=v1 && (!v1->title().isEmpty() || !v1->artist().isEmpty() || !v1->album().isEmpty());
|
||||
|
||||
if (writeTags(fileref, Song(), Song(), RgTags(rg))) {
|
||||
if (writeTags(fileref, Song(), Song(), RgTags(rg), QByteArray())) {
|
||||
if (mpeg && !haveV1) {
|
||||
return mpeg->save(TagLib::MPEG::File::ID3v2) ? Update_Modified : Update_Failed;
|
||||
}
|
||||
return fileref.file()->save() ? Update_Modified : Update_Failed;
|
||||
}
|
||||
return Update_None;
|
||||
}
|
||||
|
||||
Update embedImage(const QString &fileName, const QByteArray &cover)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
ensureFileTypeResolvers();
|
||||
|
||||
TagLib::FileRef fileref = getFileRef(fileName);
|
||||
|
||||
if (fileref.isNull()) {
|
||||
return Update_Failed;
|
||||
}
|
||||
|
||||
TagLib::MPEG::File *mpeg=dynamic_cast<TagLib::MPEG::File *>(fileref.file());
|
||||
TagLib::ID3v1::Tag *v1=mpeg ? mpeg->ID3v1Tag(false) : 0;
|
||||
bool haveV1=v1 && (!v1->title().isEmpty() || !v1->artist().isEmpty() || !v1->album().isEmpty());
|
||||
|
||||
if (writeTags(fileref, Song(), Song(), RgTags(), cover)) {
|
||||
if (mpeg && !haveV1) {
|
||||
return mpeg->save(TagLib::MPEG::File::ID3v2) ? Update_Modified : Update_Failed;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace Tags
|
||||
extern Update update(const QString &fileName, const Song &from, const Song &to);
|
||||
extern ReplayGain readReplaygain(const QString &fileName);
|
||||
extern Update updateReplaygain(const QString &fileName, const ReplayGain &rg);
|
||||
extern Update embedImage(const QString &fileName, const QByteArray &cover);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user