aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/controllers/api/users/index.ts2
-rw-r--r--server/controllers/api/users/my-video-playlists.ts47
-rw-r--r--server/controllers/api/video-playlist.ts34
-rw-r--r--server/helpers/custom-validators/misc.ts10
-rw-r--r--server/initializers/constants.ts2
-rw-r--r--server/middlewares/validators/videos/video-playlists.ts23
-rw-r--r--server/models/video/video-playlist.ts23
7 files changed, 125 insertions, 16 deletions
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts
index 5758c8227..f7edbddf3 100644
--- a/server/controllers/api/users/index.ts
+++ b/server/controllers/api/users/index.ts
@@ -38,6 +38,7 @@ import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../h
38import { meRouter } from './me' 38import { meRouter } from './me'
39import { deleteUserToken } from '../../../lib/oauth-model' 39import { deleteUserToken } from '../../../lib/oauth-model'
40import { myBlocklistRouter } from './my-blocklist' 40import { myBlocklistRouter } from './my-blocklist'
41import { myVideoPlaylistsRouter } from './my-video-playlists'
41import { myVideosHistoryRouter } from './my-history' 42import { myVideosHistoryRouter } from './my-history'
42import { myNotificationsRouter } from './my-notifications' 43import { myNotificationsRouter } from './my-notifications'
43import { Notifier } from '../../../lib/notifier' 44import { Notifier } from '../../../lib/notifier'
@@ -60,6 +61,7 @@ usersRouter.use('/', myNotificationsRouter)
60usersRouter.use('/', mySubscriptionsRouter) 61usersRouter.use('/', mySubscriptionsRouter)
61usersRouter.use('/', myBlocklistRouter) 62usersRouter.use('/', myBlocklistRouter)
62usersRouter.use('/', myVideosHistoryRouter) 63usersRouter.use('/', myVideosHistoryRouter)
64usersRouter.use('/', myVideoPlaylistsRouter)
63usersRouter.use('/', meRouter) 65usersRouter.use('/', meRouter)
64 66
65usersRouter.get('/autocomplete', 67usersRouter.get('/autocomplete',
diff --git a/server/controllers/api/users/my-video-playlists.ts b/server/controllers/api/users/my-video-playlists.ts
new file mode 100644
index 000000000..1ec175f64
--- /dev/null
+++ b/server/controllers/api/users/my-video-playlists.ts
@@ -0,0 +1,47 @@
1import * as express from 'express'
2import { asyncMiddleware, authenticate } from '../../../middlewares'
3import { UserModel } from '../../../models/account/user'
4import { doVideosInPlaylistExistValidator } from '../../../middlewares/validators/videos/video-playlists'
5import { VideoPlaylistModel } from '../../../models/video/video-playlist'
6import { VideoExistInPlaylist } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
7
8const myVideoPlaylistsRouter = express.Router()
9
10myVideoPlaylistsRouter.get('/me/video-playlists/videos-exist',
11 authenticate,
12 doVideosInPlaylistExistValidator,
13 asyncMiddleware(doVideosInPlaylistExist)
14)
15
16// ---------------------------------------------------------------------------
17
18export {
19 myVideoPlaylistsRouter
20}
21
22// ---------------------------------------------------------------------------
23
24async function doVideosInPlaylistExist (req: express.Request, res: express.Response) {
25 const videoIds = req.query.videoIds as number[]
26 const user = res.locals.oauth.token.User as UserModel
27
28 const results = await VideoPlaylistModel.listPlaylistIdsOf(user.Account.id, videoIds)
29
30 const existObject: VideoExistInPlaylist = {}
31
32 for (const videoId of videoIds) {
33 existObject[videoId] = []
34 }
35
36 for (const result of results) {
37 for (const element of result.VideoPlaylistElements) {
38 existObject[element.videoId].push({
39 playlistId: result.id,
40 startTimestamp: element.startTimestamp,
41 stopTimestamp: element.stopTimestamp
42 })
43 }
44 }
45
46 return res.json(existObject)
47}
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts
index 145764d35..49432d3aa 100644
--- a/server/controllers/api/video-playlist.ts
+++ b/server/controllers/api/video-playlist.ts
@@ -291,23 +291,26 @@ async function addVideoInPlaylist (req: express.Request, res: express.Response)
291 videoId: video.id 291 videoId: video.id
292 }, { transaction: t }) 292 }, { transaction: t })
293 293
294 // If the user did not set a thumbnail, automatically take the video thumbnail 294 videoPlaylist.updatedAt = new Date()
295 if (playlistElement.position === 1) { 295 await videoPlaylist.save({ transaction: t })
296 const playlistThumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, videoPlaylist.getThumbnailName())
297
298 if (await pathExists(playlistThumbnailPath) === false) {
299 logger.info('Generating default thumbnail to playlist %s.', videoPlaylist.url)
300
301 const videoThumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName())
302 await copy(videoThumbnailPath, playlistThumbnailPath)
303 }
304 }
305 296
306 await sendUpdateVideoPlaylist(videoPlaylist, t) 297 await sendUpdateVideoPlaylist(videoPlaylist, t)
307 298
308 return playlistElement 299 return playlistElement
309 }) 300 })
310 301
302 // If the user did not set a thumbnail, automatically take the video thumbnail
303 if (playlistElement.position === 1) {
304 const playlistThumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, videoPlaylist.getThumbnailName())
305
306 if (await pathExists(playlistThumbnailPath) === false) {
307 logger.info('Generating default thumbnail to playlist %s.', videoPlaylist.url)
308
309 const videoThumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName())
310 await copy(videoThumbnailPath, playlistThumbnailPath)
311 }
312 }
313
311 logger.info('Video added in playlist %s at position %d.', videoPlaylist.uuid, playlistElement.position) 314 logger.info('Video added in playlist %s at position %d.', videoPlaylist.uuid, playlistElement.position)
312 315
313 return res.json({ 316 return res.json({
@@ -328,6 +331,9 @@ async function updateVideoPlaylistElement (req: express.Request, res: express.Re
328 331
329 const element = await videoPlaylistElement.save({ transaction: t }) 332 const element = await videoPlaylistElement.save({ transaction: t })
330 333
334 videoPlaylist.updatedAt = new Date()
335 await videoPlaylist.save({ transaction: t })
336
331 await sendUpdateVideoPlaylist(videoPlaylist, t) 337 await sendUpdateVideoPlaylist(videoPlaylist, t)
332 338
333 return element 339 return element
@@ -349,6 +355,9 @@ async function removeVideoFromPlaylist (req: express.Request, res: express.Respo
349 // Decrease position of the next elements 355 // Decrease position of the next elements
350 await VideoPlaylistElementModel.increasePositionOf(videoPlaylist.id, positionToDelete, null, -1, t) 356 await VideoPlaylistElementModel.increasePositionOf(videoPlaylist.id, positionToDelete, null, -1, t)
351 357
358 videoPlaylist.updatedAt = new Date()
359 await videoPlaylist.save({ transaction: t })
360
352 await sendUpdateVideoPlaylist(videoPlaylist, t) 361 await sendUpdateVideoPlaylist(videoPlaylist, t)
353 362
354 logger.info('Video playlist element %d of playlist %s deleted.', videoPlaylistElement.position, videoPlaylist.uuid) 363 logger.info('Video playlist element %d of playlist %s deleted.', videoPlaylistElement.position, videoPlaylist.uuid)
@@ -390,6 +399,9 @@ async function reorderVideosPlaylist (req: express.Request, res: express.Respons
390 // Decrease positions of elements after the old position of our ordered elements (decrease) 399 // Decrease positions of elements after the old position of our ordered elements (decrease)
391 await VideoPlaylistElementModel.increasePositionOf(videoPlaylist.id, oldPosition, null, -reorderLength, t) 400 await VideoPlaylistElementModel.increasePositionOf(videoPlaylist.id, oldPosition, null, -reorderLength, t)
392 401
402 videoPlaylist.updatedAt = new Date()
403 await videoPlaylist.save({ transaction: t })
404
393 await sendUpdateVideoPlaylist(videoPlaylist, t) 405 await sendUpdateVideoPlaylist(videoPlaylist, t)
394 }) 406 })
395 407
diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts
index 76647fea2..3a3deab0c 100644
--- a/server/helpers/custom-validators/misc.ts
+++ b/server/helpers/custom-validators/misc.ts
@@ -49,12 +49,19 @@ function toValueOrNull (value: string) {
49 return value 49 return value
50} 50}
51 51
52function toArray (value: string) { 52function toArray (value: any) {
53 if (value && isArray(value) === false) return [ value ] 53 if (value && isArray(value) === false) return [ value ]
54 54
55 return value 55 return value
56} 56}
57 57
58function toIntArray (value: any) {
59 if (!value) return []
60 if (isArray(value) === false) return [ validator.toInt(value) ]
61
62 return value.map(v => validator.toInt(v))
63}
64
58function isFileValid ( 65function isFileValid (
59 files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], 66 files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[],
60 mimeTypeRegex: string, 67 mimeTypeRegex: string,
@@ -97,5 +104,6 @@ export {
97 isBooleanValid, 104 isBooleanValid,
98 toIntOrNull, 105 toIntOrNull,
99 toArray, 106 toArray,
107 toIntArray,
100 isFileValid 108 isFileValid
101} 109}
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 54c390540..169a98ceb 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -56,7 +56,7 @@ const SORTABLE_COLUMNS = {
56 56
57 USER_NOTIFICATIONS: [ 'createdAt' ], 57 USER_NOTIFICATIONS: [ 'createdAt' ],
58 58
59 VIDEO_PLAYLISTS: [ 'createdAt' ] 59 VIDEO_PLAYLISTS: [ 'displayName', 'createdAt', 'updatedAt' ]
60} 60}
61 61
62const OAUTH_LIFETIME = { 62const OAUTH_LIFETIME = {
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts
index 22b8b8ff1..87d2c7b51 100644
--- a/server/middlewares/validators/videos/video-playlists.ts
+++ b/server/middlewares/validators/videos/video-playlists.ts
@@ -4,9 +4,9 @@ import { UserRight } from '../../../../shared'
4import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { UserModel } from '../../../models/account/user' 5import { UserModel } from '../../../models/account/user'
6import { areValidationErrors } from '../utils' 6import { areValidationErrors } from '../utils'
7import { isVideoExist, isVideoImage } from '../../../helpers/custom-validators/videos' 7import { isVideoExist, isVideoFileInfoHashValid, isVideoImage } from '../../../helpers/custom-validators/videos'
8import { CONSTRAINTS_FIELDS } from '../../../initializers' 8import { CONSTRAINTS_FIELDS } from '../../../initializers'
9import { isIdOrUUIDValid, isUUIDValid, toValueOrNull } from '../../../helpers/custom-validators/misc' 9import { isArrayOf, isIdOrUUIDValid, isIdValid, isUUIDValid, toArray, toValueOrNull, toIntArray } from '../../../helpers/custom-validators/misc'
10import { 10import {
11 isVideoPlaylistDescriptionValid, 11 isVideoPlaylistDescriptionValid,
12 isVideoPlaylistExist, 12 isVideoPlaylistExist,
@@ -23,6 +23,7 @@ import { VideoModel } from '../../../models/video/video'
23import { authenticatePromiseIfNeeded } from '../../oauth' 23import { authenticatePromiseIfNeeded } from '../../oauth'
24import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' 24import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
25import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model' 25import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
26import { areValidActorHandles } from '../../../helpers/custom-validators/activitypub/actor'
26 27
27const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([ 28const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
28 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 29 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
@@ -305,6 +306,20 @@ const commonVideoPlaylistFiltersValidator = [
305 } 306 }
306] 307]
307 308
309const doVideosInPlaylistExistValidator = [
310 query('videoIds')
311 .customSanitizer(toIntArray)
312 .custom(v => isArrayOf(v, isIdValid)).withMessage('Should have a valid video ids array'),
313
314 (req: express.Request, res: express.Response, next: express.NextFunction) => {
315 logger.debug('Checking areVideosInPlaylistExistValidator parameters', { parameters: req.query })
316
317 if (areValidationErrors(req, res)) return
318
319 return next()
320 }
321]
322
308// --------------------------------------------------------------------------- 323// ---------------------------------------------------------------------------
309 324
310export { 325export {
@@ -319,7 +334,9 @@ export {
319 334
320 videoPlaylistElementAPGetValidator, 335 videoPlaylistElementAPGetValidator,
321 336
322 commonVideoPlaylistFiltersValidator 337 commonVideoPlaylistFiltersValidator,
338
339 doVideosInPlaylistExistValidator
323} 340}
324 341
325// --------------------------------------------------------------------------- 342// ---------------------------------------------------------------------------
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts
index 4d2ea0a66..aa42687cd 100644
--- a/server/models/video/video-playlist.ts
+++ b/server/models/video/video-playlist.ts
@@ -317,6 +317,29 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
317 }) 317 })
318 } 318 }
319 319
320 static listPlaylistIdsOf (accountId: number, videoIds: number[]) {
321 const query = {
322 attributes: [ 'id' ],
323 where: {
324 ownerAccountId: accountId
325 },
326 include: [
327 {
328 attributes: [ 'videoId', 'startTimestamp', 'stopTimestamp' ],
329 model: VideoPlaylistElementModel.unscoped(),
330 where: {
331 videoId: {
332 [Sequelize.Op.any]: videoIds
333 }
334 },
335 required: true
336 }
337 ]
338 }
339
340 return VideoPlaylistModel.findAll(query)
341 }
342
320 static doesPlaylistExist (url: string) { 343 static doesPlaylistExist (url: string) {
321 const query = { 344 const query = {
322 attributes: [], 345 attributes: [],