Skip to content

Commit

Permalink
Update MiscController api routes to load library items from db
Browse files Browse the repository at this point in the history
  • Loading branch information
advplyr committed Aug 13, 2023
1 parent fc44c80 commit 8d03b23
Show file tree
Hide file tree
Showing 3 changed files with 289 additions and 64 deletions.
226 changes: 163 additions & 63 deletions server/controllers/MiscController.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
const Sequelize = require('sequelize')
const Path = require('path')
const fs = require('../libs/fsExtra')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')

const libraryItemFilters = require('../utils/queries/libraryItemFilters')
const filePerms = require('../utils/filePerms')
const patternValidation = require('../libs/nodeCron/pattern-validation')
const { isObject } = require('../utils/index')
Expand All @@ -14,7 +16,12 @@ const { isObject } = require('../utils/index')
class MiscController {
constructor() { }

// POST: api/upload
/**
* POST: /api/upload
* Update library item
* @param {*} req
* @param {*} res
*/
async handleUpload(req, res) {
if (!req.user.canUpload) {
Logger.warn('User attempted to upload without permission', req.user)
Expand Down Expand Up @@ -88,7 +95,12 @@ class MiscController {
res.sendStatus(200)
}

// GET: api/tasks
/**
* GET: /api/tasks
* Get tasks for task manager
* @param {*} req
* @param {*} res
*/
getTasks(req, res) {
const includeArray = (req.query.include || '').split(',')

Expand All @@ -105,7 +117,12 @@ class MiscController {
res.json(data)
}

// PATCH: api/settings (admin)
/**
* PATCH: /api/settings
* Update server settings
* @param {*} req
* @param {*} res
*/
async updateServerSettings(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error('User other than admin attempting to update server settings', req.user)
Expand Down Expand Up @@ -147,26 +164,55 @@ class MiscController {
res.json(userResponse)
}

// GET: api/tags
getAllTags(req, res) {
/**
* GET: /api/tags
* Get all tags
* @param {*} req
* @param {*} res
*/
async getAllTags(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user attempted to getAllTags`)
return res.sendStatus(404)
}

const tags = []
Database.libraryItems.forEach((li) => {
if (li.media.tags && li.media.tags.length) {
li.media.tags.forEach((tag) => {
if (!tags.includes(tag)) tags.push(tag)
})
const books = await Database.models.book.findAll({
attributes: ['tags'],
where: Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('tags')), {
[Sequelize.Op.gt]: 0
})
})
for (const book of books) {
for (const tag of book.tags) {
if (!tags.includes(tag)) tags.push(tag)
}
}

const podcasts = await Database.models.podcast.findAll({
attributes: ['tags'],
where: Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('tags')), {
[Sequelize.Op.gt]: 0
})
})
for (const podcast of podcasts) {
for (const tag of podcast.tags) {
if (!tags.includes(tag)) tags.push(tag)
}
}

res.json({
tags: tags
})
}

// POST: api/tags/rename
/**
* POST: /api/tags/rename
* Rename tag
* Req.body { tag, newTag }
* @param {*} req
* @param {*} res
*/
async renameTag(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user attempted to renameTag`)
Expand All @@ -183,19 +229,24 @@ class MiscController {
let tagMerged = false
let numItemsUpdated = 0

for (const li of Database.libraryItems) {
if (!li.media.tags || !li.media.tags.length) continue

if (li.media.tags.includes(newTag)) tagMerged = true // new tag is an existing tag so this is a merge
const libraryItemsWithTag = await libraryItemFilters.getAllLibraryItemsWithTags([tag, newTag])
for (const libraryItem of libraryItemsWithTag) {
let existingTags = libraryItem.media.tags
if (existingTags.includes(newTag)) {
tagMerged = true // new tag is an existing tag so this is a merge
}

if (li.media.tags.includes(tag)) {
li.media.tags = li.media.tags.filter(t => t !== tag) // Remove old tag
if (!li.media.tags.includes(newTag)) {
li.media.tags.push(newTag) // Add new tag
if (existingTags.includes(tag)) {
existingTags = existingTags.filter(t => t !== tag) // Remove old tag
if (!existingTags.includes(newTag)) {
existingTags.push(newTag)
}
Logger.debug(`[MiscController] Rename tag "${tag}" to "${newTag}" for item "${li.media.metadata.title}"`)
await Database.updateLibraryItem(li)
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
Logger.debug(`[MiscController] Rename tag "${tag}" to "${newTag}" for item "${libraryItem.media.title}"`)
await libraryItem.media.update({
tags: existingTags
})
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
numItemsUpdated++
}
}
Expand All @@ -206,7 +257,13 @@ class MiscController {
})
}

// DELETE: api/tags/:tag
/**
* DELETE: /api/tags/:tag
* Remove a tag
* :tag param is base64 encoded
* @param {*} req
* @param {*} res
*/
async deleteTag(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user attempted to deleteTag`)
Expand All @@ -215,44 +272,74 @@ class MiscController {

const tag = Buffer.from(decodeURIComponent(req.params.tag), 'base64').toString()

// Get all items with tag
const libraryItemsWithTag = await libraryItemFilters.getAllLibraryItemsWithTags([tag])

let numItemsUpdated = 0
for (const li of Database.libraryItems) {
if (!li.media.tags || !li.media.tags.length) continue

if (li.media.tags.includes(tag)) {
li.media.tags = li.media.tags.filter(t => t !== tag)
Logger.debug(`[MiscController] Remove tag "${tag}" from item "${li.media.metadata.title}"`)
await Database.updateLibraryItem(li)
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
numItemsUpdated++
}
// Remove tag from items
for (const libraryItem of libraryItemsWithTag) {
Logger.debug(`[MiscController] Remove tag "${tag}" from item "${libraryItem.media.title}"`)
await libraryItem.media.update({
tags: libraryItem.media.tags.filter(t => t !== tag)
})
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
numItemsUpdated++
}

res.json({
numItemsUpdated
})
}

// GET: api/genres
getAllGenres(req, res) {
/**
* GET: /api/genres
* Get all genres
* @param {*} req
* @param {*} res
*/
async getAllGenres(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user attempted to getAllGenres`)
return res.sendStatus(404)
}
const genres = []
Database.libraryItems.forEach((li) => {
if (li.media.metadata.genres && li.media.metadata.genres.length) {
li.media.metadata.genres.forEach((genre) => {
if (!genres.includes(genre)) genres.push(genre)
})
const books = await Database.models.book.findAll({
attributes: ['genres'],
where: Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('genres')), {
[Sequelize.Op.gt]: 0
})
})
for (const book of books) {
for (const tag of book.genres) {
if (!genres.includes(tag)) genres.push(tag)
}
}

const podcasts = await Database.models.podcast.findAll({
attributes: ['genres'],
where: Sequelize.where(Sequelize.fn('json_array_length', Sequelize.col('genres')), {
[Sequelize.Op.gt]: 0
})
})
for (const podcast of podcasts) {
for (const tag of podcast.genres) {
if (!genres.includes(tag)) genres.push(tag)
}
}

res.json({
genres
})
}

// POST: api/genres/rename
/**
* POST: /api/genres/rename
* Rename genres
* Req.body { genre, newGenre }
* @param {*} req
* @param {*} res
*/
async renameGenre(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user attempted to renameGenre`)
Expand All @@ -269,19 +356,24 @@ class MiscController {
let genreMerged = false
let numItemsUpdated = 0

for (const li of Database.libraryItems) {
if (!li.media.metadata.genres || !li.media.metadata.genres.length) continue

if (li.media.metadata.genres.includes(newGenre)) genreMerged = true // new genre is an existing genre so this is a merge
const libraryItemsWithGenre = await libraryItemFilters.getAllLibraryItemsWithGenres([genre, newGenre])
for (const libraryItem of libraryItemsWithGenre) {
let existingGenres = libraryItem.media.genres
if (existingGenres.includes(newGenre)) {
genreMerged = true // new genre is an existing genre so this is a merge
}

if (li.media.metadata.genres.includes(genre)) {
li.media.metadata.genres = li.media.metadata.genres.filter(g => g !== genre) // Remove old genre
if (!li.media.metadata.genres.includes(newGenre)) {
li.media.metadata.genres.push(newGenre) // Add new genre
if (existingGenres.includes(genre)) {
existingGenres = existingGenres.filter(t => t !== genre) // Remove old genre
if (!existingGenres.includes(newGenre)) {
existingGenres.push(newGenre)
}
Logger.debug(`[MiscController] Rename genre "${genre}" to "${newGenre}" for item "${li.media.metadata.title}"`)
await Database.updateLibraryItem(li)
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
Logger.debug(`[MiscController] Rename genre "${genre}" to "${newGenre}" for item "${libraryItem.media.title}"`)
await libraryItem.media.update({
genres: existingGenres
})
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
numItemsUpdated++
}
}
Expand All @@ -292,7 +384,13 @@ class MiscController {
})
}

// DELETE: api/genres/:genre
/**
* DELETE: /api/genres/:genre
* Remove a genre
* :genre param is base64 encoded
* @param {*} req
* @param {*} res
*/
async deleteGenre(req, res) {
if (!req.user.isAdminOrUp) {
Logger.error(`[MiscController] Non-admin user attempted to deleteGenre`)
Expand All @@ -301,17 +399,19 @@ class MiscController {

const genre = Buffer.from(decodeURIComponent(req.params.genre), 'base64').toString()

// Get all items with genre
const libraryItemsWithGenre = await libraryItemFilters.getAllLibraryItemsWithGenres([genre])

let numItemsUpdated = 0
for (const li of Database.libraryItems) {
if (!li.media.metadata.genres || !li.media.metadata.genres.length) continue

if (li.media.metadata.genres.includes(genre)) {
li.media.metadata.genres = li.media.metadata.genres.filter(t => t !== genre)
Logger.debug(`[MiscController] Remove genre "${genre}" from item "${li.media.metadata.title}"`)
await Database.updateLibraryItem(li)
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
numItemsUpdated++
}
// Remove genre from items
for (const libraryItem of libraryItemsWithGenre) {
Logger.debug(`[MiscController] Remove genre "${genre}" from item "${libraryItem.media.title}"`)
await libraryItem.media.update({
genres: libraryItem.media.genres.filter(g => g !== genre)
})
const oldLibraryItem = Database.models.libraryItem.getOldLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', oldLibraryItem.toJSONExpanded())
numItemsUpdated++
}

res.json({
Expand Down
1 change: 0 additions & 1 deletion server/utils/queries/libraryFilters.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const Sequelize = require('sequelize')
const Database = require('../../Database')
const Logger = require('../../Logger')
const libraryItemsBookFilters = require('./libraryItemsBookFilters')
const libraryItemsPodcastFilters = require('./libraryItemsPodcastFilters')

Expand Down
Loading

0 comments on commit 8d03b23

Please sign in to comment.