diff --git a/server/Database.js b/server/Database.js index 7e119a99..be81f761 100644 --- a/server/Database.js +++ b/server/Database.js @@ -62,6 +62,10 @@ class Database { require('./models/PodcastTag')(this.sequelize) require('./models/Collection')(this.sequelize) require('./models/CollectionBook')(this.sequelize) + require('./models/Playlist')(this.sequelize) + require('./models/PlaylistMediaItem')(this.sequelize) + require('./models/Device')(this.sequelize) + require('./models/PlaybackSession')(this.sequelize) return this.sequelize.sync() } diff --git a/server/models/AudioBookmark.js b/server/models/AudioBookmark.js index 7cb3f9a7..c733a29e 100644 --- a/server/models/AudioBookmark.js +++ b/server/models/AudioBookmark.js @@ -52,20 +52,19 @@ module.exports = (sequelize) => { AudioBookmark.addHook('afterFind', findResult => { if (!Array.isArray(findResult)) findResult = [findResult] for (const instance of findResult) { - if (instance.mediaItemType === 'book' && instance.book !== undefined) { - instance.mediaItem = instance.book - } else if (instance.mediaItemType === 'podcastEpisode' && instance.podcastEpisode !== undefined) { - instance.mediaItem = instance.podcastEpisode + if (instance.mediaItemType === 'book' && instance.Book !== undefined) { + instance.MediaItem = instance.Book + } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { + instance.MediaItem = instance.PodcastEpisode } // To prevent mistakes: - delete instance.book - delete instance.dataValues.book - delete instance.podcastEpisode - delete instance.dataValues.podcastEpisode + delete instance.Book + delete instance.dataValues.Book + delete instance.PodcastEpisode + delete instance.dataValues.PodcastEpisode } }) - User.hasMany(AudioBookmark) AudioBookmark.belongsTo(User) diff --git a/server/models/AudioTrack.js b/server/models/AudioTrack.js index d4c5ea7b..9dbf05fa 100644 --- a/server/models/AudioTrack.js +++ b/server/models/AudioTrack.js @@ -51,16 +51,16 @@ module.exports = (sequelize) => { AudioTrack.addHook('afterFind', findResult => { if (!Array.isArray(findResult)) findResult = [findResult] for (const instance of findResult) { - if (instance.mediaItemType === 'book' && instance.book !== undefined) { - instance.mediaItem = instance.book - } else if (instance.mediaItemType === 'podcastEpisode' && instance.podcastEpisode !== undefined) { - instance.mediaItem = instance.podcastEpisode + if (instance.mediaItemType === 'book' && instance.Book !== undefined) { + instance.MediaItem = instance.Book + } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { + instance.MediaItem = instance.PodcastEpisode } // To prevent mistakes: - delete instance.book - delete instance.dataValues.book - delete instance.podcastEpisode - delete instance.dataValues.podcastEpisode + delete instance.Book + delete instance.dataValues.Book + delete instance.PodcastEpisode + delete instance.dataValues.PodcastEpisode } }) diff --git a/server/models/Device.js b/server/models/Device.js new file mode 100644 index 00000000..4f5a180d --- /dev/null +++ b/server/models/Device.js @@ -0,0 +1,29 @@ +const { DataTypes, Model } = require('sequelize') + +module.exports = (sequelize) => { + class Device extends Model { } + + Device.init({ + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + identifier: DataTypes.STRING, + clientName: DataTypes.STRING, // e.g. Abs Web, Abs Android + clientVersion: DataTypes.STRING, + ipAddress: DataTypes.STRING, + deviceName: DataTypes.STRING, // e.g. Windows 10 Chrome, Google Pixel 6, Apple iPhone 10,3 + deviceVersion: DataTypes.STRING // e.g. Browser version or Android SDK + }, { + sequelize, + modelName: 'Device' + }) + + const { User } = sequelize.models + + User.hasMany(Device) + Device.belongsTo(User) + + return Device +} \ No newline at end of file diff --git a/server/models/MediaProgress.js b/server/models/MediaProgress.js index 71cd4520..296f9338 100644 --- a/server/models/MediaProgress.js +++ b/server/models/MediaProgress.js @@ -55,16 +55,16 @@ module.exports = (sequelize) => { MediaProgress.addHook('afterFind', findResult => { if (!Array.isArray(findResult)) findResult = [findResult] for (const instance of findResult) { - if (instance.mediaItemType === 'book' && instance.book !== undefined) { - instance.mediaItem = instance.book - } else if (instance.mediaItemType === 'podcastEpisode' && instance.podcastEpisode !== undefined) { - instance.mediaItem = instance.podcastEpisode + if (instance.mediaItemType === 'book' && instance.Book !== undefined) { + instance.MediaItem = instance.Book + } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { + instance.MediaItem = instance.PodcastEpisode } // To prevent mistakes: - delete instance.book - delete instance.dataValues.book - delete instance.podcastEpisode - delete instance.dataValues.podcastEpisode + delete instance.Book + delete instance.dataValues.Book + delete instance.PodcastEpisode + delete instance.dataValues.PodcastEpisode } }) diff --git a/server/models/PlaybackSession.js b/server/models/PlaybackSession.js new file mode 100644 index 00000000..2697c050 --- /dev/null +++ b/server/models/PlaybackSession.js @@ -0,0 +1,79 @@ +const { DataTypes, Model } = require('sequelize') + +const uppercaseFirst = str => `${str[0].toUpperCase()}${str.substr(1)}` + +module.exports = (sequelize) => { + class PlaybackSession extends Model { + getMediaItem(options) { + if (!this.mediaItemType) return Promise.resolve(null) + const mixinMethodName = `get${uppercaseFirst(this.mediaItemType)}` + return this[mixinMethodName](options) + } + } + + PlaybackSession.init({ + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + mediaItemId: DataTypes.UUIDV4, + mediaItemType: DataTypes.STRING, + displayTitle: DataTypes.STRING, + displayAuthor: DataTypes.STRING, + duration: DataTypes.INTEGER, + playMethod: DataTypes.STRING, + mediaPlayer: DataTypes.STRING, + startTime: DataTypes.INTEGER, + currentTime: DataTypes.INTEGER, + timeListening: DataTypes.INTEGER, + serverVersion: DataTypes.STRING + }, { + sequelize, + modelName: 'PlaybackSession' + }) + + const { Book, PodcastEpisode, User, Device } = sequelize.models + + Book.hasMany(PlaybackSession, { + foreignKey: 'mediaItemId', + constraints: false, + scope: { + mediaItemType: 'book' + } + }) + PlaybackSession.belongsTo(Book, { foreignKey: 'mediaItemId', constraints: false }) + + PodcastEpisode.hasOne(PlaybackSession, { + foreignKey: 'mediaItemId', + constraints: false, + scope: { + mediaItemType: 'podcastEpisode' + } + }) + PlaybackSession.belongsTo(PodcastEpisode, { foreignKey: 'mediaItemId', constraints: false }) + + PlaybackSession.addHook('afterFind', findResult => { + if (!Array.isArray(findResult)) findResult = [findResult] + for (const instance of findResult) { + if (instance.mediaItemType === 'book' && instance.Book !== undefined) { + instance.MediaItem = instance.Book + } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { + instance.MediaItem = instance.PodcastEpisode + } + // To prevent mistakes: + delete instance.Book + delete instance.dataValues.Book + delete instance.PodcastEpisode + delete instance.dataValues.PodcastEpisode + } + }) + + User.hasMany(PlaybackSession) + PlaybackSession.belongsTo(User) + + Device.hasMany(PlaybackSession) + PlaybackSession.belongsTo(Device) + + return PlaybackSession +} \ No newline at end of file diff --git a/server/models/Playlist.js b/server/models/Playlist.js new file mode 100644 index 00000000..6fa0b4a9 --- /dev/null +++ b/server/models/Playlist.js @@ -0,0 +1,27 @@ +const { DataTypes, Model } = require('sequelize') + +module.exports = (sequelize) => { + class Playlist extends Model { } + + Playlist.init({ + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + name: DataTypes.STRING, + description: DataTypes.TEXT + }, { + sequelize, + modelName: 'Playlist' + }) + + const { Library, User } = sequelize.models + Library.hasMany(Playlist) + Playlist.belongsTo(Library) + + User.hasMany(Playlist) + Playlist.belongsTo(User) + + return Playlist +} \ No newline at end of file diff --git a/server/models/PlaylistMediaItem.js b/server/models/PlaylistMediaItem.js new file mode 100644 index 00000000..bbc8aa5d --- /dev/null +++ b/server/models/PlaylistMediaItem.js @@ -0,0 +1,67 @@ +const { DataTypes, Model } = require('sequelize') + +const uppercaseFirst = str => `${str[0].toUpperCase()}${str.substr(1)}` + +module.exports = (sequelize) => { + class PlaylistMediaItem extends Model { + getMediaItem(options) { + if (!this.mediaItemType) return Promise.resolve(null) + const mixinMethodName = `get${uppercaseFirst(this.mediaItemType)}` + return this[mixinMethodName](options) + } + } + + PlaylistMediaItem.init({ + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + mediaItemId: DataTypes.UUIDV4, + mediaItemType: DataTypes.STRING + }, { + sequelize, + modelName: 'PlaylistMediaItem' + }) + + const { Book, PodcastEpisode, Playlist } = sequelize.models + + Book.hasMany(PlaylistMediaItem, { + foreignKey: 'mediaItemId', + constraints: false, + scope: { + mediaItemType: 'book' + } + }) + PlaylistMediaItem.belongsTo(Book, { foreignKey: 'mediaItemId', constraints: false }) + + PodcastEpisode.hasOne(PlaylistMediaItem, { + foreignKey: 'mediaItemId', + constraints: false, + scope: { + mediaItemType: 'podcastEpisode' + } + }) + PlaylistMediaItem.belongsTo(PodcastEpisode, { foreignKey: 'mediaItemId', constraints: false }) + + PlaylistMediaItem.addHook('afterFind', findResult => { + if (!Array.isArray(findResult)) findResult = [findResult] + for (const instance of findResult) { + if (instance.mediaItemType === 'book' && instance.Book !== undefined) { + instance.MediaItem = instance.Book + } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { + instance.MediaItem = instance.PodcastEpisode + } + // To prevent mistakes: + delete instance.Book + delete instance.dataValues.Book + delete instance.PodcastEpisode + delete instance.dataValues.PodcastEpisode + } + }) + + Playlist.hasMany(PlaylistMediaItem) + PlaylistMediaItem.belongsTo(Playlist) + + return PlaylistMediaItem +} \ No newline at end of file diff --git a/server/models/User.js b/server/models/User.js index a15b77f6..0c4868ba 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -10,6 +10,7 @@ module.exports = (sequelize) => { primaryKey: true }, username: DataTypes.STRING, + email: DataTypes.STRING, pash: DataTypes.STRING, type: DataTypes.STRING, token: DataTypes.STRING,