traxxx/src/tags.js

108 lines
2.9 KiB
JavaScript
Raw Normal View History

'use strict';
const knex = require('./knex');
const slugify = require('./utils/slugify');
async function matchReleaseTags(releases) {
const rawTags = releases
.map(release => release.tags).flat()
.filter(Boolean);
const casedTags = [...new Set(
rawTags
.concat(rawTags.map(tag => tag.toLowerCase()))
.concat(rawTags.map(tag => tag.toUpperCase())),
)];
const tagEntries = await knex('tags')
.select('tags.id', 'tags.name', 'tags.alias_for')
.whereIn('tags.name', casedTags);
const tagIdsBySlug = tagEntries
.reduce((acc, tag) => ({
...acc,
[slugify(tag.name)]: tag.alias_for || tag.id,
}), {});
return tagIdsBySlug;
}
async function getEntityTags(releases) {
const entityIds = releases.map(release => release.entity.id);
const entityTags = await knex('entities_tags').whereIn('entity_id', entityIds);
const entityTagIdsByEntityId = entityTags.reduce((acc, entityTag) => {
if (!acc[entityTag.entity_id]) {
acc[entityTag.entity_id] = [];
}
acc[entityTag.entity_id].push(entityTag.tag_id);
return acc;
}, {});
return entityTagIdsByEntityId;
}
function buildReleaseTagAssociations(releases, tagIdsBySlug, entityTagIdsByEntityId) {
const tagAssociations = releases
.map((release) => {
const entityTagIds = entityTagIdsByEntityId[release.entity.id];
const releaseTags = release.tags || [];
const releaseTagIds = releaseTags.every(tag => typeof tag === 'number')
? releaseTags // obsolete scraper returned pre-matched tags
: releaseTags.map(tag => tagIdsBySlug[slugify(tag)]);
const tags = [...new Set(
// filter duplicates and empties
releaseTagIds
.concat(entityTagIds)
.filter(Boolean),
)]
.map(tagId => ({
release_id: release.id,
tag_id: tagId,
}));
return tags;
})
.flat();
return tagAssociations;
}
2020-01-13 22:45:09 +00:00
async function filterUniqueAssociations(tagAssociations) {
const duplicateAssociations = await knex('releases_tags')
.whereIn(['release_id', 'tag_id'], tagAssociations.map(association => [association.release_id, association.tag_id]));
2020-01-13 22:45:09 +00:00
const duplicateAssociationsByReleaseIdAndTagId = duplicateAssociations.reduce((acc, association) => {
if (!acc[association.release_id]) {
acc[association.release_id] = {};
}
acc[association.release_id][association.tag_id] = true;
return acc;
}, {});
const uniqueAssociations = tagAssociations
.filter(association => !duplicateAssociationsByReleaseIdAndTagId[association.release_id]?.[association.tag_id]);
return uniqueAssociations;
}
async function associateReleaseTags(releases) {
const tagIdsBySlug = await matchReleaseTags(releases);
const EntityTagIdsByEntityId = await getEntityTags(releases);
const tagAssociations = buildReleaseTagAssociations(releases, tagIdsBySlug, EntityTagIdsByEntityId);
const uniqueAssociations = await filterUniqueAssociations(tagAssociations);
await knex('releases_tags').insert(uniqueAssociations);
}
module.exports = {
associateReleaseTags,
};