aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers')
-rw-r--r--server/controllers/api/accounts.ts16
-rw-r--r--server/controllers/api/config.ts6
-rw-r--r--server/controllers/api/users/index.ts37
-rw-r--r--server/controllers/api/users/me.ts16
-rw-r--r--server/controllers/api/video-channel.ts37
-rw-r--r--server/controllers/api/video-playlist.ts6
-rw-r--r--server/controllers/api/videos/index.ts54
-rw-r--r--server/controllers/static.ts2
8 files changed, 128 insertions, 46 deletions
diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts
index 8d4db1e75..5a1d652f2 100644
--- a/server/controllers/api/accounts.ts
+++ b/server/controllers/api/accounts.ts
@@ -16,7 +16,8 @@ import {
16 accountNameWithHostGetValidator, 16 accountNameWithHostGetValidator,
17 accountsSortValidator, 17 accountsSortValidator,
18 ensureAuthUserOwnsAccountValidator, 18 ensureAuthUserOwnsAccountValidator,
19 videosSortValidator 19 videosSortValidator,
20 videoChannelsSortValidator
20} from '../../middlewares/validators' 21} from '../../middlewares/validators'
21import { AccountModel } from '../../models/account/account' 22import { AccountModel } from '../../models/account/account'
22import { AccountVideoRateModel } from '../../models/account/account-video-rate' 23import { AccountVideoRateModel } from '../../models/account/account-video-rate'
@@ -56,6 +57,10 @@ accountsRouter.get('/:accountName/videos',
56 57
57accountsRouter.get('/:accountName/video-channels', 58accountsRouter.get('/:accountName/video-channels',
58 asyncMiddleware(accountNameWithHostGetValidator), 59 asyncMiddleware(accountNameWithHostGetValidator),
60 paginationValidator,
61 videoChannelsSortValidator,
62 setDefaultSort,
63 setDefaultPagination,
59 asyncMiddleware(listAccountChannels) 64 asyncMiddleware(listAccountChannels)
60) 65)
61 66
@@ -108,7 +113,14 @@ async function listAccounts (req: express.Request, res: express.Response) {
108} 113}
109 114
110async function listAccountChannels (req: express.Request, res: express.Response) { 115async function listAccountChannels (req: express.Request, res: express.Response) {
111 const resultList = await VideoChannelModel.listByAccount(res.locals.account.id) 116 const options = {
117 accountId: res.locals.account.id,
118 start: req.query.start,
119 count: req.query.count,
120 sort: req.query.sort
121 }
122
123 const resultList = await VideoChannelModel.listByAccount(options)
112 124
113 return res.json(getFormattedObjects(resultList.data, resultList.total)) 125 return res.json(getFormattedObjects(resultList.data, resultList.total))
114} 126}
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index 40012c03b..1d12f701b 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -51,7 +51,7 @@ async function getConfig (req: express.Request, res: express.Response) {
51 if (serverCommit === undefined) serverCommit = await getServerCommit() 51 if (serverCommit === undefined) serverCommit = await getServerCommit()
52 52
53 const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) 53 const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
54 .filter(key => CONFIG.TRANSCODING.ENABLED === CONFIG.TRANSCODING.RESOLUTIONS[key] === true) 54 .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
55 .map(r => parseInt(r, 10)) 55 .map(r => parseInt(r, 10))
56 56
57 const json: ServerConfig = { 57 const json: ServerConfig = {
@@ -255,13 +255,15 @@ function customConfig (): CustomConfig {
255 transcoding: { 255 transcoding: {
256 enabled: CONFIG.TRANSCODING.ENABLED, 256 enabled: CONFIG.TRANSCODING.ENABLED,
257 allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS, 257 allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS,
258 allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES,
258 threads: CONFIG.TRANSCODING.THREADS, 259 threads: CONFIG.TRANSCODING.THREADS,
259 resolutions: { 260 resolutions: {
260 '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], 261 '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ],
261 '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ], 262 '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ],
262 '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], 263 '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ],
263 '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], 264 '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ],
264 '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ] 265 '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ],
266 '2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ]
265 }, 267 },
266 hls: { 268 hls: {
267 enabled: CONFIG.TRANSCODING.HLS.ENABLED 269 enabled: CONFIG.TRANSCODING.HLS.ENABLED
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts
index 0aafba66e..c1d72087c 100644
--- a/server/controllers/api/users/index.ts
+++ b/server/controllers/api/users/index.ts
@@ -6,7 +6,7 @@ import { getFormattedObjects } from '../../../helpers/utils'
6import { RATES_LIMIT, WEBSERVER } from '../../../initializers/constants' 6import { RATES_LIMIT, WEBSERVER } from '../../../initializers/constants'
7import { Emailer } from '../../../lib/emailer' 7import { Emailer } from '../../../lib/emailer'
8import { Redis } from '../../../lib/redis' 8import { Redis } from '../../../lib/redis'
9import { createUserAccountAndChannelAndPlaylist } from '../../../lib/user' 9import { createUserAccountAndChannelAndPlaylist, sendVerifyUserEmail } from '../../../lib/user'
10import { 10import {
11 asyncMiddleware, 11 asyncMiddleware,
12 asyncRetryTransactionMiddleware, 12 asyncRetryTransactionMiddleware,
@@ -46,14 +46,18 @@ import { mySubscriptionsRouter } from './my-subscriptions'
46import { CONFIG } from '../../../initializers/config' 46import { CONFIG } from '../../../initializers/config'
47import { sequelizeTypescript } from '../../../initializers/database' 47import { sequelizeTypescript } from '../../../initializers/database'
48import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' 48import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
49import { UserRegister } from '../../../../shared/models/users/user-register.model'
49 50
50const auditLogger = auditLoggerFactory('users') 51const auditLogger = auditLoggerFactory('users')
51 52
52const loginRateLimiter = new RateLimit({ 53// FIXME: https://github.com/nfriedly/express-rate-limit/issues/138
54// @ts-ignore
55const loginRateLimiter = RateLimit({
53 windowMs: RATES_LIMIT.LOGIN.WINDOW_MS, 56 windowMs: RATES_LIMIT.LOGIN.WINDOW_MS,
54 max: RATES_LIMIT.LOGIN.MAX 57 max: RATES_LIMIT.LOGIN.MAX
55}) 58})
56 59
60// @ts-ignore
57const askSendEmailLimiter = new RateLimit({ 61const askSendEmailLimiter = new RateLimit({
58 windowMs: RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS, 62 windowMs: RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS,
59 max: RATES_LIMIT.ASK_SEND_EMAIL.MAX 63 max: RATES_LIMIT.ASK_SEND_EMAIL.MAX
@@ -143,7 +147,7 @@ usersRouter.post('/:id/reset-password',
143usersRouter.post('/ask-send-verify-email', 147usersRouter.post('/ask-send-verify-email',
144 askSendEmailLimiter, 148 askSendEmailLimiter,
145 asyncMiddleware(usersAskSendVerifyEmailValidator), 149 asyncMiddleware(usersAskSendVerifyEmailValidator),
146 asyncMiddleware(askSendVerifyUserEmail) 150 asyncMiddleware(reSendVerifyUserEmail)
147) 151)
148 152
149usersRouter.post('/:id/verify-email', 153usersRouter.post('/:id/verify-email',
@@ -180,7 +184,7 @@ async function createUser (req: express.Request, res: express.Response) {
180 adminFlags: body.adminFlags || UserAdminFlag.NONE 184 adminFlags: body.adminFlags || UserAdminFlag.NONE
181 }) 185 })
182 186
183 const { user, account } = await createUserAccountAndChannelAndPlaylist(userToCreate) 187 const { user, account } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate })
184 188
185 auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) 189 auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()))
186 logger.info('User %s with its channel and account created.', body.username) 190 logger.info('User %s with its channel and account created.', body.username)
@@ -189,15 +193,14 @@ async function createUser (req: express.Request, res: express.Response) {
189 user: { 193 user: {
190 id: user.id, 194 id: user.id,
191 account: { 195 account: {
192 id: account.id, 196 id: account.id
193 uuid: account.Actor.uuid
194 } 197 }
195 } 198 }
196 }).end() 199 }).end()
197} 200}
198 201
199async function registerUser (req: express.Request, res: express.Response) { 202async function registerUser (req: express.Request, res: express.Response) {
200 const body: UserCreate = req.body 203 const body: UserRegister = req.body
201 204
202 const userToCreate = new UserModel({ 205 const userToCreate = new UserModel({
203 username: body.username, 206 username: body.username,
@@ -211,7 +214,11 @@ async function registerUser (req: express.Request, res: express.Response) {
211 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null 214 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
212 }) 215 })
213 216
214 const { user } = await createUserAccountAndChannelAndPlaylist(userToCreate) 217 const { user } = await createUserAccountAndChannelAndPlaylist({
218 userToCreate: userToCreate,
219 userDisplayName: body.displayName || undefined,
220 channelNames: body.channel
221 })
215 222
216 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON())) 223 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
217 logger.info('User %s with its channel and account registered.', body.username) 224 logger.info('User %s with its channel and account registered.', body.username)
@@ -313,14 +320,7 @@ async function resetUserPassword (req: express.Request, res: express.Response) {
313 return res.status(204).end() 320 return res.status(204).end()
314} 321}
315 322
316async function sendVerifyUserEmail (user: UserModel) { 323async function reSendVerifyUserEmail (req: express.Request, res: express.Response) {
317 const verificationString = await Redis.Instance.setVerifyEmailVerificationString(user.id)
318 const url = WEBSERVER.URL + '/verify-account/email?userId=' + user.id + '&verificationString=' + verificationString
319 await Emailer.Instance.addVerifyEmailJob(user.email, url)
320 return
321}
322
323async function askSendVerifyUserEmail (req: express.Request, res: express.Response) {
324 const user = res.locals.user 324 const user = res.locals.user
325 325
326 await sendVerifyUserEmail(user) 326 await sendVerifyUserEmail(user)
@@ -332,6 +332,11 @@ async function verifyUserEmail (req: express.Request, res: express.Response) {
332 const user = res.locals.user 332 const user = res.locals.user
333 user.emailVerified = true 333 user.emailVerified = true
334 334
335 if (req.body.isPendingEmail === true) {
336 user.email = user.pendingEmail
337 user.pendingEmail = null
338 }
339
335 await user.save() 340 await user.save()
336 341
337 return res.status(204).end() 342 return res.status(204).end()
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts
index ddb239e7b..1750a02e9 100644
--- a/server/controllers/api/users/me.ts
+++ b/server/controllers/api/users/me.ts
@@ -28,6 +28,7 @@ import { VideoImportModel } from '../../../models/video/video-import'
28import { AccountModel } from '../../../models/account/account' 28import { AccountModel } from '../../../models/account/account'
29import { CONFIG } from '../../../initializers/config' 29import { CONFIG } from '../../../initializers/config'
30import { sequelizeTypescript } from '../../../initializers/database' 30import { sequelizeTypescript } from '../../../initializers/database'
31import { sendVerifyUserEmail } from '../../../lib/user'
31 32
32const auditLogger = auditLoggerFactory('users-me') 33const auditLogger = auditLoggerFactory('users-me')
33 34
@@ -171,17 +172,26 @@ async function deleteMe (req: express.Request, res: express.Response) {
171 172
172async function updateMe (req: express.Request, res: express.Response) { 173async function updateMe (req: express.Request, res: express.Response) {
173 const body: UserUpdateMe = req.body 174 const body: UserUpdateMe = req.body
175 let sendVerificationEmail = false
174 176
175 const user = res.locals.oauth.token.user 177 const user = res.locals.oauth.token.user
176 const oldUserAuditView = new UserAuditView(user.toFormattedJSON({})) 178 const oldUserAuditView = new UserAuditView(user.toFormattedJSON({}))
177 179
178 if (body.password !== undefined) user.password = body.password 180 if (body.password !== undefined) user.password = body.password
179 if (body.email !== undefined) user.email = body.email
180 if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy 181 if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy
181 if (body.webTorrentEnabled !== undefined) user.webTorrentEnabled = body.webTorrentEnabled 182 if (body.webTorrentEnabled !== undefined) user.webTorrentEnabled = body.webTorrentEnabled
182 if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo 183 if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo
183 if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled 184 if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled
184 185
186 if (body.email !== undefined) {
187 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
188 user.pendingEmail = body.email
189 sendVerificationEmail = true
190 } else {
191 user.email = body.email
192 }
193 }
194
185 await sequelizeTypescript.transaction(async t => { 195 await sequelizeTypescript.transaction(async t => {
186 const userAccount = await AccountModel.load(user.Account.id) 196 const userAccount = await AccountModel.load(user.Account.id)
187 197
@@ -196,6 +206,10 @@ async function updateMe (req: express.Request, res: express.Response) {
196 auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON({})), oldUserAuditView) 206 auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON({})), oldUserAuditView)
197 }) 207 })
198 208
209 if (sendVerificationEmail === true) {
210 await sendVerifyUserEmail(user, true)
211 }
212
199 return res.sendStatus(204) 213 return res.sendStatus(204)
200} 214}
201 215
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts
index 3d6dbfe70..81a03a62b 100644
--- a/server/controllers/api/video-channel.ts
+++ b/server/controllers/api/video-channel.ts
@@ -19,7 +19,7 @@ import { VideoChannelModel } from '../../models/video/video-channel'
19import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators' 19import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators'
20import { sendUpdateActor } from '../../lib/activitypub/send' 20import { sendUpdateActor } from '../../lib/activitypub/send'
21import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' 21import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared'
22import { createVideoChannel } from '../../lib/video-channel' 22import { createVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel'
23import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' 23import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
24import { setAsyncActorKeys } from '../../lib/activitypub' 24import { setAsyncActorKeys } from '../../lib/activitypub'
25import { AccountModel } from '../../models/account/account' 25import { AccountModel } from '../../models/account/account'
@@ -143,15 +143,14 @@ async function addVideoChannel (req: express.Request, res: express.Response) {
143 }) 143 })
144 144
145 setAsyncActorKeys(videoChannelCreated.Actor) 145 setAsyncActorKeys(videoChannelCreated.Actor)
146 .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err })) 146 .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.url, { err }))
147 147
148 auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON())) 148 auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON()))
149 logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid) 149 logger.info('Video channel %s created.', videoChannelCreated.Actor.url)
150 150
151 return res.json({ 151 return res.json({
152 videoChannel: { 152 videoChannel: {
153 id: videoChannelCreated.id, 153 id: videoChannelCreated.id
154 uuid: videoChannelCreated.Actor.uuid
155 } 154 }
156 }).end() 155 }).end()
157} 156}
@@ -161,6 +160,7 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
161 const videoChannelFieldsSave = videoChannelInstance.toJSON() 160 const videoChannelFieldsSave = videoChannelInstance.toJSON()
162 const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) 161 const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())
163 const videoChannelInfoToUpdate = req.body as VideoChannelUpdate 162 const videoChannelInfoToUpdate = req.body as VideoChannelUpdate
163 let doBulkVideoUpdate = false
164 164
165 try { 165 try {
166 await sequelizeTypescript.transaction(async t => { 166 await sequelizeTypescript.transaction(async t => {
@@ -168,9 +168,18 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
168 transaction: t 168 transaction: t
169 } 169 }
170 170
171 if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.displayName) 171 if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.name = videoChannelInfoToUpdate.displayName
172 if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description) 172 if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.description = videoChannelInfoToUpdate.description
173 if (videoChannelInfoToUpdate.support !== undefined) videoChannelInstance.set('support', videoChannelInfoToUpdate.support) 173
174 if (videoChannelInfoToUpdate.support !== undefined) {
175 const oldSupportField = videoChannelInstance.support
176 videoChannelInstance.support = videoChannelInfoToUpdate.support
177
178 if (videoChannelInfoToUpdate.bulkVideosSupportUpdate === true && oldSupportField !== videoChannelInfoToUpdate.support) {
179 doBulkVideoUpdate = true
180 await VideoModel.bulkUpdateSupportField(videoChannelInstance, t)
181 }
182 }
174 183
175 const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions) 184 const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions)
176 await sendUpdateActor(videoChannelInstanceUpdated, t) 185 await sendUpdateActor(videoChannelInstanceUpdated, t)
@@ -180,7 +189,8 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
180 new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()), 189 new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()),
181 oldVideoChannelAuditKeys 190 oldVideoChannelAuditKeys
182 ) 191 )
183 logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) 192
193 logger.info('Video channel %s updated.', videoChannelInstance.Actor.url)
184 }) 194 })
185 } catch (err) { 195 } catch (err) {
186 logger.debug('Cannot update the video channel.', { err }) 196 logger.debug('Cannot update the video channel.', { err })
@@ -193,7 +203,12 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
193 throw err 203 throw err
194 } 204 }
195 205
196 return res.type('json').status(204).end() 206 res.type('json').status(204).end()
207
208 // Don't process in a transaction, and after the response because it could be long
209 if (doBulkVideoUpdate) {
210 await federateAllVideosOfChannel(videoChannelInstance)
211 }
197} 212}
198 213
199async function removeVideoChannel (req: express.Request, res: express.Response) { 214async function removeVideoChannel (req: express.Request, res: express.Response) {
@@ -205,7 +220,7 @@ async function removeVideoChannel (req: express.Request, res: express.Response)
205 await videoChannelInstance.destroy({ transaction: t }) 220 await videoChannelInstance.destroy({ transaction: t })
206 221
207 auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())) 222 auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()))
208 logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) 223 logger.info('Video channel %s deleted.', videoChannelInstance.Actor.url)
209 }) 224 })
210 225
211 return res.type('json').status(204).end() 226 return res.type('json').status(204).end()
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts
index a17136401..62490e63b 100644
--- a/server/controllers/api/video-playlist.ts
+++ b/server/controllers/api/video-playlist.ts
@@ -203,7 +203,9 @@ async function updateVideoPlaylist (req: express.Request, res: express.Response)
203 const videoPlaylistInstance = res.locals.videoPlaylist 203 const videoPlaylistInstance = res.locals.videoPlaylist
204 const videoPlaylistFieldsSave = videoPlaylistInstance.toJSON() 204 const videoPlaylistFieldsSave = videoPlaylistInstance.toJSON()
205 const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate 205 const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate
206
206 const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE 207 const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE
208 const wasNotPrivatePlaylist = videoPlaylistInstance.privacy !== VideoPlaylistPrivacy.PRIVATE
207 209
208 const thumbnailField = req.files['thumbnailfile'] 210 const thumbnailField = req.files['thumbnailfile']
209 const thumbnailModel = thumbnailField 211 const thumbnailModel = thumbnailField
@@ -232,6 +234,10 @@ async function updateVideoPlaylist (req: express.Request, res: express.Response)
232 234
233 if (videoPlaylistInfoToUpdate.privacy !== undefined) { 235 if (videoPlaylistInfoToUpdate.privacy !== undefined) {
234 videoPlaylistInstance.privacy = parseInt(videoPlaylistInfoToUpdate.privacy.toString(), 10) 236 videoPlaylistInstance.privacy = parseInt(videoPlaylistInfoToUpdate.privacy.toString(), 10)
237
238 if (wasNotPrivatePlaylist === true && videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE) {
239 await sendDeleteVideoPlaylist(videoPlaylistInstance, t)
240 }
235 } 241 }
236 242
237 const playlistUpdated = await videoPlaylistInstance.save(sequelizeOptions) 243 const playlistUpdated = await videoPlaylistInstance.save(sequelizeOptions)
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 1a18a8ae8..5ebd8fbc4 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -6,7 +6,14 @@ import { logger } from '../../../helpers/logger'
6import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' 6import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger'
7import { getFormattedObjects, getServerActor } from '../../../helpers/utils' 7import { getFormattedObjects, getServerActor } from '../../../helpers/utils'
8import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' 8import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist'
9import { MIMETYPES, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers/constants' 9import {
10 DEFAULT_AUDIO_RESOLUTION,
11 MIMETYPES,
12 VIDEO_CATEGORIES,
13 VIDEO_LANGUAGES,
14 VIDEO_LICENCES,
15 VIDEO_PRIVACIES
16} from '../../../initializers/constants'
10import { 17import {
11 changeVideoChannelShare, 18 changeVideoChannelShare,
12 federateVideoIfNeeded, 19 federateVideoIfNeeded,
@@ -54,6 +61,7 @@ import { CONFIG } from '../../../initializers/config'
54import { sequelizeTypescript } from '../../../initializers/database' 61import { sequelizeTypescript } from '../../../initializers/database'
55import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail' 62import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail'
56import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' 63import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type'
64import { VideoTranscodingPayload } from '../../../lib/job-queue/handlers/video-transcoding'
57 65
58const auditLogger = auditLoggerFactory('videos') 66const auditLogger = auditLoggerFactory('videos')
59const videosRouter = express.Router() 67const videosRouter = express.Router()
@@ -191,17 +199,17 @@ async function addVideo (req: express.Request, res: express.Response) {
191 const video = new VideoModel(videoData) 199 const video = new VideoModel(videoData)
192 video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object 200 video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object
193 201
194 // Build the file object 202 const videoFile = new VideoFileModel({
195 const { videoFileResolution } = await getVideoFileResolution(videoPhysicalFile.path)
196 const fps = await getVideoFileFPS(videoPhysicalFile.path)
197
198 const videoFileData = {
199 extname: extname(videoPhysicalFile.filename), 203 extname: extname(videoPhysicalFile.filename),
200 resolution: videoFileResolution, 204 size: videoPhysicalFile.size
201 size: videoPhysicalFile.size, 205 })
202 fps 206
207 if (videoFile.isAudio()) {
208 videoFile.resolution = DEFAULT_AUDIO_RESOLUTION
209 } else {
210 videoFile.fps = await getVideoFileFPS(videoPhysicalFile.path)
211 videoFile.resolution = (await getVideoFileResolution(videoPhysicalFile.path)).videoFileResolution
203 } 212 }
204 const videoFile = new VideoFileModel(videoFileData)
205 213
206 // Move physical file 214 // Move physical file
207 const videoDir = CONFIG.STORAGE.VIDEOS_DIR 215 const videoDir = CONFIG.STORAGE.VIDEOS_DIR
@@ -279,9 +287,21 @@ async function addVideo (req: express.Request, res: express.Response) {
279 287
280 if (video.state === VideoState.TO_TRANSCODE) { 288 if (video.state === VideoState.TO_TRANSCODE) {
281 // Put uuid because we don't have id auto incremented for now 289 // Put uuid because we don't have id auto incremented for now
282 const dataInput = { 290 let dataInput: VideoTranscodingPayload
283 videoUUID: videoCreated.uuid, 291
284 isNewVideo: true 292 if (videoFile.isAudio()) {
293 dataInput = {
294 type: 'merge-audio' as 'merge-audio',
295 resolution: DEFAULT_AUDIO_RESOLUTION,
296 videoUUID: videoCreated.uuid,
297 isNewVideo: true
298 }
299 } else {
300 dataInput = {
301 type: 'optimize' as 'optimize',
302 videoUUID: videoCreated.uuid,
303 isNewVideo: true
304 }
285 } 305 }
286 306
287 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) 307 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
@@ -300,7 +320,9 @@ async function updateVideo (req: express.Request, res: express.Response) {
300 const videoFieldsSave = videoInstance.toJSON() 320 const videoFieldsSave = videoInstance.toJSON()
301 const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON()) 321 const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON())
302 const videoInfoToUpdate: VideoUpdate = req.body 322 const videoInfoToUpdate: VideoUpdate = req.body
323
303 const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE 324 const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE
325 const wasNotPrivateVideo = videoInstance.privacy !== VideoPrivacy.PRIVATE
304 const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED 326 const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED
305 327
306 // Process thumbnail or create it from the video 328 // Process thumbnail or create it from the video
@@ -336,9 +358,15 @@ async function updateVideo (req: express.Request, res: express.Response) {
336 const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10) 358 const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10)
337 videoInstance.privacy = newPrivacy 359 videoInstance.privacy = newPrivacy
338 360
361 // The video was private, and is not anymore -> publish it
339 if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) { 362 if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) {
340 videoInstance.publishedAt = new Date() 363 videoInstance.publishedAt = new Date()
341 } 364 }
365
366 // The video was not private, but now it is -> we need to unfederate it
367 if (wasNotPrivateVideo === true && newPrivacy === VideoPrivacy.PRIVATE) {
368 await VideoModel.sendDelete(videoInstance, { transaction: t })
369 }
342 } 370 }
343 371
344 const videoInstanceUpdated = await videoInstance.save(sequelizeOptions) 372 const videoInstanceUpdated = await videoInstance.save(sequelizeOptions)
diff --git a/server/controllers/static.ts b/server/controllers/static.ts
index fb2e7742a..a6b462443 100644
--- a/server/controllers/static.ts
+++ b/server/controllers/static.ts
@@ -194,7 +194,7 @@ async function getVideoCaption (req: express.Request, res: express.Response) {
194 return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE }) 194 return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE })
195} 195}
196 196
197async function generateNodeinfo (req: express.Request, res: express.Response, next: express.NextFunction) { 197async function generateNodeinfo (req: express.Request, res: express.Response) {
198 const { totalVideos } = await VideoModel.getStats() 198 const { totalVideos } = await VideoModel.getStats()
199 const { totalLocalVideoComments } = await VideoCommentModel.getStats() 199 const { totalLocalVideoComments } = await VideoCommentModel.getStats()
200 const { totalUsers } = await UserModel.getStats() 200 const { totalUsers } = await UserModel.getStats()