aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-07-12 19:02:00 +0200
committerChocobozzz <me@florianbigard.com>2018-07-16 11:50:08 +0200
commit40e87e9ecc54e3513fb586928330a7855eb192c6 (patch)
treeaf1111ecba85f9cd8286811ff332a67cf21be2f6 /server/controllers/api
parentd4557fd3ecc8d4ed4fb0e5c868929bc36c959ed2 (diff)
downloadPeerTube-40e87e9ecc54e3513fb586928330a7855eb192c6.tar.gz
PeerTube-40e87e9ecc54e3513fb586928330a7855eb192c6.tar.zst
PeerTube-40e87e9ecc54e3513fb586928330a7855eb192c6.zip
Implement captions/subtitles
Diffstat (limited to 'server/controllers/api')
-rw-r--r--server/controllers/api/config.ts14
-rw-r--r--server/controllers/api/videos/captions.ts100
-rw-r--r--server/controllers/api/videos/index.ts2
3 files changed, 115 insertions, 1 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index f678e3c4a..3788975a9 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -80,6 +80,14 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
80 extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME 80 extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
81 } 81 }
82 }, 82 },
83 videoCaption: {
84 file: {
85 size: {
86 max: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max
87 },
88 extensions: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME
89 }
90 },
83 user: { 91 user: {
84 videoQuota: CONFIG.USER.VIDEO_QUOTA 92 videoQuota: CONFIG.USER.VIDEO_QUOTA
85 } 93 }
@@ -122,12 +130,13 @@ async function updateCustomConfig (req: express.Request, res: express.Response,
122 130
123 // Force number conversion 131 // Force number conversion
124 toUpdate.cache.previews.size = parseInt('' + toUpdate.cache.previews.size, 10) 132 toUpdate.cache.previews.size = parseInt('' + toUpdate.cache.previews.size, 10)
133 toUpdate.cache.captions.size = parseInt('' + toUpdate.cache.captions.size, 10)
125 toUpdate.signup.limit = parseInt('' + toUpdate.signup.limit, 10) 134 toUpdate.signup.limit = parseInt('' + toUpdate.signup.limit, 10)
126 toUpdate.user.videoQuota = parseInt('' + toUpdate.user.videoQuota, 10) 135 toUpdate.user.videoQuota = parseInt('' + toUpdate.user.videoQuota, 10)
127 toUpdate.transcoding.threads = parseInt('' + toUpdate.transcoding.threads, 10) 136 toUpdate.transcoding.threads = parseInt('' + toUpdate.transcoding.threads, 10)
128 137
129 // camelCase to snake_case key 138 // camelCase to snake_case key
130 const toUpdateJSON = omit(toUpdate, 'user.videoQuota', 'instance.defaultClientRoute', 'instance.shortDescription') 139 const toUpdateJSON = omit(toUpdate, 'user.videoQuota', 'instance.defaultClientRoute', 'instance.shortDescription', 'cache.videoCaptions')
131 toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota 140 toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota
132 toUpdateJSON.instance['default_client_route'] = toUpdate.instance.defaultClientRoute 141 toUpdateJSON.instance['default_client_route'] = toUpdate.instance.defaultClientRoute
133 toUpdateJSON.instance['short_description'] = toUpdate.instance.shortDescription 142 toUpdateJSON.instance['short_description'] = toUpdate.instance.shortDescription
@@ -172,6 +181,9 @@ function customConfig (): CustomConfig {
172 cache: { 181 cache: {
173 previews: { 182 previews: {
174 size: CONFIG.CACHE.PREVIEWS.SIZE 183 size: CONFIG.CACHE.PREVIEWS.SIZE
184 },
185 captions: {
186 size: CONFIG.CACHE.VIDEO_CAPTIONS.SIZE
175 } 187 }
176 }, 188 },
177 signup: { 189 signup: {
diff --git a/server/controllers/api/videos/captions.ts b/server/controllers/api/videos/captions.ts
new file mode 100644
index 000000000..05412a17f
--- /dev/null
+++ b/server/controllers/api/videos/captions.ts
@@ -0,0 +1,100 @@
1import * as express from 'express'
2import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares'
3import {
4 addVideoCaptionValidator,
5 deleteVideoCaptionValidator,
6 listVideoCaptionsValidator
7} from '../../../middlewares/validators/video-captions'
8import { createReqFiles } from '../../../helpers/express-utils'
9import { CONFIG, sequelizeTypescript, VIDEO_CAPTIONS_MIMETYPE_EXT } from '../../../initializers'
10import { getFormattedObjects } from '../../../helpers/utils'
11import { VideoCaptionModel } from '../../../models/video/video-caption'
12import { renamePromise } from '../../../helpers/core-utils'
13import { join } from 'path'
14import { VideoModel } from '../../../models/video/video'
15import { logger } from '../../../helpers/logger'
16import { federateVideoIfNeeded } from '../../../lib/activitypub'
17
18const reqVideoCaptionAdd = createReqFiles(
19 [ 'captionfile' ],
20 VIDEO_CAPTIONS_MIMETYPE_EXT,
21 {
22 captionfile: CONFIG.STORAGE.CAPTIONS_DIR
23 }
24)
25
26const videoCaptionsRouter = express.Router()
27
28videoCaptionsRouter.get('/:videoId/captions',
29 asyncMiddleware(listVideoCaptionsValidator),
30 asyncMiddleware(listVideoCaptions)
31)
32videoCaptionsRouter.put('/:videoId/captions/:captionLanguage',
33 authenticate,
34 reqVideoCaptionAdd,
35 asyncMiddleware(addVideoCaptionValidator),
36 asyncRetryTransactionMiddleware(addVideoCaption)
37)
38videoCaptionsRouter.delete('/:videoId/captions/:captionLanguage',
39 authenticate,
40 asyncMiddleware(deleteVideoCaptionValidator),
41 asyncRetryTransactionMiddleware(deleteVideoCaption)
42)
43
44// ---------------------------------------------------------------------------
45
46export {
47 videoCaptionsRouter
48}
49
50// ---------------------------------------------------------------------------
51
52async function listVideoCaptions (req: express.Request, res: express.Response) {
53 const data = await VideoCaptionModel.listVideoCaptions(res.locals.video.id)
54
55 return res.json(getFormattedObjects(data, data.length))
56}
57
58async function addVideoCaption (req: express.Request, res: express.Response) {
59 const videoCaptionPhysicalFile = req.files['captionfile'][0]
60 const video = res.locals.video as VideoModel
61
62 const videoCaption = new VideoCaptionModel({
63 videoId: video.id,
64 language: req.params.captionLanguage
65 })
66 videoCaption.Video = video
67
68 // Move physical file
69 const videoCaptionsDir = CONFIG.STORAGE.CAPTIONS_DIR
70 const destination = join(videoCaptionsDir, videoCaption.getCaptionName())
71 await renamePromise(videoCaptionPhysicalFile.path, destination)
72 // This is important in case if there is another attempt in the retry process
73 videoCaptionPhysicalFile.filename = videoCaption.getCaptionName()
74 videoCaptionPhysicalFile.path = destination
75
76 await sequelizeTypescript.transaction(async t => {
77 await VideoCaptionModel.insertOrReplaceLanguage(video.id, req.params.captionLanguage, t)
78
79 // Update video update
80 await federateVideoIfNeeded(video, false, t)
81 })
82
83 return res.status(204).end()
84}
85
86async function deleteVideoCaption (req: express.Request, res: express.Response) {
87 const video = res.locals.video as VideoModel
88 const videoCaption = res.locals.videoCaption as VideoCaptionModel
89
90 await sequelizeTypescript.transaction(async t => {
91 await videoCaption.destroy({ transaction: t })
92
93 // Send video update
94 await federateVideoIfNeeded(video, false, t)
95 })
96
97 logger.info('Video caption %s of video %s deleted.', videoCaption.language, video.uuid)
98
99 return res.type('json').status(204).end()
100}
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 8c93ae89c..bbb5b8b4c 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -53,6 +53,7 @@ import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
53import { VideoSortField } from '../../../../client/src/app/shared/video/sort-field.type' 53import { VideoSortField } from '../../../../client/src/app/shared/video/sort-field.type'
54import { createReqFiles, isNSFWHidden } from '../../../helpers/express-utils' 54import { createReqFiles, isNSFWHidden } from '../../../helpers/express-utils'
55import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update' 55import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update'
56import { videoCaptionsRouter } from './captions'
56 57
57const videosRouter = express.Router() 58const videosRouter = express.Router()
58 59
@@ -78,6 +79,7 @@ videosRouter.use('/', abuseVideoRouter)
78videosRouter.use('/', blacklistRouter) 79videosRouter.use('/', blacklistRouter)
79videosRouter.use('/', rateVideoRouter) 80videosRouter.use('/', rateVideoRouter)
80videosRouter.use('/', videoCommentRouter) 81videosRouter.use('/', videoCommentRouter)
82videosRouter.use('/', videoCaptionsRouter)
81 83
82videosRouter.get('/categories', listVideoCategories) 84videosRouter.get('/categories', listVideoCategories)
83videosRouter.get('/licences', listVideoLicences) 85videosRouter.get('/licences', listVideoLicences)