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.
|
||||
- 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.
|
||||
- The content of fields that are absent in the tag is set to `undefined`. You may also set
|
||||
the content of fields to `undefined` to delete them (`null` works as well).
|
||||
- The property for fields that are absent in the tag have an empty array assigned. You may
|
||||
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`
|
||||
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
|
||||
|
|
|
@ -218,24 +218,6 @@ QString TagObject::type() const
|
|||
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)
|
||||
{
|
||||
static const auto reverseMapping = [] {
|
||||
|
@ -254,6 +236,30 @@ QString TagObject::propertyNameForField(TagParser::KnownField field)
|
|||
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()
|
||||
{
|
||||
auto context = !m_tag.target().isEmpty() || m_tag.type() == TagParser::TagType::MatroskaTag
|
||||
|
@ -273,22 +279,35 @@ void TagObject::applyChanges()
|
|||
continue;
|
||||
}
|
||||
auto propertyValue = m_fields.property(propertyName);
|
||||
auto fieldDisplayName = Settings::KnownFieldModel::fieldName(field);
|
||||
if (const auto *const tagValueObj = qobject_cast<const TagValueObject *>(propertyValue.toQObject())) {
|
||||
if (!tagValueObj->isInitial()) {
|
||||
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);
|
||||
if (!propertyValue.isArray()) {
|
||||
m_engine->throwError(QJSValue::TypeError, QStringLiteral("non-array assigned to field ") + propertyName);
|
||||
goto end;
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -34,9 +34,9 @@ void parseFileName(const QString &fileName, QString &title, int &trackNumber);
|
|||
QString printModel(QAbstractItemModel *model);
|
||||
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)
|
||||
|
|
|
@ -14,13 +14,20 @@ export function main(file) {
|
|||
return false;
|
||||
}
|
||||
|
||||
const mainTextFields = ["title", "artist", "album"];
|
||||
const personalFields = ["comment", "rating"];
|
||||
|
||||
function isString(value) {
|
||||
return typeof(value) === "string" || value instanceof String;
|
||||
}
|
||||
|
||||
function changeTagFields(tag) {
|
||||
// log supported fields
|
||||
// log tag type and supported fields
|
||||
const fields = tag.fields;
|
||||
utility.diag("debug", tag.type, "tag");
|
||||
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)) {
|
||||
const content = value.content;
|
||||
if (content !== undefined && content != null && !(content instanceof ArrayBuffer)) {
|
||||
|
@ -28,9 +35,22 @@ function changeTagFields(tag) {
|
|||
}
|
||||
}
|
||||
|
||||
// change some fields
|
||||
fields.title.content = "foo";
|
||||
fields.artist.content = "bar";
|
||||
// apply fixes to main text fields
|
||||
for (const key of mainTextFields) {
|
||||
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.comment.clear();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue