mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Merge pull request #1231 from k9withabone/server/respond-with-objects
Server respond with objects
This commit is contained in:
		
						commit
						05d10b73c3
					
				@ -122,7 +122,7 @@ export default {
 | 
				
			|||||||
      return this.$store.state.globals.selectedMediaItems
 | 
					      return this.$store.state.globals.selectedMediaItems
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    selectedMediaItemsArePlayable() {
 | 
					    selectedMediaItemsArePlayable() {
 | 
				
			||||||
      return !this.selectedMediaItems.some(i => !i.hasTracks)
 | 
					      return !this.selectedMediaItems.some((i) => !i.hasTracks)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    userMediaProgress() {
 | 
					    userMediaProgress() {
 | 
				
			||||||
      return this.$store.state.user.user.mediaProgress || []
 | 
					      return this.$store.state.user.user.mediaProgress || []
 | 
				
			||||||
@ -164,7 +164,10 @@ export default {
 | 
				
			|||||||
      this.$store.commit('setProcessingBatch', true)
 | 
					      this.$store.commit('setProcessingBatch', true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const libraryItemIds = this.selectedMediaItems.map((i) => i.id)
 | 
					      const libraryItemIds = this.selectedMediaItems.map((i) => i.id)
 | 
				
			||||||
      const libraryItems = await this.$axios.$post(`/api/items/batch/get`, { libraryItemIds }).catch((error) => {
 | 
					      const libraryItems = await this.$axios
 | 
				
			||||||
 | 
					        .$post(`/api/items/batch/get`, { libraryItemIds })
 | 
				
			||||||
 | 
					        .then((res) => res.libraryItems)
 | 
				
			||||||
 | 
					        .catch((error) => {
 | 
				
			||||||
          const errorMsg = error.response.data || 'Failed to get items'
 | 
					          const errorMsg = error.response.data || 'Failed to get items'
 | 
				
			||||||
          console.error(errorMsg, error)
 | 
					          console.error(errorMsg, error)
 | 
				
			||||||
          this.$toast.error(errorMsg)
 | 
					          this.$toast.error(errorMsg)
 | 
				
			||||||
 | 
				
			|||||||
@ -201,8 +201,8 @@ export default {
 | 
				
			|||||||
      this.loadingTags = true
 | 
					      this.loadingTags = true
 | 
				
			||||||
      this.$axios
 | 
					      this.$axios
 | 
				
			||||||
        .$get(`/api/tags`)
 | 
					        .$get(`/api/tags`)
 | 
				
			||||||
        .then((tags) => {
 | 
					        .then((res) => {
 | 
				
			||||||
          this.tags = tags
 | 
					          this.tags = res.tags
 | 
				
			||||||
          this.loadingTags = false
 | 
					          this.loadingTags = false
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .catch((error) => {
 | 
					        .catch((error) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -303,8 +303,11 @@ export default {
 | 
				
			|||||||
      this.persistProvider()
 | 
					      this.persistProvider()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.isProcessing = true
 | 
					      this.isProcessing = true
 | 
				
			||||||
      var searchQuery = this.getSearchQuery()
 | 
					      const searchQuery = this.getSearchQuery()
 | 
				
			||||||
      var results = await this.$axios.$get(`/api/search/covers?${searchQuery}`).catch((error) => {
 | 
					      const results = await this.$axios
 | 
				
			||||||
 | 
					        .$get(`/api/search/covers?${searchQuery}`)
 | 
				
			||||||
 | 
					        .then((res) => res.results)
 | 
				
			||||||
 | 
					        .catch((error) => {
 | 
				
			||||||
          console.error('Failed', error)
 | 
					          console.error('Failed', error)
 | 
				
			||||||
          return []
 | 
					          return []
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
				
			|||||||
@ -306,13 +306,13 @@ export default {
 | 
				
			|||||||
      this.runSearch()
 | 
					      this.runSearch()
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    async runSearch() {
 | 
					    async runSearch() {
 | 
				
			||||||
      var searchQuery = this.getSearchQuery()
 | 
					      const searchQuery = this.getSearchQuery()
 | 
				
			||||||
      if (this.lastSearch === searchQuery) return
 | 
					      if (this.lastSearch === searchQuery) return
 | 
				
			||||||
      this.searchResults = []
 | 
					      this.searchResults = []
 | 
				
			||||||
      this.isProcessing = true
 | 
					      this.isProcessing = true
 | 
				
			||||||
      this.lastSearch = searchQuery
 | 
					      this.lastSearch = searchQuery
 | 
				
			||||||
      var searchEntity = this.isPodcast ? 'podcast' : 'books'
 | 
					      const searchEntity = this.isPodcast ? 'podcast' : 'books'
 | 
				
			||||||
      var results = await this.$axios.$get(`/api/search/${searchEntity}?${searchQuery}`, { timeout: 20000 }).catch((error) => {
 | 
					      let results = await this.$axios.$get(`/api/search/${searchEntity}?${searchQuery}`, { timeout: 20000 }).catch((error) => {
 | 
				
			||||||
        console.error('Failed', error)
 | 
					        console.error('Failed', error)
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
				
			|||||||
@ -109,8 +109,8 @@ export default {
 | 
				
			|||||||
    loadUsers() {
 | 
					    loadUsers() {
 | 
				
			||||||
      this.$axios
 | 
					      this.$axios
 | 
				
			||||||
        .$get('/api/users')
 | 
					        .$get('/api/users')
 | 
				
			||||||
        .then((users) => {
 | 
					        .then((res) => {
 | 
				
			||||||
          this.users = users.sort((a, b) => {
 | 
					          this.users = res.users.sort((a, b) => {
 | 
				
			||||||
            return a.createdAt - b.createdAt
 | 
					            return a.createdAt - b.createdAt
 | 
				
			||||||
          })
 | 
					          })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
				
			|||||||
@ -82,10 +82,10 @@ export default {
 | 
				
			|||||||
      })
 | 
					      })
 | 
				
			||||||
      var newOrder = libraryOrderData.map((lib) => lib.id).join(',')
 | 
					      var newOrder = libraryOrderData.map((lib) => lib.id).join(',')
 | 
				
			||||||
      if (currOrder !== newOrder) {
 | 
					      if (currOrder !== newOrder) {
 | 
				
			||||||
        this.$axios.$post('/api/libraries/order', libraryOrderData).then((libraries) => {
 | 
					        this.$axios.$post('/api/libraries/order', libraryOrderData).then((response) => {
 | 
				
			||||||
          if (libraries && libraries.length) {
 | 
					          if (response.libraries && response.libraries.length) {
 | 
				
			||||||
            this.$toast.success('Library order saved', { timeout: 1500 })
 | 
					            this.$toast.success('Library order saved', { timeout: 1500 })
 | 
				
			||||||
            this.$store.commit('libraries/set', libraries)
 | 
					            this.$store.commit('libraries/set', response.libraries)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -96,7 +96,10 @@ export default {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const libraryItemIds = store.state.globals.selectedMediaItems.map((i) => i.id)
 | 
					    const libraryItemIds = store.state.globals.selectedMediaItems.map((i) => i.id)
 | 
				
			||||||
    const libraryItems = await app.$axios.$post(`/api/items/batch/get`, { libraryItemIds }).catch((error) => {
 | 
					    const libraryItems = await app.$axios
 | 
				
			||||||
 | 
					      .$post(`/api/items/batch/get`, { libraryItemIds })
 | 
				
			||||||
 | 
					      .then((res) => res.libraryItems)
 | 
				
			||||||
 | 
					      .catch((error) => {
 | 
				
			||||||
        const errorMsg = error.response.data || 'Failed to get items'
 | 
					        const errorMsg = error.response.data || 'Failed to get items'
 | 
				
			||||||
        console.error(errorMsg, error)
 | 
					        console.error(errorMsg, error)
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
 | 
				
			|||||||
@ -61,10 +61,10 @@
 | 
				
			|||||||
<script>
 | 
					<script>
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  async asyncData({ params, redirect, app }) {
 | 
					  async asyncData({ params, redirect, app }) {
 | 
				
			||||||
    var users = await app.$axios
 | 
					    const users = await app.$axios
 | 
				
			||||||
      .$get('/api/users')
 | 
					      .$get('/api/users')
 | 
				
			||||||
      .then((users) => {
 | 
					      .then((res) => {
 | 
				
			||||||
        return users.sort((a, b) => {
 | 
					        return res.users.sort((a, b) => {
 | 
				
			||||||
          return a.createdAt - b.createdAt
 | 
					          return a.createdAt - b.createdAt
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
				
			|||||||
@ -48,7 +48,10 @@ export default {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    async init() {
 | 
					    async init() {
 | 
				
			||||||
      this.authors = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/authors`).catch((error) => {
 | 
					      this.authors = await this.$axios
 | 
				
			||||||
 | 
					        .$get(`/api/libraries/${this.currentLibraryId}/authors`)
 | 
				
			||||||
 | 
					        .then((response) => response.authors)
 | 
				
			||||||
 | 
					        .catch((error) => {
 | 
				
			||||||
          console.error('Failed to load authors', error)
 | 
					          console.error('Failed to load authors', error)
 | 
				
			||||||
          return []
 | 
					          return []
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
				
			|||||||
@ -86,8 +86,8 @@ export const actions = {
 | 
				
			|||||||
      .$get('/api/filesystem')
 | 
					      .$get('/api/filesystem')
 | 
				
			||||||
      .then((res) => {
 | 
					      .then((res) => {
 | 
				
			||||||
        console.log('Settings folders', res)
 | 
					        console.log('Settings folders', res)
 | 
				
			||||||
        commit('setFolders', res)
 | 
					        commit('setFolders', res.directories)
 | 
				
			||||||
        return res
 | 
					        return res.directories
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .catch((error) => {
 | 
					      .catch((error) => {
 | 
				
			||||||
        console.error('Failed to load dirs', error)
 | 
					        console.error('Failed to load dirs', error)
 | 
				
			||||||
@ -151,7 +151,7 @@ export const actions = {
 | 
				
			|||||||
    this.$axios
 | 
					    this.$axios
 | 
				
			||||||
      .$get(`/api/libraries`)
 | 
					      .$get(`/api/libraries`)
 | 
				
			||||||
      .then((data) => {
 | 
					      .then((data) => {
 | 
				
			||||||
        commit('set', data)
 | 
					        commit('set', data.libraries)
 | 
				
			||||||
        commit('setLastLoad')
 | 
					        commit('setLastLoad')
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .catch((error) => {
 | 
					      .catch((error) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -148,7 +148,9 @@ class AuthorController {
 | 
				
			|||||||
    var limit = (req.query.limit && !isNaN(req.query.limit)) ? Number(req.query.limit) : 25
 | 
					    var limit = (req.query.limit && !isNaN(req.query.limit)) ? Number(req.query.limit) : 25
 | 
				
			||||||
    var authors = this.db.authors.filter(au => au.name.toLowerCase().includes(q))
 | 
					    var authors = this.db.authors.filter(au => au.name.toLowerCase().includes(q))
 | 
				
			||||||
    authors = authors.slice(0, limit)
 | 
					    authors = authors.slice(0, limit)
 | 
				
			||||||
    res.json(authors)
 | 
					    res.json({
 | 
				
			||||||
 | 
					      results: authors
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async match(req, res) {
 | 
					  async match(req, res) {
 | 
				
			||||||
 | 
				
			|||||||
@ -20,8 +20,9 @@ class CollectionController {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  findAll(req, res) {
 | 
					  findAll(req, res) {
 | 
				
			||||||
    var expandedCollections = this.db.collections.map(c => c.toJSONExpanded(this.db.libraryItems))
 | 
					    res.json({
 | 
				
			||||||
    res.json(expandedCollections)
 | 
					      collections: this.db.collections.map(c => c.toJSONExpanded(this.db.libraryItems))
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  findOne(req, res) {
 | 
					  findOne(req, res) {
 | 
				
			||||||
 | 
				
			|||||||
@ -19,8 +19,9 @@ class FileSystemController {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Logger.debug(`[Server] get file system paths, excluded: ${excludedDirs.join(', ')}`)
 | 
					    Logger.debug(`[Server] get file system paths, excluded: ${excludedDirs.join(', ')}`)
 | 
				
			||||||
    var dirs = await this.getDirectories(global.appRoot, '/', excludedDirs)
 | 
					    res.json({
 | 
				
			||||||
    res.json(dirs)
 | 
					      directories: await this.getDirectories(global.appRoot, '/', excludedDirs)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
module.exports = new FileSystemController()
 | 
					module.exports = new FileSystemController()
 | 
				
			||||||
@ -62,7 +62,9 @@ class LibraryController {
 | 
				
			|||||||
      return res.json(this.db.libraries.filter(lib => librariesAccessible.includes(lib.id)).map(lib => lib.toJSON()))
 | 
					      return res.json(this.db.libraries.filter(lib => librariesAccessible.includes(lib.id)).map(lib => lib.toJSON()))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res.json(this.db.libraries.map(lib => lib.toJSON()))
 | 
					    res.json({
 | 
				
			||||||
 | 
					      libraries: this.db.libraries.map(lib => lib.toJSON())
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async findOne(req, res) {
 | 
					  async findOne(req, res) {
 | 
				
			||||||
@ -496,8 +498,9 @@ class LibraryController {
 | 
				
			|||||||
      Logger.debug(`[LibraryController] Library orders were up to date`)
 | 
					      Logger.debug(`[LibraryController] Library orders were up to date`)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var libraries = this.db.libraries.map(lib => lib.toJSON())
 | 
					    res.json({
 | 
				
			||||||
    res.json(libraries)
 | 
					      libraries: this.db.libraries.map(lib => lib.toJSON())
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // GET: Global library search
 | 
					  // GET: Global library search
 | 
				
			||||||
@ -603,7 +606,9 @@ class LibraryController {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res.json(naturalSort(Object.values(authors)).asc(au => au.name))
 | 
					    res.json({
 | 
				
			||||||
 | 
					      authors: naturalSort(Object.values(authors)).asc(au => au.name)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async matchAll(req, res) {
 | 
					  async matchAll(req, res) {
 | 
				
			||||||
 | 
				
			|||||||
@ -308,16 +308,18 @@ class LibraryItemController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // POST: api/items/batch/get
 | 
					  // POST: api/items/batch/get
 | 
				
			||||||
  async batchGet(req, res) {
 | 
					  async batchGet(req, res) {
 | 
				
			||||||
    var libraryItemIds = req.body.libraryItemIds || []
 | 
					    const libraryItemIds = req.body.libraryItemIds || []
 | 
				
			||||||
    if (!libraryItemIds.length) {
 | 
					    if (!libraryItemIds.length) {
 | 
				
			||||||
      return res.status(403).send('Invalid payload')
 | 
					      return res.status(403).send('Invalid payload')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    var libraryItems = []
 | 
					    const libraryItems = []
 | 
				
			||||||
    libraryItemIds.forEach((lid) => {
 | 
					    libraryItemIds.forEach((lid) => {
 | 
				
			||||||
      const li = this.db.libraryItems.find(_li => _li.id === lid)
 | 
					      const li = this.db.libraryItems.find(_li => _li.id === lid)
 | 
				
			||||||
      if (li) libraryItems.push(li.toJSONExpanded())
 | 
					      if (li) libraryItems.push(li.toJSONExpanded())
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    res.json(libraryItems)
 | 
					    res.json({
 | 
				
			||||||
 | 
					      libraryItems
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // POST: api/items/batch/quickmatch
 | 
					  // POST: api/items/batch/quickmatch
 | 
				
			||||||
 | 
				
			|||||||
@ -137,7 +137,9 @@ class MiscController {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    res.json(tags)
 | 
					    res.json({
 | 
				
			||||||
 | 
					      tags: tags
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  validateCronExpression(req, res) {
 | 
					  validateCronExpression(req, res) {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,15 +4,15 @@ class SearchController {
 | 
				
			|||||||
  constructor() { }
 | 
					  constructor() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async findBooks(req, res) {
 | 
					  async findBooks(req, res) {
 | 
				
			||||||
    var provider = req.query.provider || 'google'
 | 
					    const provider = req.query.provider || 'google'
 | 
				
			||||||
    var title = req.query.title || ''
 | 
					    const title = req.query.title || ''
 | 
				
			||||||
    var author = req.query.author || ''
 | 
					    const author = req.query.author || ''
 | 
				
			||||||
    var results = await this.bookFinder.search(provider, title, author)
 | 
					    const results = await this.bookFinder.search(provider, title, author)
 | 
				
			||||||
    res.json(results)
 | 
					    res.json(results)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async findCovers(req, res) {
 | 
					  async findCovers(req, res) {
 | 
				
			||||||
    var query = req.query
 | 
					    const query = req.query
 | 
				
			||||||
    const podcast = query.podcast == 1
 | 
					    const podcast = query.podcast == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!query.title) {
 | 
					    if (!query.title) {
 | 
				
			||||||
@ -20,28 +20,30 @@ class SearchController {
 | 
				
			|||||||
      return res.sendStatus(400)
 | 
					      return res.sendStatus(400)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var result = null
 | 
					    let results = null
 | 
				
			||||||
    if (podcast) result = await this.podcastFinder.findCovers(query.title)
 | 
					    if (podcast) results = await this.podcastFinder.findCovers(query.title)
 | 
				
			||||||
    else result = await this.bookFinder.findCovers(query.provider || 'google', query.title, query.author || null)
 | 
					    else results = await this.bookFinder.findCovers(query.provider || 'google', query.title, query.author || null)
 | 
				
			||||||
    res.json(result)
 | 
					    res.json({
 | 
				
			||||||
 | 
					      results
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async findPodcasts(req, res) {
 | 
					  async findPodcasts(req, res) {
 | 
				
			||||||
    var term = req.query.term
 | 
					    const term = req.query.term
 | 
				
			||||||
    var results = await this.podcastFinder.search(term)
 | 
					    const results = await this.podcastFinder.search(term)
 | 
				
			||||||
    res.json(results)
 | 
					    res.json(results)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async findAuthor(req, res) {
 | 
					  async findAuthor(req, res) {
 | 
				
			||||||
    var query = req.query.q
 | 
					    const query = req.query.q
 | 
				
			||||||
    var author = await this.authorFinder.findAuthorByName(query)
 | 
					    const author = await this.authorFinder.findAuthorByName(query)
 | 
				
			||||||
    res.json(author)
 | 
					    res.json(author)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async findChapters(req, res) {
 | 
					  async findChapters(req, res) {
 | 
				
			||||||
    var asin = req.query.asin
 | 
					    const asin = req.query.asin
 | 
				
			||||||
    var region = (req.query.region || 'us').toLowerCase()
 | 
					    const region = (req.query.region || 'us').toLowerCase()
 | 
				
			||||||
    var chapterData = await this.bookFinder.findChapters(asin, region)
 | 
					    const chapterData = await this.bookFinder.findChapters(asin, region)
 | 
				
			||||||
    if (!chapterData) {
 | 
					    if (!chapterData) {
 | 
				
			||||||
      return res.json({ error: 'Chapters not found' })
 | 
					      return res.json({ error: 'Chapters not found' })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -32,7 +32,9 @@ class SeriesController {
 | 
				
			|||||||
    var limit = (req.query.limit && !isNaN(req.query.limit)) ? Number(req.query.limit) : 25
 | 
					    var limit = (req.query.limit && !isNaN(req.query.limit)) ? Number(req.query.limit) : 25
 | 
				
			||||||
    var series = this.db.series.filter(se => se.name.toLowerCase().includes(q))
 | 
					    var series = this.db.series.filter(se => se.name.toLowerCase().includes(q))
 | 
				
			||||||
    series = series.slice(0, limit)
 | 
					    series = series.slice(0, limit)
 | 
				
			||||||
    res.json(series)
 | 
					    res.json({
 | 
				
			||||||
 | 
					      results: series
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async update(req, res) {
 | 
					  async update(req, res) {
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,9 @@ class UserController {
 | 
				
			|||||||
    if (!req.user.isAdminOrUp) return res.sendStatus(403)
 | 
					    if (!req.user.isAdminOrUp) return res.sendStatus(403)
 | 
				
			||||||
    const hideRootToken = !req.user.isRoot
 | 
					    const hideRootToken = !req.user.isRoot
 | 
				
			||||||
    const users = this.db.users.map(u => this.userJsonWithItemProgressDetails(u, hideRootToken))
 | 
					    const users = this.db.users.map(u => this.userJsonWithItemProgressDetails(u, hideRootToken))
 | 
				
			||||||
    res.json(users)
 | 
					    res.json({
 | 
				
			||||||
 | 
					      users: users
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  findOne(req, res) {
 | 
					  findOne(req, res) {
 | 
				
			||||||
 | 
				
			|||||||
@ -31,7 +31,7 @@ class PlaybackSessionManager {
 | 
				
			|||||||
    return this.sessions.find(s => s.userId === userId)
 | 
					    return this.sessions.find(s => s.userId === userId)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  getStream(sessionId) {
 | 
					  getStream(sessionId) {
 | 
				
			||||||
    var session = this.getSession(sessionId)
 | 
					    const session = this.getSession(sessionId)
 | 
				
			||||||
    return session ? session.stream : null
 | 
					    return session ? session.stream : null
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -54,7 +54,7 @@ class PlaybackSessionManager {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async syncSessionRequest(user, session, payload, res) {
 | 
					  async syncSessionRequest(user, session, payload, res) {
 | 
				
			||||||
    var result = await this.syncSession(user, session, payload)
 | 
					    const result = await this.syncSession(user, session, payload)
 | 
				
			||||||
    if (result) {
 | 
					    if (result) {
 | 
				
			||||||
      res.json(session.toJSONForClient(result.libraryItem))
 | 
					      res.json(session.toJSONForClient(result.libraryItem))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -66,7 +66,7 @@ class PlaybackSessionManager {
 | 
				
			|||||||
      return res.status(500).send('Local session is locked and already syncing')
 | 
					      return res.status(500).send('Local session is locked and already syncing')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var libraryItem = this.db.getLibraryItem(sessionJson.libraryItemId)
 | 
					    const libraryItem = this.db.getLibraryItem(sessionJson.libraryItemId)
 | 
				
			||||||
    if (!libraryItem) {
 | 
					    if (!libraryItem) {
 | 
				
			||||||
      Logger.error(`[PlaybackSessionManager] syncLocalSessionRequest: Library item not found for session "${sessionJson.libraryItemId}"`)
 | 
					      Logger.error(`[PlaybackSessionManager] syncLocalSessionRequest: Library item not found for session "${sessionJson.libraryItemId}"`)
 | 
				
			||||||
      return res.status(500).send('Library item not found')
 | 
					      return res.status(500).send('Library item not found')
 | 
				
			||||||
@ -74,7 +74,7 @@ class PlaybackSessionManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    this.localSessionLock[sessionJson.id] = true // Lock local session
 | 
					    this.localSessionLock[sessionJson.id] = true // Lock local session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var session = await this.db.getPlaybackSession(sessionJson.id)
 | 
					    let session = await this.db.getPlaybackSession(sessionJson.id)
 | 
				
			||||||
    if (!session) {
 | 
					    if (!session) {
 | 
				
			||||||
      // New session from local
 | 
					      // New session from local
 | 
				
			||||||
      session = new PlaybackSession(sessionJson)
 | 
					      session = new PlaybackSession(sessionJson)
 | 
				
			||||||
@ -96,10 +96,10 @@ class PlaybackSessionManager {
 | 
				
			|||||||
      progress: session.progress,
 | 
					      progress: session.progress,
 | 
				
			||||||
      lastUpdate: session.updatedAt // Keep media progress update times the same as local
 | 
					      lastUpdate: session.updatedAt // Keep media progress update times the same as local
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    var wasUpdated = user.createUpdateMediaProgress(libraryItem, itemProgressUpdate, session.episodeId)
 | 
					    const wasUpdated = user.createUpdateMediaProgress(libraryItem, itemProgressUpdate, session.episodeId)
 | 
				
			||||||
    if (wasUpdated) {
 | 
					    if (wasUpdated) {
 | 
				
			||||||
      await this.db.updateEntity('user', user)
 | 
					      await this.db.updateEntity('user', user)
 | 
				
			||||||
      var itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
 | 
					      const itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
 | 
				
			||||||
      SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
 | 
					      SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
 | 
				
			||||||
        id: itemProgress.id,
 | 
					        id: itemProgress.id,
 | 
				
			||||||
        data: itemProgress.toJSON()
 | 
					        data: itemProgress.toJSON()
 | 
				
			||||||
@ -118,18 +118,25 @@ class PlaybackSessionManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  async startSession(user, deviceInfo, libraryItem, episodeId, options) {
 | 
					  async startSession(user, deviceInfo, libraryItem, episodeId, options) {
 | 
				
			||||||
    // Close any sessions already open for user
 | 
					    // Close any sessions already open for user
 | 
				
			||||||
    var userSessions = this.sessions.filter(playbackSession => playbackSession.userId === user.id)
 | 
					    const userSessions = this.sessions.filter(playbackSession => playbackSession.userId === user.id)
 | 
				
			||||||
    for (const session of userSessions) {
 | 
					    for (const session of userSessions) {
 | 
				
			||||||
      Logger.info(`[PlaybackSessionManager] startSession: Closing open session "${session.displayTitle}" for user "${user.username}"`)
 | 
					      Logger.info(`[PlaybackSessionManager] startSession: Closing open session "${session.displayTitle}" for user "${user.username}"`)
 | 
				
			||||||
      await this.closeSession(user, session, null)
 | 
					      await this.closeSession(user, session, null)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var shouldDirectPlay = options.forceDirectPlay || (!options.forceTranscode && libraryItem.media.checkCanDirectPlay(options, episodeId))
 | 
					    const shouldDirectPlay = options.forceDirectPlay || (!options.forceTranscode && libraryItem.media.checkCanDirectPlay(options, episodeId))
 | 
				
			||||||
    var mediaPlayer = options.mediaPlayer || 'unknown'
 | 
					    const mediaPlayer = options.mediaPlayer || 'unknown'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const userProgress = user.getMediaProgress(libraryItem.id, episodeId)
 | 
					    const userProgress = user.getMediaProgress(libraryItem.id, episodeId)
 | 
				
			||||||
    var userStartTime = 0
 | 
					    let userStartTime = 0
 | 
				
			||||||
    if (userProgress) userStartTime = Number.parseFloat(userProgress.currentTime) || 0
 | 
					    if (userProgress) {
 | 
				
			||||||
 | 
					      if (userProgress.isFinished) {
 | 
				
			||||||
 | 
					        Logger.info(`[PlaybackSessionManager] Starting session for user "${user.username}" and resetting progress for finished item "${libraryItem.media.metadata.title}"`)
 | 
				
			||||||
 | 
					        // Keep userStartTime as 0 so the client restarts the media
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        userStartTime = Number.parseFloat(userProgress.currentTime) || 0
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    const newPlaybackSession = new PlaybackSession()
 | 
					    const newPlaybackSession = new PlaybackSession()
 | 
				
			||||||
    newPlaybackSession.setData(libraryItem, user, mediaPlayer, deviceInfo, userStartTime, episodeId)
 | 
					    newPlaybackSession.setData(libraryItem, user, mediaPlayer, deviceInfo, userStartTime, episodeId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -142,14 +149,14 @@ class PlaybackSessionManager {
 | 
				
			|||||||
        // HLS not supported for video yet
 | 
					        // HLS not supported for video yet
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      var audioTracks = []
 | 
					      let audioTracks = []
 | 
				
			||||||
      if (shouldDirectPlay) {
 | 
					      if (shouldDirectPlay) {
 | 
				
			||||||
        Logger.debug(`[PlaybackSessionManager] "${user.username}" starting direct play session for item "${libraryItem.id}"`)
 | 
					        Logger.debug(`[PlaybackSessionManager] "${user.username}" starting direct play session for item "${libraryItem.id}"`)
 | 
				
			||||||
        audioTracks = libraryItem.getDirectPlayTracklist(episodeId)
 | 
					        audioTracks = libraryItem.getDirectPlayTracklist(episodeId)
 | 
				
			||||||
        newPlaybackSession.playMethod = PlayMethod.DIRECTPLAY
 | 
					        newPlaybackSession.playMethod = PlayMethod.DIRECTPLAY
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        Logger.debug(`[PlaybackSessionManager] "${user.username}" starting stream session for item "${libraryItem.id}"`)
 | 
					        Logger.debug(`[PlaybackSessionManager] "${user.username}" starting stream session for item "${libraryItem.id}"`)
 | 
				
			||||||
        var stream = new Stream(newPlaybackSession.id, this.StreamsPath, user, libraryItem, episodeId, userStartTime)
 | 
					        const stream = new Stream(newPlaybackSession.id, this.StreamsPath, user, libraryItem, episodeId, userStartTime)
 | 
				
			||||||
        await stream.generatePlaylist()
 | 
					        await stream.generatePlaylist()
 | 
				
			||||||
        stream.start() // Start transcode
 | 
					        stream.start() // Start transcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -175,7 +182,7 @@ class PlaybackSessionManager {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async syncSession(user, session, syncData) {
 | 
					  async syncSession(user, session, syncData) {
 | 
				
			||||||
    var libraryItem = this.db.libraryItems.find(li => li.id === session.libraryItemId)
 | 
					    const libraryItem = this.db.libraryItems.find(li => li.id === session.libraryItemId)
 | 
				
			||||||
    if (!libraryItem) {
 | 
					    if (!libraryItem) {
 | 
				
			||||||
      Logger.error(`[PlaybackSessionManager] syncSession Library Item not found "${session.libraryItemId}"`)
 | 
					      Logger.error(`[PlaybackSessionManager] syncSession Library Item not found "${session.libraryItemId}"`)
 | 
				
			||||||
      return null
 | 
					      return null
 | 
				
			||||||
@ -190,11 +197,11 @@ class PlaybackSessionManager {
 | 
				
			|||||||
      currentTime: syncData.currentTime,
 | 
					      currentTime: syncData.currentTime,
 | 
				
			||||||
      progress: session.progress
 | 
					      progress: session.progress
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    var wasUpdated = user.createUpdateMediaProgress(libraryItem, itemProgressUpdate, session.episodeId)
 | 
					    const wasUpdated = user.createUpdateMediaProgress(libraryItem, itemProgressUpdate, session.episodeId)
 | 
				
			||||||
    if (wasUpdated) {
 | 
					    if (wasUpdated) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      await this.db.updateEntity('user', user)
 | 
					      await this.db.updateEntity('user', user)
 | 
				
			||||||
      var itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
 | 
					      const itemProgress = user.getMediaProgress(session.libraryItemId, session.episodeId)
 | 
				
			||||||
      SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
 | 
					      SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
 | 
				
			||||||
        id: itemProgress.id,
 | 
					        id: itemProgress.id,
 | 
				
			||||||
        data: itemProgress.toJSON()
 | 
					        data: itemProgress.toJSON()
 | 
				
			||||||
@ -229,7 +236,7 @@ class PlaybackSessionManager {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async removeSession(sessionId) {
 | 
					  async removeSession(sessionId) {
 | 
				
			||||||
    var session = this.sessions.find(s => s.id === sessionId)
 | 
					    const session = this.sessions.find(s => s.id === sessionId)
 | 
				
			||||||
    if (!session) return
 | 
					    if (!session) return
 | 
				
			||||||
    if (session.stream) {
 | 
					    if (session.stream) {
 | 
				
			||||||
      await session.stream.close()
 | 
					      await session.stream.close()
 | 
				
			||||||
@ -242,13 +249,13 @@ class PlaybackSessionManager {
 | 
				
			|||||||
  async removeOrphanStreams() {
 | 
					  async removeOrphanStreams() {
 | 
				
			||||||
    await fs.ensureDir(this.StreamsPath)
 | 
					    await fs.ensureDir(this.StreamsPath)
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      var streamsInPath = await fs.readdir(this.StreamsPath)
 | 
					      const streamsInPath = await fs.readdir(this.StreamsPath)
 | 
				
			||||||
      for (let i = 0; i < streamsInPath.length; i++) {
 | 
					      for (let i = 0; i < streamsInPath.length; i++) {
 | 
				
			||||||
        var streamId = streamsInPath[i]
 | 
					        const streamId = streamsInPath[i]
 | 
				
			||||||
        if (streamId.startsWith('play_')) { // Make sure to only remove folders that are a stream
 | 
					        if (streamId.startsWith('play_')) { // Make sure to only remove folders that are a stream
 | 
				
			||||||
          var session = this.sessions.find(se => se.id === streamId)
 | 
					          const session = this.sessions.find(se => se.id === streamId)
 | 
				
			||||||
          if (!session) {
 | 
					          if (!session) {
 | 
				
			||||||
            var streamPath = Path.join(this.StreamsPath, streamId)
 | 
					            const streamPath = Path.join(this.StreamsPath, streamId)
 | 
				
			||||||
            Logger.debug(`[PlaybackSessionManager] Removing orphan stream "${streamPath}"`)
 | 
					            Logger.debug(`[PlaybackSessionManager] Removing orphan stream "${streamPath}"`)
 | 
				
			||||||
            await fs.remove(streamPath)
 | 
					            await fs.remove(streamPath)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user