Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better file export #3572

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8dbb96f
Add Grantlee lib to dependencies
poelzi Jan 18, 2021
5874dbe
Major track export overhaul
poelzi Jan 18, 2021
ad7ac51
Use the the last right click selected playlist, not the current
poelzi Jan 18, 2021
167550a
Add libgrantlee5-dev to debian build env
poelzi Jan 18, 2021
69f357d
Fix build problems
poelzi Jan 18, 2021
4672c8b
Make Key a Q_GADGET and add string properties for formatting
poelzi Jan 18, 2021
b97b6cc
Use index for position index and dup for duplication counter
poelzi Jan 19, 2021
0d9618e
Add support for exporting files from context menu
poelzi Jan 19, 2021
d129f2d
Export crate summary into file exporter context
poelzi Jan 19, 2021
e2d9ec9
Add render function which does not escape html characters
poelzi Jan 20, 2021
19f00f6
Add grantlee plugin with mixxx specific filters
poelzi Jan 21, 2021
715355c
Fix Exporter Test
poelzi Jan 21, 2021
fc287dc
Use CrateSummaryWrapper as QObject wrapper
poelzi Jan 22, 2021
993a5e7
Add zeropad filter for adding 0 prefixes
poelzi Jan 22, 2021
515d393
Move exportPlaylistItemsIntoFile to Parser
poelzi Jan 22, 2021
999edbf
Add support for creating a playlist on file export
poelzi Jan 23, 2021
7c86579
Add PlaylistSummary for repersenting playlists
poelzi Nov 22, 2020
f6fc540
Add PlaylistSummary wrapper and export to track exporter
poelzi Jan 23, 2021
cc9b5fa
Add round filter, move default patterns to code
poelzi Jan 23, 2021
998667f
Compile fixes
poelzi Jan 24, 2021
9324697
Merge branch 'main' of https://github.com/mixxxdj/mixxx into better-e…
poelzi Jan 25, 2021
7c1d480
Merge branch 'main' of https://github.com/mixxxdj/mixxx into better-e…
poelzi Jan 26, 2021
1d64ce4
Add function to ensure safe filename on all platforms
poelzi Feb 1, 2021
3057941
Use tabwidget for export dialog
poelzi Feb 1, 2021
dd3d9e6
cleanup group filter
poelzi Feb 1, 2021
3a79ffa
Fix missing assignment of crateWrapper
poelzi Feb 2, 2021
7fad172
Properly escape problematic filenames on all platforms
poelzi Feb 2, 2021
488671b
Use Dropdown Menu for pattern suggestions, not a ComboBox
poelzi Feb 3, 2021
4d0ce25
Implement default lookup function for keys (not working)
poelzi Feb 3, 2021
049c65d
fix clazy warnings
poelzi Feb 5, 2021
2118737
clazy fixes
poelzi Feb 7, 2021
87aa753
Use one button line in export
poelzi Feb 7, 2021
49aa05d
Escape playlist name in menu
poelzi Feb 7, 2021
1dd67eb
Prevent crashes on patterns like "{{ }}"
poelzi Feb 18, 2021
82652f0
Go back to a QComboBox but with custom item handling
poelzi Feb 19, 2021
28f0439
Merge branch 'main' of https://github.com/mixxxdj/mixxx into better-e…
poelzi Apr 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 26 additions & 14 deletions src/library/export/trackexportworker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const auto kResultCantCreateFile = QStringLiteral("Could not create file");
const auto kDefaultPattern = QStringLiteral(
"{{ track.basename }}{% if dup %}-{{dup}}{% endif %}"
".{{track.extension}}");
const auto kEmptyMsg = QLatin1String("");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can become just:
const QString kEmptyMsg;

} // namespace

TrackExportWorker::TrackExportWorker(const QString& destDir,
Expand Down Expand Up @@ -120,31 +121,42 @@ void TrackExportWorker::setPattern(QString* pattern) {
if (pattern == nullptr) {
m_pattern = nullptr;
if (!m_template.isNull()) {
m_template_valid = false;
m_template.reset();
}
return;
}
if (!m_engine) {
m_engine = Formatter::getEngine(this);
m_engine->setSmartTrimEnabled(true);
// smartTrimEnabled would be good, but causes crashes on invalid pattern '{{ }}'
// m_engine->setSmartTrimEnabled(true);
}
m_pattern = pattern;
updateTemplate();
}

void TrackExportWorker::updateTemplate() {
QString tmpl = m_destDir + QDir::separator().toLatin1() +
(m_pattern ? *m_pattern : kDefaultPattern);
m_template = m_engine->newTemplate(tmpl, QStringLiteral("export"));
QString fullPattern;
if (m_pattern) {
QString trimmed = m_pattern->trimmed();
fullPattern = m_destDir + QDir::separator().toLatin1() + trimmed;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can omit .toLatin1() here and below.

} else {
fullPattern = m_destDir + QDir::separator().toLatin1() + kDefaultPattern;
}
m_template = m_engine->newTemplate(fullPattern, QStringLiteral("export"));
if (m_template->error()) {
m_errorMessage = m_template->errorString();
m_template_valid = false;
} else {
m_errorMessage = QString();
m_template_valid = true;
}
}

void TrackExportWorker::run() {
m_running = true;
m_bStop = false;
m_overwriteMode = OverwriteMode::ASK;
int i = 0;
auto skippedTracks = TrackPointerList();
QMap<QString, TrackFile> copy_list = createCopylist(m_tracks, &skippedTracks);
Expand All @@ -154,7 +166,7 @@ void TrackExportWorker::run() {
jobsTotal++;
}

for (TrackPointer track : qAsConst(skippedTracks)) {
for (const TrackPointer& track : qAsConst(skippedTracks)) {
QString fileName = track->fileName();
emit progress(fileName, nullptr, 0, jobsTotal);
emit result(TrackExportWorker::ExportResult::SKIPPED, kResultEmptyPattern);
Expand All @@ -178,10 +190,10 @@ void TrackExportWorker::run() {
}
if (!m_playlist.isEmpty()) {
const auto targetDir = QDir(m_destDir);
const QString plsPath = targetDir.filePath(m_playlist);
const QString plsPath = targetDir.filePath(FileUtils::escapeFileName(m_playlist));
QFileInfo plsPathFileinfo(plsPath);

emit progress(QStringLiteral("export playlist"), m_playlist, i, jobsTotal);
emit progress(QStringLiteral("export playlist"), plsPath, i, jobsTotal);

QDir plsDir = plsPathFileinfo.absoluteDir();
if (!plsDir.mkpath(plsDir.absolutePath())) {
Expand All @@ -208,7 +220,7 @@ void TrackExportWorker::run() {
i++;
}

emit progress(QStringLiteral(""), QStringLiteral(""), i, jobsTotal);
emit progress(kEmptyMsg, kEmptyMsg, i, jobsTotal);
emit result(TrackExportWorker::ExportResult::EXPORT_COMPLETE, kResultOk);
m_running = false;
}
Expand All @@ -223,19 +235,19 @@ QString TrackExportWorker::applyPattern(
TrackPointer track,
int index,
int duplicateCounter) {
VERIFY_OR_DEBUG_ASSERT(!m_destDir.isEmpty()) {
qWarning() << "empty target directory";
if (!m_template_valid) {
return QString();
}
VERIFY_OR_DEBUG_ASSERT(!m_template.isNull()) {
qWarning() << "template missing";
VERIFY_OR_DEBUG_ASSERT(!m_destDir.isEmpty()) {
qWarning() << "empty target directory";
return QString();
}
VERIFY_OR_DEBUG_ASSERT(m_engine) {
qWarning() << "engine missing";
return QString();
}
// fill the context with the proper variables

// fill the context with the proper variables.
m_context->push();
m_context->insert(QStringLiteral("directory"), m_destDir);
// this is safe since the context stack is popped after rendering
Expand All @@ -249,7 +261,7 @@ QString TrackExportWorker::applyPattern(
m_context->pop();

// replace bad filename characters with spaces
return newName;
return newName.trimmed();
}

void TrackExportWorker::copyFile(const QFileInfo& source_fileinfo,
Expand Down
1 change: 1 addition & 0 deletions src/library/export/trackexportworker.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class TrackExportWorker : public QThread {
QString* m_pattern;
Grantlee::Context* m_context;
Grantlee::Template m_template;
bool m_template_valid{false};
Grantlee::Engine* m_engine{nullptr};
QString m_playlist;
};
4 changes: 2 additions & 2 deletions src/test/fileutils_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ TEST_F(FileUtilsTest, TestSafeFilename) {

TEST_F(FileUtilsTest, TestDirReplace) {
// Generate a file name for the temporary file
const auto fileName = QStringLiteral("filename/with\\characters.mp3");
const auto expected = QStringLiteral("filename-with-characters.mp3");
const auto fileName = QStringLiteral("filename/with\\chara-cters.mp3");
const auto expected = QStringLiteral("filename-with-chara-cters.mp3");
auto output = FileUtils::replaceDirChars(fileName);
ASSERT_EQ(expected, output);
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/formatter_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ TEST_F(FormatterTest, TestEscape) {
// Generate a file name for the temporary file
auto engine = Formatter::getEngine(nullptr);
auto context = new Context();
context->insert(QStringLiteral("file"), QStringLiteral("file<>|with_/&terrible.name"));
context->insert(QStringLiteral("file"), QStringLiteral("file<>|with_/&terr-ible.name"));
context->insert(QStringLiteral("dir"), QStringLiteral("extra/bad\\directory"));
Template t1 = engine->newTemplate(QStringLiteral("{{dir}}/{{file}}"), QStringLiteral("t1"));

EXPECT_EQ(Formatter::renderFilenameEscape(t1, *context),
QString("extra-bad-directory/file###with_-&terrible.name"));
QString("extra-bad-directory/file###with_-&terr-ible.name"));
}