mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-06-05 14:44:14 -04:00
Remove unused functions, jsdoc updates, auto-formatting
This commit is contained in:
parent
964ef910b6
commit
3fd290c518
@ -26,11 +26,6 @@ class Author extends Model {
|
|||||||
this.createdAt
|
this.createdAt
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getOldAuthors() {
|
|
||||||
const authors = await this.findAll()
|
|
||||||
return authors.map(au => au.getOldAuthor())
|
|
||||||
}
|
|
||||||
|
|
||||||
getOldAuthor() {
|
getOldAuthor() {
|
||||||
return new oldAuthor({
|
return new oldAuthor({
|
||||||
id: this.id,
|
id: this.id,
|
||||||
@ -85,7 +80,7 @@ class Author extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get oldAuthor by id
|
* Get oldAuthor by id
|
||||||
* @param {string} authorId
|
* @param {string} authorId
|
||||||
* @returns {Promise<oldAuthor>}
|
* @returns {Promise<oldAuthor>}
|
||||||
*/
|
*/
|
||||||
static async getOldById(authorId) {
|
static async getOldById(authorId) {
|
||||||
@ -96,7 +91,7 @@ class Author extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if author exists
|
* Check if author exists
|
||||||
* @param {string} authorId
|
* @param {string} authorId
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
static async checkExistsById(authorId) {
|
static async checkExistsById(authorId) {
|
||||||
@ -106,60 +101,67 @@ class Author extends Model {
|
|||||||
/**
|
/**
|
||||||
* Get old author by name and libraryId. name case insensitive
|
* Get old author by name and libraryId. name case insensitive
|
||||||
* TODO: Look for authors ignoring punctuation
|
* TODO: Look for authors ignoring punctuation
|
||||||
*
|
*
|
||||||
* @param {string} authorName
|
* @param {string} authorName
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @returns {Promise<oldAuthor>}
|
* @returns {Promise<oldAuthor>}
|
||||||
*/
|
*/
|
||||||
static async getOldByNameAndLibrary(authorName, libraryId) {
|
static async getOldByNameAndLibrary(authorName, libraryId) {
|
||||||
const author = (await this.findOne({
|
const author = (
|
||||||
where: [
|
await this.findOne({
|
||||||
where(fn('lower', col('name')), authorName.toLowerCase()),
|
where: [
|
||||||
{
|
where(fn('lower', col('name')), authorName.toLowerCase()),
|
||||||
libraryId
|
{
|
||||||
}
|
libraryId
|
||||||
]
|
}
|
||||||
}))?.getOldAuthor()
|
]
|
||||||
|
})
|
||||||
|
)?.getOldAuthor()
|
||||||
return author
|
return author
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
},
|
primaryKey: true
|
||||||
name: DataTypes.STRING,
|
|
||||||
lastFirst: DataTypes.STRING,
|
|
||||||
asin: DataTypes.STRING,
|
|
||||||
description: DataTypes.TEXT,
|
|
||||||
imagePath: DataTypes.STRING
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'author',
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
fields: [{
|
|
||||||
name: 'name',
|
|
||||||
collate: 'NOCASE'
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
// {
|
name: DataTypes.STRING,
|
||||||
// fields: [{
|
lastFirst: DataTypes.STRING,
|
||||||
// name: 'lastFirst',
|
asin: DataTypes.STRING,
|
||||||
// collate: 'NOCASE'
|
description: DataTypes.TEXT,
|
||||||
// }]
|
imagePath: DataTypes.STRING
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
fields: ['libraryId']
|
sequelize,
|
||||||
}
|
modelName: 'author',
|
||||||
]
|
indexes: [
|
||||||
})
|
{
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'name',
|
||||||
|
collate: 'NOCASE'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// fields: [{
|
||||||
|
// name: 'lastFirst',
|
||||||
|
// collate: 'NOCASE'
|
||||||
|
// }]
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
fields: ['libraryId']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const { library } = sequelize.models
|
const { library } = sequelize.models
|
||||||
library.hasMany(Author, {
|
library.hasMany(Author, {
|
||||||
|
@ -21,13 +21,13 @@ const Logger = require('../Logger')
|
|||||||
/**
|
/**
|
||||||
* @typedef SeriesExpandedProperties
|
* @typedef SeriesExpandedProperties
|
||||||
* @property {{sequence:string}} bookSeries
|
* @property {{sequence:string}} bookSeries
|
||||||
*
|
*
|
||||||
* @typedef {import('./Series') & SeriesExpandedProperties} SeriesExpanded
|
* @typedef {import('./Series') & SeriesExpandedProperties} SeriesExpanded
|
||||||
*
|
*
|
||||||
* @typedef BookExpandedProperties
|
* @typedef BookExpandedProperties
|
||||||
* @property {import('./Author')[]} authors
|
* @property {import('./Author')[]} authors
|
||||||
* @property {SeriesExpanded[]} series
|
* @property {SeriesExpanded[]} series
|
||||||
*
|
*
|
||||||
* @typedef {Book & BookExpandedProperties} BookExpanded
|
* @typedef {Book & BookExpandedProperties} BookExpanded
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -112,29 +112,31 @@ class Book extends Model {
|
|||||||
const bookExpanded = libraryItemExpanded.media
|
const bookExpanded = libraryItemExpanded.media
|
||||||
let authors = []
|
let authors = []
|
||||||
if (bookExpanded.authors?.length) {
|
if (bookExpanded.authors?.length) {
|
||||||
authors = bookExpanded.authors.map(au => {
|
authors = bookExpanded.authors.map((au) => {
|
||||||
return {
|
return {
|
||||||
id: au.id,
|
id: au.id,
|
||||||
name: au.name
|
name: au.name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (bookExpanded.bookAuthors?.length) {
|
} else if (bookExpanded.bookAuthors?.length) {
|
||||||
authors = bookExpanded.bookAuthors.map(ba => {
|
authors = bookExpanded.bookAuthors
|
||||||
if (ba.author) {
|
.map((ba) => {
|
||||||
return {
|
if (ba.author) {
|
||||||
id: ba.author.id,
|
return {
|
||||||
name: ba.author.name
|
id: ba.author.id,
|
||||||
|
name: ba.author.name
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Logger.error(`[Book] Invalid bookExpanded bookAuthors: no author`, ba)
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
Logger.error(`[Book] Invalid bookExpanded bookAuthors: no author`, ba)
|
.filter((a) => a)
|
||||||
return null
|
|
||||||
}
|
|
||||||
}).filter(a => a)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let series = []
|
let series = []
|
||||||
if (bookExpanded.series?.length) {
|
if (bookExpanded.series?.length) {
|
||||||
series = bookExpanded.series.map(se => {
|
series = bookExpanded.series.map((se) => {
|
||||||
return {
|
return {
|
||||||
id: se.id,
|
id: se.id,
|
||||||
name: se.name,
|
name: se.name,
|
||||||
@ -142,18 +144,20 @@ class Book extends Model {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else if (bookExpanded.bookSeries?.length) {
|
} else if (bookExpanded.bookSeries?.length) {
|
||||||
series = bookExpanded.bookSeries.map(bs => {
|
series = bookExpanded.bookSeries
|
||||||
if (bs.series) {
|
.map((bs) => {
|
||||||
return {
|
if (bs.series) {
|
||||||
id: bs.series.id,
|
return {
|
||||||
name: bs.series.name,
|
id: bs.series.id,
|
||||||
sequence: bs.sequence
|
name: bs.series.name,
|
||||||
|
sequence: bs.sequence
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Logger.error(`[Book] Invalid bookExpanded bookSeries: no series`, bs)
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
Logger.error(`[Book] Invalid bookExpanded bookSeries: no series`, bs)
|
.filter((s) => s)
|
||||||
return null
|
|
||||||
}
|
|
||||||
}).filter(s => s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -185,7 +189,7 @@ class Book extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} oldBook
|
* @param {object} oldBook
|
||||||
* @returns {boolean} true if updated
|
* @returns {boolean} true if updated
|
||||||
*/
|
*/
|
||||||
static saveFromOld(oldBook) {
|
static saveFromOld(oldBook) {
|
||||||
@ -194,10 +198,12 @@ class Book extends Model {
|
|||||||
where: {
|
where: {
|
||||||
id: book.id
|
id: book.id
|
||||||
}
|
}
|
||||||
}).then(result => result[0] > 0).catch((error) => {
|
|
||||||
Logger.error(`[Book] Failed to save book ${book.id}`, error)
|
|
||||||
return false
|
|
||||||
})
|
})
|
||||||
|
.then((result) => result[0] > 0)
|
||||||
|
.catch((error) => {
|
||||||
|
Logger.error(`[Book] Failed to save book ${book.id}`, error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static getFromOld(oldBook) {
|
static getFromOld(oldBook) {
|
||||||
@ -219,7 +225,7 @@ class Book extends Model {
|
|||||||
ebookFile: oldBook.ebookFile?.toJSON() || null,
|
ebookFile: oldBook.ebookFile?.toJSON() || null,
|
||||||
coverPath: oldBook.coverPath,
|
coverPath: oldBook.coverPath,
|
||||||
duration: oldBook.duration,
|
duration: oldBook.duration,
|
||||||
audioFiles: oldBook.audioFiles?.map(af => af.toJSON()) || [],
|
audioFiles: oldBook.audioFiles?.map((af) => af.toJSON()) || [],
|
||||||
chapters: oldBook.chapters,
|
chapters: oldBook.chapters,
|
||||||
tags: oldBook.tags,
|
tags: oldBook.tags,
|
||||||
genres: oldBook.metadata.genres
|
genres: oldBook.metadata.genres
|
||||||
@ -229,12 +235,12 @@ class Book extends Model {
|
|||||||
getAbsMetadataJson() {
|
getAbsMetadataJson() {
|
||||||
return {
|
return {
|
||||||
tags: this.tags || [],
|
tags: this.tags || [],
|
||||||
chapters: this.chapters?.map(c => ({ ...c })) || [],
|
chapters: this.chapters?.map((c) => ({ ...c })) || [],
|
||||||
title: this.title,
|
title: this.title,
|
||||||
subtitle: this.subtitle,
|
subtitle: this.subtitle,
|
||||||
authors: this.authors.map(a => a.name),
|
authors: this.authors.map((a) => a.name),
|
||||||
narrators: this.narrators,
|
narrators: this.narrators,
|
||||||
series: this.series.map(se => {
|
series: this.series.map((se) => {
|
||||||
const sequence = se.bookSeries?.sequence || ''
|
const sequence = se.bookSeries?.sequence || ''
|
||||||
if (!sequence) return se.name
|
if (!sequence) return se.name
|
||||||
return `${se.name} #${sequence}`
|
return `${se.name} #${sequence}`
|
||||||
@ -254,61 +260,66 @@ class Book extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
},
|
primaryKey: true
|
||||||
title: DataTypes.STRING,
|
},
|
||||||
titleIgnorePrefix: DataTypes.STRING,
|
title: DataTypes.STRING,
|
||||||
subtitle: DataTypes.STRING,
|
titleIgnorePrefix: DataTypes.STRING,
|
||||||
publishedYear: DataTypes.STRING,
|
subtitle: DataTypes.STRING,
|
||||||
publishedDate: DataTypes.STRING,
|
publishedYear: DataTypes.STRING,
|
||||||
publisher: DataTypes.STRING,
|
publishedDate: DataTypes.STRING,
|
||||||
description: DataTypes.TEXT,
|
publisher: DataTypes.STRING,
|
||||||
isbn: DataTypes.STRING,
|
description: DataTypes.TEXT,
|
||||||
asin: DataTypes.STRING,
|
isbn: DataTypes.STRING,
|
||||||
language: DataTypes.STRING,
|
asin: DataTypes.STRING,
|
||||||
explicit: DataTypes.BOOLEAN,
|
language: DataTypes.STRING,
|
||||||
abridged: DataTypes.BOOLEAN,
|
explicit: DataTypes.BOOLEAN,
|
||||||
coverPath: DataTypes.STRING,
|
abridged: DataTypes.BOOLEAN,
|
||||||
duration: DataTypes.FLOAT,
|
coverPath: DataTypes.STRING,
|
||||||
|
duration: DataTypes.FLOAT,
|
||||||
|
|
||||||
narrators: DataTypes.JSON,
|
narrators: DataTypes.JSON,
|
||||||
audioFiles: DataTypes.JSON,
|
audioFiles: DataTypes.JSON,
|
||||||
ebookFile: DataTypes.JSON,
|
ebookFile: DataTypes.JSON,
|
||||||
chapters: DataTypes.JSON,
|
chapters: DataTypes.JSON,
|
||||||
tags: DataTypes.JSON,
|
tags: DataTypes.JSON,
|
||||||
genres: DataTypes.JSON
|
genres: DataTypes.JSON
|
||||||
}, {
|
},
|
||||||
sequelize,
|
{
|
||||||
modelName: 'book',
|
sequelize,
|
||||||
indexes: [
|
modelName: 'book',
|
||||||
{
|
indexes: [
|
||||||
fields: [{
|
{
|
||||||
name: 'title',
|
fields: [
|
||||||
collate: 'NOCASE'
|
{
|
||||||
}]
|
name: 'title',
|
||||||
},
|
collate: 'NOCASE'
|
||||||
// {
|
}
|
||||||
// fields: [{
|
]
|
||||||
// name: 'titleIgnorePrefix',
|
},
|
||||||
// collate: 'NOCASE'
|
// {
|
||||||
// }]
|
// fields: [{
|
||||||
// },
|
// name: 'titleIgnorePrefix',
|
||||||
{
|
// collate: 'NOCASE'
|
||||||
fields: ['publishedYear']
|
// }]
|
||||||
},
|
// },
|
||||||
// {
|
{
|
||||||
// fields: ['duration']
|
fields: ['publishedYear']
|
||||||
// }
|
}
|
||||||
]
|
// {
|
||||||
})
|
// fields: ['duration']
|
||||||
|
// }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Book
|
module.exports = Book
|
||||||
|
@ -25,21 +25,24 @@ class BookAuthor extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequelize,
|
||||||
|
modelName: 'bookAuthor',
|
||||||
|
timestamps: true,
|
||||||
|
updatedAt: false
|
||||||
}
|
}
|
||||||
}, {
|
)
|
||||||
sequelize,
|
|
||||||
modelName: 'bookAuthor',
|
|
||||||
timestamps: true,
|
|
||||||
updatedAt: false
|
|
||||||
})
|
|
||||||
|
|
||||||
// Super Many-to-Many
|
// 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
|
// ref: https://sequelize.org/docs/v6/advanced-association-concepts/advanced-many-to-many/#the-best-of-both-worlds-the-super-many-to-many-relationship
|
||||||
@ -58,4 +61,4 @@ class BookAuthor extends Model {
|
|||||||
BookAuthor.belongsTo(author)
|
BookAuthor.belongsTo(author)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = BookAuthor
|
module.exports = BookAuthor
|
||||||
|
@ -27,22 +27,25 @@ class BookSeries extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
sequence: DataTypes.STRING
|
||||||
},
|
},
|
||||||
sequence: DataTypes.STRING
|
{
|
||||||
}, {
|
sequelize,
|
||||||
sequelize,
|
modelName: 'bookSeries',
|
||||||
modelName: 'bookSeries',
|
timestamps: true,
|
||||||
timestamps: true,
|
updatedAt: false
|
||||||
updatedAt: false
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
// Super Many-to-Many
|
// 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
|
// ref: https://sequelize.org/docs/v6/advanced-association-concepts/advanced-many-to-many/#the-best-of-both-worlds-the-super-many-to-many-relationship
|
||||||
@ -62,4 +65,4 @@ class BookSeries extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BookSeries
|
module.exports = BookSeries
|
||||||
|
@ -2,7 +2,6 @@ const { DataTypes, Model, Sequelize } = require('sequelize')
|
|||||||
|
|
||||||
const oldCollection = require('../objects/Collection')
|
const oldCollection = require('../objects/Collection')
|
||||||
|
|
||||||
|
|
||||||
class Collection extends Model {
|
class Collection extends Model {
|
||||||
constructor(values, options) {
|
constructor(values, options) {
|
||||||
super(values, options)
|
super(values, options)
|
||||||
@ -20,27 +19,13 @@ class Collection extends Model {
|
|||||||
/** @type {Date} */
|
/** @type {Date} */
|
||||||
this.createdAt
|
this.createdAt
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Get all old collections
|
|
||||||
* @returns {Promise<oldCollection[]>}
|
|
||||||
*/
|
|
||||||
static async getOldCollections() {
|
|
||||||
const collections = await this.findAll({
|
|
||||||
include: {
|
|
||||||
model: this.sequelize.models.book,
|
|
||||||
include: this.sequelize.models.libraryItem
|
|
||||||
},
|
|
||||||
order: [[this.sequelize.models.book, this.sequelize.models.collectionBook, 'order', 'ASC']]
|
|
||||||
})
|
|
||||||
return collections.map(c => this.getOldCollection(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all old collections toJSONExpanded, items filtered for user permissions
|
* Get all old collections toJSONExpanded, items filtered for user permissions
|
||||||
* @param {[oldUser]} user
|
* @param {oldUser} [user]
|
||||||
* @param {[string]} libraryId
|
* @param {string} [libraryId]
|
||||||
* @param {[string[]]} include
|
* @param {string[]} [include]
|
||||||
* @returns {Promise<object[]>} oldCollection.toJSONExpanded
|
* @returns {Promise<oldCollection[]>} oldCollection.toJSONExpanded
|
||||||
*/
|
*/
|
||||||
static async getOldCollectionsJsonExpanded(user, libraryId, include) {
|
static async getOldCollectionsJsonExpanded(user, libraryId, include) {
|
||||||
let collectionWhere = null
|
let collectionWhere = null
|
||||||
@ -78,8 +63,7 @@ class Collection extends Model {
|
|||||||
through: {
|
through: {
|
||||||
attributes: ['sequence']
|
attributes: ['sequence']
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
...collectionIncludes
|
...collectionIncludes
|
||||||
@ -87,11 +71,84 @@ class Collection extends Model {
|
|||||||
order: [[this.sequelize.models.book, this.sequelize.models.collectionBook, 'order', 'ASC']]
|
order: [[this.sequelize.models.book, this.sequelize.models.collectionBook, 'order', 'ASC']]
|
||||||
})
|
})
|
||||||
// TODO: Handle user permission restrictions on initial query
|
// TODO: Handle user permission restrictions on initial query
|
||||||
return collections.map(c => {
|
return collections
|
||||||
const oldCollection = this.getOldCollection(c)
|
.map((c) => {
|
||||||
|
const oldCollection = this.getOldCollection(c)
|
||||||
|
|
||||||
// Filter books using user permissions
|
// Filter books using user permissions
|
||||||
const books = c.books?.filter(b => {
|
const books =
|
||||||
|
c.books?.filter((b) => {
|
||||||
|
if (user) {
|
||||||
|
if (b.tags?.length && !user.checkCanAccessLibraryItemWithTags(b.tags)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (b.explicit === true && !user.canAccessExplicitContent) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}) || []
|
||||||
|
|
||||||
|
// Map to library items
|
||||||
|
const libraryItems = books.map((b) => {
|
||||||
|
const libraryItem = b.libraryItem
|
||||||
|
delete b.libraryItem
|
||||||
|
libraryItem.media = b
|
||||||
|
return this.sequelize.models.libraryItem.getOldLibraryItem(libraryItem)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Users with restricted permissions will not see this collection
|
||||||
|
if (!books.length && oldCollection.books.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const collectionExpanded = oldCollection.toJSONExpanded(libraryItems)
|
||||||
|
|
||||||
|
// Map feed if found
|
||||||
|
if (c.feeds?.length) {
|
||||||
|
collectionExpanded.rssFeed = this.sequelize.models.feed.getOldFeed(c.feeds[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return collectionExpanded
|
||||||
|
})
|
||||||
|
.filter((c) => c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get old collection toJSONExpanded, items filtered for user permissions
|
||||||
|
* @param {oldUser} [user]
|
||||||
|
* @param {string[]} [include]
|
||||||
|
* @returns {Promise<oldCollection>} oldCollection.toJSONExpanded
|
||||||
|
*/
|
||||||
|
async getOldJsonExpanded(user, include) {
|
||||||
|
this.books =
|
||||||
|
(await this.getBooks({
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: this.sequelize.models.libraryItem
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: this.sequelize.models.author,
|
||||||
|
through: {
|
||||||
|
attributes: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: this.sequelize.models.series,
|
||||||
|
through: {
|
||||||
|
attributes: ['sequence']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
order: [Sequelize.literal('`collectionBook.order` ASC')]
|
||||||
|
})) || []
|
||||||
|
|
||||||
|
const oldCollection = this.sequelize.models.collection.getOldCollection(this)
|
||||||
|
|
||||||
|
// Filter books using user permissions
|
||||||
|
// TODO: Handle user permission restrictions on initial query
|
||||||
|
const books =
|
||||||
|
this.books?.filter((b) => {
|
||||||
if (user) {
|
if (user) {
|
||||||
if (b.tags?.length && !user.checkCanAccessLibraryItemWithTags(b.tags)) {
|
if (b.tags?.length && !user.checkCanAccessLibraryItemWithTags(b.tags)) {
|
||||||
return false
|
return false
|
||||||
@ -103,77 +160,8 @@ class Collection extends Model {
|
|||||||
return true
|
return true
|
||||||
}) || []
|
}) || []
|
||||||
|
|
||||||
// Map to library items
|
|
||||||
const libraryItems = books.map(b => {
|
|
||||||
const libraryItem = b.libraryItem
|
|
||||||
delete b.libraryItem
|
|
||||||
libraryItem.media = b
|
|
||||||
return this.sequelize.models.libraryItem.getOldLibraryItem(libraryItem)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Users with restricted permissions will not see this collection
|
|
||||||
if (!books.length && oldCollection.books.length) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const collectionExpanded = oldCollection.toJSONExpanded(libraryItems)
|
|
||||||
|
|
||||||
// Map feed if found
|
|
||||||
if (c.feeds?.length) {
|
|
||||||
collectionExpanded.rssFeed = this.sequelize.models.feed.getOldFeed(c.feeds[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
return collectionExpanded
|
|
||||||
}).filter(c => c)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get old collection toJSONExpanded, items filtered for user permissions
|
|
||||||
* @param {[oldUser]} user
|
|
||||||
* @param {[string[]]} include
|
|
||||||
* @returns {Promise<object>} oldCollection.toJSONExpanded
|
|
||||||
*/
|
|
||||||
async getOldJsonExpanded(user, include) {
|
|
||||||
this.books = await this.getBooks({
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: this.sequelize.models.libraryItem
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: this.sequelize.models.author,
|
|
||||||
through: {
|
|
||||||
attributes: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: this.sequelize.models.series,
|
|
||||||
through: {
|
|
||||||
attributes: ['sequence']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
],
|
|
||||||
order: [Sequelize.literal('`collectionBook.order` ASC')]
|
|
||||||
}) || []
|
|
||||||
|
|
||||||
const oldCollection = this.sequelize.models.collection.getOldCollection(this)
|
|
||||||
|
|
||||||
// Filter books using user permissions
|
|
||||||
// TODO: Handle user permission restrictions on initial query
|
|
||||||
const books = this.books?.filter(b => {
|
|
||||||
if (user) {
|
|
||||||
if (b.tags?.length && !user.checkCanAccessLibraryItemWithTags(b.tags)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (b.explicit === true && !user.canAccessExplicitContent) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}) || []
|
|
||||||
|
|
||||||
// Map to library items
|
// Map to library items
|
||||||
const libraryItems = books.map(b => {
|
const libraryItems = books.map((b) => {
|
||||||
const libraryItem = b.libraryItem
|
const libraryItem = b.libraryItem
|
||||||
delete b.libraryItem
|
delete b.libraryItem
|
||||||
libraryItem.media = b
|
libraryItem.media = b
|
||||||
@ -199,11 +187,11 @@ class Collection extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get old collection from Collection
|
* Get old collection from Collection
|
||||||
* @param {Collection} collectionExpanded
|
* @param {Collection} collectionExpanded
|
||||||
* @returns {oldCollection}
|
* @returns {oldCollection}
|
||||||
*/
|
*/
|
||||||
static getOldCollection(collectionExpanded) {
|
static getOldCollection(collectionExpanded) {
|
||||||
const libraryItemIds = collectionExpanded.books?.map(b => b.libraryItem?.id || null).filter(lid => lid) || []
|
const libraryItemIds = collectionExpanded.books?.map((b) => b.libraryItem?.id || null).filter((lid) => lid) || []
|
||||||
return new oldCollection({
|
return new oldCollection({
|
||||||
id: collectionExpanded.id,
|
id: collectionExpanded.id,
|
||||||
libraryId: collectionExpanded.libraryId,
|
libraryId: collectionExpanded.libraryId,
|
||||||
@ -215,6 +203,11 @@ class Collection extends Model {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {oldCollection} oldCollection
|
||||||
|
* @returns {Promise<Collection>}
|
||||||
|
*/
|
||||||
static createFromOld(oldCollection) {
|
static createFromOld(oldCollection) {
|
||||||
const collection = this.getFromOld(oldCollection)
|
const collection = this.getFromOld(oldCollection)
|
||||||
return this.create(collection)
|
return this.create(collection)
|
||||||
@ -239,7 +232,7 @@ class Collection extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get old collection by id
|
* Get old collection by id
|
||||||
* @param {string} collectionId
|
* @param {string} collectionId
|
||||||
* @returns {Promise<oldCollection|null>} returns null if not found
|
* @returns {Promise<oldCollection|null>} returns null if not found
|
||||||
*/
|
*/
|
||||||
static async getOldById(collectionId) {
|
static async getOldById(collectionId) {
|
||||||
@ -260,34 +253,34 @@ class Collection extends Model {
|
|||||||
* @returns {Promise<oldCollection>}
|
* @returns {Promise<oldCollection>}
|
||||||
*/
|
*/
|
||||||
async getOld() {
|
async getOld() {
|
||||||
this.books = await this.getBooks({
|
this.books =
|
||||||
include: [
|
(await this.getBooks({
|
||||||
{
|
include: [
|
||||||
model: this.sequelize.models.libraryItem
|
{
|
||||||
},
|
model: this.sequelize.models.libraryItem
|
||||||
{
|
},
|
||||||
model: this.sequelize.models.author,
|
{
|
||||||
through: {
|
model: this.sequelize.models.author,
|
||||||
attributes: []
|
through: {
|
||||||
|
attributes: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: this.sequelize.models.series,
|
||||||
|
through: {
|
||||||
|
attributes: ['sequence']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
],
|
||||||
{
|
order: [Sequelize.literal('`collectionBook.order` ASC')]
|
||||||
model: this.sequelize.models.series,
|
})) || []
|
||||||
through: {
|
|
||||||
attributes: ['sequence']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
],
|
|
||||||
order: [Sequelize.literal('`collectionBook.order` ASC')]
|
|
||||||
}) || []
|
|
||||||
|
|
||||||
return this.sequelize.models.collection.getOldCollection(this)
|
return this.sequelize.models.collection.getOldCollection(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all collections belonging to library
|
* Remove all collections belonging to library
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @returns {Promise<number>} number of collections destroyed
|
* @returns {Promise<number>} number of collections destroyed
|
||||||
*/
|
*/
|
||||||
static async removeAllForLibrary(libraryId) {
|
static async removeAllForLibrary(libraryId) {
|
||||||
@ -299,38 +292,26 @@ class Collection extends Model {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getAllForBook(bookId) {
|
|
||||||
const collections = await this.findAll({
|
|
||||||
include: {
|
|
||||||
model: this.sequelize.models.book,
|
|
||||||
where: {
|
|
||||||
id: bookId
|
|
||||||
},
|
|
||||||
required: true,
|
|
||||||
include: this.sequelize.models.libraryItem
|
|
||||||
},
|
|
||||||
order: [[this.sequelize.models.book, this.sequelize.models.collectionBook, 'order', 'ASC']]
|
|
||||||
})
|
|
||||||
return collections.map(c => this.getOldCollection(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
name: DataTypes.STRING,
|
||||||
|
description: DataTypes.TEXT
|
||||||
},
|
},
|
||||||
name: DataTypes.STRING,
|
{
|
||||||
description: DataTypes.TEXT
|
sequelize,
|
||||||
}, {
|
modelName: 'collection'
|
||||||
sequelize,
|
}
|
||||||
modelName: 'collection'
|
)
|
||||||
})
|
|
||||||
|
|
||||||
const { library } = sequelize.models
|
const { library } = sequelize.models
|
||||||
|
|
||||||
@ -339,4 +320,4 @@ class Collection extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Collection
|
module.exports = Collection
|
||||||
|
@ -26,19 +26,22 @@ class CollectionBook extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
order: DataTypes.INTEGER
|
||||||
},
|
},
|
||||||
order: DataTypes.INTEGER
|
{
|
||||||
}, {
|
sequelize,
|
||||||
sequelize,
|
timestamps: true,
|
||||||
timestamps: true,
|
updatedAt: false,
|
||||||
updatedAt: false,
|
modelName: 'collectionBook'
|
||||||
modelName: 'collectionBook'
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
// Super Many-to-Many
|
// 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
|
// ref: https://sequelize.org/docs/v6/advanced-association-concepts/advanced-many-to-many/#the-best-of-both-worlds-the-super-many-to-many-relationship
|
||||||
@ -58,4 +61,4 @@ class CollectionBook extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = CollectionBook
|
module.exports = CollectionBook
|
||||||
|
@ -114,26 +114,29 @@ class Device extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
deviceId: DataTypes.STRING,
|
||||||
|
clientName: DataTypes.STRING, // e.g. Abs Web, Abs Android
|
||||||
|
clientVersion: DataTypes.STRING, // e.g. Server version or mobile version
|
||||||
|
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
|
||||||
|
extraData: DataTypes.JSON
|
||||||
},
|
},
|
||||||
deviceId: DataTypes.STRING,
|
{
|
||||||
clientName: DataTypes.STRING, // e.g. Abs Web, Abs Android
|
sequelize,
|
||||||
clientVersion: DataTypes.STRING, // e.g. Server version or mobile version
|
modelName: 'device'
|
||||||
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
|
|
||||||
extraData: DataTypes.JSON
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'device'
|
|
||||||
})
|
|
||||||
|
|
||||||
const { user } = sequelize.models
|
const { user } = sequelize.models
|
||||||
|
|
||||||
@ -144,4 +147,4 @@ class Device extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Device
|
module.exports = Device
|
||||||
|
@ -58,7 +58,7 @@ class Feed extends Model {
|
|||||||
model: this.sequelize.models.feedEpisode
|
model: this.sequelize.models.feedEpisode
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return feeds.map(f => this.getOldFeed(f))
|
return feeds.map((f) => this.getOldFeed(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,7 +117,7 @@ class Feed extends Model {
|
|||||||
entityType: 'libraryItem'
|
entityType: 'libraryItem'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return feeds.map(f => f.entityId).filter(f => f) || []
|
return feeds.map((f) => f.entityId).filter((f) => f) || []
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -179,7 +179,7 @@ class Feed extends Model {
|
|||||||
|
|
||||||
// Remove and update existing feed episodes
|
// Remove and update existing feed episodes
|
||||||
for (const feedEpisode of existingFeed.feedEpisodes) {
|
for (const feedEpisode of existingFeed.feedEpisodes) {
|
||||||
const oldFeedEpisode = oldFeedEpisodes.find(ep => ep.id === feedEpisode.id)
|
const oldFeedEpisode = oldFeedEpisodes.find((ep) => ep.id === feedEpisode.id)
|
||||||
// Episode removed
|
// Episode removed
|
||||||
if (!oldFeedEpisode) {
|
if (!oldFeedEpisode) {
|
||||||
feedEpisode.destroy()
|
feedEpisode.destroy()
|
||||||
@ -200,7 +200,7 @@ class Feed extends Model {
|
|||||||
|
|
||||||
// Add new feed episodes
|
// Add new feed episodes
|
||||||
for (const episode of oldFeedEpisodes) {
|
for (const episode of oldFeedEpisodes) {
|
||||||
if (!existingFeed.feedEpisodes.some(fe => fe.id === episode.id)) {
|
if (!existingFeed.feedEpisodes.some((fe) => fe.id === episode.id)) {
|
||||||
await this.sequelize.models.feedEpisode.createFromOld(feedObj.id, episode)
|
await this.sequelize.models.feedEpisode.createFromOld(feedObj.id, episode)
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
}
|
}
|
||||||
@ -258,41 +258,44 @@ class Feed extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
*
|
*
|
||||||
* Polymorphic association: Feeds can be created from LibraryItem, Collection, Playlist or Series
|
* Polymorphic association: Feeds can be created from LibraryItem, Collection, Playlist or Series
|
||||||
* @see https://sequelize.org/docs/v6/advanced-association-concepts/polymorphic-associations/
|
* @see https://sequelize.org/docs/v6/advanced-association-concepts/polymorphic-associations/
|
||||||
*
|
*
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
slug: DataTypes.STRING,
|
||||||
|
entityType: DataTypes.STRING,
|
||||||
|
entityId: DataTypes.UUIDV4,
|
||||||
|
entityUpdatedAt: DataTypes.DATE,
|
||||||
|
serverAddress: DataTypes.STRING,
|
||||||
|
feedURL: DataTypes.STRING,
|
||||||
|
imageURL: DataTypes.STRING,
|
||||||
|
siteURL: DataTypes.STRING,
|
||||||
|
title: DataTypes.STRING,
|
||||||
|
description: DataTypes.TEXT,
|
||||||
|
author: DataTypes.STRING,
|
||||||
|
podcastType: DataTypes.STRING,
|
||||||
|
language: DataTypes.STRING,
|
||||||
|
ownerName: DataTypes.STRING,
|
||||||
|
ownerEmail: DataTypes.STRING,
|
||||||
|
explicit: DataTypes.BOOLEAN,
|
||||||
|
preventIndexing: DataTypes.BOOLEAN,
|
||||||
|
coverPath: DataTypes.STRING
|
||||||
},
|
},
|
||||||
slug: DataTypes.STRING,
|
{
|
||||||
entityType: DataTypes.STRING,
|
sequelize,
|
||||||
entityId: DataTypes.UUIDV4,
|
modelName: 'feed'
|
||||||
entityUpdatedAt: DataTypes.DATE,
|
}
|
||||||
serverAddress: DataTypes.STRING,
|
)
|
||||||
feedURL: DataTypes.STRING,
|
|
||||||
imageURL: DataTypes.STRING,
|
|
||||||
siteURL: DataTypes.STRING,
|
|
||||||
title: DataTypes.STRING,
|
|
||||||
description: DataTypes.TEXT,
|
|
||||||
author: DataTypes.STRING,
|
|
||||||
podcastType: DataTypes.STRING,
|
|
||||||
language: DataTypes.STRING,
|
|
||||||
ownerName: DataTypes.STRING,
|
|
||||||
ownerEmail: DataTypes.STRING,
|
|
||||||
explicit: DataTypes.BOOLEAN,
|
|
||||||
preventIndexing: DataTypes.BOOLEAN,
|
|
||||||
coverPath: DataTypes.STRING
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'feed'
|
|
||||||
})
|
|
||||||
|
|
||||||
const { user, libraryItem, collection, series, playlist } = sequelize.models
|
const { user, libraryItem, collection, series, playlist } = sequelize.models
|
||||||
|
|
||||||
@ -335,7 +338,7 @@ class Feed extends Model {
|
|||||||
})
|
})
|
||||||
Feed.belongsTo(playlist, { foreignKey: 'entityId', constraints: false })
|
Feed.belongsTo(playlist, { foreignKey: 'entityId', constraints: false })
|
||||||
|
|
||||||
Feed.addHook('afterFind', findResult => {
|
Feed.addHook('afterFind', (findResult) => {
|
||||||
if (!findResult) return
|
if (!findResult) return
|
||||||
|
|
||||||
if (!Array.isArray(findResult)) findResult = [findResult]
|
if (!Array.isArray(findResult)) findResult = [findResult]
|
||||||
@ -368,4 +371,4 @@ class Feed extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Feed
|
module.exports = Feed
|
||||||
|
@ -65,9 +65,9 @@ class FeedEpisode extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create feed episode from old model
|
* Create feed episode from old model
|
||||||
*
|
*
|
||||||
* @param {string} feedId
|
* @param {string} feedId
|
||||||
* @param {Object} oldFeedEpisode
|
* @param {Object} oldFeedEpisode
|
||||||
* @returns {Promise<FeedEpisode>}
|
* @returns {Promise<FeedEpisode>}
|
||||||
*/
|
*/
|
||||||
static createFromOld(feedId, oldFeedEpisode) {
|
static createFromOld(feedId, oldFeedEpisode) {
|
||||||
@ -98,33 +98,36 @@ class FeedEpisode extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
title: DataTypes.STRING,
|
||||||
|
author: DataTypes.STRING,
|
||||||
|
description: DataTypes.TEXT,
|
||||||
|
siteURL: DataTypes.STRING,
|
||||||
|
enclosureURL: DataTypes.STRING,
|
||||||
|
enclosureType: DataTypes.STRING,
|
||||||
|
enclosureSize: DataTypes.BIGINT,
|
||||||
|
pubDate: DataTypes.STRING,
|
||||||
|
season: DataTypes.STRING,
|
||||||
|
episode: DataTypes.STRING,
|
||||||
|
episodeType: DataTypes.STRING,
|
||||||
|
duration: DataTypes.FLOAT,
|
||||||
|
filePath: DataTypes.STRING,
|
||||||
|
explicit: DataTypes.BOOLEAN
|
||||||
},
|
},
|
||||||
title: DataTypes.STRING,
|
{
|
||||||
author: DataTypes.STRING,
|
sequelize,
|
||||||
description: DataTypes.TEXT,
|
modelName: 'feedEpisode'
|
||||||
siteURL: DataTypes.STRING,
|
}
|
||||||
enclosureURL: DataTypes.STRING,
|
)
|
||||||
enclosureType: DataTypes.STRING,
|
|
||||||
enclosureSize: DataTypes.BIGINT,
|
|
||||||
pubDate: DataTypes.STRING,
|
|
||||||
season: DataTypes.STRING,
|
|
||||||
episode: DataTypes.STRING,
|
|
||||||
episodeType: DataTypes.STRING,
|
|
||||||
duration: DataTypes.FLOAT,
|
|
||||||
filePath: DataTypes.STRING,
|
|
||||||
explicit: DataTypes.BOOLEAN
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'feedEpisode'
|
|
||||||
})
|
|
||||||
|
|
||||||
const { feed } = sequelize.models
|
const { feed } = sequelize.models
|
||||||
|
|
||||||
@ -135,4 +138,4 @@ class FeedEpisode extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = FeedEpisode
|
module.exports = FeedEpisode
|
||||||
|
@ -10,7 +10,7 @@ const oldLibrary = require('../objects/Library')
|
|||||||
* @property {boolean} skipMatchingMediaWithIsbn
|
* @property {boolean} skipMatchingMediaWithIsbn
|
||||||
* @property {string} autoScanCronExpression
|
* @property {string} autoScanCronExpression
|
||||||
* @property {boolean} audiobooksOnly
|
* @property {boolean} audiobooksOnly
|
||||||
* @property {boolean} hideSingleBookSeries Do not show series that only have 1 book
|
* @property {boolean} hideSingleBookSeries Do not show series that only have 1 book
|
||||||
* @property {boolean} onlyShowLaterBooksInContinueSeries Skip showing books that are earlier than the max sequence read
|
* @property {boolean} onlyShowLaterBooksInContinueSeries Skip showing books that are earlier than the max sequence read
|
||||||
* @property {string[]} metadataPrecedence
|
* @property {string[]} metadataPrecedence
|
||||||
*/
|
*/
|
||||||
@ -54,16 +54,16 @@ class Library extends Model {
|
|||||||
include: this.sequelize.models.libraryFolder,
|
include: this.sequelize.models.libraryFolder,
|
||||||
order: [['displayOrder', 'ASC']]
|
order: [['displayOrder', 'ASC']]
|
||||||
})
|
})
|
||||||
return libraries.map(lib => this.getOldLibrary(lib))
|
return libraries.map((lib) => this.getOldLibrary(lib))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert expanded Library to oldLibrary
|
* Convert expanded Library to oldLibrary
|
||||||
* @param {Library} libraryExpanded
|
* @param {Library} libraryExpanded
|
||||||
* @returns {Promise<oldLibrary>}
|
* @returns {Promise<oldLibrary>}
|
||||||
*/
|
*/
|
||||||
static getOldLibrary(libraryExpanded) {
|
static getOldLibrary(libraryExpanded) {
|
||||||
const folders = libraryExpanded.libraryFolders.map(folder => {
|
const folders = libraryExpanded.libraryFolders.map((folder) => {
|
||||||
return {
|
return {
|
||||||
id: folder.id,
|
id: folder.id,
|
||||||
fullPath: folder.path,
|
fullPath: folder.path,
|
||||||
@ -90,13 +90,13 @@ class Library extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} oldLibrary
|
* @param {object} oldLibrary
|
||||||
* @returns {Library|null}
|
* @returns {Library|null}
|
||||||
*/
|
*/
|
||||||
static async createFromOld(oldLibrary) {
|
static async createFromOld(oldLibrary) {
|
||||||
const library = this.getFromOld(oldLibrary)
|
const library = this.getFromOld(oldLibrary)
|
||||||
|
|
||||||
library.libraryFolders = oldLibrary.folders.map(folder => {
|
library.libraryFolders = oldLibrary.folders.map((folder) => {
|
||||||
return {
|
return {
|
||||||
id: folder.id,
|
id: folder.id,
|
||||||
path: folder.fullPath
|
path: folder.fullPath
|
||||||
@ -113,8 +113,8 @@ class Library extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update library and library folders
|
* Update library and library folders
|
||||||
* @param {object} oldLibrary
|
* @param {object} oldLibrary
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
static async updateFromOld(oldLibrary) {
|
static async updateFromOld(oldLibrary) {
|
||||||
const existingLibrary = await this.findByPk(oldLibrary.id, {
|
const existingLibrary = await this.findByPk(oldLibrary.id, {
|
||||||
@ -127,7 +127,7 @@ class Library extends Model {
|
|||||||
|
|
||||||
const library = this.getFromOld(oldLibrary)
|
const library = this.getFromOld(oldLibrary)
|
||||||
|
|
||||||
const libraryFolders = oldLibrary.folders.map(folder => {
|
const libraryFolders = oldLibrary.folders.map((folder) => {
|
||||||
return {
|
return {
|
||||||
id: folder.id,
|
id: folder.id,
|
||||||
path: folder.fullPath,
|
path: folder.fullPath,
|
||||||
@ -135,7 +135,7 @@ class Library extends Model {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
for (const libraryFolder of libraryFolders) {
|
for (const libraryFolder of libraryFolders) {
|
||||||
const existingLibraryFolder = existingLibrary.libraryFolders.find(lf => lf.id === libraryFolder.id)
|
const existingLibraryFolder = existingLibrary.libraryFolders.find((lf) => lf.id === libraryFolder.id)
|
||||||
if (!existingLibraryFolder) {
|
if (!existingLibraryFolder) {
|
||||||
await this.sequelize.models.libraryFolder.create(libraryFolder)
|
await this.sequelize.models.libraryFolder.create(libraryFolder)
|
||||||
} else if (existingLibraryFolder.path !== libraryFolder.path) {
|
} else if (existingLibraryFolder.path !== libraryFolder.path) {
|
||||||
@ -143,7 +143,7 @@ class Library extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const libraryFoldersRemoved = existingLibrary.libraryFolders.filter(lf => !libraryFolders.some(_lf => _lf.id === lf.id))
|
const libraryFoldersRemoved = existingLibrary.libraryFolders.filter((lf) => !libraryFolders.some((_lf) => _lf.id === lf.id))
|
||||||
for (const existingLibraryFolder of libraryFoldersRemoved) {
|
for (const existingLibraryFolder of libraryFoldersRemoved) {
|
||||||
await existingLibraryFolder.destroy()
|
await existingLibraryFolder.destroy()
|
||||||
}
|
}
|
||||||
@ -177,8 +177,8 @@ class Library extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy library by id
|
* Destroy library by id
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
static removeById(libraryId) {
|
static removeById(libraryId) {
|
||||||
return this.destroy({
|
return this.destroy({
|
||||||
@ -197,12 +197,12 @@ class Library extends Model {
|
|||||||
attributes: ['id', 'displayOrder'],
|
attributes: ['id', 'displayOrder'],
|
||||||
order: [['displayOrder', 'ASC']]
|
order: [['displayOrder', 'ASC']]
|
||||||
})
|
})
|
||||||
return libraries.map(l => l.id)
|
return libraries.map((l) => l.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find Library by primary key & return oldLibrary
|
* Find Library by primary key & return oldLibrary
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @returns {Promise<oldLibrary|null>} Returns null if not found
|
* @returns {Promise<oldLibrary|null>} Returns null if not found
|
||||||
*/
|
*/
|
||||||
static async getOldById(libraryId) {
|
static async getOldById(libraryId) {
|
||||||
@ -244,29 +244,32 @@ class Library extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
name: DataTypes.STRING,
|
||||||
|
displayOrder: DataTypes.INTEGER,
|
||||||
|
icon: DataTypes.STRING,
|
||||||
|
mediaType: DataTypes.STRING,
|
||||||
|
provider: DataTypes.STRING,
|
||||||
|
lastScan: DataTypes.DATE,
|
||||||
|
lastScanVersion: DataTypes.STRING,
|
||||||
|
settings: DataTypes.JSON,
|
||||||
|
extraData: DataTypes.JSON
|
||||||
},
|
},
|
||||||
name: DataTypes.STRING,
|
{
|
||||||
displayOrder: DataTypes.INTEGER,
|
sequelize,
|
||||||
icon: DataTypes.STRING,
|
modelName: 'library'
|
||||||
mediaType: DataTypes.STRING,
|
}
|
||||||
provider: DataTypes.STRING,
|
)
|
||||||
lastScan: DataTypes.DATE,
|
|
||||||
lastScanVersion: DataTypes.STRING,
|
|
||||||
settings: DataTypes.JSON,
|
|
||||||
extraData: DataTypes.JSON
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'library'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Library
|
module.exports = Library
|
||||||
|
@ -16,33 +16,25 @@ class LibraryFolder extends Model {
|
|||||||
this.updatedAt
|
this.updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets all library folder path strings
|
|
||||||
* @returns {Promise<string[]>} array of library folder paths
|
|
||||||
*/
|
|
||||||
static async getAllLibraryFolderPaths() {
|
|
||||||
const libraryFolders = await this.findAll({
|
|
||||||
attributes: ['path']
|
|
||||||
})
|
|
||||||
return libraryFolders.map(l => l.path)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
path: DataTypes.STRING
|
||||||
},
|
},
|
||||||
path: DataTypes.STRING
|
{
|
||||||
}, {
|
sequelize,
|
||||||
sequelize,
|
modelName: 'libraryFolder'
|
||||||
modelName: 'libraryFolder'
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
const { library } = sequelize.models
|
const { library } = sequelize.models
|
||||||
library.hasMany(LibraryFolder, {
|
library.hasMany(LibraryFolder, {
|
||||||
@ -52,4 +44,4 @@ class LibraryFolder extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = LibraryFolder
|
module.exports = LibraryFolder
|
||||||
|
@ -21,8 +21,8 @@ const Podcast = require('./Podcast')
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef LibraryItemExpandedProperties
|
* @typedef LibraryItemExpandedProperties
|
||||||
* @property {Book.BookExpanded|Podcast.PodcastExpanded} media
|
* @property {Book.BookExpanded|Podcast.PodcastExpanded} media
|
||||||
*
|
*
|
||||||
* @typedef {LibraryItem & LibraryItemExpandedProperties} LibraryItemExpanded
|
* @typedef {LibraryItem & LibraryItemExpandedProperties} LibraryItemExpanded
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ class LibraryItem extends Model {
|
|||||||
/**
|
/**
|
||||||
* Gets library items partially expanded, not including podcast episodes
|
* Gets library items partially expanded, not including podcast episodes
|
||||||
* @todo temporary solution
|
* @todo temporary solution
|
||||||
*
|
*
|
||||||
* @param {number} offset
|
* @param {number} offset
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {Promise<LibraryItem[]>} LibraryItem
|
* @returns {Promise<LibraryItem[]>} LibraryItem
|
||||||
@ -154,13 +154,13 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
return libraryItems.map(ti => this.getOldLibraryItem(ti))
|
return libraryItems.map((ti) => this.getOldLibraryItem(ti))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an expanded LibraryItem into an old library item
|
* Convert an expanded LibraryItem into an old library item
|
||||||
*
|
*
|
||||||
* @param {Model<LibraryItem>} libraryItemExpanded
|
* @param {Model<LibraryItem>} libraryItemExpanded
|
||||||
* @returns {oldLibraryItem}
|
* @returns {oldLibraryItem}
|
||||||
*/
|
*/
|
||||||
static getOldLibraryItem(libraryItemExpanded) {
|
static getOldLibraryItem(libraryItemExpanded) {
|
||||||
@ -231,8 +231,8 @@ class LibraryItem extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates libraryItem, book, authors and series from old library item
|
* Updates libraryItem, book, authors and series from old library item
|
||||||
*
|
*
|
||||||
* @param {oldLibraryItem} oldLibraryItem
|
* @param {oldLibraryItem} oldLibraryItem
|
||||||
* @returns {Promise<boolean>} true if updates were made
|
* @returns {Promise<boolean>} true if updates were made
|
||||||
*/
|
*/
|
||||||
static async fullUpdateFromOld(oldLibraryItem) {
|
static async fullUpdateFromOld(oldLibraryItem) {
|
||||||
@ -280,14 +280,14 @@ class LibraryItem extends Model {
|
|||||||
|
|
||||||
for (const existingPodcastEpisode of existingPodcastEpisodes) {
|
for (const existingPodcastEpisode of existingPodcastEpisodes) {
|
||||||
// Episode was removed
|
// Episode was removed
|
||||||
if (!updatedPodcastEpisodes.some(ep => ep.id === existingPodcastEpisode.id)) {
|
if (!updatedPodcastEpisodes.some((ep) => ep.id === existingPodcastEpisode.id)) {
|
||||||
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" episode "${existingPodcastEpisode.title}" was removed`)
|
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" episode "${existingPodcastEpisode.title}" was removed`)
|
||||||
await existingPodcastEpisode.destroy()
|
await existingPodcastEpisode.destroy()
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const updatedPodcastEpisode of updatedPodcastEpisodes) {
|
for (const updatedPodcastEpisode of updatedPodcastEpisodes) {
|
||||||
const existingEpisodeMatch = existingPodcastEpisodes.find(ep => ep.id === updatedPodcastEpisode.id)
|
const existingEpisodeMatch = existingPodcastEpisodes.find((ep) => ep.id === updatedPodcastEpisode.id)
|
||||||
if (!existingEpisodeMatch) {
|
if (!existingEpisodeMatch) {
|
||||||
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" episode "${updatedPodcastEpisode.title}" was added`)
|
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" episode "${updatedPodcastEpisode.title}" was added`)
|
||||||
await this.sequelize.models.podcastEpisode.createFromOld(updatedPodcastEpisode)
|
await this.sequelize.models.podcastEpisode.createFromOld(updatedPodcastEpisode)
|
||||||
@ -316,12 +316,12 @@ class LibraryItem extends Model {
|
|||||||
const existingAuthors = libraryItemExpanded.media.authors || []
|
const existingAuthors = libraryItemExpanded.media.authors || []
|
||||||
const existingSeriesAll = libraryItemExpanded.media.series || []
|
const existingSeriesAll = libraryItemExpanded.media.series || []
|
||||||
const updatedAuthors = oldLibraryItem.media.metadata.authors || []
|
const updatedAuthors = oldLibraryItem.media.metadata.authors || []
|
||||||
const uniqueUpdatedAuthors = updatedAuthors.filter((au, idx) => updatedAuthors.findIndex(a => a.id === au.id) === idx)
|
const uniqueUpdatedAuthors = updatedAuthors.filter((au, idx) => updatedAuthors.findIndex((a) => a.id === au.id) === idx)
|
||||||
const updatedSeriesAll = oldLibraryItem.media.metadata.series || []
|
const updatedSeriesAll = oldLibraryItem.media.metadata.series || []
|
||||||
|
|
||||||
for (const existingAuthor of existingAuthors) {
|
for (const existingAuthor of existingAuthors) {
|
||||||
// Author was removed from Book
|
// Author was removed from Book
|
||||||
if (!uniqueUpdatedAuthors.some(au => au.id === existingAuthor.id)) {
|
if (!uniqueUpdatedAuthors.some((au) => au.id === existingAuthor.id)) {
|
||||||
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" author "${existingAuthor.name}" was removed`)
|
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" author "${existingAuthor.name}" was removed`)
|
||||||
await this.sequelize.models.bookAuthor.removeByIds(existingAuthor.id, libraryItemExpanded.media.id)
|
await this.sequelize.models.bookAuthor.removeByIds(existingAuthor.id, libraryItemExpanded.media.id)
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
@ -329,7 +329,7 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
for (const updatedAuthor of uniqueUpdatedAuthors) {
|
for (const updatedAuthor of uniqueUpdatedAuthors) {
|
||||||
// Author was added
|
// Author was added
|
||||||
if (!existingAuthors.some(au => au.id === updatedAuthor.id)) {
|
if (!existingAuthors.some((au) => au.id === updatedAuthor.id)) {
|
||||||
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" author "${updatedAuthor.name}" was added`)
|
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" author "${updatedAuthor.name}" was added`)
|
||||||
await this.sequelize.models.bookAuthor.create({ authorId: updatedAuthor.id, bookId: libraryItemExpanded.media.id })
|
await this.sequelize.models.bookAuthor.create({ authorId: updatedAuthor.id, bookId: libraryItemExpanded.media.id })
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
@ -337,7 +337,7 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
for (const existingSeries of existingSeriesAll) {
|
for (const existingSeries of existingSeriesAll) {
|
||||||
// Series was removed
|
// Series was removed
|
||||||
if (!updatedSeriesAll.some(se => se.id === existingSeries.id)) {
|
if (!updatedSeriesAll.some((se) => se.id === existingSeries.id)) {
|
||||||
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" series "${existingSeries.name}" was removed`)
|
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" series "${existingSeries.name}" was removed`)
|
||||||
await this.sequelize.models.bookSeries.removeByIds(existingSeries.id, libraryItemExpanded.media.id)
|
await this.sequelize.models.bookSeries.removeByIds(existingSeries.id, libraryItemExpanded.media.id)
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
@ -345,7 +345,7 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
for (const updatedSeries of updatedSeriesAll) {
|
for (const updatedSeries of updatedSeriesAll) {
|
||||||
// Series was added/updated
|
// Series was added/updated
|
||||||
const existingSeriesMatch = existingSeriesAll.find(se => se.id === updatedSeries.id)
|
const existingSeriesMatch = existingSeriesAll.find((se) => se.id === updatedSeries.id)
|
||||||
if (!existingSeriesMatch) {
|
if (!existingSeriesMatch) {
|
||||||
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" series "${updatedSeries.name}" was added`)
|
Logger.debug(`[LibraryItem] "${libraryItemExpanded.media.title}" series "${updatedSeries.name}" was added`)
|
||||||
await this.sequelize.models.bookSeries.create({ seriesId: updatedSeries.id, bookId: libraryItemExpanded.media.id, sequence: updatedSeries.sequence })
|
await this.sequelize.models.bookSeries.create({ seriesId: updatedSeries.id, bookId: libraryItemExpanded.media.id, sequence: updatedSeries.sequence })
|
||||||
@ -420,7 +420,7 @@ class LibraryItem extends Model {
|
|||||||
lastScanVersion: oldLibraryItem.scanVersion,
|
lastScanVersion: oldLibraryItem.scanVersion,
|
||||||
libraryId: oldLibraryItem.libraryId,
|
libraryId: oldLibraryItem.libraryId,
|
||||||
libraryFolderId: oldLibraryItem.folderId,
|
libraryFolderId: oldLibraryItem.folderId,
|
||||||
libraryFiles: oldLibraryItem.libraryFiles?.map(lf => lf.toJSON()) || [],
|
libraryFiles: oldLibraryItem.libraryFiles?.map((lf) => lf.toJSON()) || [],
|
||||||
extraData
|
extraData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,8 +435,8 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} libraryItemId
|
* @param {string} libraryItemId
|
||||||
* @returns {Promise<LibraryItemExpanded>}
|
* @returns {Promise<LibraryItemExpanded>}
|
||||||
*/
|
*/
|
||||||
static async getExpandedById(libraryItemId) {
|
static async getExpandedById(libraryItemId) {
|
||||||
@ -485,7 +485,7 @@ class LibraryItem extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get old library item by id
|
* Get old library item by id
|
||||||
* @param {string} libraryItemId
|
* @param {string} libraryItemId
|
||||||
* @returns {oldLibraryItem}
|
* @returns {oldLibraryItem}
|
||||||
*/
|
*/
|
||||||
static async getOldById(libraryItemId) {
|
static async getOldById(libraryItemId) {
|
||||||
@ -534,9 +534,9 @@ class LibraryItem extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get library items using filter and sort
|
* Get library items using filter and sort
|
||||||
* @param {oldLibrary} library
|
* @param {oldLibrary} library
|
||||||
* @param {oldUser} user
|
* @param {oldUser} user
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
* @returns {object} { libraryItems:oldLibraryItem[], count:number }
|
* @returns {object} { libraryItems:oldLibraryItem[], count:number }
|
||||||
*/
|
*/
|
||||||
static async getByFilterAndSort(library, user, options) {
|
static async getByFilterAndSort(library, user, options) {
|
||||||
@ -545,7 +545,7 @@ class LibraryItem extends Model {
|
|||||||
Logger.debug(`Loaded ${libraryItems.length} of ${count} items for libary page in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
Logger.debug(`Loaded ${libraryItems.length} of ${count} items for libary page in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
libraryItems: libraryItems.map(li => {
|
libraryItems: libraryItems.map((li) => {
|
||||||
const oldLibraryItem = this.getOldLibraryItem(li).toJSONMinified()
|
const oldLibraryItem = this.getOldLibraryItem(li).toJSONMinified()
|
||||||
if (li.collapsedSeries) {
|
if (li.collapsedSeries) {
|
||||||
oldLibraryItem.collapsedSeries = li.collapsedSeries
|
oldLibraryItem.collapsedSeries = li.collapsedSeries
|
||||||
@ -574,10 +574,10 @@ class LibraryItem extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get home page data personalized shelves
|
* Get home page data personalized shelves
|
||||||
* @param {oldLibrary} library
|
* @param {oldLibrary} library
|
||||||
* @param {oldUser} user
|
* @param {oldUser} user
|
||||||
* @param {string[]} include
|
* @param {string[]} include
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @returns {object[]} array of shelf objects
|
* @returns {object[]} array of shelf objects
|
||||||
*/
|
*/
|
||||||
static async getPersonalizedShelves(library, user, include, limit) {
|
static async getPersonalizedShelves(library, user, include, limit) {
|
||||||
@ -588,8 +588,8 @@ class LibraryItem extends Model {
|
|||||||
// "Continue Listening" shelf
|
// "Continue Listening" shelf
|
||||||
const itemsInProgressPayload = await libraryFilters.getMediaItemsInProgress(library, user, include, limit, false)
|
const itemsInProgressPayload = await libraryFilters.getMediaItemsInProgress(library, user, include, limit, false)
|
||||||
if (itemsInProgressPayload.items.length) {
|
if (itemsInProgressPayload.items.length) {
|
||||||
const ebookOnlyItemsInProgress = itemsInProgressPayload.items.filter(li => li.media.isEBookOnly)
|
const ebookOnlyItemsInProgress = itemsInProgressPayload.items.filter((li) => li.media.isEBookOnly)
|
||||||
const audioOnlyItemsInProgress = itemsInProgressPayload.items.filter(li => !li.media.isEBookOnly)
|
const audioOnlyItemsInProgress = itemsInProgressPayload.items.filter((li) => !li.media.isEBookOnly)
|
||||||
|
|
||||||
shelves.push({
|
shelves.push({
|
||||||
id: 'continue-listening',
|
id: 'continue-listening',
|
||||||
@ -697,8 +697,8 @@ class LibraryItem extends Model {
|
|||||||
// "Listen Again" shelf
|
// "Listen Again" shelf
|
||||||
const mediaFinishedPayload = await libraryFilters.getMediaFinished(library, user, include, limit)
|
const mediaFinishedPayload = await libraryFilters.getMediaFinished(library, user, include, limit)
|
||||||
if (mediaFinishedPayload.items.length) {
|
if (mediaFinishedPayload.items.length) {
|
||||||
const ebookOnlyItemsInProgress = mediaFinishedPayload.items.filter(li => li.media.isEBookOnly)
|
const ebookOnlyItemsInProgress = mediaFinishedPayload.items.filter((li) => li.media.isEBookOnly)
|
||||||
const audioOnlyItemsInProgress = mediaFinishedPayload.items.filter(li => !li.media.isEBookOnly)
|
const audioOnlyItemsInProgress = mediaFinishedPayload.items.filter((li) => !li.media.isEBookOnly)
|
||||||
|
|
||||||
shelves.push({
|
shelves.push({
|
||||||
id: 'listen-again',
|
id: 'listen-again',
|
||||||
@ -748,27 +748,27 @@ class LibraryItem extends Model {
|
|||||||
/**
|
/**
|
||||||
* Get book library items for author, optional use user permissions
|
* Get book library items for author, optional use user permissions
|
||||||
* @param {oldAuthor} author
|
* @param {oldAuthor} author
|
||||||
* @param {[oldUser]} user
|
* @param {[oldUser]} user
|
||||||
* @returns {Promise<oldLibraryItem[]>}
|
* @returns {Promise<oldLibraryItem[]>}
|
||||||
*/
|
*/
|
||||||
static async getForAuthor(author, user = null) {
|
static async getForAuthor(author, user = null) {
|
||||||
const { libraryItems } = await libraryFilters.getLibraryItemsForAuthor(author, user, undefined, undefined)
|
const { libraryItems } = await libraryFilters.getLibraryItemsForAuthor(author, user, undefined, undefined)
|
||||||
return libraryItems.map(li => this.getOldLibraryItem(li))
|
return libraryItems.map((li) => this.getOldLibraryItem(li))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get book library items in a collection
|
* Get book library items in a collection
|
||||||
* @param {oldCollection} collection
|
* @param {oldCollection} collection
|
||||||
* @returns {Promise<oldLibraryItem[]>}
|
* @returns {Promise<oldLibraryItem[]>}
|
||||||
*/
|
*/
|
||||||
static async getForCollection(collection) {
|
static async getForCollection(collection) {
|
||||||
const libraryItems = await libraryFilters.getLibraryItemsForCollection(collection)
|
const libraryItems = await libraryFilters.getLibraryItemsForCollection(collection)
|
||||||
return libraryItems.map(li => this.getOldLibraryItem(li))
|
return libraryItems.map((li) => this.getOldLibraryItem(li))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if library item exists
|
* Check if library item exists
|
||||||
* @param {string} libraryItemId
|
* @param {string} libraryItemId
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
static async checkExistsById(libraryItemId) {
|
static async checkExistsById(libraryItemId) {
|
||||||
@ -776,8 +776,8 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {import('sequelize').WhereOptions} where
|
* @param {import('sequelize').WhereOptions} where
|
||||||
* @param {import('sequelize').BindOrReplacements} replacements
|
* @param {import('sequelize').BindOrReplacements} replacements
|
||||||
* @returns {Object} oldLibraryItem
|
* @returns {Object} oldLibraryItem
|
||||||
*/
|
*/
|
||||||
@ -822,8 +822,8 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {import('sequelize').FindOptions} options
|
* @param {import('sequelize').FindOptions} options
|
||||||
* @returns {Promise<Book|Podcast>}
|
* @returns {Promise<Book|Podcast>}
|
||||||
*/
|
*/
|
||||||
getMedia(options) {
|
getMedia(options) {
|
||||||
@ -833,7 +833,7 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns {Promise<Book|Podcast>}
|
* @returns {Promise<Book|Podcast>}
|
||||||
*/
|
*/
|
||||||
getMediaExpanded() {
|
getMediaExpanded() {
|
||||||
@ -870,7 +870,7 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
async saveMetadataFile() {
|
async saveMetadataFile() {
|
||||||
@ -887,18 +887,18 @@ class LibraryItem extends Model {
|
|||||||
const metadataFilePath = Path.join(metadataPath, `metadata.${global.ServerSettings.metadataFileFormat}`)
|
const metadataFilePath = Path.join(metadataPath, `metadata.${global.ServerSettings.metadataFileFormat}`)
|
||||||
|
|
||||||
// Expanded with series, authors, podcastEpisodes
|
// Expanded with series, authors, podcastEpisodes
|
||||||
const mediaExpanded = this.media || await this.getMediaExpanded()
|
const mediaExpanded = this.media || (await this.getMediaExpanded())
|
||||||
|
|
||||||
let jsonObject = {}
|
let jsonObject = {}
|
||||||
if (this.mediaType === 'book') {
|
if (this.mediaType === 'book') {
|
||||||
jsonObject = {
|
jsonObject = {
|
||||||
tags: mediaExpanded.tags || [],
|
tags: mediaExpanded.tags || [],
|
||||||
chapters: mediaExpanded.chapters?.map(c => ({ ...c })) || [],
|
chapters: mediaExpanded.chapters?.map((c) => ({ ...c })) || [],
|
||||||
title: mediaExpanded.title,
|
title: mediaExpanded.title,
|
||||||
subtitle: mediaExpanded.subtitle,
|
subtitle: mediaExpanded.subtitle,
|
||||||
authors: mediaExpanded.authors.map(a => a.name),
|
authors: mediaExpanded.authors.map((a) => a.name),
|
||||||
narrators: mediaExpanded.narrators,
|
narrators: mediaExpanded.narrators,
|
||||||
series: mediaExpanded.series.map(se => {
|
series: mediaExpanded.series.map((se) => {
|
||||||
const sequence = se.bookSeries?.sequence || ''
|
const sequence = se.bookSeries?.sequence || ''
|
||||||
if (!sequence) return se.name
|
if (!sequence) return se.name
|
||||||
return `${se.name} #${sequence}`
|
return `${se.name} #${sequence}`
|
||||||
@ -934,96 +934,101 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fsExtra
|
||||||
return fsExtra.writeFile(metadataFilePath, JSON.stringify(jsonObject, null, 2)).then(async () => {
|
.writeFile(metadataFilePath, JSON.stringify(jsonObject, null, 2))
|
||||||
// Add metadata.json to libraryFiles array if it is new
|
.then(async () => {
|
||||||
let metadataLibraryFile = this.libraryFiles.find(lf => lf.metadata.path === filePathToPOSIX(metadataFilePath))
|
// Add metadata.json to libraryFiles array if it is new
|
||||||
if (storeMetadataWithItem) {
|
let metadataLibraryFile = this.libraryFiles.find((lf) => lf.metadata.path === filePathToPOSIX(metadataFilePath))
|
||||||
if (!metadataLibraryFile) {
|
if (storeMetadataWithItem) {
|
||||||
const newLibraryFile = new LibraryFile()
|
if (!metadataLibraryFile) {
|
||||||
await newLibraryFile.setDataFromPath(metadataFilePath, `metadata.json`)
|
const newLibraryFile = new LibraryFile()
|
||||||
metadataLibraryFile = newLibraryFile.toJSON()
|
await newLibraryFile.setDataFromPath(metadataFilePath, `metadata.json`)
|
||||||
this.libraryFiles.push(metadataLibraryFile)
|
metadataLibraryFile = newLibraryFile.toJSON()
|
||||||
} else {
|
this.libraryFiles.push(metadataLibraryFile)
|
||||||
const fileTimestamps = await getFileTimestampsWithIno(metadataFilePath)
|
} else {
|
||||||
if (fileTimestamps) {
|
const fileTimestamps = await getFileTimestampsWithIno(metadataFilePath)
|
||||||
metadataLibraryFile.metadata.mtimeMs = fileTimestamps.mtimeMs
|
if (fileTimestamps) {
|
||||||
metadataLibraryFile.metadata.ctimeMs = fileTimestamps.ctimeMs
|
metadataLibraryFile.metadata.mtimeMs = fileTimestamps.mtimeMs
|
||||||
metadataLibraryFile.metadata.size = fileTimestamps.size
|
metadataLibraryFile.metadata.ctimeMs = fileTimestamps.ctimeMs
|
||||||
metadataLibraryFile.ino = fileTimestamps.ino
|
metadataLibraryFile.metadata.size = fileTimestamps.size
|
||||||
|
metadataLibraryFile.ino = fileTimestamps.ino
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const libraryItemDirTimestamps = await getFileTimestampsWithIno(this.path)
|
||||||
|
if (libraryItemDirTimestamps) {
|
||||||
|
this.mtime = libraryItemDirTimestamps.mtimeMs
|
||||||
|
this.ctime = libraryItemDirTimestamps.ctimeMs
|
||||||
|
let size = 0
|
||||||
|
this.libraryFiles.forEach((lf) => (size += !isNaN(lf.metadata.size) ? Number(lf.metadata.size) : 0))
|
||||||
|
this.size = size
|
||||||
|
await this.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const libraryItemDirTimestamps = await getFileTimestampsWithIno(this.path)
|
|
||||||
if (libraryItemDirTimestamps) {
|
|
||||||
this.mtime = libraryItemDirTimestamps.mtimeMs
|
|
||||||
this.ctime = libraryItemDirTimestamps.ctimeMs
|
|
||||||
let size = 0
|
|
||||||
this.libraryFiles.forEach((lf) => size += (!isNaN(lf.metadata.size) ? Number(lf.metadata.size) : 0))
|
|
||||||
this.size = size
|
|
||||||
await this.save()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.debug(`Success saving abmetadata to "${metadataFilePath}"`)
|
Logger.debug(`Success saving abmetadata to "${metadataFilePath}"`)
|
||||||
|
|
||||||
return metadataLibraryFile
|
return metadataLibraryFile
|
||||||
}).catch((error) => {
|
})
|
||||||
Logger.error(`Failed to save json file at "${metadataFilePath}"`, error)
|
.catch((error) => {
|
||||||
return null
|
Logger.error(`Failed to save json file at "${metadataFilePath}"`, error)
|
||||||
})
|
return null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
ino: DataTypes.STRING,
|
||||||
|
path: DataTypes.STRING,
|
||||||
|
relPath: DataTypes.STRING,
|
||||||
|
mediaId: DataTypes.UUIDV4,
|
||||||
|
mediaType: DataTypes.STRING,
|
||||||
|
isFile: DataTypes.BOOLEAN,
|
||||||
|
isMissing: DataTypes.BOOLEAN,
|
||||||
|
isInvalid: DataTypes.BOOLEAN,
|
||||||
|
mtime: DataTypes.DATE(6),
|
||||||
|
ctime: DataTypes.DATE(6),
|
||||||
|
birthtime: DataTypes.DATE(6),
|
||||||
|
size: DataTypes.BIGINT,
|
||||||
|
lastScan: DataTypes.DATE,
|
||||||
|
lastScanVersion: DataTypes.STRING,
|
||||||
|
libraryFiles: DataTypes.JSON,
|
||||||
|
extraData: DataTypes.JSON
|
||||||
},
|
},
|
||||||
ino: DataTypes.STRING,
|
{
|
||||||
path: DataTypes.STRING,
|
sequelize,
|
||||||
relPath: DataTypes.STRING,
|
modelName: 'libraryItem',
|
||||||
mediaId: DataTypes.UUIDV4,
|
indexes: [
|
||||||
mediaType: DataTypes.STRING,
|
{
|
||||||
isFile: DataTypes.BOOLEAN,
|
fields: ['createdAt']
|
||||||
isMissing: DataTypes.BOOLEAN,
|
},
|
||||||
isInvalid: DataTypes.BOOLEAN,
|
{
|
||||||
mtime: DataTypes.DATE(6),
|
fields: ['mediaId']
|
||||||
ctime: DataTypes.DATE(6),
|
},
|
||||||
birthtime: DataTypes.DATE(6),
|
{
|
||||||
size: DataTypes.BIGINT,
|
fields: ['libraryId', 'mediaType']
|
||||||
lastScan: DataTypes.DATE,
|
},
|
||||||
lastScanVersion: DataTypes.STRING,
|
{
|
||||||
libraryFiles: DataTypes.JSON,
|
fields: ['libraryId', 'mediaId', 'mediaType']
|
||||||
extraData: DataTypes.JSON
|
},
|
||||||
}, {
|
{
|
||||||
sequelize,
|
fields: ['birthtime']
|
||||||
modelName: 'libraryItem',
|
},
|
||||||
indexes: [
|
{
|
||||||
{
|
fields: ['mtime']
|
||||||
fields: ['createdAt']
|
}
|
||||||
},
|
]
|
||||||
{
|
}
|
||||||
fields: ['mediaId']
|
)
|
||||||
},
|
|
||||||
{
|
|
||||||
fields: ['libraryId', 'mediaType']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fields: ['libraryId', 'mediaId', 'mediaType']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fields: ['birthtime']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fields: ['mtime']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
const { library, libraryFolder, book, podcast } = sequelize.models
|
const { library, libraryFolder, book, podcast } = sequelize.models
|
||||||
library.hasMany(LibraryItem)
|
library.hasMany(LibraryItem)
|
||||||
@ -1050,7 +1055,7 @@ class LibraryItem extends Model {
|
|||||||
})
|
})
|
||||||
LibraryItem.belongsTo(podcast, { foreignKey: 'mediaId', constraints: false })
|
LibraryItem.belongsTo(podcast, { foreignKey: 'mediaId', constraints: false })
|
||||||
|
|
||||||
LibraryItem.addHook('afterFind', findResult => {
|
LibraryItem.addHook('afterFind', (findResult) => {
|
||||||
if (!findResult) return
|
if (!findResult) return
|
||||||
|
|
||||||
if (!Array.isArray(findResult)) findResult = [findResult]
|
if (!Array.isArray(findResult)) findResult = [findResult]
|
||||||
@ -1070,7 +1075,7 @@ class LibraryItem extends Model {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
LibraryItem.addHook('afterDestroy', async instance => {
|
LibraryItem.addHook('afterDestroy', async (instance) => {
|
||||||
if (!instance) return
|
if (!instance) return
|
||||||
const media = await instance.getMedia()
|
const media = await instance.getMedia()
|
||||||
if (media) {
|
if (media) {
|
||||||
|
@ -100,38 +100,41 @@ class MediaProgress extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
*
|
*
|
||||||
* Polymorphic association: Book has many MediaProgress. PodcastEpisode has many MediaProgress.
|
* Polymorphic association: Book has many MediaProgress. PodcastEpisode has many MediaProgress.
|
||||||
* @see https://sequelize.org/docs/v6/advanced-association-concepts/polymorphic-associations/
|
* @see https://sequelize.org/docs/v6/advanced-association-concepts/polymorphic-associations/
|
||||||
*
|
*
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
mediaItemId: DataTypes.UUIDV4,
|
||||||
|
mediaItemType: DataTypes.STRING,
|
||||||
|
duration: DataTypes.FLOAT,
|
||||||
|
currentTime: DataTypes.FLOAT,
|
||||||
|
isFinished: DataTypes.BOOLEAN,
|
||||||
|
hideFromContinueListening: DataTypes.BOOLEAN,
|
||||||
|
ebookLocation: DataTypes.STRING,
|
||||||
|
ebookProgress: DataTypes.FLOAT,
|
||||||
|
finishedAt: DataTypes.DATE,
|
||||||
|
extraData: DataTypes.JSON
|
||||||
},
|
},
|
||||||
mediaItemId: DataTypes.UUIDV4,
|
{
|
||||||
mediaItemType: DataTypes.STRING,
|
sequelize,
|
||||||
duration: DataTypes.FLOAT,
|
modelName: 'mediaProgress',
|
||||||
currentTime: DataTypes.FLOAT,
|
indexes: [
|
||||||
isFinished: DataTypes.BOOLEAN,
|
{
|
||||||
hideFromContinueListening: DataTypes.BOOLEAN,
|
fields: ['updatedAt']
|
||||||
ebookLocation: DataTypes.STRING,
|
}
|
||||||
ebookProgress: DataTypes.FLOAT,
|
]
|
||||||
finishedAt: DataTypes.DATE,
|
}
|
||||||
extraData: DataTypes.JSON
|
)
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'mediaProgress',
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
fields: ['updatedAt']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
const { book, podcastEpisode, user } = sequelize.models
|
const { book, podcastEpisode, user } = sequelize.models
|
||||||
|
|
||||||
@ -153,7 +156,7 @@ class MediaProgress extends Model {
|
|||||||
})
|
})
|
||||||
MediaProgress.belongsTo(podcastEpisode, { foreignKey: 'mediaItemId', constraints: false })
|
MediaProgress.belongsTo(podcastEpisode, { foreignKey: 'mediaItemId', constraints: false })
|
||||||
|
|
||||||
MediaProgress.addHook('afterFind', findResult => {
|
MediaProgress.addHook('afterFind', (findResult) => {
|
||||||
if (!findResult) return
|
if (!findResult) return
|
||||||
|
|
||||||
if (!Array.isArray(findResult)) findResult = [findResult]
|
if (!Array.isArray(findResult)) findResult = [findResult]
|
||||||
@ -181,4 +184,4 @@ class MediaProgress extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = MediaProgress
|
module.exports = MediaProgress
|
||||||
|
@ -2,7 +2,6 @@ const { DataTypes, Model } = require('sequelize')
|
|||||||
|
|
||||||
const oldPlaybackSession = require('../objects/PlaybackSession')
|
const oldPlaybackSession = require('../objects/PlaybackSession')
|
||||||
|
|
||||||
|
|
||||||
class PlaybackSession extends Model {
|
class PlaybackSession extends Model {
|
||||||
constructor(values, options) {
|
constructor(values, options) {
|
||||||
super(values, options)
|
super(values, options)
|
||||||
@ -62,7 +61,7 @@ class PlaybackSession extends Model {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
return playbackSessions.map(session => this.getOldPlaybackSession(session))
|
return playbackSessions.map((session) => this.getOldPlaybackSession(session))
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getById(sessionId) {
|
static async getById(sessionId) {
|
||||||
@ -170,35 +169,38 @@ class PlaybackSession extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
mediaItemId: DataTypes.UUIDV4,
|
||||||
|
mediaItemType: DataTypes.STRING,
|
||||||
|
displayTitle: DataTypes.STRING,
|
||||||
|
displayAuthor: DataTypes.STRING,
|
||||||
|
duration: DataTypes.FLOAT,
|
||||||
|
playMethod: DataTypes.INTEGER,
|
||||||
|
mediaPlayer: DataTypes.STRING,
|
||||||
|
startTime: DataTypes.FLOAT,
|
||||||
|
currentTime: DataTypes.FLOAT,
|
||||||
|
serverVersion: DataTypes.STRING,
|
||||||
|
coverPath: DataTypes.STRING,
|
||||||
|
timeListening: DataTypes.INTEGER,
|
||||||
|
mediaMetadata: DataTypes.JSON,
|
||||||
|
date: DataTypes.STRING,
|
||||||
|
dayOfWeek: DataTypes.STRING,
|
||||||
|
extraData: DataTypes.JSON
|
||||||
},
|
},
|
||||||
mediaItemId: DataTypes.UUIDV4,
|
{
|
||||||
mediaItemType: DataTypes.STRING,
|
sequelize,
|
||||||
displayTitle: DataTypes.STRING,
|
modelName: 'playbackSession'
|
||||||
displayAuthor: DataTypes.STRING,
|
}
|
||||||
duration: DataTypes.FLOAT,
|
)
|
||||||
playMethod: DataTypes.INTEGER,
|
|
||||||
mediaPlayer: DataTypes.STRING,
|
|
||||||
startTime: DataTypes.FLOAT,
|
|
||||||
currentTime: DataTypes.FLOAT,
|
|
||||||
serverVersion: DataTypes.STRING,
|
|
||||||
coverPath: DataTypes.STRING,
|
|
||||||
timeListening: DataTypes.INTEGER,
|
|
||||||
mediaMetadata: DataTypes.JSON,
|
|
||||||
date: DataTypes.STRING,
|
|
||||||
dayOfWeek: DataTypes.STRING,
|
|
||||||
extraData: DataTypes.JSON
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'playbackSession'
|
|
||||||
})
|
|
||||||
|
|
||||||
const { book, podcastEpisode, user, device, library } = sequelize.models
|
const { book, podcastEpisode, user, device, library } = sequelize.models
|
||||||
|
|
||||||
@ -229,7 +231,7 @@ class PlaybackSession extends Model {
|
|||||||
})
|
})
|
||||||
PlaybackSession.belongsTo(podcastEpisode, { foreignKey: 'mediaItemId', constraints: false })
|
PlaybackSession.belongsTo(podcastEpisode, { foreignKey: 'mediaItemId', constraints: false })
|
||||||
|
|
||||||
PlaybackSession.addHook('afterFind', findResult => {
|
PlaybackSession.addHook('afterFind', (findResult) => {
|
||||||
if (!findResult) return
|
if (!findResult) return
|
||||||
|
|
||||||
if (!Array.isArray(findResult)) findResult = [findResult]
|
if (!Array.isArray(findResult)) findResult = [findResult]
|
||||||
|
@ -23,29 +23,6 @@ class Playlist extends Model {
|
|||||||
this.updatedAt
|
this.updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getOldPlaylists() {
|
|
||||||
const playlists = await this.findAll({
|
|
||||||
include: {
|
|
||||||
model: this.sequelize.models.playlistMediaItem,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: this.sequelize.models.book,
|
|
||||||
include: this.sequelize.models.libraryItem
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: this.sequelize.models.podcastEpisode,
|
|
||||||
include: {
|
|
||||||
model: this.sequelize.models.podcast,
|
|
||||||
include: this.sequelize.models.libraryItem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
order: [['playlistMediaItems', 'order', 'ASC']]
|
|
||||||
})
|
|
||||||
return playlists.map((p) => this.getOldPlaylist(p))
|
|
||||||
}
|
|
||||||
|
|
||||||
static getOldPlaylist(playlistExpanded) {
|
static getOldPlaylist(playlistExpanded) {
|
||||||
const items = playlistExpanded.playlistMediaItems
|
const items = playlistExpanded.playlistMediaItems
|
||||||
.map((pmi) => {
|
.map((pmi) => {
|
||||||
@ -76,8 +53,8 @@ class Playlist extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get old playlist toJSONExpanded
|
* Get old playlist toJSONExpanded
|
||||||
* @param {[string[]]} include
|
* @param {string[]} [include]
|
||||||
* @returns {Promise<object>} oldPlaylist.toJSONExpanded
|
* @returns {Promise<oldPlaylist>} oldPlaylist.toJSONExpanded
|
||||||
*/
|
*/
|
||||||
async getOldJsonExpanded(include) {
|
async getOldJsonExpanded(include) {
|
||||||
this.playlistMediaItems =
|
this.playlistMediaItems =
|
||||||
|
@ -35,24 +35,27 @@ class PlaylistMediaItem extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
mediaItemId: DataTypes.UUIDV4,
|
||||||
|
mediaItemType: DataTypes.STRING,
|
||||||
|
order: DataTypes.INTEGER
|
||||||
},
|
},
|
||||||
mediaItemId: DataTypes.UUIDV4,
|
{
|
||||||
mediaItemType: DataTypes.STRING,
|
sequelize,
|
||||||
order: DataTypes.INTEGER
|
timestamps: true,
|
||||||
}, {
|
updatedAt: false,
|
||||||
sequelize,
|
modelName: 'playlistMediaItem'
|
||||||
timestamps: true,
|
}
|
||||||
updatedAt: false,
|
)
|
||||||
modelName: 'playlistMediaItem'
|
|
||||||
})
|
|
||||||
|
|
||||||
const { book, podcastEpisode, playlist } = sequelize.models
|
const { book, podcastEpisode, playlist } = sequelize.models
|
||||||
|
|
||||||
@ -74,7 +77,7 @@ class PlaylistMediaItem extends Model {
|
|||||||
})
|
})
|
||||||
PlaylistMediaItem.belongsTo(podcastEpisode, { foreignKey: 'mediaItemId', constraints: false })
|
PlaylistMediaItem.belongsTo(podcastEpisode, { foreignKey: 'mediaItemId', constraints: false })
|
||||||
|
|
||||||
PlaylistMediaItem.addHook('afterFind', findResult => {
|
PlaylistMediaItem.addHook('afterFind', (findResult) => {
|
||||||
if (!findResult) return
|
if (!findResult) return
|
||||||
|
|
||||||
if (!Array.isArray(findResult)) findResult = [findResult]
|
if (!Array.isArray(findResult)) findResult = [findResult]
|
||||||
|
@ -3,7 +3,7 @@ const { DataTypes, Model } = require('sequelize')
|
|||||||
/**
|
/**
|
||||||
* @typedef PodcastExpandedProperties
|
* @typedef PodcastExpandedProperties
|
||||||
* @property {import('./PodcastEpisode')[]} podcastEpisodes
|
* @property {import('./PodcastEpisode')[]} podcastEpisodes
|
||||||
*
|
*
|
||||||
* @typedef {Podcast & PodcastExpandedProperties} PodcastExpanded
|
* @typedef {Podcast & PodcastExpandedProperties} PodcastExpanded
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class Podcast extends Model {
|
|||||||
|
|
||||||
static getOldPodcast(libraryItemExpanded) {
|
static getOldPodcast(libraryItemExpanded) {
|
||||||
const podcastExpanded = libraryItemExpanded.media
|
const podcastExpanded = libraryItemExpanded.media
|
||||||
const podcastEpisodes = podcastExpanded.podcastEpisodes?.map(ep => ep.getOldPodcastEpisode(libraryItemExpanded.id).toJSON()).sort((a, b) => a.index - b.index)
|
const podcastEpisodes = podcastExpanded.podcastEpisodes?.map((ep) => ep.getOldPodcastEpisode(libraryItemExpanded.id).toJSON()).sort((a, b) => a.index - b.index)
|
||||||
return {
|
return {
|
||||||
id: podcastExpanded.id,
|
id: podcastExpanded.id,
|
||||||
libraryItemId: libraryItemExpanded.id,
|
libraryItemId: libraryItemExpanded.id,
|
||||||
@ -140,42 +140,45 @@ class Podcast extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
},
|
primaryKey: true
|
||||||
title: DataTypes.STRING,
|
},
|
||||||
titleIgnorePrefix: DataTypes.STRING,
|
title: DataTypes.STRING,
|
||||||
author: DataTypes.STRING,
|
titleIgnorePrefix: DataTypes.STRING,
|
||||||
releaseDate: DataTypes.STRING,
|
author: DataTypes.STRING,
|
||||||
feedURL: DataTypes.STRING,
|
releaseDate: DataTypes.STRING,
|
||||||
imageURL: DataTypes.STRING,
|
feedURL: DataTypes.STRING,
|
||||||
description: DataTypes.TEXT,
|
imageURL: DataTypes.STRING,
|
||||||
itunesPageURL: DataTypes.STRING,
|
description: DataTypes.TEXT,
|
||||||
itunesId: DataTypes.STRING,
|
itunesPageURL: DataTypes.STRING,
|
||||||
itunesArtistId: DataTypes.STRING,
|
itunesId: DataTypes.STRING,
|
||||||
language: DataTypes.STRING,
|
itunesArtistId: DataTypes.STRING,
|
||||||
podcastType: DataTypes.STRING,
|
language: DataTypes.STRING,
|
||||||
explicit: DataTypes.BOOLEAN,
|
podcastType: DataTypes.STRING,
|
||||||
|
explicit: DataTypes.BOOLEAN,
|
||||||
|
|
||||||
autoDownloadEpisodes: DataTypes.BOOLEAN,
|
autoDownloadEpisodes: DataTypes.BOOLEAN,
|
||||||
autoDownloadSchedule: DataTypes.STRING,
|
autoDownloadSchedule: DataTypes.STRING,
|
||||||
lastEpisodeCheck: DataTypes.DATE,
|
lastEpisodeCheck: DataTypes.DATE,
|
||||||
maxEpisodesToKeep: DataTypes.INTEGER,
|
maxEpisodesToKeep: DataTypes.INTEGER,
|
||||||
maxNewEpisodesToDownload: DataTypes.INTEGER,
|
maxNewEpisodesToDownload: DataTypes.INTEGER,
|
||||||
coverPath: DataTypes.STRING,
|
coverPath: DataTypes.STRING,
|
||||||
tags: DataTypes.JSON,
|
tags: DataTypes.JSON,
|
||||||
genres: DataTypes.JSON
|
genres: DataTypes.JSON
|
||||||
}, {
|
},
|
||||||
sequelize,
|
{
|
||||||
modelName: 'podcast'
|
sequelize,
|
||||||
})
|
modelName: 'podcast'
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Podcast
|
module.exports = Podcast
|
||||||
|
@ -54,7 +54,7 @@ class PodcastEpisode extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} libraryItemId
|
* @param {string} libraryItemId
|
||||||
* @returns {oldPodcastEpisode}
|
* @returns {oldPodcastEpisode}
|
||||||
*/
|
*/
|
||||||
getOldPodcastEpisode(libraryItemId = null) {
|
getOldPodcastEpisode(libraryItemId = null) {
|
||||||
@ -125,40 +125,43 @@ class PodcastEpisode extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
},
|
primaryKey: true
|
||||||
index: DataTypes.INTEGER,
|
},
|
||||||
season: DataTypes.STRING,
|
index: DataTypes.INTEGER,
|
||||||
episode: DataTypes.STRING,
|
season: DataTypes.STRING,
|
||||||
episodeType: DataTypes.STRING,
|
episode: DataTypes.STRING,
|
||||||
title: DataTypes.STRING,
|
episodeType: DataTypes.STRING,
|
||||||
subtitle: DataTypes.STRING(1000),
|
title: DataTypes.STRING,
|
||||||
description: DataTypes.TEXT,
|
subtitle: DataTypes.STRING(1000),
|
||||||
pubDate: DataTypes.STRING,
|
description: DataTypes.TEXT,
|
||||||
enclosureURL: DataTypes.STRING,
|
pubDate: DataTypes.STRING,
|
||||||
enclosureSize: DataTypes.BIGINT,
|
enclosureURL: DataTypes.STRING,
|
||||||
enclosureType: DataTypes.STRING,
|
enclosureSize: DataTypes.BIGINT,
|
||||||
publishedAt: DataTypes.DATE,
|
enclosureType: DataTypes.STRING,
|
||||||
|
publishedAt: DataTypes.DATE,
|
||||||
|
|
||||||
audioFile: DataTypes.JSON,
|
audioFile: DataTypes.JSON,
|
||||||
chapters: DataTypes.JSON,
|
chapters: DataTypes.JSON,
|
||||||
extraData: DataTypes.JSON
|
extraData: DataTypes.JSON
|
||||||
}, {
|
},
|
||||||
sequelize,
|
{
|
||||||
modelName: 'podcastEpisode',
|
sequelize,
|
||||||
indexes: [
|
modelName: 'podcastEpisode',
|
||||||
{
|
indexes: [
|
||||||
fields: ['createdAt']
|
{
|
||||||
}
|
fields: ['createdAt']
|
||||||
]
|
}
|
||||||
})
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const { podcast } = sequelize.models
|
const { podcast } = sequelize.models
|
||||||
podcast.hasMany(PodcastEpisode, {
|
podcast.hasMany(PodcastEpisode, {
|
||||||
@ -168,4 +171,4 @@ class PodcastEpisode extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = PodcastEpisode
|
module.exports = PodcastEpisode
|
||||||
|
@ -24,7 +24,7 @@ class Series extends Model {
|
|||||||
|
|
||||||
static async getAllOldSeries() {
|
static async getAllOldSeries() {
|
||||||
const series = await this.findAll()
|
const series = await this.findAll()
|
||||||
return series.map(se => se.getOldSeries())
|
return series.map((se) => se.getOldSeries())
|
||||||
}
|
}
|
||||||
|
|
||||||
getOldSeries() {
|
getOldSeries() {
|
||||||
@ -77,7 +77,7 @@ class Series extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get oldSeries by id
|
* Get oldSeries by id
|
||||||
* @param {string} seriesId
|
* @param {string} seriesId
|
||||||
* @returns {Promise<oldSeries>}
|
* @returns {Promise<oldSeries>}
|
||||||
*/
|
*/
|
||||||
static async getOldById(seriesId) {
|
static async getOldById(seriesId) {
|
||||||
@ -88,7 +88,7 @@ class Series extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if series exists
|
* Check if series exists
|
||||||
* @param {string} seriesId
|
* @param {string} seriesId
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
static async checkExistsById(seriesId) {
|
static async checkExistsById(seriesId) {
|
||||||
@ -97,58 +97,65 @@ class Series extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get old series by name and libraryId. name case insensitive
|
* Get old series by name and libraryId. name case insensitive
|
||||||
*
|
*
|
||||||
* @param {string} seriesName
|
* @param {string} seriesName
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @returns {Promise<oldSeries>}
|
* @returns {Promise<oldSeries>}
|
||||||
*/
|
*/
|
||||||
static async getOldByNameAndLibrary(seriesName, libraryId) {
|
static async getOldByNameAndLibrary(seriesName, libraryId) {
|
||||||
const series = (await this.findOne({
|
const series = (
|
||||||
where: [
|
await this.findOne({
|
||||||
where(fn('lower', col('name')), seriesName.toLowerCase()),
|
where: [
|
||||||
{
|
where(fn('lower', col('name')), seriesName.toLowerCase()),
|
||||||
libraryId
|
{
|
||||||
}
|
libraryId
|
||||||
]
|
}
|
||||||
}))?.getOldSeries()
|
]
|
||||||
|
})
|
||||||
|
)?.getOldSeries()
|
||||||
return series
|
return series
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
},
|
primaryKey: true
|
||||||
name: DataTypes.STRING,
|
|
||||||
nameIgnorePrefix: DataTypes.STRING,
|
|
||||||
description: DataTypes.TEXT
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'series',
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
fields: [{
|
|
||||||
name: 'name',
|
|
||||||
collate: 'NOCASE'
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
// {
|
name: DataTypes.STRING,
|
||||||
// fields: [{
|
nameIgnorePrefix: DataTypes.STRING,
|
||||||
// name: 'nameIgnorePrefix',
|
description: DataTypes.TEXT
|
||||||
// collate: 'NOCASE'
|
},
|
||||||
// }]
|
{
|
||||||
// },
|
sequelize,
|
||||||
{
|
modelName: 'series',
|
||||||
fields: ['libraryId']
|
indexes: [
|
||||||
}
|
{
|
||||||
]
|
fields: [
|
||||||
})
|
{
|
||||||
|
name: 'name',
|
||||||
|
collate: 'NOCASE'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// fields: [{
|
||||||
|
// name: 'nameIgnorePrefix',
|
||||||
|
// collate: 'NOCASE'
|
||||||
|
// }]
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
fields: ['libraryId']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const { library } = sequelize.models
|
const { library } = sequelize.models
|
||||||
library.hasMany(Series, {
|
library.hasMany(Series, {
|
||||||
@ -158,4 +165,4 @@ class Series extends Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Series
|
module.exports = Series
|
||||||
|
@ -19,12 +19,11 @@ class Setting extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async getOldSettings() {
|
static async getOldSettings() {
|
||||||
const settings = (await this.findAll()).map(se => se.value)
|
const settings = (await this.findAll()).map((se) => se.value)
|
||||||
|
|
||||||
|
const emailSettingsJson = settings.find((se) => se.id === 'email-settings')
|
||||||
const emailSettingsJson = settings.find(se => se.id === 'email-settings')
|
const serverSettingsJson = settings.find((se) => se.id === 'server-settings')
|
||||||
const serverSettingsJson = settings.find(se => se.id === 'server-settings')
|
const notificationSettingsJson = settings.find((se) => se.id === 'notification-settings')
|
||||||
const notificationSettingsJson = settings.find(se => se.id === 'notification-settings')
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings,
|
settings,
|
||||||
@ -43,20 +42,23 @@ class Setting extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
key: {
|
{
|
||||||
type: DataTypes.STRING,
|
key: {
|
||||||
primaryKey: true
|
type: DataTypes.STRING,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
value: DataTypes.JSON
|
||||||
},
|
},
|
||||||
value: DataTypes.JSON
|
{
|
||||||
}, {
|
sequelize,
|
||||||
sequelize,
|
modelName: 'setting'
|
||||||
modelName: 'setting'
|
}
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Setting
|
module.exports = Setting
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const uuidv4 = require("uuid").v4
|
const uuidv4 = require('uuid').v4
|
||||||
const sequelize = require('sequelize')
|
const sequelize = require('sequelize')
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const oldUser = require('../objects/user/User')
|
const oldUser = require('../objects/user/User')
|
||||||
@ -45,17 +45,17 @@ class User extends Model {
|
|||||||
const users = await this.findAll({
|
const users = await this.findAll({
|
||||||
include: this.sequelize.models.mediaProgress
|
include: this.sequelize.models.mediaProgress
|
||||||
})
|
})
|
||||||
return users.map(u => this.getOldUser(u))
|
return users.map((u) => this.getOldUser(u))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get old user model from new
|
* Get old user model from new
|
||||||
*
|
*
|
||||||
* @param {Object} userExpanded
|
* @param {Object} userExpanded
|
||||||
* @returns {oldUser}
|
* @returns {oldUser}
|
||||||
*/
|
*/
|
||||||
static getOldUser(userExpanded) {
|
static getOldUser(userExpanded) {
|
||||||
const mediaProgress = userExpanded.mediaProgresses.map(mp => mp.getOldMediaProgress())
|
const mediaProgress = userExpanded.mediaProgresses.map((mp) => mp.getOldMediaProgress())
|
||||||
|
|
||||||
const librariesAccessible = userExpanded.permissions?.librariesAccessible || []
|
const librariesAccessible = userExpanded.permissions?.librariesAccessible || []
|
||||||
const itemTagsSelected = userExpanded.permissions?.itemTagsSelected || []
|
const itemTagsSelected = userExpanded.permissions?.itemTagsSelected || []
|
||||||
@ -86,8 +86,8 @@ class User extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {oldUser} oldUser
|
* @param {oldUser} oldUser
|
||||||
* @returns {Promise<User>}
|
* @returns {Promise<User>}
|
||||||
*/
|
*/
|
||||||
static createFromOld(oldUser) {
|
static createFromOld(oldUser) {
|
||||||
@ -97,8 +97,8 @@ class User extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update User from old user model
|
* Update User from old user model
|
||||||
*
|
*
|
||||||
* @param {oldUser} oldUser
|
* @param {oldUser} oldUser
|
||||||
* @param {boolean} [hooks=true] Run before / after bulk update hooks?
|
* @param {boolean} [hooks=true] Run before / after bulk update hooks?
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
@ -109,16 +109,18 @@ class User extends Model {
|
|||||||
where: {
|
where: {
|
||||||
id: user.id
|
id: user.id
|
||||||
}
|
}
|
||||||
}).then((result) => result[0] > 0).catch((error) => {
|
|
||||||
Logger.error(`[User] Failed to save user ${oldUser.id}`, error)
|
|
||||||
return false
|
|
||||||
})
|
})
|
||||||
|
.then((result) => result[0] > 0)
|
||||||
|
.catch((error) => {
|
||||||
|
Logger.error(`[User] Failed to save user ${oldUser.id}`, error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get new User model from old
|
* Get new User model from old
|
||||||
*
|
*
|
||||||
* @param {oldUser} oldUser
|
* @param {oldUser} oldUser
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
static getFromOld(oldUser) {
|
static getFromOld(oldUser) {
|
||||||
@ -160,9 +162,9 @@ class User extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create root user
|
* Create root user
|
||||||
* @param {string} username
|
* @param {string} username
|
||||||
* @param {string} pash
|
* @param {string} pash
|
||||||
* @param {Auth} auth
|
* @param {Auth} auth
|
||||||
* @returns {Promise<oldUser>}
|
* @returns {Promise<oldUser>}
|
||||||
*/
|
*/
|
||||||
static async createRootUser(username, pash, auth) {
|
static async createRootUser(username, pash, auth) {
|
||||||
@ -185,15 +187,15 @@ class User extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create user from openid userinfo
|
* Create user from openid userinfo
|
||||||
* @param {Object} userinfo
|
* @param {Object} userinfo
|
||||||
* @param {Auth} auth
|
* @param {Auth} auth
|
||||||
* @returns {Promise<oldUser>}
|
* @returns {Promise<oldUser>}
|
||||||
*/
|
*/
|
||||||
static async createUserFromOpenIdUserInfo(userinfo, auth) {
|
static async createUserFromOpenIdUserInfo(userinfo, auth) {
|
||||||
const userId = uuidv4()
|
const userId = uuidv4()
|
||||||
// TODO: Ensure username is unique?
|
// TODO: Ensure username is unique?
|
||||||
const username = userinfo.preferred_username || userinfo.name || userinfo.sub
|
const username = userinfo.preferred_username || userinfo.name || userinfo.sub
|
||||||
const email = (userinfo.email && userinfo.email_verified) ? userinfo.email : null
|
const email = userinfo.email && userinfo.email_verified ? userinfo.email : null
|
||||||
|
|
||||||
const token = await auth.generateAccessToken({ id: userId, username })
|
const token = await auth.generateAccessToken({ id: userId, username })
|
||||||
|
|
||||||
@ -218,7 +220,7 @@ class User extends Model {
|
|||||||
/**
|
/**
|
||||||
* Get a user by id or by the old database id
|
* Get a user by id or by the old database id
|
||||||
* @temp User ids were updated in v2.3.0 migration and old API tokens may still use that id
|
* @temp User ids were updated in v2.3.0 migration and old API tokens may still use that id
|
||||||
* @param {string} userId
|
* @param {string} userId
|
||||||
* @returns {Promise<oldUser|null>} null if not found
|
* @returns {Promise<oldUser|null>} null if not found
|
||||||
*/
|
*/
|
||||||
static async getUserByIdOrOldId(userId) {
|
static async getUserByIdOrOldId(userId) {
|
||||||
@ -244,7 +246,7 @@ class User extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user by username case insensitive
|
* Get user by username case insensitive
|
||||||
* @param {string} username
|
* @param {string} username
|
||||||
* @returns {Promise<oldUser|null>} returns null if not found
|
* @returns {Promise<oldUser|null>} returns null if not found
|
||||||
*/
|
*/
|
||||||
static async getUserByUsername(username) {
|
static async getUserByUsername(username) {
|
||||||
@ -263,7 +265,7 @@ class User extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user by email case insensitive
|
* Get user by email case insensitive
|
||||||
* @param {string} username
|
* @param {string} username
|
||||||
* @returns {Promise<oldUser|null>} returns null if not found
|
* @returns {Promise<oldUser|null>} returns null if not found
|
||||||
*/
|
*/
|
||||||
static async getUserByEmail(email) {
|
static async getUserByEmail(email) {
|
||||||
@ -282,7 +284,7 @@ class User extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user by id
|
* Get user by id
|
||||||
* @param {string} userId
|
* @param {string} userId
|
||||||
* @returns {Promise<oldUser|null>} returns null if not found
|
* @returns {Promise<oldUser|null>} returns null if not found
|
||||||
*/
|
*/
|
||||||
static async getUserById(userId) {
|
static async getUserById(userId) {
|
||||||
@ -296,7 +298,7 @@ class User extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user by openid sub
|
* Get user by openid sub
|
||||||
* @param {string} sub
|
* @param {string} sub
|
||||||
* @returns {Promise<oldUser|null>} returns null if not found
|
* @returns {Promise<oldUser|null>} returns null if not found
|
||||||
*/
|
*/
|
||||||
static async getUserByOpenIDSub(sub) {
|
static async getUserByOpenIDSub(sub) {
|
||||||
@ -317,7 +319,7 @@ class User extends Model {
|
|||||||
const users = await this.findAll({
|
const users = await this.findAll({
|
||||||
attributes: ['id', 'username']
|
attributes: ['id', 'username']
|
||||||
})
|
})
|
||||||
return users.map(u => {
|
return users.map((u) => {
|
||||||
return {
|
return {
|
||||||
id: u.id,
|
id: u.id,
|
||||||
username: u.username
|
username: u.username
|
||||||
@ -340,37 +342,40 @@ class User extends Model {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize model
|
* Initialize model
|
||||||
* @param {import('../Database').sequelize} sequelize
|
* @param {import('../Database').sequelize} sequelize
|
||||||
*/
|
*/
|
||||||
static init(sequelize) {
|
static init(sequelize) {
|
||||||
super.init({
|
super.init(
|
||||||
id: {
|
{
|
||||||
type: DataTypes.UUID,
|
id: {
|
||||||
defaultValue: DataTypes.UUIDV4,
|
type: DataTypes.UUID,
|
||||||
primaryKey: true
|
defaultValue: DataTypes.UUIDV4,
|
||||||
|
primaryKey: true
|
||||||
|
},
|
||||||
|
username: DataTypes.STRING,
|
||||||
|
email: DataTypes.STRING,
|
||||||
|
pash: DataTypes.STRING,
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
token: DataTypes.STRING,
|
||||||
|
isActive: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
isLocked: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
defaultValue: false
|
||||||
|
},
|
||||||
|
lastSeen: DataTypes.DATE,
|
||||||
|
permissions: DataTypes.JSON,
|
||||||
|
bookmarks: DataTypes.JSON,
|
||||||
|
extraData: DataTypes.JSON
|
||||||
},
|
},
|
||||||
username: DataTypes.STRING,
|
{
|
||||||
email: DataTypes.STRING,
|
sequelize,
|
||||||
pash: DataTypes.STRING,
|
modelName: 'user'
|
||||||
type: DataTypes.STRING,
|
}
|
||||||
token: DataTypes.STRING,
|
)
|
||||||
isActive: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
defaultValue: false
|
|
||||||
},
|
|
||||||
isLocked: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
defaultValue: false
|
|
||||||
},
|
|
||||||
lastSeen: DataTypes.DATE,
|
|
||||||
permissions: DataTypes.JSON,
|
|
||||||
bookmarks: DataTypes.JSON,
|
|
||||||
extraData: DataTypes.JSON
|
|
||||||
}, {
|
|
||||||
sequelize,
|
|
||||||
modelName: 'user'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = User
|
module.exports = User
|
||||||
|
Loading…
x
Reference in New Issue
Block a user