diff --git a/client/components/app/BookShelfCategorized.vue b/client/components/app/BookShelfCategorized.vue
index f01e829e..ff0c5ff7 100644
--- a/client/components/app/BookShelfCategorized.vue
+++ b/client/components/app/BookShelfCategorized.vue
@@ -168,7 +168,7 @@ export default {
},
async fetchCategories() {
const categories = await this.$axios
- .$get(`/api/libraries/${this.currentLibraryId}/personalized?include=rssfeed,numEpisodesIncomplete`)
+ .$get(`/api/libraries/${this.currentLibraryId}/personalized?include=rssfeed,numEpisodesIncomplete,share`)
.then((data) => {
return data
})
diff --git a/client/components/app/LazyBookshelf.vue b/client/components/app/LazyBookshelf.vue
index bb088b84..fa47ce99 100644
--- a/client/components/app/LazyBookshelf.vue
+++ b/client/components/app/LazyBookshelf.vue
@@ -312,7 +312,7 @@ export default {
let entityPath = this.entityName === 'series-books' ? 'items' : this.entityName
const sfQueryString = this.currentSFQueryString ? this.currentSFQueryString + '&' : ''
- const fullQueryString = `?${sfQueryString}limit=${this.booksPerFetch}&page=${page}&minified=1&include=rssfeed,numEpisodesIncomplete`
+ const fullQueryString = `?${sfQueryString}limit=${this.booksPerFetch}&page=${page}&minified=1&include=rssfeed,numEpisodesIncomplete,share`
const payload = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/${entityPath}${fullQueryString}`).catch((error) => {
console.error('failed to fetch items', error)
diff --git a/client/components/cards/LazyBookCard.vue b/client/components/cards/LazyBookCard.vue
index 5357267b..426a43d0 100644
--- a/client/components/cards/LazyBookCard.vue
+++ b/client/components/cards/LazyBookCard.vue
@@ -91,9 +91,14 @@
+
rss_feed
+
+
+ public
+
@@ -627,6 +632,9 @@ export default {
rssFeed() {
if (this.booksInSeries) return null
return this._libraryItem.rssFeed || null
+ },
+ mediaItemShare() {
+ return this._libraryItem.mediaItemShare || null
}
},
methods: {
diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js
index 32b098ed..3f72603f 100644
--- a/server/controllers/LibraryItemController.js
+++ b/server/controllers/LibraryItemController.js
@@ -21,7 +21,7 @@ class LibraryItemController {
/**
* GET: /api/items/:id
* Optional query params:
- * ?include=progress,rssfeed,downloads
+ * ?include=progress,rssfeed,downloads,share
* ?expanded=1
*
* @param {import('express').Request} req
diff --git a/server/models/LibraryItem.js b/server/models/LibraryItem.js
index 2eccee19..cffcb80a 100644
--- a/server/models/LibraryItem.js
+++ b/server/models/LibraryItem.js
@@ -10,6 +10,8 @@ const LibraryFile = require('../objects/files/LibraryFile')
const Book = require('./Book')
const Podcast = require('./Podcast')
+const ShareManager = require('../managers/ShareManager')
+
/**
* @typedef LibraryFileObject
* @property {string} ino
@@ -537,7 +539,7 @@ class LibraryItem extends Model {
* @param {oldLibrary} library
* @param {oldUser} user
* @param {object} options
- * @returns {object} { libraryItems:oldLibraryItem[], count:number }
+ * @returns {{ libraryItems:oldLibraryItem[], count:number }}
*/
static async getByFilterAndSort(library, user, options) {
let start = Date.now()
@@ -565,6 +567,10 @@ class LibraryItem extends Model {
if (li.numEpisodesIncomplete) {
oldLibraryItem.numEpisodesIncomplete = li.numEpisodesIncomplete
}
+ if (li.mediaType === 'book' && options.include?.includes?.('share')) {
+ console.log('Lookup share for media item id', li.mediaId)
+ oldLibraryItem.mediaItemShare = ShareManager.findByMediaItemId(li.mediaId)
+ }
return oldLibraryItem
}),
diff --git a/server/utils/queries/libraryFilters.js b/server/utils/queries/libraryFilters.js
index a2efb664..ffcbd83e 100644
--- a/server/utils/queries/libraryFilters.js
+++ b/server/utils/queries/libraryFilters.js
@@ -15,9 +15,9 @@ module.exports = {
/**
* Get library items using filter and sort
- * @param {import('../../objects/Library')} library
- * @param {import('../../objects/user/User')} user
- * @param {object} options
+ * @param {import('../../objects/Library')} library
+ * @param {import('../../objects/user/User')} user
+ * @param {object} options
* @returns {object} { libraryItems:LibraryItem[], count:number }
*/
async getFilteredLibraryItems(library, user, options) {
@@ -27,7 +27,7 @@ module.exports = {
let filterGroup = null
if (filterBy) {
const searchGroups = ['genres', 'tags', 'series', 'authors', 'progress', 'narrators', 'publishers', 'missing', 'languages', 'tracks', 'ebooks']
- const group = searchGroups.find(_group => filterBy.startsWith(_group + '.'))
+ const group = searchGroups.find((_group) => filterBy.startsWith(_group + '.'))
filterGroup = group || filterBy
filterValue = group ? this.decode(filterBy.replace(`${group}.`, '')) : null
}
@@ -41,21 +41,24 @@ module.exports = {
/**
* Get library items for continue listening & continue reading shelves
- * @param {import('../../objects/Library')} library
- * @param {import('../../objects/user/User')} user
- * @param {string[]} include
- * @param {number} limit
+ * @param {import('../../objects/Library')} library
+ * @param {import('../../objects/user/User')} user
+ * @param {string[]} include
+ * @param {number} limit
* @returns {Promise<{ items:import('../../models/LibraryItem')[], count:number }>}
*/
async getMediaItemsInProgress(library, user, include, limit) {
if (library.mediaType === 'book') {
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'progress', 'in-progress', 'progress', true, false, include, limit, 0, true)
return {
- items: libraryItems.map(li => {
+ items: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
}
+ if (li.mediaItemShare) {
+ oldLibraryItem.mediaItemShare = li.mediaItemShare
+ }
return oldLibraryItem
}),
count
@@ -64,7 +67,7 @@ module.exports = {
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, user, 'progress', 'in-progress', 'progress', true, limit, 0, true)
return {
count,
- items: libraryItems.map(li => {
+ items: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
oldLibraryItem.recentEpisode = li.recentEpisode
return oldLibraryItem
@@ -75,17 +78,17 @@ module.exports = {
/**
* Get library items for most recently added shelf
- * @param {import('../../objects/Library')} library
- * @param {oldUser} user
- * @param {string[]} include
- * @param {number} limit
+ * @param {import('../../objects/Library')} library
+ * @param {oldUser} user
+ * @param {string[]} include
+ * @param {number} limit
* @returns {object} { libraryItems:LibraryItem[], count:number }
*/
async getLibraryItemsMostRecentlyAdded(library, user, include, limit) {
if (library.mediaType === 'book') {
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'recent', null, 'addedAt', true, false, include, limit, 0)
return {
- libraryItems: libraryItems.map(li => {
+ libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
@@ -93,6 +96,9 @@ module.exports = {
if (li.size && !oldLibraryItem.media.size) {
oldLibraryItem.media.size = li.size
}
+ if (li.mediaItemShare) {
+ oldLibraryItem.mediaItemShare = li.mediaItemShare
+ }
return oldLibraryItem
}),
count
@@ -100,7 +106,7 @@ module.exports = {
} else {
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredLibraryItems(library.id, user, 'recent', null, 'addedAt', true, include, limit, 0)
return {
- libraryItems: libraryItems.map(li => {
+ libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
@@ -120,16 +126,16 @@ module.exports = {
/**
* Get library items for continue series shelf
- * @param {import('../../objects/Library')} library
- * @param {oldUser} user
- * @param {string[]} include
- * @param {number} limit
+ * @param {import('../../objects/Library')} library
+ * @param {oldUser} user
+ * @param {string[]} include
+ * @param {number} limit
* @returns {object} { libraryItems:LibraryItem[], count:number }
*/
async getLibraryItemsContinueSeries(library, user, include, limit) {
const { libraryItems, count } = await libraryItemsBookFilters.getContinueSeriesLibraryItems(library, user, include, limit, 0)
return {
- libraryItems: libraryItems.map(li => {
+ libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
@@ -137,6 +143,9 @@ module.exports = {
if (li.series) {
oldLibraryItem.media.metadata.series = li.series
}
+ if (li.mediaItemShare) {
+ oldLibraryItem.mediaItemShare = li.mediaItemShare
+ }
return oldLibraryItem
}),
count
@@ -145,21 +154,24 @@ module.exports = {
/**
* Get library items or podcast episodes for the "Listen Again" and "Read Again" shelf
- * @param {import('../../objects/Library')} library
- * @param {oldUser} user
- * @param {string[]} include
- * @param {number} limit
+ * @param {import('../../objects/Library')} library
+ * @param {oldUser} user
+ * @param {string[]} include
+ * @param {number} limit
* @returns {object} { items:object[], count:number }
*/
async getMediaFinished(library, user, include, limit) {
if (library.mediaType === 'book') {
const { libraryItems, count } = await libraryItemsBookFilters.getFilteredLibraryItems(library.id, user, 'progress', 'finished', 'progress', true, false, include, limit, 0)
return {
- items: libraryItems.map(li => {
+ items: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
}
+ if (li.mediaItemShare) {
+ oldLibraryItem.mediaItemShare = li.mediaItemShare
+ }
return oldLibraryItem
}),
count
@@ -168,7 +180,7 @@ module.exports = {
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, user, 'progress', 'finished', 'progress', true, limit, 0)
return {
count,
- items: libraryItems.map(li => {
+ items: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
oldLibraryItem.recentEpisode = li.recentEpisode
return oldLibraryItem
@@ -179,11 +191,11 @@ module.exports = {
/**
* Get series for recent series shelf
- * @param {import('../../objects/Library')} library
+ * @param {import('../../objects/Library')} library
* @param {import('../../objects/user/User')} user
- * @param {string[]} include
- * @param {number} limit
- * @returns {{ series:import('../../objects/entities/Series')[], count:number}}
+ * @param {string[]} include
+ * @param {number} limit
+ * @returns {{ series:import('../../objects/entities/Series')[], count:number}}
*/
async getSeriesMostRecentlyAdded(library, user, include, limit) {
if (!library.isBook) return { series: [], count: 0 }
@@ -201,7 +213,7 @@ module.exports = {
{
libraryId: library.id,
createdAt: {
- [Sequelize.Op.gte]: new Date(new Date() - (60 * 24 * 60 * 60 * 1000)) // 60 days ago
+ [Sequelize.Op.gte]: new Date(new Date() - 60 * 24 * 60 * 60 * 1000) // 60 days ago
}
}
]
@@ -209,9 +221,11 @@ module.exports = {
// Handle library setting to hide single book series
// TODO: Merge with existing query
if (library.settings.hideSingleBookSeries) {
- seriesWhere.push(Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id)`), {
- [Sequelize.Op.gt]: 1
- }))
+ seriesWhere.push(
+ Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM books b, bookSeries bs WHERE bs.seriesId = series.id AND bs.bookId = b.id)`), {
+ [Sequelize.Op.gt]: 1
+ })
+ )
}
// Handle user permissions to only include series with at least 1 book
@@ -228,9 +242,11 @@ module.exports = {
attrQuery += ' AND (SELECT count(*) FROM json_each(tags) WHERE json_valid(tags) AND json_each.value IN (:userTagsSelected)) > 0'
}
}
- seriesWhere.push(Sequelize.where(Sequelize.literal(`(${attrQuery})`), {
- [Sequelize.Op.gt]: 0
- }))
+ seriesWhere.push(
+ Sequelize.where(Sequelize.literal(`(${attrQuery})`), {
+ [Sequelize.Op.gt]: 0
+ })
+ )
}
const { rows: series, count } = await Database.seriesModel.findAndCountAll({
@@ -254,9 +270,7 @@ module.exports = {
},
...seriesIncludes
],
- order: [
- ['createdAt', 'DESC']
- ]
+ order: [['createdAt', 'DESC']]
})
const allOldSeries = []
@@ -276,18 +290,20 @@ module.exports = {
sensitivity: 'base'
})
})
- oldSeries.books = s.bookSeries.map(bs => {
- const libraryItem = bs.book.libraryItem?.toJSON()
- if (!libraryItem) {
- Logger.warn(`Book series book has no libraryItem`, bs, bs.book, 'series=', series)
- return null
- }
+ oldSeries.books = s.bookSeries
+ .map((bs) => {
+ const libraryItem = bs.book.libraryItem?.toJSON()
+ if (!libraryItem) {
+ Logger.warn(`Book series book has no libraryItem`, bs, bs.book, 'series=', series)
+ return null
+ }
- delete bs.book.libraryItem
- libraryItem.media = bs.book
- const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSONMinified()
- return oldLibraryItem
- }).filter(b => b)
+ delete bs.book.libraryItem
+ libraryItem.media = bs.book
+ const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(libraryItem).toJSONMinified()
+ return oldLibraryItem
+ })
+ .filter((b) => b)
allOldSeries.push(oldSeries)
}
@@ -300,9 +316,9 @@ module.exports = {
/**
* Get most recently created authors for "Newest Authors" shelf
* Author must be linked to at least 1 book
- * @param {oldLibrary} library
+ * @param {oldLibrary} library
* @param {oldUser} user
- * @param {number} limit
+ * @param {number} limit
* @returns {object} { authors:oldAuthor[], count:number }
*/
async getNewestAuthors(library, user, limit) {
@@ -314,7 +330,7 @@ module.exports = {
where: {
libraryId: library.id,
createdAt: {
- [Sequelize.Op.gte]: new Date(new Date() - (60 * 24 * 60 * 60 * 1000)) // 60 days ago
+ [Sequelize.Op.gte]: new Date(new Date() - 60 * 24 * 60 * 60 * 1000) // 60 days ago
}
},
replacements,
@@ -329,9 +345,7 @@ module.exports = {
},
limit,
distinct: true,
- order: [
- ['createdAt', 'DESC']
- ]
+ order: [['createdAt', 'DESC']]
})
return {
@@ -345,10 +359,10 @@ module.exports = {
/**
* Get book library items for the "Discover" shelf
- * @param {oldLibrary} library
- * @param {oldUser} user
- * @param {string[]} include
- * @param {number} limit
+ * @param {oldLibrary} library
+ * @param {oldUser} user
+ * @param {string[]} include
+ * @param {number} limit
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
*/
async getLibraryItemsToDiscover(library, user, include, limit) {
@@ -356,11 +370,14 @@ module.exports = {
const { libraryItems, count } = await libraryItemsBookFilters.getDiscoverLibraryItems(library.id, user, include, limit)
return {
- libraryItems: libraryItems.map(li => {
+ libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
if (li.rssFeed) {
oldLibraryItem.rssFeed = Database.feedModel.getOldFeed(li.rssFeed).toJSONMinified()
}
+ if (li.mediaItemShare) {
+ oldLibraryItem.mediaItemShare = li.mediaItemShare
+ }
return oldLibraryItem
}),
count
@@ -369,9 +386,9 @@ module.exports = {
/**
* Get podcast episodes most recently added
- * @param {oldLibrary} library
- * @param {oldUser} user
- * @param {number} limit
+ * @param {oldLibrary} library
+ * @param {oldUser} user
+ * @param {number} limit
* @returns {object} {libraryItems:oldLibraryItem[], count:number}
*/
async getNewestPodcastEpisodes(library, user, limit) {
@@ -380,7 +397,7 @@ module.exports = {
const { libraryItems, count } = await libraryItemsPodcastFilters.getFilteredPodcastEpisodes(library.id, user, 'recent', null, 'createdAt', true, limit, 0)
return {
count,
- libraryItems: libraryItems.map(li => {
+ libraryItems: libraryItems.map((li) => {
const oldLibraryItem = Database.libraryItemModel.getOldLibraryItem(li).toJSONMinified()
oldLibraryItem.recentEpisode = li.recentEpisode
return oldLibraryItem
@@ -390,10 +407,10 @@ module.exports = {
/**
* Get library items for an author, optional use user permissions
- * @param {oldAuthor} author
- * @param {[oldUser]} user
- * @param {number} limit
- * @param {number} offset
+ * @param {oldAuthor} author
+ * @param {[oldUser]} user
+ * @param {number} limit
+ * @param {number} offset
* @returns {Promise