124 lines
3.4 KiB
C++
124 lines
3.4 KiB
C++
#include "denote_metadata.h"
|
|
|
|
#include <QFileInfo>
|
|
#include <QRegularExpression>
|
|
|
|
namespace Denote {
|
|
|
|
QDateTime Metadata::creationDate() const
|
|
{
|
|
if (identifier.isEmpty())
|
|
return {};
|
|
return QDateTime::fromString(identifier, QStringLiteral("yyyyMMdd'T'HHmmss"));
|
|
}
|
|
|
|
Metadata parseFilename(const QString &path)
|
|
{
|
|
Metadata meta;
|
|
meta.path = path;
|
|
|
|
const QString fname = QFileInfo(path).fileName();
|
|
|
|
// Identifier: leading YYYYMMDDTHHMMSS
|
|
static const QRegularExpression reId(QStringLiteral("^(\\d{8}T\\d{6})"));
|
|
auto m = reId.match(fname);
|
|
if (m.hasMatch())
|
|
meta.identifier = m.captured(1);
|
|
|
|
// Signature: ==sig-- (between identifier and title)
|
|
static const QRegularExpression reSig(QStringLiteral("==([^-]+?)--"));
|
|
m = reSig.match(fname);
|
|
if (m.hasMatch())
|
|
meta.signature = m.captured(1);
|
|
|
|
// Title: --title (first -- delimited segment, before __ or .)
|
|
static const QRegularExpression reTitle(QStringLiteral("--([^_\\.]+)"));
|
|
m = reTitle.match(fname);
|
|
if (m.hasMatch()) {
|
|
QString raw = m.captured(1);
|
|
raw.replace(QLatin1Char('-'), QLatin1Char(' '));
|
|
meta.title = raw;
|
|
}
|
|
|
|
// Tags: __tag1_tag2 (before extension or end)
|
|
static const QRegularExpression reTags(QStringLiteral("__(.+?)(?:\\.|$)"));
|
|
m = reTags.match(fname);
|
|
if (m.hasMatch()) {
|
|
meta.tags = m.captured(1).split(QLatin1Char('_'), Qt::SkipEmptyParts);
|
|
}
|
|
|
|
return meta;
|
|
}
|
|
|
|
QString generateIdentifier()
|
|
{
|
|
return QDateTime::currentDateTime().toString(QStringLiteral("yyyyMMdd'T'HHmmss"));
|
|
}
|
|
|
|
QString slugifyTitle(const QString &title)
|
|
{
|
|
QString slug = title.toLower();
|
|
slug.replace(QLatin1Char(' '), QLatin1Char('-'));
|
|
slug.replace(QLatin1Char('_'), QLatin1Char('-'));
|
|
|
|
// Remove anything that isn't a-z, 0-9, or hyphen
|
|
static const QRegularExpression reClean(QStringLiteral("[^a-z0-9-]"));
|
|
slug.remove(reClean);
|
|
|
|
return slug;
|
|
}
|
|
|
|
bool isValidTag(const QString &tag)
|
|
{
|
|
if (tag.isEmpty())
|
|
return false;
|
|
for (const QChar &ch : tag) {
|
|
if (!ch.isLetterOrNumber())
|
|
return false;
|
|
if (ch.isLetter() && ch.isUpper())
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QString buildFilename(const QString &title,
|
|
const QStringList &tags,
|
|
const QString &signature,
|
|
const QString &ext)
|
|
{
|
|
QString result = generateIdentifier();
|
|
|
|
// Signature
|
|
if (!signature.isEmpty()) {
|
|
QString sig = signature.toLower();
|
|
sig.replace(QLatin1Char(' '), QStringLiteral("=="));
|
|
sig.replace(QLatin1Char('_'), QStringLiteral("=="));
|
|
// Remove special chars
|
|
static const QRegularExpression reSigClean(
|
|
QStringLiteral("[{}!@#$%^&*()+\'\"?,.\\\\|;:~`\u2018\u2019\u201c\u201d/-]"));
|
|
sig.remove(reSigClean);
|
|
// Normalize consecutive equals
|
|
static const QRegularExpression reEq(QStringLiteral("={3,}"));
|
|
sig.replace(reEq, QStringLiteral("=="));
|
|
// Trim trailing =
|
|
while (sig.endsWith(QLatin1Char('=')))
|
|
sig.chop(1);
|
|
result += QStringLiteral("==") + sig;
|
|
}
|
|
|
|
// Title
|
|
result += QStringLiteral("--") + slugifyTitle(title);
|
|
|
|
// Tags
|
|
if (!tags.isEmpty()) {
|
|
result += QStringLiteral("__") + tags.join(QLatin1Char('_'));
|
|
}
|
|
|
|
// Extension
|
|
result += ext;
|
|
|
|
return result;
|
|
}
|
|
|
|
} // namespace Denote
|