Add ability to a video multiple times in a playlist
This commit is contained in:
parent
b75410b87d
commit
371906639e
7 changed files with 53 additions and 40 deletions
|
@ -159,7 +159,7 @@ activityPubClientRouter.get('/video-playlists/:playlistId',
|
||||||
asyncMiddleware(videoPlaylistsGetValidator('all')),
|
asyncMiddleware(videoPlaylistsGetValidator('all')),
|
||||||
asyncMiddleware(videoPlaylistController)
|
asyncMiddleware(videoPlaylistController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/video-playlists/:playlistId/:videoId',
|
activityPubClientRouter.get('/video-playlists/:playlistId/videos/:playlistElementId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
asyncMiddleware(videoPlaylistElementAPGetValidator),
|
asyncMiddleware(videoPlaylistElementAPGetValidator),
|
||||||
videoPlaylistElementController
|
videoPlaylistElementController
|
||||||
|
|
|
@ -297,7 +297,6 @@ async function addVideoInPlaylist (req: express.Request, res: express.Response)
|
||||||
const position = await VideoPlaylistElementModel.getNextPositionOf(videoPlaylist.id, t)
|
const position = await VideoPlaylistElementModel.getNextPositionOf(videoPlaylist.id, t)
|
||||||
|
|
||||||
const playlistElement = await VideoPlaylistElementModel.create({
|
const playlistElement = await VideoPlaylistElementModel.create({
|
||||||
url: getVideoPlaylistElementActivityPubUrl(videoPlaylist, video),
|
|
||||||
position,
|
position,
|
||||||
startTimestamp: body.startTimestamp || null,
|
startTimestamp: body.startTimestamp || null,
|
||||||
stopTimestamp: body.stopTimestamp || null,
|
stopTimestamp: body.stopTimestamp || null,
|
||||||
|
@ -305,6 +304,9 @@ async function addVideoInPlaylist (req: express.Request, res: express.Response)
|
||||||
videoId: video.id
|
videoId: video.id
|
||||||
}, { transaction: t })
|
}, { transaction: t })
|
||||||
|
|
||||||
|
playlistElement.url = getVideoPlaylistElementActivityPubUrl(videoPlaylist, playlistElement)
|
||||||
|
await playlistElement.save({ transaction: t })
|
||||||
|
|
||||||
videoPlaylist.changed('updatedAt', true)
|
videoPlaylist.changed('updatedAt', true)
|
||||||
await videoPlaylist.save({ transaction: t })
|
await videoPlaylist.save({ transaction: t })
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {
|
||||||
MVideoId,
|
MVideoId,
|
||||||
MVideoUrl,
|
MVideoUrl,
|
||||||
MVideoUUID,
|
MVideoUUID,
|
||||||
MAbuseId
|
MAbuseId,
|
||||||
|
MVideoPlaylistElement
|
||||||
} from '../../types/models'
|
} from '../../types/models'
|
||||||
import { MVideoPlaylist, MVideoPlaylistUUID } from '../../types/models/video/video-playlist'
|
import { MVideoPlaylist, MVideoPlaylistUUID } from '../../types/models/video/video-playlist'
|
||||||
import { MVideoFileVideoUUID } from '../../types/models/video/video-file'
|
import { MVideoFileVideoUUID } from '../../types/models/video/video-file'
|
||||||
|
@ -22,8 +23,8 @@ function getVideoPlaylistActivityPubUrl (videoPlaylist: MVideoPlaylist) {
|
||||||
return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid
|
return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVideoPlaylistElementActivityPubUrl (videoPlaylist: MVideoPlaylistUUID, video: MVideoUUID) {
|
function getVideoPlaylistElementActivityPubUrl (videoPlaylist: MVideoPlaylistUUID, videoPlaylistElement: MVideoPlaylistElement) {
|
||||||
return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/' + video.uuid
|
return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/videos/' + videoPlaylistElement.id
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVideoCacheFileActivityPubUrl (videoFile: MVideoFileVideoUUID) {
|
function getVideoCacheFileActivityPubUrl (videoFile: MVideoFileVideoUUID) {
|
||||||
|
|
|
@ -199,16 +199,6 @@ const videoPlaylistsAddVideoValidator = [
|
||||||
if (!await doesVideoExist(req.body.videoId, res, 'only-video')) return
|
if (!await doesVideoExist(req.body.videoId, res, 'only-video')) return
|
||||||
|
|
||||||
const videoPlaylist = getPlaylist(res)
|
const videoPlaylist = getPlaylist(res)
|
||||||
const video = res.locals.onlyVideo
|
|
||||||
|
|
||||||
const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndVideo(videoPlaylist.id, video.id)
|
|
||||||
if (videoPlaylistElement) {
|
|
||||||
res.status(409)
|
|
||||||
.json({ error: 'This video in this playlist already exists' })
|
|
||||||
.end()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, videoPlaylist, UserRight.UPDATE_ANY_VIDEO_PLAYLIST, res)) {
|
if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, videoPlaylist, UserRight.UPDATE_ANY_VIDEO_PLAYLIST, res)) {
|
||||||
return
|
return
|
||||||
|
@ -258,15 +248,18 @@ const videoPlaylistsUpdateOrRemoveVideoValidator = [
|
||||||
const videoPlaylistElementAPGetValidator = [
|
const videoPlaylistElementAPGetValidator = [
|
||||||
param('playlistId')
|
param('playlistId')
|
||||||
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
|
.custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
|
||||||
param('videoId')
|
param('playlistElementId')
|
||||||
.custom(isIdOrUUIDValid).withMessage('Should have an video id/uuid'),
|
.custom(isIdValid).withMessage('Should have an playlist element id'),
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug('Checking videoPlaylistElementAPGetValidator parameters', { parameters: req.params })
|
logger.debug('Checking videoPlaylistElementAPGetValidator parameters', { parameters: req.params })
|
||||||
|
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndVideoForAP(req.params.playlistId, req.params.videoId)
|
const playlistElementId = parseInt(req.params.playlistElementId + '', 10)
|
||||||
|
const playlistId = req.params.playlistId
|
||||||
|
|
||||||
|
const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndElementIdForAP(playlistId, playlistElementId)
|
||||||
if (!videoPlaylistElement) {
|
if (!videoPlaylistElement) {
|
||||||
res.status(404)
|
res.status(404)
|
||||||
.json({ error: 'Video playlist element not found' })
|
.json({ error: 'Video playlist element not found' })
|
||||||
|
|
|
@ -43,10 +43,6 @@ import { MUserAccountId } from '@server/types/models'
|
||||||
{
|
{
|
||||||
fields: [ 'videoId' ]
|
fields: [ 'videoId' ]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
fields: [ 'videoPlaylistId', 'videoId' ],
|
|
||||||
unique: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
fields: [ 'url' ],
|
fields: [ 'url' ],
|
||||||
unique: true
|
unique: true
|
||||||
|
@ -60,8 +56,8 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
|
|
||||||
@AllowNull(false)
|
@AllowNull(true)
|
||||||
@Is('VideoPlaylistUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
|
@Is('VideoPlaylistUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url', true))
|
||||||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.URL.max))
|
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.URL.max))
|
||||||
url: string
|
url: string
|
||||||
|
|
||||||
|
@ -185,12 +181,11 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
|
||||||
return VideoPlaylistElementModel.findByPk(playlistElementId)
|
return VideoPlaylistElementModel.findByPk(playlistElementId)
|
||||||
}
|
}
|
||||||
|
|
||||||
static loadByPlaylistAndVideoForAP (
|
static loadByPlaylistAndElementIdForAP (
|
||||||
playlistId: number | string,
|
playlistId: number | string,
|
||||||
videoId: number | string
|
playlistElementId: number
|
||||||
): Bluebird<MVideoPlaylistElementVideoUrlPlaylistPrivacy> {
|
): Bluebird<MVideoPlaylistElementVideoUrlPlaylistPrivacy> {
|
||||||
const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId }
|
const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId }
|
||||||
const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId }
|
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
include: [
|
include: [
|
||||||
|
@ -201,10 +196,12 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributes: [ 'url' ],
|
attributes: [ 'url' ],
|
||||||
model: VideoModel.unscoped(),
|
model: VideoModel.unscoped()
|
||||||
where: videoWhere
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
where: {
|
||||||
|
id: playlistElementId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return VideoPlaylistElementModel.findOne(query)
|
return VideoPlaylistElementModel.findOne(query)
|
||||||
|
|
|
@ -346,11 +346,6 @@ describe('Test video playlists API validator', function () {
|
||||||
const res = await addVideoInPlaylist(params)
|
const res = await addVideoInPlaylist(params)
|
||||||
playlistElementId = res.body.videoPlaylistElement.id
|
playlistElementId = res.body.videoPlaylistElement.id
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail if the video was already added in the playlist', async function () {
|
|
||||||
const params = getBase({}, { expectedStatus: 409 })
|
|
||||||
await addVideoInPlaylist(params)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('When updating an element in a playlist', function () {
|
describe('When updating an element in a playlist', function () {
|
||||||
|
|
|
@ -552,6 +552,9 @@ describe('Test video playlists', function () {
|
||||||
{
|
{
|
||||||
const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 })
|
const res = await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 5 })
|
||||||
playlistElementNSFW = res.body.videoPlaylistElement.id
|
playlistElementNSFW = res.body.videoPlaylistElement.id
|
||||||
|
|
||||||
|
await addVideo({ videoId: nsfwVideoServer1, startTimestamp: 4 })
|
||||||
|
await addVideo({ videoId: nsfwVideoServer1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitJobs(servers)
|
await waitJobs(servers)
|
||||||
|
@ -563,10 +566,10 @@ describe('Test video playlists', function () {
|
||||||
for (const server of servers) {
|
for (const server of servers) {
|
||||||
const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
|
const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
|
||||||
|
|
||||||
expect(res.body.total).to.equal(6)
|
expect(res.body.total).to.equal(8)
|
||||||
|
|
||||||
const videoElements: VideoPlaylistElement[] = res.body.data
|
const videoElements: VideoPlaylistElement[] = res.body.data
|
||||||
expect(videoElements).to.have.lengthOf(6)
|
expect(videoElements).to.have.lengthOf(8)
|
||||||
|
|
||||||
expect(videoElements[0].video.name).to.equal('video 0 server 1')
|
expect(videoElements[0].video.name).to.equal('video 0 server 1')
|
||||||
expect(videoElements[0].position).to.equal(1)
|
expect(videoElements[0].position).to.equal(1)
|
||||||
|
@ -598,6 +601,16 @@ describe('Test video playlists', function () {
|
||||||
expect(videoElements[5].startTimestamp).to.equal(5)
|
expect(videoElements[5].startTimestamp).to.equal(5)
|
||||||
expect(videoElements[5].stopTimestamp).to.be.null
|
expect(videoElements[5].stopTimestamp).to.be.null
|
||||||
|
|
||||||
|
expect(videoElements[6].video.name).to.equal('NSFW video')
|
||||||
|
expect(videoElements[6].position).to.equal(7)
|
||||||
|
expect(videoElements[6].startTimestamp).to.equal(4)
|
||||||
|
expect(videoElements[6].stopTimestamp).to.be.null
|
||||||
|
|
||||||
|
expect(videoElements[7].video.name).to.equal('NSFW video')
|
||||||
|
expect(videoElements[7].position).to.equal(8)
|
||||||
|
expect(videoElements[7].startTimestamp).to.be.null
|
||||||
|
expect(videoElements[7].stopTimestamp).to.be.null
|
||||||
|
|
||||||
const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
|
const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
|
||||||
expect(res3.body.data).to.have.lengthOf(2)
|
expect(res3.body.data).to.have.lengthOf(2)
|
||||||
}
|
}
|
||||||
|
@ -807,6 +820,8 @@ describe('Test video playlists', function () {
|
||||||
'video 1 server 3',
|
'video 1 server 3',
|
||||||
'video 3 server 1',
|
'video 3 server 1',
|
||||||
'video 4 server 1',
|
'video 4 server 1',
|
||||||
|
'NSFW video',
|
||||||
|
'NSFW video',
|
||||||
'NSFW video'
|
'NSFW video'
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -836,6 +851,8 @@ describe('Test video playlists', function () {
|
||||||
'video 2 server 3',
|
'video 2 server 3',
|
||||||
'video 1 server 3',
|
'video 1 server 3',
|
||||||
'video 4 server 1',
|
'video 4 server 1',
|
||||||
|
'NSFW video',
|
||||||
|
'NSFW video',
|
||||||
'NSFW video'
|
'NSFW video'
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -865,7 +882,9 @@ describe('Test video playlists', function () {
|
||||||
'video 2 server 3',
|
'video 2 server 3',
|
||||||
'NSFW video',
|
'NSFW video',
|
||||||
'video 1 server 3',
|
'video 1 server 3',
|
||||||
'video 4 server 1'
|
'video 4 server 1',
|
||||||
|
'NSFW video',
|
||||||
|
'NSFW video'
|
||||||
])
|
])
|
||||||
|
|
||||||
for (let i = 1; i <= elements.length; i++) {
|
for (let i = 1; i <= elements.length; i++) {
|
||||||
|
@ -1023,10 +1042,10 @@ describe('Test video playlists', function () {
|
||||||
for (const server of servers) {
|
for (const server of servers) {
|
||||||
const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
|
const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
|
||||||
|
|
||||||
expect(res.body.total).to.equal(4)
|
expect(res.body.total).to.equal(6)
|
||||||
|
|
||||||
const elements: VideoPlaylistElement[] = res.body.data
|
const elements: VideoPlaylistElement[] = res.body.data
|
||||||
expect(elements).to.have.lengthOf(4)
|
expect(elements).to.have.lengthOf(6)
|
||||||
|
|
||||||
expect(elements[0].video.name).to.equal('video 0 server 1')
|
expect(elements[0].video.name).to.equal('video 0 server 1')
|
||||||
expect(elements[0].position).to.equal(1)
|
expect(elements[0].position).to.equal(1)
|
||||||
|
@ -1039,6 +1058,12 @@ describe('Test video playlists', function () {
|
||||||
|
|
||||||
expect(elements[3].video.name).to.equal('video 4 server 1')
|
expect(elements[3].video.name).to.equal('video 4 server 1')
|
||||||
expect(elements[3].position).to.equal(4)
|
expect(elements[3].position).to.equal(4)
|
||||||
|
|
||||||
|
expect(elements[4].video.name).to.equal('NSFW video')
|
||||||
|
expect(elements[4].position).to.equal(5)
|
||||||
|
|
||||||
|
expect(elements[5].video.name).to.equal('NSFW video')
|
||||||
|
expect(elements[5].position).to.equal(6)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue