From 40e87e9ecc54e3513fb586928330a7855eb192c6 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 12 Jul 2018 19:02:00 +0200 Subject: Implement captions/subtitles --- server/helpers/activitypub.ts | 1 + .../custom-validators/activitypub/videos.ts | 13 +++++++ server/helpers/custom-validators/video-captions.ts | 41 ++++++++++++++++++++++ server/helpers/custom-validators/videos.ts | 24 +++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 server/helpers/custom-validators/video-captions.ts (limited to 'server/helpers') diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index 37a251697..c49142a04 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts @@ -18,6 +18,7 @@ function activityPubContextify (data: T) { uuid: 'http://schema.org/identifier', category: 'http://schema.org/category', licence: 'http://schema.org/license', + subtitleLanguage: 'http://schema.org/subtitleLanguage', sensitive: 'as:sensitive', language: 'http://schema.org/inLanguage', views: 'http://schema.org/Number', diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts index 37c90a0c8..d97bbd2a9 100644 --- a/server/helpers/custom-validators/activitypub/videos.ts +++ b/server/helpers/custom-validators/activitypub/videos.ts @@ -51,6 +51,7 @@ function sanitizeAndCheckVideoTorrentObject (video: any) { if (!setValidRemoteVideoUrls(video)) return false if (!setRemoteVideoTruncatedContent(video)) return false if (!setValidAttributedTo(video)) return false + if (!setValidRemoteCaptions(video)) return false // Default attributes if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED @@ -98,6 +99,18 @@ function setValidRemoteTags (video: any) { return true } +function setValidRemoteCaptions (video: any) { + if (!video.subtitleLanguage) video.subtitleLanguage = [] + + if (Array.isArray(video.subtitleLanguage) === false) return false + + video.subtitleLanguage = video.subtitleLanguage.filter(caption => { + return isRemoteStringIdentifierValid(caption) + }) + + return true +} + function isRemoteNumberIdentifierValid (data: any) { return validator.isInt(data.identifier, { min: 0 }) } diff --git a/server/helpers/custom-validators/video-captions.ts b/server/helpers/custom-validators/video-captions.ts new file mode 100644 index 000000000..fd4dc740b --- /dev/null +++ b/server/helpers/custom-validators/video-captions.ts @@ -0,0 +1,41 @@ +import { CONSTRAINTS_FIELDS, VIDEO_LANGUAGES } from '../../initializers' +import { exists, isFileValid } from './misc' +import { Response } from 'express' +import { VideoModel } from '../../models/video/video' +import { VideoCaptionModel } from '../../models/video/video-caption' + +function isVideoCaptionLanguageValid (value: any) { + return exists(value) && VIDEO_LANGUAGES[ value ] !== undefined +} + +const videoCaptionTypes = CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME + .map(v => v.replace('.', '')) + .join('|') +const videoCaptionsTypesRegex = `text/(${videoCaptionTypes})` + +function isVideoCaptionFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) { + return isFileValid(files, videoCaptionsTypesRegex, field, CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max) +} + +async function isVideoCaptionExist (video: VideoModel, language: string, res: Response) { + const videoCaption = await VideoCaptionModel.loadByVideoIdAndLanguage(video.id, language) + + if (!videoCaption) { + res.status(404) + .json({ error: 'Video caption not found' }) + .end() + + return false + } + + res.locals.videoCaption = videoCaption + return true +} + +// --------------------------------------------------------------------------- + +export { + isVideoCaptionFile, + isVideoCaptionLanguageValid, + isVideoCaptionExist +} diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index 672f06dc0..b5cb126d9 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts @@ -126,6 +126,29 @@ function isVideoFileSizeValid (value: string) { return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE) } +function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: Response) { + // Retrieve the user who did the request + if (video.isOwned() === false) { + res.status(403) + .json({ error: 'Cannot manage a video of another server.' }) + .end() + return false + } + + // Check if the user can delete the video + // The user can delete it if he has the right + // Or if s/he is the video's account + const account = video.VideoChannel.Account + if (user.hasRight(right) === false && account.userId !== user.id) { + res.status(403) + .json({ error: 'Cannot manage a video of another user.' }) + .end() + return false + } + + return true +} + async function isVideoExist (id: string, res: Response) { let video: VideoModel @@ -179,6 +202,7 @@ async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, export { isVideoCategoryValid, + checkUserCanManageVideo, isVideoLicenceValid, isVideoLanguageValid, isVideoTruncatedDescriptionValid, -- cgit v1.2.3