Allow dealing with multiple fields values in JavaScript
This commit is contained in:
parent
9cb8702d13
commit
c3af3d43e6
|
@ -360,8 +360,8 @@ Here are some Bash examples which illustrate getting and setting tag information
|
||||||
- Common tag fields are exposed as object properties as shown in the mentioned example.
|
- Common tag fields are exposed as object properties as shown in the mentioned example.
|
||||||
- Only properties for fields that are supported by the tag are added to the "fields" object.
|
- Only properties for fields that are supported by the tag are added to the "fields" object.
|
||||||
- Adding properties of unsupported fields manually does not work; those will just be ignored.
|
- Adding properties of unsupported fields manually does not work; those will just be ignored.
|
||||||
- The content of fields that are absent in the tag is set to `undefined`. You may also set
|
- The property for fields that are absent in the tag have an empty array assigned. You may
|
||||||
the content of fields to `undefined` to delete them (`null` works as well).
|
also assign an empty array to fields to delete them.
|
||||||
- The content of binary fields is exposed as `ArrayBuffer`. Use must also use an `ArrayBuffer`
|
- The content of binary fields is exposed as `ArrayBuffer`. Use must also use an `ArrayBuffer`
|
||||||
to set the value of binary fields such as the cover.
|
to set the value of binary fields such as the cover.
|
||||||
- The content of other fields is mostly exposed as `String` or `Number`. Use must also use
|
- The content of other fields is mostly exposed as `String` or `Number`. Use must also use
|
||||||
|
|
|
@ -218,24 +218,6 @@ QString TagObject::type() const
|
||||||
return Utility::qstr(m_tag.typeName());
|
return Utility::qstr(m_tag.typeName());
|
||||||
}
|
}
|
||||||
|
|
||||||
QJSValue &TagObject::fields()
|
|
||||||
{
|
|
||||||
if (!m_fields.isUndefined()) {
|
|
||||||
return m_fields;
|
|
||||||
}
|
|
||||||
static const auto fieldRegex = QRegularExpression(QStringLiteral("\\s(\\w)"));
|
|
||||||
m_fields = m_engine->newObject();
|
|
||||||
for (auto field = TagParser::firstKnownField; field != TagParser::KnownField::Invalid; field = TagParser::nextKnownField(field)) {
|
|
||||||
if (!m_tag.supportsField(field)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (const auto propertyName = propertyNameForField(field); !propertyName.isEmpty()) {
|
|
||||||
m_fields.setProperty(propertyName, m_engine->newQObject(new TagValueObject(m_tag.value(field), m_engine, this)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m_fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TagObject::propertyNameForField(TagParser::KnownField field)
|
QString TagObject::propertyNameForField(TagParser::KnownField field)
|
||||||
{
|
{
|
||||||
static const auto reverseMapping = [] {
|
static const auto reverseMapping = [] {
|
||||||
|
@ -254,6 +236,30 @@ QString TagObject::propertyNameForField(TagParser::KnownField field)
|
||||||
return reverseMapping.value(field, QString());
|
return reverseMapping.value(field, QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJSValue &TagObject::fields()
|
||||||
|
{
|
||||||
|
if (!m_fields.isUndefined()) {
|
||||||
|
return m_fields;
|
||||||
|
}
|
||||||
|
static const auto fieldRegex = QRegularExpression(QStringLiteral("\\s(\\w)"));
|
||||||
|
m_fields = m_engine->newObject();
|
||||||
|
for (auto field = TagParser::firstKnownField; field != TagParser::KnownField::Invalid; field = TagParser::nextKnownField(field)) {
|
||||||
|
if (!m_tag.supportsField(field)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (const auto propertyName = propertyNameForField(field); !propertyName.isEmpty()) {
|
||||||
|
const auto values = m_tag.values(field);
|
||||||
|
const auto size = Utility::sizeToInt<quint32>(values.size());
|
||||||
|
auto array = m_engine->newArray(size);
|
||||||
|
for (auto i = quint32(); i != size; ++i) {
|
||||||
|
array.setProperty(i, m_engine->newQObject(new TagValueObject(m_tag.value(field), m_engine, this)));
|
||||||
|
}
|
||||||
|
m_fields.setProperty(propertyName, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m_fields;
|
||||||
|
}
|
||||||
|
|
||||||
void TagObject::applyChanges()
|
void TagObject::applyChanges()
|
||||||
{
|
{
|
||||||
auto context = !m_tag.target().isEmpty() || m_tag.type() == TagParser::TagType::MatroskaTag
|
auto context = !m_tag.target().isEmpty() || m_tag.type() == TagParser::TagType::MatroskaTag
|
||||||
|
@ -273,22 +279,35 @@ void TagObject::applyChanges()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto propertyValue = m_fields.property(propertyName);
|
auto propertyValue = m_fields.property(propertyName);
|
||||||
auto fieldDisplayName = Settings::KnownFieldModel::fieldName(field);
|
if (!propertyValue.isArray()) {
|
||||||
if (const auto *const tagValueObj = qobject_cast<const TagValueObject *>(propertyValue.toQObject())) {
|
m_engine->throwError(QJSValue::TypeError, QStringLiteral("non-array assigned to field ") + propertyName);
|
||||||
if (!tagValueObj->isInitial()) {
|
goto end;
|
||||||
auto value = tagValueObj->toTagValue(encoding);
|
|
||||||
m_diag.emplace_back(TagParser::DiagLevel::Debug,
|
|
||||||
value.isNull()
|
|
||||||
? CppUtilities::argsToString(" - delete '", fieldDisplayName, '\'')
|
|
||||||
: CppUtilities::argsToString(" - change '", fieldDisplayName, "' from '",
|
|
||||||
tagValueObj->initialContent().toString().toStdString(), "' to '", tagValueObj->content().toString().toStdString(), '\''),
|
|
||||||
std::string());
|
|
||||||
m_tag.setValue(field, std::move(value));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_engine->throwError(QJSValue::TypeError, QStringLiteral("invalid value assigned to field ") + propertyName);
|
|
||||||
}
|
}
|
||||||
|
const auto size = propertyValue.property(QStringLiteral("length")).toUInt();
|
||||||
|
auto values = std::vector<TagParser::TagValue>();
|
||||||
|
values.reserve(size);
|
||||||
|
for (auto i = quint32(); i != size; ++i) {
|
||||||
|
const auto *const tagValueObj = qobject_cast<const TagValueObject *>(propertyValue.property(i).toQObject());
|
||||||
|
if (!tagValueObj) {
|
||||||
|
m_engine->throwError(QJSValue::TypeError, QStringLiteral("invalid value present in value-array of field ") + propertyName);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (tagValueObj->isInitial()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto &value = values.emplace_back(tagValueObj->toTagValue(encoding));
|
||||||
|
m_diag.emplace_back(TagParser::DiagLevel::Debug,
|
||||||
|
value.isNull() ? CppUtilities::argsToString(" - delete ", propertyName.toStdString(), '[', i, ']')
|
||||||
|
: (tagValueObj->initialContent().isNull() ? CppUtilities::argsToString(
|
||||||
|
" - set ", propertyName.toStdString(), '[', i, "] to '", tagValueObj->content().toString().toStdString(), '\'')
|
||||||
|
: CppUtilities::argsToString(" - change ", propertyName.toStdString(), '[',
|
||||||
|
i, "] from '", tagValueObj->initialContent().toString().toStdString(),
|
||||||
|
"' to '", tagValueObj->content().toString().toStdString(), '\'')),
|
||||||
|
std::string());
|
||||||
|
}
|
||||||
|
m_tag.setValues(field, values);
|
||||||
}
|
}
|
||||||
|
end:;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaFileInfoObject::MediaFileInfoObject(TagParser::MediaFileInfo &mediaFileInfo, TagParser::Diagnostics &diag, QJSEngine *engine, QObject *parent)
|
MediaFileInfoObject::MediaFileInfoObject(TagParser::MediaFileInfo &mediaFileInfo, TagParser::Diagnostics &diag, QJSEngine *engine, QObject *parent)
|
||||||
|
|
|
@ -34,9 +34,9 @@ void parseFileName(const QString &fileName, QString &title, int &trackNumber);
|
||||||
QString printModel(QAbstractItemModel *model);
|
QString printModel(QAbstractItemModel *model);
|
||||||
void printModelIndex(const QModelIndex &index, QString &res, int level);
|
void printModelIndex(const QModelIndex &index, QString &res, int level);
|
||||||
|
|
||||||
constexpr int sizeToInt(std::size_t size)
|
template <typename IntType = int> constexpr IntType sizeToInt(std::size_t size)
|
||||||
{
|
{
|
||||||
return size > std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : static_cast<int>(size);
|
return size > std::numeric_limits<IntType>::max() ? std::numeric_limits<IntType>::max() : static_cast<IntType>(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int containerSizeToInt(typename QStringList::size_type size)
|
constexpr int containerSizeToInt(typename QStringList::size_type size)
|
||||||
|
|
|
@ -14,13 +14,20 @@ export function main(file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mainTextFields = ["title", "artist", "album"];
|
||||||
|
const personalFields = ["comment", "rating"];
|
||||||
|
|
||||||
|
function isString(value) {
|
||||||
|
return typeof(value) === "string" || value instanceof String;
|
||||||
|
}
|
||||||
|
|
||||||
function changeTagFields(tag) {
|
function changeTagFields(tag) {
|
||||||
// log supported fields
|
// log tag type and supported fields
|
||||||
const fields = tag.fields;
|
const fields = tag.fields;
|
||||||
utility.diag("debug", tag.type, "tag");
|
utility.diag("debug", tag.type, "tag");
|
||||||
utility.diag("debug", Object.keys(fields).join(", "), "supported fields");
|
utility.diag("debug", Object.keys(fields).join(", "), "supported fields");
|
||||||
|
|
||||||
// log tag type and fields for debugging purposes
|
// log fields for debugging purposes
|
||||||
for (const [key, value] of Object.entries(fields)) {
|
for (const [key, value] of Object.entries(fields)) {
|
||||||
const content = value.content;
|
const content = value.content;
|
||||||
if (content !== undefined && content != null && !(content instanceof ArrayBuffer)) {
|
if (content !== undefined && content != null && !(content instanceof ArrayBuffer)) {
|
||||||
|
@ -28,9 +35,22 @@ function changeTagFields(tag) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// change some fields
|
// apply fixes to main text fields
|
||||||
fields.title.content = "foo";
|
for (const key of mainTextFields) {
|
||||||
fields.artist.content = "bar";
|
for (const value of fields[key]) {
|
||||||
|
if (isString(value.content)) {
|
||||||
|
value.content = value.content.trim();
|
||||||
|
value.content = utility.fixUmlauts(value.content);
|
||||||
|
value.content = utility.formatName(value.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure personal fields are cleared
|
||||||
|
for (const key of personalFields) {
|
||||||
|
fields[key] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// set some other fields
|
||||||
fields.track.content = "4/17";
|
fields.track.content = "4/17";
|
||||||
fields.comment.clear();
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue