mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Complete migration file
This commit is contained in:
		
							parent
							
								
									b8de041497
								
							
						
					
					
						commit
						243bc7b0d0
					
				| @ -61,6 +61,7 @@ class Database { | ||||
|     require('./models/BookChapter')(this.sequelize) | ||||
|     require('./models/Genre')(this.sequelize) | ||||
|     require('./models/BookGenre')(this.sequelize) | ||||
|     require('./models/PodcastGenre')(this.sequelize) | ||||
|     require('./models/BookNarrator')(this.sequelize) | ||||
|     require('./models/Series')(this.sequelize) | ||||
|     require('./models/BookSeries')(this.sequelize) | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| const { DataTypes, Model } = require('sequelize') | ||||
| 
 | ||||
| const uppercaseFirst = str => `${str[0].toUpperCase()}${str.substr(1)}` | ||||
| 
 | ||||
| /* | ||||
|  * Polymorphic association: https://sequelize.org/docs/v6/advanced-association-concepts/polymorphic-associations/
 | ||||
|  * Book has many AudioBookmark. PodcastEpisode has many AudioBookmark. | ||||
| @ -10,7 +8,7 @@ module.exports = (sequelize) => { | ||||
|   class AudioBookmark extends Model { | ||||
|     getMediaItem(options) { | ||||
|       if (!this.mediaItemType) return Promise.resolve(null) | ||||
|       const mixinMethodName = `get${uppercaseFirst(this.mediaItemType)}` | ||||
|       const mixinMethodName = `get${this.mediaItemType}` | ||||
|       return this[mixinMethodName](options) | ||||
|     } | ||||
|   } | ||||
| @ -21,7 +19,7 @@ module.exports = (sequelize) => { | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     mediaItemId: DataTypes.UUIDV4, | ||||
|     MediaItemId: DataTypes.UUIDV4, | ||||
|     mediaItemType: DataTypes.STRING, | ||||
|     title: DataTypes.STRING, | ||||
|     time: DataTypes.INTEGER | ||||
| @ -32,29 +30,29 @@ module.exports = (sequelize) => { | ||||
| 
 | ||||
|   const { User, Book, PodcastEpisode } = sequelize.models | ||||
|   Book.hasMany(AudioBookmark, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'book' | ||||
|       mediaItemType: 'Book' | ||||
|     } | ||||
|   }) | ||||
|   AudioBookmark.belongsTo(Book, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   AudioBookmark.belongsTo(Book, { foreignKey: 'MediaItemId', constraints: false }) | ||||
| 
 | ||||
|   PodcastEpisode.hasMany(AudioBookmark, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'podcastEpisode' | ||||
|       mediaItemType: 'PodcastEpisode' | ||||
|     } | ||||
|   }) | ||||
|   AudioBookmark.belongsTo(PodcastEpisode, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   AudioBookmark.belongsTo(PodcastEpisode, { foreignKey: 'MediaItemId', constraints: false }) | ||||
| 
 | ||||
|   AudioBookmark.addHook('afterFind', findResult => { | ||||
|     if (!Array.isArray(findResult)) findResult = [findResult] | ||||
|     for (const instance of findResult) { | ||||
|       if (instance.mediaItemType === 'book' && instance.Book !== undefined) { | ||||
|       if (instance.mediaItemType === 'Book' && instance.Book !== undefined) { | ||||
|         instance.MediaItem = instance.Book | ||||
|       } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|       } else if (instance.mediaItemType === 'PodcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|         instance.MediaItem = instance.PodcastEpisode | ||||
|       } | ||||
|       // To prevent mistakes:
 | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| const { DataTypes, Model } = require('sequelize') | ||||
| 
 | ||||
| const uppercaseFirst = str => `${str[0].toUpperCase()}${str.substr(1)}` | ||||
| 
 | ||||
| /* | ||||
|  * Polymorphic association: https://sequelize.org/docs/v6/advanced-association-concepts/polymorphic-associations/
 | ||||
|  * Book has many AudioTrack. PodcastEpisode has one AudioTrack. | ||||
| @ -10,7 +8,7 @@ module.exports = (sequelize) => { | ||||
|   class AudioTrack extends Model { | ||||
|     getMediaItem(options) { | ||||
|       if (!this.mediaItemType) return Promise.resolve(null) | ||||
|       const mixinMethodName = `get${uppercaseFirst(this.mediaItemType)}` | ||||
|       const mixinMethodName = `get${this.mediaItemType}` | ||||
|       return this[mixinMethodName](options) | ||||
|     } | ||||
|   } | ||||
| @ -21,14 +19,16 @@ module.exports = (sequelize) => { | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     mediaItemId: DataTypes.UUIDV4, | ||||
|     MediaItemId: DataTypes.UUIDV4, | ||||
|     mediaItemType: DataTypes.STRING, | ||||
|     index: DataTypes.INTEGER, | ||||
|     startOffset: DataTypes.INTEGER, | ||||
|     duration: DataTypes.INTEGER, | ||||
|     startOffset: DataTypes.FLOAT, | ||||
|     duration: DataTypes.FLOAT, | ||||
|     title: DataTypes.STRING, | ||||
|     mimeType: DataTypes.STRING, | ||||
|     codec: DataTypes.STRING | ||||
|     codec: DataTypes.STRING, | ||||
|     trackNumber: DataTypes.INTEGER, | ||||
|     discNumber: DataTypes.INTEGER | ||||
|   }, { | ||||
|     sequelize, | ||||
|     modelName: 'AudioTrack' | ||||
| @ -40,29 +40,29 @@ module.exports = (sequelize) => { | ||||
|   AudioTrack.belongsTo(MediaFile) | ||||
| 
 | ||||
|   Book.hasMany(AudioTrack, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'book' | ||||
|       mediaItemType: 'Book' | ||||
|     } | ||||
|   }) | ||||
|   AudioTrack.belongsTo(Book, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   AudioTrack.belongsTo(Book, { foreignKey: 'MediaItemId', constraints: false }) | ||||
| 
 | ||||
|   PodcastEpisode.hasOne(AudioTrack, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'podcastEpisode' | ||||
|       mediaItemType: 'PodcastEpisode' | ||||
|     } | ||||
|   }) | ||||
|   AudioTrack.belongsTo(PodcastEpisode, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   AudioTrack.belongsTo(PodcastEpisode, { foreignKey: 'MediaItemId', constraints: false }) | ||||
| 
 | ||||
|   AudioTrack.addHook('afterFind', findResult => { | ||||
|     if (!Array.isArray(findResult)) findResult = [findResult] | ||||
|     for (const instance of findResult) { | ||||
|       if (instance.mediaItemType === 'book' && instance.Book !== undefined) { | ||||
|       if (instance.mediaItemType === 'Book' && instance.Book !== undefined) { | ||||
|         instance.MediaItem = instance.Book | ||||
|       } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|       } else if (instance.mediaItemType === 'PodcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|         instance.MediaItem = instance.PodcastEpisode | ||||
|       } | ||||
|       // To prevent mistakes:
 | ||||
|  | ||||
| @ -30,8 +30,8 @@ module.exports = (sequelize) => { | ||||
|   LibraryItem.hasOne(Book) | ||||
|   Book.belongsTo(LibraryItem) | ||||
| 
 | ||||
|   FileMetadata.hasOne(Book) | ||||
|   Book.belongsTo(FileMetadata, { as: 'ImageFile' }) // Ref: https://sequelize.org/docs/v6/core-concepts/assocs/#defining-an-alias
 | ||||
|   FileMetadata.hasOne(Book, { foreignKey: 'ImageFileId ' }) | ||||
|   Book.belongsTo(FileMetadata, { as: 'ImageFile', foreignKey: 'ImageFileId' }) // Ref: https://sequelize.org/docs/v6/core-concepts/assocs/#defining-an-alias
 | ||||
| 
 | ||||
|   EBookFile.hasOne(Book) | ||||
|   Book.belongsTo(EBookFile) | ||||
|  | ||||
| @ -11,6 +11,8 @@ module.exports = (sequelize) => { | ||||
|     } | ||||
|   }, { | ||||
|     sequelize, | ||||
|     timestamps: true, | ||||
|     updatedAt: false, | ||||
|     modelName: 'CollectionBook' | ||||
|   }) | ||||
| 
 | ||||
|  | ||||
| @ -16,8 +16,8 @@ module.exports = (sequelize) => { | ||||
| 
 | ||||
|   const { FileMetadata } = sequelize.models | ||||
| 
 | ||||
|   FileMetadata.hasOne(EBookFile) | ||||
|   EBookFile.belongsTo(FileMetadata) | ||||
|   FileMetadata.hasOne(EBookFile, { foreignKey: 'FileMetadataId' }) | ||||
|   EBookFile.belongsTo(FileMetadata, { as: 'FileMetadata', foreignKey: 'FileMetadataId' }) | ||||
| 
 | ||||
|   return EBookFile | ||||
| } | ||||
| @ -1,7 +1,5 @@ | ||||
| const { DataTypes, Model } = require('sequelize') | ||||
| 
 | ||||
| const uppercaseFirst = str => `${str[0].toUpperCase()}${str.substr(1)}` | ||||
| 
 | ||||
| /* | ||||
|  * Polymorphic association: https://sequelize.org/docs/v6/advanced-association-concepts/polymorphic-associations/
 | ||||
|  * Feeds can be created from LibraryItem, Collection, Playlist or Series | ||||
| @ -10,7 +8,7 @@ module.exports = (sequelize) => { | ||||
|   class Feed extends Model { | ||||
|     getEntity(options) { | ||||
|       if (!this.entityType) return Promise.resolve(null) | ||||
|       const mixinMethodName = `get${uppercaseFirst(this.entityType)}` | ||||
|       const mixinMethodName = `get${this.entityType}` | ||||
|       return this[mixinMethodName](options) | ||||
|     } | ||||
|   } | ||||
| @ -23,7 +21,7 @@ module.exports = (sequelize) => { | ||||
|     }, | ||||
|     slug: DataTypes.STRING, | ||||
|     entityType: DataTypes.STRING, | ||||
|     entityId: DataTypes.UUIDV4, | ||||
|     EntityId: DataTypes.UUIDV4, | ||||
|     entityUpdatedAt: DataTypes.DATE, | ||||
|     serverAddress: DataTypes.STRING, | ||||
|     feedURL: DataTypes.STRING, | ||||
| @ -49,51 +47,51 @@ module.exports = (sequelize) => { | ||||
|   Feed.belongsTo(User) | ||||
| 
 | ||||
|   LibraryItem.hasMany(Feed, { | ||||
|     foreignKey: 'entityId', | ||||
|     foreignKey: 'EntityId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       entityType: 'libraryItem' | ||||
|       entityType: 'LibraryItem' | ||||
|     } | ||||
|   }) | ||||
|   Feed.belongsTo(LibraryItem, { foreignKey: 'entityId', constraints: false }) | ||||
|   Feed.belongsTo(LibraryItem, { foreignKey: 'EntityId', constraints: false }) | ||||
| 
 | ||||
|   Collection.hasMany(Feed, { | ||||
|     foreignKey: 'entityId', | ||||
|     foreignKey: 'EntityId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       entityType: 'collection' | ||||
|       entityType: 'Collection' | ||||
|     } | ||||
|   }) | ||||
|   Feed.belongsTo(Collection, { foreignKey: 'entityId', constraints: false }) | ||||
|   Feed.belongsTo(Collection, { foreignKey: 'EntityId', constraints: false }) | ||||
| 
 | ||||
|   Series.hasMany(Feed, { | ||||
|     foreignKey: 'entityId', | ||||
|     foreignKey: 'EntityId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       entityType: 'series' | ||||
|       entityType: 'Series' | ||||
|     } | ||||
|   }) | ||||
|   Feed.belongsTo(Series, { foreignKey: 'entityId', constraints: false }) | ||||
|   Feed.belongsTo(Series, { foreignKey: 'EntityId', constraints: false }) | ||||
| 
 | ||||
|   Playlist.hasMany(Feed, { | ||||
|     foreignKey: 'entityId', | ||||
|     foreignKey: 'EntityId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       entityType: 'playlist' | ||||
|       entityType: 'Playlist' | ||||
|     } | ||||
|   }) | ||||
|   Feed.belongsTo(Playlist, { foreignKey: 'entityId', constraints: false }) | ||||
|   Feed.belongsTo(Playlist, { foreignKey: 'EntityId', constraints: false }) | ||||
| 
 | ||||
|   Feed.addHook('afterFind', findResult => { | ||||
|     if (!Array.isArray(findResult)) findResult = [findResult] | ||||
|     for (const instance of findResult) { | ||||
|       if (instance.entityType === 'libraryItem' && instance.LibraryItem !== undefined) { | ||||
|       if (instance.entityType === 'LibraryItem' && instance.LibraryItem !== undefined) { | ||||
|         instance.Entity = instance.LibraryItem | ||||
|       } else if (instance.mediaItemType === 'collection' && instance.Collection !== undefined) { | ||||
|       } else if (instance.mediaItemType === 'Collection' && instance.Collection !== undefined) { | ||||
|         instance.Entity = instance.Collection | ||||
|       } else if (instance.mediaItemType === 'series' && instance.Series !== undefined) { | ||||
|       } else if (instance.mediaItemType === 'Series' && instance.Series !== undefined) { | ||||
|         instance.Entity = instance.Series | ||||
|       } else if (instance.mediaItemType === 'playlist' && instance.Playlist !== undefined) { | ||||
|       } else if (instance.mediaItemType === 'Playlist' && instance.Playlist !== undefined) { | ||||
|         instance.Entity = instance.Playlist | ||||
|       } | ||||
| 
 | ||||
|  | ||||
| @ -20,7 +20,7 @@ module.exports = (sequelize) => { | ||||
|     season: DataTypes.STRING, | ||||
|     episode: DataTypes.STRING, | ||||
|     episodeType: DataTypes.STRING, | ||||
|     duration: DataTypes.INTEGER, | ||||
|     duration: DataTypes.FLOAT, | ||||
|     filePath: DataTypes.STRING, | ||||
|     explicit: DataTypes.BOOLEAN | ||||
|   }, { | ||||
|  | ||||
| @ -20,6 +20,10 @@ module.exports = (sequelize) => { | ||||
|   }, { | ||||
|     sequelize, | ||||
|     freezeTableName: true, // sequelize uses datum as singular of data
 | ||||
|     name: { | ||||
|       singular: 'FileMetadata', | ||||
|       plural: 'FileMetadata' | ||||
|     }, | ||||
|     modelName: 'FileMetadata' | ||||
|   }) | ||||
| 
 | ||||
|  | ||||
| @ -9,7 +9,8 @@ module.exports = (sequelize) => { | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     name: DataTypes.STRING | ||||
|     name: DataTypes.STRING, | ||||
|     cleanName: DataTypes.STRING | ||||
|   }, { | ||||
|     sequelize, | ||||
|     modelName: 'Genre' | ||||
|  | ||||
| @ -18,8 +18,8 @@ module.exports = (sequelize) => { | ||||
|   LibraryItem.hasMany(LibraryFile) | ||||
|   LibraryFile.belongsTo(LibraryItem) | ||||
| 
 | ||||
|   FileMetadata.hasOne(LibraryFile) | ||||
|   LibraryFile.belongsTo(FileMetadata) | ||||
|   FileMetadata.hasOne(LibraryFile, { foreignKey: 'FileMetadataId' }) | ||||
|   LibraryFile.belongsTo(FileMetadata, { as: 'FileMetadata', foreignKey: 'FileMetadataId' }) | ||||
| 
 | ||||
|   return LibraryFile | ||||
| } | ||||
| @ -22,8 +22,8 @@ module.exports = (sequelize) => { | ||||
| 
 | ||||
|   const { FileMetadata } = sequelize.models | ||||
| 
 | ||||
|   FileMetadata.hasOne(MediaFile) | ||||
|   MediaFile.belongsTo(FileMetadata) | ||||
|   FileMetadata.hasOne(MediaFile, { foreignKey: 'FileMetadataId' }) | ||||
|   MediaFile.belongsTo(FileMetadata, { as: 'FileMetadata', foreignKey: 'FileMetadataId' }) | ||||
| 
 | ||||
|   return MediaFile | ||||
| } | ||||
| @ -1,7 +1,5 @@ | ||||
| const { DataTypes, Model } = require('sequelize') | ||||
| 
 | ||||
| const uppercaseFirst = str => `${str[0].toUpperCase()}${str.substr(1)}` | ||||
| 
 | ||||
| /* | ||||
|  * Polymorphic association: https://sequelize.org/docs/v6/advanced-association-concepts/polymorphic-associations/
 | ||||
|  * Book has many MediaProgress. PodcastEpisode has many MediaProgress. | ||||
| @ -10,7 +8,7 @@ module.exports = (sequelize) => { | ||||
|   class MediaProgress extends Model { | ||||
|     getMediaItem(options) { | ||||
|       if (!this.mediaItemType) return Promise.resolve(null) | ||||
|       const mixinMethodName = `get${uppercaseFirst(this.mediaItemType)}` | ||||
|       const mixinMethodName = `get${this.mediaItemType}` | ||||
|       return this[mixinMethodName](options) | ||||
|     } | ||||
|   } | ||||
| @ -21,10 +19,10 @@ module.exports = (sequelize) => { | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     mediaItemId: DataTypes.UUIDV4, | ||||
|     MediaItemId: DataTypes.UUIDV4, | ||||
|     mediaItemType: DataTypes.STRING, | ||||
|     duration: DataTypes.INTEGER, | ||||
|     currentTime: DataTypes.INTEGER, | ||||
|     duration: DataTypes.FLOAT, | ||||
|     currentTime: DataTypes.FLOAT, | ||||
|     isFinished: DataTypes.BOOLEAN, | ||||
|     hideFromContinueListening: DataTypes.BOOLEAN, | ||||
|     finishedAt: DataTypes.DATE | ||||
| @ -35,29 +33,29 @@ module.exports = (sequelize) => { | ||||
| 
 | ||||
|   const { Book, PodcastEpisode, User } = sequelize.models | ||||
|   Book.hasMany(MediaProgress, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'book' | ||||
|       mediaItemType: 'Book' | ||||
|     } | ||||
|   }) | ||||
|   MediaProgress.belongsTo(Book, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   MediaProgress.belongsTo(Book, { foreignKey: 'MediaItemId', constraints: false }) | ||||
| 
 | ||||
|   PodcastEpisode.hasMany(MediaProgress, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'podcastEpisode' | ||||
|       mediaItemType: 'PodcastEpisode' | ||||
|     } | ||||
|   }) | ||||
|   MediaProgress.belongsTo(PodcastEpisode, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   MediaProgress.belongsTo(PodcastEpisode, { foreignKey: 'MediaItemId', constraints: false }) | ||||
| 
 | ||||
|   MediaProgress.addHook('afterFind', findResult => { | ||||
|     if (!Array.isArray(findResult)) findResult = [findResult] | ||||
|     for (const instance of findResult) { | ||||
|       if (instance.mediaItemType === 'book' && instance.Book !== undefined) { | ||||
|       if (instance.mediaItemType === 'Book' && instance.Book !== undefined) { | ||||
|         instance.MediaItem = instance.Book | ||||
|       } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|       } else if (instance.mediaItemType === 'PodcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|         instance.MediaItem = instance.PodcastEpisode | ||||
|       } | ||||
|       // To prevent mistakes:
 | ||||
|  | ||||
| @ -10,7 +10,7 @@ module.exports = (sequelize) => { | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     eventName: DataTypes.STRING, | ||||
|     urls: DataTypes.TEXT, // JSON array of urls
 | ||||
|     urls: DataTypes.JSON, // JSON array of urls
 | ||||
|     titleTemplate: DataTypes.STRING(1000), | ||||
|     bodyTemplate: DataTypes.TEXT, | ||||
|     type: DataTypes.STRING, | ||||
| @ -18,16 +18,12 @@ module.exports = (sequelize) => { | ||||
|     lastAttemptFailed: DataTypes.BOOLEAN, | ||||
|     numConsecutiveFailedAttempts: DataTypes.INTEGER, | ||||
|     numTimesFired: DataTypes.INTEGER, | ||||
|     enabled: DataTypes.BOOLEAN | ||||
|     enabled: DataTypes.BOOLEAN, | ||||
|     extraData: DataTypes.JSON | ||||
|   }, { | ||||
|     sequelize, | ||||
|     modelName: 'Notification' | ||||
|   }) | ||||
| 
 | ||||
|   const { Library } = sequelize.models | ||||
| 
 | ||||
|   Library.hasMany(Notification) | ||||
|   Notification.belongsTo(Library) | ||||
| 
 | ||||
|   return Notification | ||||
| } | ||||
| @ -19,8 +19,8 @@ module.exports = (sequelize) => { | ||||
|   }) | ||||
| 
 | ||||
|   const { FileMetadata } = sequelize.models | ||||
|   FileMetadata.hasMany(Person) | ||||
|   Person.belongsTo(FileMetadata, { as: 'ImageFile' }) // Ref: https://sequelize.org/docs/v6/core-concepts/assocs/#defining-an-alias
 | ||||
|   FileMetadata.hasMany(Person, { foreignKey: 'ImageFileId' }) | ||||
|   Person.belongsTo(FileMetadata, { as: 'ImageFile', foreignKey: 'ImageFileId' }) // Ref: https://sequelize.org/docs/v6/core-concepts/assocs/#defining-an-alias
 | ||||
| 
 | ||||
|   return Person | ||||
| } | ||||
| @ -1,12 +1,10 @@ | ||||
| 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)}` | ||||
|       const mixinMethodName = `get${this.mediaItemType}` | ||||
|       return this[mixinMethodName](options) | ||||
|     } | ||||
|   } | ||||
| @ -17,16 +15,15 @@ module.exports = (sequelize) => { | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     mediaItemId: DataTypes.UUIDV4, | ||||
|     MediaItemId: DataTypes.UUIDV4, | ||||
|     mediaItemType: DataTypes.STRING, | ||||
|     displayTitle: DataTypes.STRING, | ||||
|     displayAuthor: DataTypes.STRING, | ||||
|     duration: DataTypes.INTEGER, | ||||
|     duration: DataTypes.FLOAT, | ||||
|     playMethod: DataTypes.STRING, | ||||
|     mediaPlayer: DataTypes.STRING, | ||||
|     startTime: DataTypes.INTEGER, | ||||
|     currentTime: DataTypes.INTEGER, | ||||
|     timeListening: DataTypes.INTEGER, | ||||
|     startTime: DataTypes.FLOAT, | ||||
|     currentTime: DataTypes.FLOAT, | ||||
|     serverVersion: DataTypes.STRING | ||||
|   }, { | ||||
|     sequelize, | ||||
| @ -42,29 +39,29 @@ module.exports = (sequelize) => { | ||||
|   PlaybackSession.belongsTo(Device) | ||||
| 
 | ||||
|   Book.hasMany(PlaybackSession, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'book' | ||||
|       mediaItemType: 'Book' | ||||
|     } | ||||
|   }) | ||||
|   PlaybackSession.belongsTo(Book, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   PlaybackSession.belongsTo(Book, { foreignKey: 'MediaItemId', constraints: false }) | ||||
| 
 | ||||
|   PodcastEpisode.hasOne(PlaybackSession, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'podcastEpisode' | ||||
|       mediaItemType: 'PodcastEpisode' | ||||
|     } | ||||
|   }) | ||||
|   PlaybackSession.belongsTo(PodcastEpisode, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   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) { | ||||
|       if (instance.mediaItemType === 'Book' && instance.Book !== undefined) { | ||||
|         instance.MediaItem = instance.Book | ||||
|       } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|       } else if (instance.mediaItemType === 'PodcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|         instance.MediaItem = instance.PodcastEpisode | ||||
|       } | ||||
|       // To prevent mistakes:
 | ||||
|  | ||||
| @ -1,12 +1,10 @@ | ||||
| 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)}` | ||||
|       const mixinMethodName = `get${this.mediaItemType}` | ||||
|       return this[mixinMethodName](options) | ||||
|     } | ||||
|   } | ||||
| @ -17,39 +15,41 @@ module.exports = (sequelize) => { | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     mediaItemId: DataTypes.UUIDV4, | ||||
|     MediaItemId: DataTypes.UUIDV4, | ||||
|     mediaItemType: DataTypes.STRING | ||||
|   }, { | ||||
|     sequelize, | ||||
|     timestamps: true, | ||||
|     updatedAt: false, | ||||
|     modelName: 'PlaylistMediaItem' | ||||
|   }) | ||||
| 
 | ||||
|   const { Book, PodcastEpisode, Playlist } = sequelize.models | ||||
| 
 | ||||
|   Book.hasMany(PlaylistMediaItem, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'book' | ||||
|       mediaItemType: 'Book' | ||||
|     } | ||||
|   }) | ||||
|   PlaylistMediaItem.belongsTo(Book, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   PlaylistMediaItem.belongsTo(Book, { foreignKey: 'MediaItemId', constraints: false }) | ||||
| 
 | ||||
|   PodcastEpisode.hasOne(PlaylistMediaItem, { | ||||
|     foreignKey: 'mediaItemId', | ||||
|     foreignKey: 'MediaItemId', | ||||
|     constraints: false, | ||||
|     scope: { | ||||
|       mediaItemType: 'podcastEpisode' | ||||
|       mediaItemType: 'PodcastEpisode' | ||||
|     } | ||||
|   }) | ||||
|   PlaylistMediaItem.belongsTo(PodcastEpisode, { foreignKey: 'mediaItemId', constraints: false }) | ||||
|   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) { | ||||
|       if (instance.mediaItemType === 'Book' && instance.Book !== undefined) { | ||||
|         instance.MediaItem = instance.Book | ||||
|       } else if (instance.mediaItemType === 'podcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|       } else if (instance.mediaItemType === 'PodcastEpisode' && instance.PodcastEpisode !== undefined) { | ||||
|         instance.MediaItem = instance.PodcastEpisode | ||||
|       } | ||||
|       // To prevent mistakes:
 | ||||
|  | ||||
| @ -13,14 +13,14 @@ module.exports = (sequelize) => { | ||||
|     title: DataTypes.STRING, | ||||
|     author: DataTypes.STRING, | ||||
|     releaseDate: DataTypes.STRING, | ||||
|     feedUrl: DataTypes.STRING, | ||||
|     imageUrl: DataTypes.STRING, | ||||
|     feedURL: DataTypes.STRING, | ||||
|     imageURL: DataTypes.STRING, | ||||
|     description: DataTypes.TEXT, | ||||
|     itunesPageUrl: DataTypes.STRING, | ||||
|     itunesPageURL: DataTypes.STRING, | ||||
|     itunesId: DataTypes.STRING, | ||||
|     itunesArtistId: DataTypes.STRING, | ||||
|     language: DataTypes.STRING, | ||||
|     type: DataTypes.STRING, | ||||
|     podcastType: DataTypes.STRING, | ||||
|     explicit: DataTypes.BOOLEAN, | ||||
| 
 | ||||
|     autoDownloadEpisodes: DataTypes.BOOLEAN, | ||||
| @ -39,8 +39,8 @@ module.exports = (sequelize) => { | ||||
|   LibraryItem.hasOne(Podcast) | ||||
|   Podcast.belongsTo(LibraryItem) | ||||
| 
 | ||||
|   FileMetadata.hasOne(Podcast) | ||||
|   Podcast.belongsTo(FileMetadata, { as: 'ImageFile' }) // Ref: https://sequelize.org/docs/v6/core-concepts/assocs/#defining-an-alias
 | ||||
|   FileMetadata.hasOne(Podcast, { foreignKey: 'ImageFileId' }) | ||||
|   Podcast.belongsTo(FileMetadata, { as: 'ImageFile', foreignKey: 'ImageFileId' }) // Ref: https://sequelize.org/docs/v6/core-concepts/assocs/#defining-an-alias
 | ||||
| 
 | ||||
|   return Podcast | ||||
| } | ||||
							
								
								
									
										31
									
								
								server/models/PodcastGenre.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								server/models/PodcastGenre.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| const { DataTypes, Model } = require('sequelize') | ||||
| 
 | ||||
| module.exports = (sequelize) => { | ||||
|   class PodcastGenre extends Model { } | ||||
| 
 | ||||
|   PodcastGenre.init({ | ||||
|     id: { | ||||
|       type: DataTypes.UUID, | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       primaryKey: true | ||||
|     } | ||||
|   }, { | ||||
|     sequelize, | ||||
|     modelName: 'PodcastGenre', | ||||
|     timestamps: false | ||||
|   }) | ||||
| 
 | ||||
|   // Super Many-to-Many
 | ||||
|   // ref: https://sequelize.org/docs/v6/advanced-association-concepts/advanced-many-to-many/#the-best-of-both-worlds-the-super-many-to-many-relationship
 | ||||
|   const { Podcast, Genre } = sequelize.models | ||||
|   Podcast.belongsToMany(Genre, { through: PodcastGenre }) | ||||
|   Genre.belongsToMany(Podcast, { through: PodcastGenre }) | ||||
| 
 | ||||
|   Podcast.hasMany(PodcastGenre) | ||||
|   PodcastGenre.belongsTo(Podcast) | ||||
| 
 | ||||
|   Genre.hasMany(PodcastGenre) | ||||
|   PodcastGenre.belongsTo(Genre) | ||||
| 
 | ||||
|   return PodcastGenre | ||||
| } | ||||
| @ -9,7 +9,8 @@ module.exports = (sequelize) => { | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     name: DataTypes.STRING | ||||
|     name: DataTypes.STRING, | ||||
|     cleanName: DataTypes.STRING | ||||
|   }, { | ||||
|     sequelize, | ||||
|     modelName: 'Tag' | ||||
|  | ||||
| @ -22,7 +22,8 @@ module.exports = (sequelize) => { | ||||
|       type: DataTypes.BOOLEAN, | ||||
|       defaultValue: false | ||||
|     }, | ||||
|     lastSeen: DataTypes.DATE | ||||
|     lastSeen: DataTypes.DATE, | ||||
|     extraData: DataTypes.JSON | ||||
|   }, { | ||||
|     sequelize, | ||||
|     modelName: 'User' | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user