From 8f4056faa6a617646719a6821462ba70454eaada Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Thu, 9 Apr 2020 18:14:02 +0200 Subject: [PATCH] Allow all characters except slash and backslash when organising music Fixes #404 --- .../albumcoverchoicecontroller.cpp | 2 +- src/covermanager/albumcoverloader.cpp | 4 +- src/organise/organiseformat.cpp | 54 ++++++++++++------- src/organise/organiseformat.h | 2 +- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/covermanager/albumcoverchoicecontroller.cpp b/src/covermanager/albumcoverchoicecontroller.cpp index 54a5545cd..b7fd84fc3 100644 --- a/src/covermanager/albumcoverchoicecontroller.cpp +++ b/src/covermanager/albumcoverchoicecontroller.cpp @@ -164,7 +164,7 @@ void AlbumCoverChoiceController::SaveCoverToFileManual(const Song &song, const Q initial_file_name = initial_file_name + "-" + (song.effective_album().isEmpty() ? tr("unknown") : song.effective_album()) + ".jpg"; initial_file_name = initial_file_name.toLower(); initial_file_name.replace(QRegExp("\\s"), "-"); - initial_file_name.remove(OrganiseFormat::kValidFatCharacters); + initial_file_name.remove(OrganiseFormat::kInvalidFatCharacters); QString save_filename = QFileDialog::getSaveFileName(this, tr("Save album cover"), GetInitialPathForFileDialog(song, initial_file_name), tr(kSaveImageFileFilter) + ";;" + tr(kAllFilesFilter)); diff --git a/src/covermanager/albumcoverloader.cpp b/src/covermanager/albumcoverloader.cpp index 03ea95429..6f60c2c0e 100644 --- a/src/covermanager/albumcoverloader.cpp +++ b/src/covermanager/albumcoverloader.cpp @@ -145,7 +145,7 @@ QString AlbumCoverLoader::CoverFilePath(const Song::Source source, const QString QString filename; if (source == Song::Source_Collection && cover_album_dir_ && cover_filename_ == CollectionSettingsPage::SaveCover_Pattern && !cover_pattern_.isEmpty()) { filename = CreateCoverFilename(artist, album) + ".jpg"; - filename.remove(OrganiseFormat::kValidFatCharacters); + filename.remove(OrganiseFormat::kInvalidFatCharacters); if (cover_lowercase_) filename = filename.toLower(); if (cover_replace_spaces_) filename.replace(QRegExp("\\s"), "-"); } @@ -186,7 +186,7 @@ QString AlbumCoverLoader::AlbumCoverFileName(QString artist, QString album) { filename = Utilities::UnicodeToAscii(filename.toLower()); filename.replace(' ', '-'); filename.replace("--", "-"); - filename.remove(OrganiseFormat::kValidFatCharacters); + filename.remove(OrganiseFormat::kInvalidFatCharacters); return filename; diff --git a/src/organise/organiseformat.cpp b/src/organise/organiseformat.cpp index 1bbc0b970..3963ad9a7 100644 --- a/src/organise/organiseformat.cpp +++ b/src/organise/organiseformat.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -30,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -68,9 +69,9 @@ const QStringList OrganiseFormat::kKnownTags = QStringList() << "title" << "grouping" << "lyrics"; +const QRegExp OrganiseFormat::kInvalidDirCharacters("[/\\\\]"); // From http://en.wikipedia.org/wiki/8.3_filename#Directory_table -const QRegExp OrganiseFormat::kValidFatCharacters("[^a-zA-Z0-9!#\\$%&'()\\-@\\^_`{}~/. ]"); -const QRegExp OrganiseFormat::kInvalidFatCharacters("[\"*\\:<>?|/.]"); +const QRegExp OrganiseFormat::kInvalidFatCharacters("[^a-zA-Z0-9!#\\$%&'()\\-@\\^_`{}~/. ]"); const char OrganiseFormat::kInvalidPrefixCharacters[] = "."; const int OrganiseFormat::kInvalidPrefixCharactersCount = arraysize(OrganiseFormat::kInvalidPrefixCharacters) - 1; @@ -116,14 +117,13 @@ QString OrganiseFormat::GetFilenameForSong(const Song &song) const { } if (remove_non_fat_ || (remove_non_ascii_ && !allow_ascii_ext_)) filename = Utilities::UnicodeToAscii(filename); - if (remove_non_fat_) filename.remove(kValidFatCharacters); - if (replace_spaces_) filename.replace(QRegExp("\\s"), "_"); + if (remove_non_fat_) filename.remove(kInvalidFatCharacters); if (remove_non_ascii_) { int ascii = 128; if (allow_ascii_ext_) ascii = 255; QString stripped; - for (int i = 0; i < filename.length(); ++i) { + for (int i = 0 ; i < filename.length() ; ++i) { const QCharRef c = filename[i]; if (c < ascii) { stripped.append(c); @@ -132,26 +132,41 @@ QString OrganiseFormat::GetFilenameForSong(const Song &song) const { const QString decomposition = c.decomposition(); if (!decomposition.isEmpty() && decomposition[0] < ascii) stripped.append(decomposition[0]); - else - stripped.append("_"); } } filename = stripped; } + // Remove repeated whitespaces in the filename. + filename = filename.simplified(); + + QFileInfo info(filename); + QString extension = info.suffix(); + QString filepath = info.path() + QDir::separator() + info.completeBaseName(); + // Fix any parts of the path that start with dots. - QStringList parts = filename.split("/"); - for (int i = 0; i < parts.count(); ++i) { - QString *part = &parts[i]; - for (int j = 0; j < kInvalidPrefixCharactersCount; ++j) { - if (part->startsWith(kInvalidPrefixCharacters[j])) { - part->replace(0, 1, '_'); + QStringList parts_old = filepath.split("/"); + QStringList parts_new; + for (int i = 0 ; i < parts_old.count() ; ++i) { + QString part = parts_old[i]; + for (int j = 0 ; j < kInvalidPrefixCharactersCount ; ++j) { + if (part.startsWith(kInvalidPrefixCharacters[j])) { + part.remove(0, 1); break; } } + part = part.trimmed(); + parts_new.append(part); + } + filename = parts_new.join("/"); + + if (replace_spaces_) filename.replace(QRegExp("\\s"), "_"); + + if (!extension.isEmpty()) { + filename.append(QString(".%1").arg(extension)); } - return parts.join("/"); + return filename; } @@ -223,8 +238,10 @@ QString OrganiseFormat::TagValue(const QString &tag, const Song &song) const { value = QString::number(song.length_nanosec() / kNsecPerSec); else if (tag == "bitrate") value = QString::number(song.bitrate()); - else if (tag == "samplerate") value = QString::number(song.samplerate()); - else if (tag == "bitdepth") value = QString::number(song.bitdepth()); + else if (tag == "samplerate") + value = QString::number(song.samplerate()); + else if (tag == "bitdepth") + value = QString::number(song.bitdepth()); else if (tag == "extension") value = QFileInfo(song.url().toLocalFile()).suffix(); else if (tag == "artistinitial") { @@ -244,7 +261,8 @@ QString OrganiseFormat::TagValue(const QString &tag, const Song &song) const { if (tag == "track" && value.length() == 1) value.prepend('0'); // Replace characters that really shouldn't be in paths - value.remove(kInvalidFatCharacters); + value = value.remove(kInvalidDirCharacters); + value = value.trimmed(); return value; diff --git a/src/organise/organiseformat.h b/src/organise/organiseformat.h index 49b22506f..9454182f2 100644 --- a/src/organise/organiseformat.h +++ b/src/organise/organiseformat.h @@ -43,7 +43,7 @@ class OrganiseFormat { static const char *kTagPattern; static const char *kBlockPattern; static const QStringList kKnownTags; - static const QRegExp kValidFatCharacters; + static const QRegExp kInvalidDirCharacters; static const QRegExp kInvalidFatCharacters; static const char kInvalidPrefixCharacters[];