Move organise files, add option to strip all non-fat characters

This commit is contained in:
Jonas Kvinge 2018-12-29 15:37:16 +01:00
parent 2e1b601508
commit 2a54cb17e7
17 changed files with 96 additions and 95 deletions

View File

@ -771,11 +771,10 @@ optional_source(HAVE_LIBPULSE
# MusicBrainz, Organise and transcode require GStreamer
optional_source(HAVE_GSTREAMER
SOURCES
core/organise.cpp
core/organiseformat.cpp
settings/transcodersettingspage.cpp
dialogs/organisedialog.cpp
dialogs/organiseerrordialog.cpp
organise/organise.cpp
organise/organiseformat.cpp
organise/organisedialog.cpp
organise/organiseerrordialog.cpp
transcoder/transcoder.cpp
transcoder/transcodedialog.cpp
transcoder/transcoderoptionsaac.cpp
@ -786,19 +785,19 @@ SOURCES
transcoder/transcoderoptionsspeex.cpp
transcoder/transcoderoptionsvorbis.cpp
transcoder/transcoderoptionswma.cpp
settings/transcodersettingspage.cpp
HEADERS
core/organise.h
settings/transcodersettingspage.h
dialogs/organisedialog.h
dialogs/organiseerrordialog.h
organise/organise.h
organise/organisedialog.h
organise/organiseerrordialog.h
transcoder/transcoder.h
transcoder/transcodedialog.h
transcoder/transcoderoptionsdialog.h
transcoder/transcoderoptionsmp3.h
settings/transcodersettingspage.h
UI
settings/transcodersettingspage.ui
dialogs/organisedialog.ui
dialogs/organiseerrordialog.ui
organise/organisedialog.ui
organise/organiseerrordialog.ui
transcoder/transcodedialog.ui
transcoder/transcodelogdialog.ui
transcoder/transcoderoptionsaac.ui
@ -809,6 +808,7 @@ UI
transcoder/transcoderoptionsspeex.ui
transcoder/transcoderoptionsvorbis.ui
transcoder/transcoderoptionswma.ui
settings/transcodersettingspage.ui
)
# CDIO backend and device

View File

@ -74,7 +74,7 @@
#endif
#include "dialogs/edittagdialog.h"
#ifdef HAVE_GSTREAMER
#include "dialogs/organisedialog.h"
#include "organise/organisedialog.h"
#endif
#include "settings/collectionsettingspage.h"

View File

@ -74,7 +74,7 @@
#endif
#include "dialogs/edittagdialog.h"
#ifdef HAVE_GSTREAMER
#include "dialogs/organisedialog.h"
#include "organise/organisedialog.h"
#endif
#include "settings/collectionsettingspage.h"

View File

@ -85,7 +85,7 @@
#include "dialogs/trackselectiondialog.h"
#include "dialogs/edittagdialog.h"
#ifdef HAVE_GSTREAMER
# include "dialogs/organisedialog.h"
# include "organise/organisedialog.h"
#endif
#include "widgets/fancytabwidget.h"
#include "widgets/playingwidget.h"

View File

@ -84,6 +84,7 @@ class Song {
static const QString kEmbeddedCover;
static const QRegExp kCoverRemoveDisc;
static const QRegExp kFilenameRemoveNonFatChars;
static QString JoinSpec(const QString &table);

View File

@ -57,8 +57,8 @@
#include "core/mergedproxymodel.h"
#include "core/mimedata.h"
#include "core/musicstorage.h"
#include "dialogs/organisedialog.h"
#include "dialogs/organiseerrordialog.h"
#include "organise/organisedialog.h"
#include "organise/organiseerrordialog.h"
#include "collection/collectiondirectorymodel.h"
#include "collection/collectionmodel.h"
#include "collection/collectionview.h"

View File

@ -31,9 +31,9 @@
#include <QtDebug>
#include "core/logging.h"
#include "utilities.h"
#include "taskmanager.h"
#include "musicstorage.h"
#include "core/utilities.h"
#include "core/taskmanager.h"
#include "core/musicstorage.h"
#include "organise.h"
#include "transcoder/transcoder.h"

View File

@ -55,11 +55,11 @@
#include "core/closure.h"
#include "core/iconloader.h"
#include "core/musicstorage.h"
#include "core/organise.h"
#include "core/tagreaderclient.h"
#include "core/utilities.h"
#include "widgets/freespacebar.h"
#include "widgets/linetextedit.h"
#include "organise.h"
#include "organisedialog.h"
#include "organiseerrordialog.h"
#include "ui_organisedialog.h"
@ -109,8 +109,8 @@ OrganiseDialog::OrganiseDialog(TaskManager *task_manager, QWidget *parent)
connect(ui_->destination, SIGNAL(currentIndexChanged(int)), SLOT(UpdatePreviews()));
connect(ui_->naming, SIGNAL(textChanged()), SLOT(UpdatePreviews()));
connect(ui_->replace_ascii, SIGNAL(toggled(bool)), SLOT(UpdatePreviews()));
connect(ui_->replace_the, SIGNAL(toggled(bool)), SLOT(UpdatePreviews()));
connect(ui_->remove_non_fat, SIGNAL(toggled(bool)), SLOT(UpdatePreviews()));
connect(ui_->remove_non_ascii, SIGNAL(toggled(bool)), SLOT(UpdatePreviews()));
connect(ui_->replace_spaces, SIGNAL(toggled(bool)), SLOT(UpdatePreviews()));
// Get the titles of the tags to put in the insert menu
@ -293,9 +293,9 @@ void OrganiseDialog::UpdatePreviews() {
// Update the format object
format_.set_format(ui_->naming->toPlainText());
format_.set_replace_non_ascii(ui_->replace_ascii->isChecked());
format_.set_remove_non_fat(ui_->remove_non_fat->isChecked());
format_.set_remove_non_ascii(ui_->remove_non_ascii->isChecked());
format_.set_replace_spaces(ui_->replace_spaces->isChecked());
format_.set_replace_the(ui_->replace_the->isChecked());
const bool format_valid = !has_local_destination || format_.IsValid();
@ -310,8 +310,8 @@ void OrganiseDialog::UpdatePreviews() {
// Update the previews
ui_->preview->clear();
ui_->preview_group->setVisible(has_local_destination);
ui_->naming_group->setVisible(has_local_destination);
ui_->groupbox_preview->setVisible(has_local_destination);
ui_->groupbox_naming->setVisible(has_local_destination);
if (has_local_destination) {
for (const Organise::NewSongInfo &song_info : new_songs_info_) {
QString filename = storage->LocalPath() + "/" + song_info.new_filename_;
@ -330,9 +330,9 @@ QSize OrganiseDialog::sizeHint() const { return QSize(650, 0); }
void OrganiseDialog::Reset() {
ui_->naming->setPlainText(kDefaultFormat);
ui_->replace_ascii->setChecked(false);
ui_->replace_spaces->setChecked(false);
ui_->replace_the->setChecked(false);
ui_->remove_non_fat->setChecked(false);
ui_->remove_non_ascii->setChecked(false);
ui_->replace_spaces->setChecked(true);
ui_->overwrite->setChecked(false);
ui_->mark_as_listened->setChecked(false);
ui_->eject_after->setChecked(false);
@ -346,9 +346,9 @@ void OrganiseDialog::showEvent(QShowEvent*) {
QSettings s;
s.beginGroup(kSettingsGroup);
ui_->naming->setPlainText(s.value("format", kDefaultFormat).toString());
ui_->replace_ascii->setChecked(s.value("replace_ascii", false).toBool());
ui_->replace_spaces->setChecked(s.value("replace_spaces", false).toBool());
ui_->replace_the->setChecked(s.value("replace_the", false).toBool());
ui_->remove_non_fat->setChecked(s.value("remove_non_fat", false).toBool());
ui_->remove_non_ascii->setChecked(s.value("remove_non_ascii", false).toBool());
ui_->replace_spaces->setChecked(s.value("replace_spaces", true).toBool());
ui_->overwrite->setChecked(s.value("overwrite", false).toBool());
ui_->mark_as_listened->setChecked(s.value("mark_as_listened", false).toBool());
ui_->eject_after->setChecked(s.value("eject_after", false).toBool());
@ -367,9 +367,9 @@ void OrganiseDialog::accept() {
s.beginGroup(kSettingsGroup);
s.setValue("format", ui_->naming->toPlainText());
s.setValue("replace_ascii", ui_->replace_ascii->isChecked());
s.setValue("remove_non_fat", ui_->remove_non_fat->isChecked());
s.setValue("remove_non_ascii", ui_->remove_non_ascii->isChecked());
s.setValue("replace_spaces", ui_->replace_spaces->isChecked());
s.setValue("replace_the", ui_->replace_the->isChecked());
s.setValue("overwrite", ui_->overwrite->isChecked());
s.setValue("mark_as_listened", ui_->overwrite->isChecked());
s.setValue("destination", ui_->destination->currentText());

View File

@ -40,8 +40,8 @@
#include <QtEvents>
#include "core/song.h"
#include "core/organise.h"
#include "core/organiseformat.h"
#include "organise.h"
#include "organiseformat.h"
class QResizeEvent;
class QShowEvent;

View File

@ -19,9 +19,9 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QFormLayout" name="formLayout">
<layout class="QFormLayout" name="layout_copying">
<item row="0" column="0">
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_destination">
<property name="text">
<string>Destination</string>
</property>
@ -31,7 +31,7 @@
<widget class="QComboBox" name="destination"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="label_after_copying">
<property name="text">
<string>After copying...</string>
</property>
@ -57,14 +57,7 @@
<widget class="FreeSpaceBar" name="free_space" native="true"/>
</item>
<item>
<widget class="QCheckBox" name="eject_after">
<property name="text">
<string>Safely remove the device after copying</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="naming_group">
<widget class="QGroupBox" name="groupbox_naming">
<property name="title">
<string>Naming options</string>
</property>
@ -99,23 +92,23 @@
</layout>
</item>
<item>
<widget class="QCheckBox" name="replace_the">
<widget class="QCheckBox" name="remove_non_fat">
<property name="text">
<string>Ignore &quot;The&quot; in artist names</string>
<string>Restrict to characters allowed on FAT filesystems</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="remove_non_ascii">
<property name="text">
<string>Restrict characters to ASCII</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="replace_spaces">
<property name="text">
<string>Replaces spaces with underscores</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="replace_ascii">
<property name="text">
<string>Restrict to ASCII characters</string>
<string>Replace spaces with underscores</string>
</property>
</widget>
</item>
@ -137,7 +130,7 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="preview_group">
<widget class="QGroupBox" name="groupbox_preview">
<property name="title">
<string>Preview</string>
</property>
@ -145,7 +138,7 @@
<item>
<widget class="QStackedWidget" name="preview_stack">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="preview_page">
<layout class="QVBoxLayout" name="verticalLayout_4">
@ -187,7 +180,7 @@
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer">
<spacer name="spacer_preview_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -207,7 +200,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<spacer name="spacer_preview_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -226,6 +219,13 @@
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="eject_after">
<property name="text">
<string>Safely remove the device after copying</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="button_box">
<property name="orientation">
@ -260,12 +260,10 @@
<tabstops>
<tabstop>destination</tabstop>
<tabstop>aftercopying</tabstop>
<tabstop>eject_after</tabstop>
<tabstop>naming</tabstop>
<tabstop>insert</tabstop>
<tabstop>replace_the</tabstop>
<tabstop>remove_non_fat</tabstop>
<tabstop>replace_spaces</tabstop>
<tabstop>replace_ascii</tabstop>
<tabstop>overwrite</tabstop>
<tabstop>button_box</tabstop>
</tabstops>

View File

@ -37,10 +37,10 @@
#include <QTextFormat>
#include "core/arraysize.h"
#include "core/timeconstants.h"
#include "core/utilities.h"
#include "core/song.h"
#include "timeconstants.h"
#include "utilities.h"
#include "song.h"
#include "organiseformat.h"
class QTextDocument;
@ -56,6 +56,7 @@ const QStringList OrganiseFormat::kKnownTags = QStringList() << "title"
<< "track"
<< "disc"
<< "year"
<< "originalyear"
<< "genre"
<< "comment"
<< "length"
@ -65,12 +66,11 @@ const QStringList OrganiseFormat::kKnownTags = QStringList() << "title"
<< "extension"
<< "performer"
<< "grouping"
<< "lyrics"
<< "originalyear";
<< "lyrics";
// From http://en.wikipedia.org/wiki/8.3_filename#Directory_table
const char OrganiseFormat::kInvalidFatCharacters[] = "\"*/\\:<>?|";
const int OrganiseFormat::kInvalidFatCharactersCount = arraysize(OrganiseFormat::kInvalidFatCharacters) - 1;
const QRegExp OrganiseFormat::kValidFatCharacters("[^a-zA-Z0-9!#\\$%&'()\\-@\\^_`{}~/. ]");
const QRegExp OrganiseFormat::kInvalidFatCharacters("[\"*\\:<>?|/]");
const char OrganiseFormat::kInvalidPrefixCharacters[] = ".";
const int OrganiseFormat::kInvalidPrefixCharactersCount = arraysize(OrganiseFormat::kInvalidPrefixCharacters) - 1;
@ -85,9 +85,9 @@ const QRgb OrganiseFormat::SyntaxHighlighter::kBlockColorDark = qRgb(64, 64, 64)
OrganiseFormat::OrganiseFormat(const QString &format)
: format_(format),
replace_non_ascii_(false),
replace_spaces_(false),
replace_the_(false) {}
remove_non_fat_(false),
remove_non_ascii_(false),
replace_spaces_(true) {}
void OrganiseFormat::set_format(const QString &v) {
format_ = v;
@ -111,13 +111,16 @@ QString OrganiseFormat::GetFilenameForSong(const Song &song) const {
if (QFileInfo(filename).completeBaseName().isEmpty()) {
// Avoid having empty filenames, or filenames with extension only: in this case, keep the original filename.
// We remove the extension from "filename" if it exists, as song.basefilename() also contains the extension.
filename =
Utilities::PathWithoutFilenameExtension(filename) + song.basefilename();
filename = Utilities::PathWithoutFilenameExtension(filename) + song.basefilename();
}
if (remove_non_fat_) {
filename.remove(kValidFatCharacters);
}
if (replace_spaces_) filename.replace(QRegExp("\\s"), "_");
if (replace_non_ascii_) {
if (remove_non_ascii_) {
QString stripped;
for (int i = 0; i < filename.length(); ++i) {
const QCharRef c = filename[i];
@ -225,27 +228,25 @@ QString OrganiseFormat::TagValue(const QString &tag, const Song &song) const {
value = QFileInfo(song.url().toLocalFile()).suffix();
else if (tag == "artistinitial") {
value = song.effective_albumartist().trimmed();
if (replace_the_ && !value.isEmpty()) value.replace(QRegExp("^the\\s+", Qt::CaseInsensitive), "");
if (!value.isEmpty()) value = value[0].toUpper();
if (!value.isEmpty()) {
value.replace(QRegExp("^the\\s+", Qt::CaseInsensitive), "");
value = value[0].toUpper();
}
}
else if (tag == "albumartist") {
value = song.is_compilation() ? "Various Artists" : song.effective_albumartist();
}
if (replace_the_ && (tag == "artist" || tag == "albumartist"))
value.replace(QRegExp("^the\\s+", Qt::CaseInsensitive), "");
if (value == "0" || value == "-1") value = "";
// Prepend a 0 to single-digit track numbers
if (tag == "track" && value.length() == 1) value.prepend('0');
// Replace characters that really shouldn't be in paths
for (int i = 0; i < kInvalidFatCharactersCount; ++i) {
value.replace(kInvalidFatCharacters[i], '_');
}
value.remove(kInvalidFatCharacters);
return value;
}
OrganiseFormat::Validator::Validator(QObject *parent) : QValidator(parent) {}

View File

@ -44,20 +44,21 @@ class OrganiseFormat {
static const char *kTagPattern;
static const char *kBlockPattern;
static const QStringList kKnownTags;
static const char kInvalidFatCharacters[];
static const int kInvalidFatCharactersCount;
static const QRegExp kValidFatCharacters;
static const QRegExp kInvalidFatCharacters;
static const char kInvalidPrefixCharacters[];
static const int kInvalidPrefixCharactersCount;
QString format() const { return format_; }
bool replace_non_ascii() const { return replace_non_ascii_; }
bool remove_non_fat() const { return remove_non_fat_; }
bool remove_non_ascii() const { return remove_non_ascii_; }
bool replace_spaces() const { return replace_spaces_; }
bool replace_the() const { return replace_the_; }
void set_format(const QString &v);
void set_replace_non_ascii(bool v) { replace_non_ascii_ = v; }
void set_remove_non_fat(bool v) { remove_non_fat_ = v; }
void set_remove_non_ascii(bool v) { remove_non_ascii_ = v; }
void set_replace_spaces(bool v) { replace_spaces_ = v; }
void set_replace_the(bool v) { replace_the_ = v; }
bool IsValid() const;
QString GetFilenameForSong(const Song &song) const;
@ -88,9 +89,9 @@ class OrganiseFormat {
QString TagValue(const QString &tag, const Song &song) const;
QString format_;
bool replace_non_ascii_;
bool remove_non_fat_;
bool remove_non_ascii_;
bool replace_spaces_;
bool replace_the_;
};

View File

@ -44,7 +44,7 @@
#include "fileviewlist.h"
#include "ui_fileview.h"
#ifdef HAVE_GSTREAMER
# include "dialogs/organiseerrordialog.h"
# include "organise/organiseerrordialog.h"
#endif
const char *FileView::kFileFilter =