Skip to content

Commit

Permalink
fix: handle ann_id being removed
Browse files Browse the repository at this point in the history
  • Loading branch information
rombat committed Jul 21, 2024
1 parent fbcd882 commit ed92022
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 39 deletions.
30 changes: 23 additions & 7 deletions lib/handlers/MBNDSynchronizer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const fs = require('fs');
const csv2json = require('csvtojson');
const { Op } = require('sequelize');
const { randomUUID } = require('crypto');
const pLimit = require('p-limit');
const camelCase = require('camelcase');
const dayjs = require('dayjs');
Expand Down Expand Up @@ -39,7 +40,7 @@ class MBNDSynchronizer {
dbFilePath: undefined
};
this.options = options;
this.limit = pLimit(500);
this.limit = pLimit(5000);

process.on('SIGINT', async () => await this.restoreDbFile());
process.on('SIGTERM', async () => await this.restoreDbFile());
Expand Down Expand Up @@ -248,13 +249,17 @@ class MBNDSynchronizer {

let annotation = foundTrack?.trackAnnotation;
if (!annotation) {
annotation = Annotation.build({
const record = {
item_type: 'media_file',
user_id: user.id,
item_id: foundTrack.id,
play_count: 0,
starred: 0
});
};
if (Annotation.getAttributes().ann_id) {
record.ann_id = randomUUID();
}
annotation = Annotation.build(record);
}

const update = {};
Expand Down Expand Up @@ -283,6 +288,7 @@ class MBNDSynchronizer {
if (!Object.keys(update).length) {
return;
}

if (!foundTrack.trackAnnotation) {
await annotation.save();
}
Expand Down Expand Up @@ -361,13 +367,18 @@ class MBNDSynchronizer {
}
let annotation = album?.albumAnnotation;
if (!annotation) {
annotation = Annotation.build({
const record = {
item_type: 'album',
user_id: user.id,
item_id: album.id,
play_count: 0,
starred: 0
});
};

if (Annotation.getAttributes().ann_id) {
record.ann_id = randomUUID();
}
annotation = Annotation.build(record);
}

const update = {};
Expand Down Expand Up @@ -472,13 +483,18 @@ class MBNDSynchronizer {

let annotation = artist?.artistAnnotation;
if (!annotation) {
annotation = Annotation.build({
const record = {
item_type: 'artist',
user_id: user.id,
item_id: artist.id,
play_count: 0,
starred: 0
});
};

if (Annotation.getAttributes().ann_id) {
record.ann_id = randomUUID();
}
annotation = Annotation.build(record);
}
const update = {};
const totalPlaycount = artist.tracks.reduce((acc, current) => {
Expand Down
16 changes: 10 additions & 6 deletions lib/handlers/dbManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,22 @@ exports.init = async dbFilePath => {
throw error;
}

createRelationships(sequelize);
await createRelationships(sequelize);

return sequelize;
};

const createRelationships = sequelize => {
const createRelationships = async sequelize => {
// handling legacy Annotation schema (ann_id removed from navidrome DB schema in this commit: https://github.com/navidrome/navidrome/commit/47378c68828861751b9d1a05d3fc9b29ce8dd9f0)
const annotationTableSchema = await sequelize.getQueryInterface().describeTable('annotation');

const Track = sequelize.define('Track', TrackDefinition.attributes, TrackDefinition.options);
const Album = sequelize.define('Album', AlbumDefinition.attributes, AlbumDefinition.options);
const Annotation = sequelize.define('Annotation', AnnotationDefinition.attributes, AnnotationDefinition.options);
const Annotation = sequelize.define(
'Annotation',
AnnotationDefinition.getAttributes(annotationTableSchema),
AnnotationDefinition.options
);
const Artist = sequelize.define('Artist', ArtistDefinition.attributes, ArtistDefinition.options);
const User = sequelize.define('User', UserDefinition.attributes, UserDefinition.options);

Expand All @@ -44,7 +51,4 @@ const createRelationships = sequelize => {
Annotation.belongsTo(Track, { as: 'track', foreignKey: 'item_id' });
Annotation.belongsTo(Album, { as: 'album', foreignKey: 'item_id' });
Annotation.belongsTo(User, { as: 'user', foreignKey: 'user_id' });
// ann_id removed from navidrome DB schema in this commit: https://github.com/navidrome/navidrome/commit/47378c68828861751b9d1a05d3fc9b29ce8dd9f0
// Sequelize sets an id attribute by default as primary key, which is not needed in this case
Annotation.removeAttribute('id');
};
57 changes: 35 additions & 22 deletions lib/models/Annotation.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,45 @@
const { DataTypes } = require('sequelize');
const dayjs = require('dayjs');

exports.attributes = {
user_id: { type: DataTypes.STRING, allowNull: false, defaultValue: '' },
item_id: { type: DataTypes.STRING, allowNull: false, defaultValue: '' },
item_type: { type: DataTypes.STRING, allowNull: false, defaultValue: '' },
play_count: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0 },
play_date: {
type: DataTypes.STRING,
defaultValue: null,
set(value) {
const date = dayjs(value);
this.setDataValue('play_date', date.format('YYYY-MM-DD HH:mm:ss'));
}
},
rating: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0, validate: { min: 0, max: 5 } },
starred: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
starred_at: {
type: DataTypes.STRING,
defaultValue: null,
set(value) {
const date = dayjs(value);
this.setDataValue('starred_at', date.isValid() ? date.format('YYYY-MM-DD HH:mm:ss') : null);
exports.getAttributes = existingSchema => {
const defaultAttributes = {
ann_id: { type: DataTypes.STRING, primaryKey: true, allowNull: false },
user_id: { type: DataTypes.STRING, allowNull: false, defaultValue: '', primaryKey: true },
item_id: { type: DataTypes.STRING, allowNull: false, defaultValue: '', primaryKey: true },
item_type: { type: DataTypes.STRING, allowNull: false, defaultValue: '', primaryKey: true },
play_count: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0 },
play_date: {
type: DataTypes.STRING,
defaultValue: null,
set(value) {
const date = dayjs(value);
this.setDataValue('play_date', date.format('YYYY-MM-DD HH:mm:ss'));
}
},
rating: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0, validate: { min: 0, max: 5 } },
starred: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false },
starred_at: {
type: DataTypes.STRING,
defaultValue: null,
set(value) {
const date = dayjs(value);
this.setDataValue('starred_at', date.isValid() ? date.format('YYYY-MM-DD HH:mm:ss') : null);
}
}
};
if (!existingSchema.ann_id) {
delete defaultAttributes.ann_id;
}
return defaultAttributes;
};

exports.options = {
tableName: 'annotation',
timestamps: false
timestamps: false,
indexes: [
{
fields: ['user_id', 'item_id', 'item_type'],
unique: true
}
]
};
28 changes: 26 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,16 @@
},
"bin": "index.js",
"pkg": {
"assets": ["node_modules/**/*"],
"targets": [ "node16-win-x64"],
"assets": [
"node_modules/**/*"
],
"targets": [
"node16-win-x64"
],
"outputPath": "dist",
"outputName": "musicbee-navidrome-sync"
},
"devDependencies": {
"prettier": "^3.3.3"
}
}

0 comments on commit ed92022

Please sign in to comment.