diff options
Diffstat (limited to 'server/controllers/api')
-rw-r--r-- | server/controllers/api/users.ts | 19 | ||||
-rw-r--r-- | server/controllers/api/videos/index.ts | 89 |
2 files changed, 77 insertions, 31 deletions
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index 6e5d09695..e3067584e 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts | |||
@@ -1,13 +1,13 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import 'multer' | ||
2 | import { extname, join } from 'path' | 3 | import { extname, join } from 'path' |
3 | import * as sharp from 'sharp' | ||
4 | import * as uuidv4 from 'uuid/v4' | 4 | import * as uuidv4 from 'uuid/v4' |
5 | import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared' | 5 | import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared' |
6 | import { unlinkPromise } from '../../helpers/core-utils' | ||
7 | import { retryTransactionWrapper } from '../../helpers/database-utils' | 6 | import { retryTransactionWrapper } from '../../helpers/database-utils' |
7 | import { processImage } from '../../helpers/image-utils' | ||
8 | import { logger } from '../../helpers/logger' | 8 | import { logger } from '../../helpers/logger' |
9 | import { createReqFiles, getFormattedObjects } from '../../helpers/utils' | 9 | import { createReqFiles, getFormattedObjects } from '../../helpers/utils' |
10 | import { AVATAR_MIMETYPE_EXT, AVATARS_SIZE, CONFIG, sequelizeTypescript } from '../../initializers' | 10 | import { AVATARS_SIZE, CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers' |
11 | import { updateActorAvatarInstance } from '../../lib/activitypub' | 11 | import { updateActorAvatarInstance } from '../../lib/activitypub' |
12 | import { sendUpdateUser } from '../../lib/activitypub/send' | 12 | import { sendUpdateUser } from '../../lib/activitypub/send' |
13 | import { Emailer } from '../../lib/emailer' | 13 | import { Emailer } from '../../lib/emailer' |
@@ -42,7 +42,7 @@ import { UserModel } from '../../models/account/user' | |||
42 | import { OAuthTokenModel } from '../../models/oauth/oauth-token' | 42 | import { OAuthTokenModel } from '../../models/oauth/oauth-token' |
43 | import { VideoModel } from '../../models/video/video' | 43 | import { VideoModel } from '../../models/video/video' |
44 | 44 | ||
45 | const reqAvatarFile = createReqFiles('avatarfile', CONFIG.STORAGE.AVATARS_DIR, AVATAR_MIMETYPE_EXT) | 45 | const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) |
46 | 46 | ||
47 | const usersRouter = express.Router() | 47 | const usersRouter = express.Router() |
48 | 48 | ||
@@ -288,17 +288,10 @@ async function updateMyAvatar (req: express.Request, res: express.Response, next | |||
288 | const user = res.locals.oauth.token.user | 288 | const user = res.locals.oauth.token.user |
289 | const actor = user.Account.Actor | 289 | const actor = user.Account.Actor |
290 | 290 | ||
291 | const avatarDir = CONFIG.STORAGE.AVATARS_DIR | ||
292 | const source = join(avatarDir, avatarPhysicalFile.filename) | ||
293 | const extension = extname(avatarPhysicalFile.filename) | 291 | const extension = extname(avatarPhysicalFile.filename) |
294 | const avatarName = uuidv4() + extension | 292 | const avatarName = uuidv4() + extension |
295 | const destination = join(avatarDir, avatarName) | 293 | const destination = join(CONFIG.STORAGE.AVATARS_DIR, avatarName) |
296 | 294 | await processImage(avatarPhysicalFile, destination, AVATARS_SIZE) | |
297 | await sharp(source) | ||
298 | .resize(AVATARS_SIZE.width, AVATARS_SIZE.height) | ||
299 | .toFile(destination) | ||
300 | |||
301 | await unlinkPromise(source) | ||
302 | 295 | ||
303 | const avatar = await sequelizeTypescript.transaction(async t => { | 296 | const avatar = await sequelizeTypescript.transaction(async t => { |
304 | const updatedActor = await updateActorAvatarInstance(actor, avatarName, t) | 297 | const updatedActor = await updateActorAvatarInstance(actor, avatarName, t) |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 459795141..1a4de081f 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -4,18 +4,36 @@ import { VideoCreate, VideoPrivacy, VideoUpdate } from '../../../../shared' | |||
4 | import { renamePromise } from '../../../helpers/core-utils' | 4 | import { renamePromise } from '../../../helpers/core-utils' |
5 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 5 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
6 | import { getVideoFileHeight } from '../../../helpers/ffmpeg-utils' | 6 | import { getVideoFileHeight } from '../../../helpers/ffmpeg-utils' |
7 | import { processImage } from '../../../helpers/image-utils' | ||
7 | import { logger } from '../../../helpers/logger' | 8 | import { logger } from '../../../helpers/logger' |
8 | import { createReqFiles, getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils' | 9 | import { createReqFiles, getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils' |
9 | import { | 10 | import { |
10 | CONFIG, sequelizeTypescript, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_MIMETYPE_EXT, | 11 | CONFIG, |
12 | IMAGE_MIMETYPE_EXT, | ||
13 | PREVIEWS_SIZE, | ||
14 | sequelizeTypescript, | ||
15 | THUMBNAILS_SIZE, | ||
16 | VIDEO_CATEGORIES, | ||
17 | VIDEO_LANGUAGES, | ||
18 | VIDEO_LICENCES, | ||
19 | VIDEO_MIMETYPE_EXT, | ||
11 | VIDEO_PRIVACIES | 20 | VIDEO_PRIVACIES |
12 | } from '../../../initializers' | 21 | } from '../../../initializers' |
13 | import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServerAndChannel } from '../../../lib/activitypub' | 22 | import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServerAndChannel } from '../../../lib/activitypub' |
14 | import { sendCreateVideo, sendCreateViewToOrigin, sendCreateViewToVideoFollowers, sendUpdateVideo } from '../../../lib/activitypub/send' | 23 | import { sendCreateVideo, sendCreateViewToOrigin, sendCreateViewToVideoFollowers, sendUpdateVideo } from '../../../lib/activitypub/send' |
15 | import { JobQueue } from '../../../lib/job-queue' | 24 | import { JobQueue } from '../../../lib/job-queue' |
16 | import { | 25 | import { |
17 | asyncMiddleware, authenticate, paginationValidator, setDefaultSort, setDefaultPagination, videosAddValidator, videosGetValidator, | 26 | asyncMiddleware, |
18 | videosRemoveValidator, videosSearchValidator, videosSortValidator, videosUpdateValidator | 27 | authenticate, |
28 | paginationValidator, | ||
29 | setDefaultPagination, | ||
30 | setDefaultSort, | ||
31 | videosAddValidator, | ||
32 | videosGetValidator, | ||
33 | videosRemoveValidator, | ||
34 | videosSearchValidator, | ||
35 | videosSortValidator, | ||
36 | videosUpdateValidator | ||
19 | } from '../../../middlewares' | 37 | } from '../../../middlewares' |
20 | import { TagModel } from '../../../models/video/tag' | 38 | import { TagModel } from '../../../models/video/tag' |
21 | import { VideoModel } from '../../../models/video/video' | 39 | import { VideoModel } from '../../../models/video/video' |
@@ -28,7 +46,23 @@ import { rateVideoRouter } from './rate' | |||
28 | 46 | ||
29 | const videosRouter = express.Router() | 47 | const videosRouter = express.Router() |
30 | 48 | ||
31 | const reqVideoFile = createReqFiles('videofile', CONFIG.STORAGE.VIDEOS_DIR, VIDEO_MIMETYPE_EXT) | 49 | const reqVideoFileAdd = createReqFiles( |
50 | [ 'videofile', 'thumbnailfile', 'previewfile' ], | ||
51 | Object.assign({}, VIDEO_MIMETYPE_EXT, IMAGE_MIMETYPE_EXT), | ||
52 | { | ||
53 | videofile: CONFIG.STORAGE.VIDEOS_DIR, | ||
54 | thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR, | ||
55 | previewfile: CONFIG.STORAGE.PREVIEWS_DIR | ||
56 | } | ||
57 | ) | ||
58 | const reqVideoFileUpdate = createReqFiles( | ||
59 | [ 'thumbnailfile', 'previewfile' ], | ||
60 | IMAGE_MIMETYPE_EXT, | ||
61 | { | ||
62 | thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR, | ||
63 | previewfile: CONFIG.STORAGE.PREVIEWS_DIR | ||
64 | } | ||
65 | ) | ||
32 | 66 | ||
33 | videosRouter.use('/', abuseVideoRouter) | 67 | videosRouter.use('/', abuseVideoRouter) |
34 | videosRouter.use('/', blacklistRouter) | 68 | videosRouter.use('/', blacklistRouter) |
@@ -58,12 +92,13 @@ videosRouter.get('/search', | |||
58 | ) | 92 | ) |
59 | videosRouter.put('/:id', | 93 | videosRouter.put('/:id', |
60 | authenticate, | 94 | authenticate, |
95 | reqVideoFileUpdate, | ||
61 | asyncMiddleware(videosUpdateValidator), | 96 | asyncMiddleware(videosUpdateValidator), |
62 | asyncMiddleware(updateVideoRetryWrapper) | 97 | asyncMiddleware(updateVideoRetryWrapper) |
63 | ) | 98 | ) |
64 | videosRouter.post('/upload', | 99 | videosRouter.post('/upload', |
65 | authenticate, | 100 | authenticate, |
66 | reqVideoFile, | 101 | reqVideoFileAdd, |
67 | asyncMiddleware(videosAddValidator), | 102 | asyncMiddleware(videosAddValidator), |
68 | asyncMiddleware(addVideoRetryWrapper) | 103 | asyncMiddleware(addVideoRetryWrapper) |
69 | ) | 104 | ) |
@@ -150,8 +185,7 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi | |||
150 | const video = new VideoModel(videoData) | 185 | const video = new VideoModel(videoData) |
151 | video.url = getVideoActivityPubUrl(video) | 186 | video.url = getVideoActivityPubUrl(video) |
152 | 187 | ||
153 | const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename) | 188 | const videoFileHeight = await getVideoFileHeight(videoPhysicalFile.path) |
154 | const videoFileHeight = await getVideoFileHeight(videoFilePath) | ||
155 | 189 | ||
156 | const videoFileData = { | 190 | const videoFileData = { |
157 | extname: extname(videoPhysicalFile.filename), | 191 | extname: extname(videoPhysicalFile.filename), |
@@ -160,21 +194,28 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi | |||
160 | } | 194 | } |
161 | const videoFile = new VideoFileModel(videoFileData) | 195 | const videoFile = new VideoFileModel(videoFileData) |
162 | const videoDir = CONFIG.STORAGE.VIDEOS_DIR | 196 | const videoDir = CONFIG.STORAGE.VIDEOS_DIR |
163 | const source = join(videoDir, videoPhysicalFile.filename) | ||
164 | const destination = join(videoDir, video.getVideoFilename(videoFile)) | 197 | const destination = join(videoDir, video.getVideoFilename(videoFile)) |
198 | await renamePromise(videoPhysicalFile.path, destination) | ||
165 | 199 | ||
166 | await renamePromise(source, destination) | 200 | // Process thumbnail or create it from the video |
167 | // This is important in case if there is another attempt in the retry process | 201 | const thumbnailField = req.files['thumbnailfile'] |
168 | videoPhysicalFile.filename = video.getVideoFilename(videoFile) | 202 | if (thumbnailField) { |
203 | const thumbnailPhysicalFile = thumbnailField[0] | ||
204 | await processImage(thumbnailPhysicalFile, join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName()), THUMBNAILS_SIZE) | ||
205 | } else { | ||
206 | await video.createThumbnail(videoFile) | ||
207 | } | ||
169 | 208 | ||
170 | const tasks = [] | 209 | // Process preview or create it from the video |
210 | const previewField = req.files['previewfile'] | ||
211 | if (previewField) { | ||
212 | const previewPhysicalFile = previewField[0] | ||
213 | await processImage(previewPhysicalFile, join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName()), PREVIEWS_SIZE) | ||
214 | } else { | ||
215 | await video.createPreview(videoFile) | ||
216 | } | ||
171 | 217 | ||
172 | tasks.push( | 218 | await video.createTorrentAndSetInfoHash(videoFile) |
173 | video.createTorrentAndSetInfoHash(videoFile), | ||
174 | video.createThumbnail(videoFile), | ||
175 | video.createPreview(videoFile) | ||
176 | ) | ||
177 | await Promise.all(tasks) | ||
178 | 219 | ||
179 | const videoCreated = await sequelizeTypescript.transaction(async t => { | 220 | const videoCreated = await sequelizeTypescript.transaction(async t => { |
180 | const sequelizeOptions = { transaction: t } | 221 | const sequelizeOptions = { transaction: t } |
@@ -237,6 +278,18 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
237 | const videoInfoToUpdate: VideoUpdate = req.body | 278 | const videoInfoToUpdate: VideoUpdate = req.body |
238 | const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE | 279 | const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE |
239 | 280 | ||
281 | // Process thumbnail or create it from the video | ||
282 | if (req.files && req.files['thumbnailfile']) { | ||
283 | const thumbnailPhysicalFile = req.files['thumbnailfile'][0] | ||
284 | await processImage(thumbnailPhysicalFile, join(CONFIG.STORAGE.THUMBNAILS_DIR, videoInstance.getThumbnailName()), THUMBNAILS_SIZE) | ||
285 | } | ||
286 | |||
287 | // Process preview or create it from the video | ||
288 | if (req.files && req.files['previewfile']) { | ||
289 | const previewPhysicalFile = req.files['previewfile'][0] | ||
290 | await processImage(previewPhysicalFile, join(CONFIG.STORAGE.PREVIEWS_DIR, videoInstance.getPreviewName()), PREVIEWS_SIZE) | ||
291 | } | ||
292 | |||
240 | try { | 293 | try { |
241 | await sequelizeTypescript.transaction(async t => { | 294 | await sequelizeTypescript.transaction(async t => { |
242 | const sequelizeOptions = { | 295 | const sequelizeOptions = { |