Add ability to set video thumbnail/preview
This commit is contained in:
parent
e883399fa6
commit
ac81d1a06d
|
@ -1,4 +1,4 @@
|
||||||
import { ElementRef, OnInit, ViewChild, ViewChildren } from '@angular/core'
|
import { ElementRef, OnInit, ViewChild } from '@angular/core'
|
||||||
import { ActivatedRoute, Router } from '@angular/router'
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
import { isInMobileView } from '@app/shared/misc/utils'
|
import { isInMobileView } from '@app/shared/misc/utils'
|
||||||
import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
|
import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
|
||||||
|
|
|
@ -158,7 +158,7 @@ app.use(function (req, res, next) {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.use(function (err, req, res, next) {
|
app.use(function (err, req, res, next) {
|
||||||
logger.error(err, err)
|
logger.error('Error in controller.', { error: err.stack || err.message || err })
|
||||||
res.sendStatus(err.status || 500)
|
res.sendStatus(err.status || 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import * as express from 'express'
|
import * as express from 'express'
|
||||||
|
import 'multer'
|
||||||
import { extname, join } from 'path'
|
import { extname, join } from 'path'
|
||||||
import * as sharp from 'sharp'
|
|
||||||
import * as uuidv4 from 'uuid/v4'
|
import * as uuidv4 from 'uuid/v4'
|
||||||
import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared'
|
import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared'
|
||||||
import { unlinkPromise } from '../../helpers/core-utils'
|
|
||||||
import { retryTransactionWrapper } from '../../helpers/database-utils'
|
import { retryTransactionWrapper } from '../../helpers/database-utils'
|
||||||
|
import { processImage } from '../../helpers/image-utils'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { createReqFiles, getFormattedObjects } from '../../helpers/utils'
|
import { createReqFiles, getFormattedObjects } from '../../helpers/utils'
|
||||||
import { AVATAR_MIMETYPE_EXT, AVATARS_SIZE, CONFIG, sequelizeTypescript } from '../../initializers'
|
import { AVATARS_SIZE, CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers'
|
||||||
import { updateActorAvatarInstance } from '../../lib/activitypub'
|
import { updateActorAvatarInstance } from '../../lib/activitypub'
|
||||||
import { sendUpdateUser } from '../../lib/activitypub/send'
|
import { sendUpdateUser } from '../../lib/activitypub/send'
|
||||||
import { Emailer } from '../../lib/emailer'
|
import { Emailer } from '../../lib/emailer'
|
||||||
|
@ -42,7 +42,7 @@ import { UserModel } from '../../models/account/user'
|
||||||
import { OAuthTokenModel } from '../../models/oauth/oauth-token'
|
import { OAuthTokenModel } from '../../models/oauth/oauth-token'
|
||||||
import { VideoModel } from '../../models/video/video'
|
import { VideoModel } from '../../models/video/video'
|
||||||
|
|
||||||
const reqAvatarFile = createReqFiles('avatarfile', CONFIG.STORAGE.AVATARS_DIR, AVATAR_MIMETYPE_EXT)
|
const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR })
|
||||||
|
|
||||||
const usersRouter = express.Router()
|
const usersRouter = express.Router()
|
||||||
|
|
||||||
|
@ -288,17 +288,10 @@ async function updateMyAvatar (req: express.Request, res: express.Response, next
|
||||||
const user = res.locals.oauth.token.user
|
const user = res.locals.oauth.token.user
|
||||||
const actor = user.Account.Actor
|
const actor = user.Account.Actor
|
||||||
|
|
||||||
const avatarDir = CONFIG.STORAGE.AVATARS_DIR
|
|
||||||
const source = join(avatarDir, avatarPhysicalFile.filename)
|
|
||||||
const extension = extname(avatarPhysicalFile.filename)
|
const extension = extname(avatarPhysicalFile.filename)
|
||||||
const avatarName = uuidv4() + extension
|
const avatarName = uuidv4() + extension
|
||||||
const destination = join(avatarDir, avatarName)
|
const destination = join(CONFIG.STORAGE.AVATARS_DIR, avatarName)
|
||||||
|
await processImage(avatarPhysicalFile, destination, AVATARS_SIZE)
|
||||||
await sharp(source)
|
|
||||||
.resize(AVATARS_SIZE.width, AVATARS_SIZE.height)
|
|
||||||
.toFile(destination)
|
|
||||||
|
|
||||||
await unlinkPromise(source)
|
|
||||||
|
|
||||||
const avatar = await sequelizeTypescript.transaction(async t => {
|
const avatar = await sequelizeTypescript.transaction(async t => {
|
||||||
const updatedActor = await updateActorAvatarInstance(actor, avatarName, t)
|
const updatedActor = await updateActorAvatarInstance(actor, avatarName, t)
|
||||||
|
|
|
@ -4,18 +4,36 @@ import { VideoCreate, VideoPrivacy, VideoUpdate } from '../../../../shared'
|
||||||
import { renamePromise } from '../../../helpers/core-utils'
|
import { renamePromise } from '../../../helpers/core-utils'
|
||||||
import { retryTransactionWrapper } from '../../../helpers/database-utils'
|
import { retryTransactionWrapper } from '../../../helpers/database-utils'
|
||||||
import { getVideoFileHeight } from '../../../helpers/ffmpeg-utils'
|
import { getVideoFileHeight } from '../../../helpers/ffmpeg-utils'
|
||||||
|
import { processImage } from '../../../helpers/image-utils'
|
||||||
import { logger } from '../../../helpers/logger'
|
import { logger } from '../../../helpers/logger'
|
||||||
import { createReqFiles, getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils'
|
import { createReqFiles, getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils'
|
||||||
import {
|
import {
|
||||||
CONFIG, sequelizeTypescript, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_MIMETYPE_EXT,
|
CONFIG,
|
||||||
|
IMAGE_MIMETYPE_EXT,
|
||||||
|
PREVIEWS_SIZE,
|
||||||
|
sequelizeTypescript,
|
||||||
|
THUMBNAILS_SIZE,
|
||||||
|
VIDEO_CATEGORIES,
|
||||||
|
VIDEO_LANGUAGES,
|
||||||
|
VIDEO_LICENCES,
|
||||||
|
VIDEO_MIMETYPE_EXT,
|
||||||
VIDEO_PRIVACIES
|
VIDEO_PRIVACIES
|
||||||
} from '../../../initializers'
|
} from '../../../initializers'
|
||||||
import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServerAndChannel } from '../../../lib/activitypub'
|
import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServerAndChannel } from '../../../lib/activitypub'
|
||||||
import { sendCreateVideo, sendCreateViewToOrigin, sendCreateViewToVideoFollowers, sendUpdateVideo } from '../../../lib/activitypub/send'
|
import { sendCreateVideo, sendCreateViewToOrigin, sendCreateViewToVideoFollowers, sendUpdateVideo } from '../../../lib/activitypub/send'
|
||||||
import { JobQueue } from '../../../lib/job-queue'
|
import { JobQueue } from '../../../lib/job-queue'
|
||||||
import {
|
import {
|
||||||
asyncMiddleware, authenticate, paginationValidator, setDefaultSort, setDefaultPagination, videosAddValidator, videosGetValidator,
|
asyncMiddleware,
|
||||||
videosRemoveValidator, videosSearchValidator, videosSortValidator, videosUpdateValidator
|
authenticate,
|
||||||
|
paginationValidator,
|
||||||
|
setDefaultPagination,
|
||||||
|
setDefaultSort,
|
||||||
|
videosAddValidator,
|
||||||
|
videosGetValidator,
|
||||||
|
videosRemoveValidator,
|
||||||
|
videosSearchValidator,
|
||||||
|
videosSortValidator,
|
||||||
|
videosUpdateValidator
|
||||||
} from '../../../middlewares'
|
} from '../../../middlewares'
|
||||||
import { TagModel } from '../../../models/video/tag'
|
import { TagModel } from '../../../models/video/tag'
|
||||||
import { VideoModel } from '../../../models/video/video'
|
import { VideoModel } from '../../../models/video/video'
|
||||||
|
@ -28,7 +46,23 @@ import { rateVideoRouter } from './rate'
|
||||||
|
|
||||||
const videosRouter = express.Router()
|
const videosRouter = express.Router()
|
||||||
|
|
||||||
const reqVideoFile = createReqFiles('videofile', CONFIG.STORAGE.VIDEOS_DIR, VIDEO_MIMETYPE_EXT)
|
const reqVideoFileAdd = createReqFiles(
|
||||||
|
[ 'videofile', 'thumbnailfile', 'previewfile' ],
|
||||||
|
Object.assign({}, VIDEO_MIMETYPE_EXT, IMAGE_MIMETYPE_EXT),
|
||||||
|
{
|
||||||
|
videofile: CONFIG.STORAGE.VIDEOS_DIR,
|
||||||
|
thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR,
|
||||||
|
previewfile: CONFIG.STORAGE.PREVIEWS_DIR
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const reqVideoFileUpdate = createReqFiles(
|
||||||
|
[ 'thumbnailfile', 'previewfile' ],
|
||||||
|
IMAGE_MIMETYPE_EXT,
|
||||||
|
{
|
||||||
|
thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR,
|
||||||
|
previewfile: CONFIG.STORAGE.PREVIEWS_DIR
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
videosRouter.use('/', abuseVideoRouter)
|
videosRouter.use('/', abuseVideoRouter)
|
||||||
videosRouter.use('/', blacklistRouter)
|
videosRouter.use('/', blacklistRouter)
|
||||||
|
@ -58,12 +92,13 @@ videosRouter.get('/search',
|
||||||
)
|
)
|
||||||
videosRouter.put('/:id',
|
videosRouter.put('/:id',
|
||||||
authenticate,
|
authenticate,
|
||||||
|
reqVideoFileUpdate,
|
||||||
asyncMiddleware(videosUpdateValidator),
|
asyncMiddleware(videosUpdateValidator),
|
||||||
asyncMiddleware(updateVideoRetryWrapper)
|
asyncMiddleware(updateVideoRetryWrapper)
|
||||||
)
|
)
|
||||||
videosRouter.post('/upload',
|
videosRouter.post('/upload',
|
||||||
authenticate,
|
authenticate,
|
||||||
reqVideoFile,
|
reqVideoFileAdd,
|
||||||
asyncMiddleware(videosAddValidator),
|
asyncMiddleware(videosAddValidator),
|
||||||
asyncMiddleware(addVideoRetryWrapper)
|
asyncMiddleware(addVideoRetryWrapper)
|
||||||
)
|
)
|
||||||
|
@ -150,8 +185,7 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
|
||||||
const video = new VideoModel(videoData)
|
const video = new VideoModel(videoData)
|
||||||
video.url = getVideoActivityPubUrl(video)
|
video.url = getVideoActivityPubUrl(video)
|
||||||
|
|
||||||
const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename)
|
const videoFileHeight = await getVideoFileHeight(videoPhysicalFile.path)
|
||||||
const videoFileHeight = await getVideoFileHeight(videoFilePath)
|
|
||||||
|
|
||||||
const videoFileData = {
|
const videoFileData = {
|
||||||
extname: extname(videoPhysicalFile.filename),
|
extname: extname(videoPhysicalFile.filename),
|
||||||
|
@ -160,21 +194,28 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
|
||||||
}
|
}
|
||||||
const videoFile = new VideoFileModel(videoFileData)
|
const videoFile = new VideoFileModel(videoFileData)
|
||||||
const videoDir = CONFIG.STORAGE.VIDEOS_DIR
|
const videoDir = CONFIG.STORAGE.VIDEOS_DIR
|
||||||
const source = join(videoDir, videoPhysicalFile.filename)
|
|
||||||
const destination = join(videoDir, video.getVideoFilename(videoFile))
|
const destination = join(videoDir, video.getVideoFilename(videoFile))
|
||||||
|
await renamePromise(videoPhysicalFile.path, destination)
|
||||||
|
|
||||||
await renamePromise(source, destination)
|
// Process thumbnail or create it from the video
|
||||||
// This is important in case if there is another attempt in the retry process
|
const thumbnailField = req.files['thumbnailfile']
|
||||||
videoPhysicalFile.filename = video.getVideoFilename(videoFile)
|
if (thumbnailField) {
|
||||||
|
const thumbnailPhysicalFile = thumbnailField[0]
|
||||||
|
await processImage(thumbnailPhysicalFile, join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName()), THUMBNAILS_SIZE)
|
||||||
|
} else {
|
||||||
|
await video.createThumbnail(videoFile)
|
||||||
|
}
|
||||||
|
|
||||||
const tasks = []
|
// Process preview or create it from the video
|
||||||
|
const previewField = req.files['previewfile']
|
||||||
|
if (previewField) {
|
||||||
|
const previewPhysicalFile = previewField[0]
|
||||||
|
await processImage(previewPhysicalFile, join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName()), PREVIEWS_SIZE)
|
||||||
|
} else {
|
||||||
|
await video.createPreview(videoFile)
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(
|
await video.createTorrentAndSetInfoHash(videoFile)
|
||||||
video.createTorrentAndSetInfoHash(videoFile),
|
|
||||||
video.createThumbnail(videoFile),
|
|
||||||
video.createPreview(videoFile)
|
|
||||||
)
|
|
||||||
await Promise.all(tasks)
|
|
||||||
|
|
||||||
const videoCreated = await sequelizeTypescript.transaction(async t => {
|
const videoCreated = await sequelizeTypescript.transaction(async t => {
|
||||||
const sequelizeOptions = { transaction: t }
|
const sequelizeOptions = { transaction: t }
|
||||||
|
@ -237,6 +278,18 @@ async function updateVideo (req: express.Request, res: express.Response) {
|
||||||
const videoInfoToUpdate: VideoUpdate = req.body
|
const videoInfoToUpdate: VideoUpdate = req.body
|
||||||
const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE
|
const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE
|
||||||
|
|
||||||
|
// Process thumbnail or create it from the video
|
||||||
|
if (req.files && req.files['thumbnailfile']) {
|
||||||
|
const thumbnailPhysicalFile = req.files['thumbnailfile'][0]
|
||||||
|
await processImage(thumbnailPhysicalFile, join(CONFIG.STORAGE.THUMBNAILS_DIR, videoInstance.getThumbnailName()), THUMBNAILS_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process preview or create it from the video
|
||||||
|
if (req.files && req.files['previewfile']) {
|
||||||
|
const previewPhysicalFile = req.files['previewfile'][0]
|
||||||
|
await processImage(previewPhysicalFile, join(CONFIG.STORAGE.PREVIEWS_DIR, videoInstance.getPreviewName()), PREVIEWS_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await sequelizeTypescript.transaction(async t => {
|
await sequelizeTypescript.transaction(async t => {
|
||||||
const sequelizeOptions = {
|
const sequelizeOptions = {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'multer'
|
||||||
import * as validator from 'validator'
|
import * as validator from 'validator'
|
||||||
|
|
||||||
function exists (value: any) {
|
function exists (value: any) {
|
||||||
|
@ -28,6 +29,29 @@ function isBooleanValid (value: string) {
|
||||||
return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
|
return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isFileValid (
|
||||||
|
files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[],
|
||||||
|
mimeTypeRegex: string,
|
||||||
|
field: string,
|
||||||
|
optional = false
|
||||||
|
) {
|
||||||
|
// Should have files
|
||||||
|
if (!files) return optional
|
||||||
|
if (isArray(files)) return optional
|
||||||
|
|
||||||
|
// Should have a file
|
||||||
|
const fileArray = files[ field ]
|
||||||
|
if (!fileArray || fileArray.length === 0) {
|
||||||
|
return optional
|
||||||
|
}
|
||||||
|
|
||||||
|
// The file should exist
|
||||||
|
const file = fileArray[ 0 ]
|
||||||
|
if (!file || !file.originalname) return false
|
||||||
|
|
||||||
|
return new RegExp(`^${mimeTypeRegex}$`, 'i').test(file.mimetype)
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -37,5 +61,6 @@ export {
|
||||||
isUUIDValid,
|
isUUIDValid,
|
||||||
isIdOrUUIDValid,
|
isIdOrUUIDValid,
|
||||||
isDateValid,
|
isDateValid,
|
||||||
isBooleanValid
|
isBooleanValid,
|
||||||
|
isFileValid
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import * as validator from 'validator'
|
|
||||||
import 'express-validator'
|
import 'express-validator'
|
||||||
|
import * as validator from 'validator'
|
||||||
import { exists, isArray } from './misc'
|
|
||||||
import { CONSTRAINTS_FIELDS } from '../../initializers'
|
|
||||||
import { UserRole } from '../../../shared'
|
import { UserRole } from '../../../shared'
|
||||||
|
import { CONSTRAINTS_FIELDS } from '../../initializers'
|
||||||
|
|
||||||
|
import { exists, isFileValid } from './misc'
|
||||||
|
|
||||||
const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS
|
const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS
|
||||||
|
|
||||||
|
@ -37,20 +37,12 @@ function isUserRoleValid (value: any) {
|
||||||
return exists(value) && validator.isInt('' + value) && UserRole[value] !== undefined
|
return exists(value) && validator.isInt('' + value) && UserRole[value] !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const avatarMimeTypes = CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME
|
||||||
|
.map(v => v.replace('.', ''))
|
||||||
|
.join('|')
|
||||||
|
const avatarMimeTypesRegex = `image/(${avatarMimeTypes})`
|
||||||
function isAvatarFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
|
function isAvatarFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
|
||||||
// Should have files
|
return isFileValid(files, avatarMimeTypesRegex, 'avatarfile')
|
||||||
if (!files) return false
|
|
||||||
if (isArray(files)) return false
|
|
||||||
|
|
||||||
// Should have videofile file
|
|
||||||
const avatarfile = files['avatarfile']
|
|
||||||
if (!avatarfile || avatarfile.length === 0) return false
|
|
||||||
|
|
||||||
// The file should exist
|
|
||||||
const file = avatarfile[0]
|
|
||||||
if (!file || !file.originalname) return false
|
|
||||||
|
|
||||||
return new RegExp('^image/(png|jpeg)$', 'i').test(file.mimetype)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -8,12 +8,12 @@ import {
|
||||||
CONSTRAINTS_FIELDS,
|
CONSTRAINTS_FIELDS,
|
||||||
VIDEO_CATEGORIES,
|
VIDEO_CATEGORIES,
|
||||||
VIDEO_LANGUAGES,
|
VIDEO_LANGUAGES,
|
||||||
VIDEO_LICENCES,
|
VIDEO_LICENCES, VIDEO_MIMETYPE_EXT,
|
||||||
VIDEO_PRIVACIES,
|
VIDEO_PRIVACIES,
|
||||||
VIDEO_RATE_TYPES
|
VIDEO_RATE_TYPES
|
||||||
} from '../../initializers'
|
} from '../../initializers'
|
||||||
import { VideoModel } from '../../models/video/video'
|
import { VideoModel } from '../../models/video/video'
|
||||||
import { exists, isArray } from './misc'
|
import { exists, isArray, isFileValid } from './misc'
|
||||||
|
|
||||||
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
|
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
|
||||||
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
|
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
|
||||||
|
@ -68,20 +68,18 @@ function isVideoRatingTypeValid (value: string) {
|
||||||
return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
|
return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const videoFileTypes = Object.keys(VIDEO_MIMETYPE_EXT).map(m => `(${m})`)
|
||||||
|
const videoFileTypesRegex = videoFileTypes.join('|')
|
||||||
function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
|
function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
|
||||||
// Should have files
|
return isFileValid(files, videoFileTypesRegex, 'videofile')
|
||||||
if (!files) return false
|
}
|
||||||
if (isArray(files)) return false
|
|
||||||
|
|
||||||
// Should have videofile file
|
const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
|
||||||
const videofile = files['videofile']
|
.map(v => v.replace('.', ''))
|
||||||
if (!videofile || videofile.length === 0) return false
|
.join('|')
|
||||||
|
const videoImageTypesRegex = `image/(${videoImageTypes})`
|
||||||
// The file should exist
|
function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) {
|
||||||
const file = videofile[0]
|
return isFileValid(files, videoImageTypesRegex, field, true)
|
||||||
if (!file || !file.originalname) return false
|
|
||||||
|
|
||||||
return new RegExp('^video/(webm|mp4|ogg)$', 'i').test(file.mimetype)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoPrivacyValid (value: string) {
|
function isVideoPrivacyValid (value: string) {
|
||||||
|
@ -141,5 +139,6 @@ export {
|
||||||
isVideoPrivacyValid,
|
isVideoPrivacyValid,
|
||||||
isVideoFileResolutionValid,
|
isVideoFileResolutionValid,
|
||||||
isVideoFileSizeValid,
|
isVideoFileSizeValid,
|
||||||
isVideoExist
|
isVideoExist,
|
||||||
|
isVideoImage
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import 'multer'
|
||||||
|
import * as sharp from 'sharp'
|
||||||
|
import { unlinkPromise } from './core-utils'
|
||||||
|
|
||||||
|
async function processImage (
|
||||||
|
physicalFile: Express.Multer.File,
|
||||||
|
destination: string,
|
||||||
|
newSize: { width: number, height: number }
|
||||||
|
) {
|
||||||
|
await sharp(physicalFile.path)
|
||||||
|
.resize(newSize.width, newSize.height)
|
||||||
|
.toFile(destination)
|
||||||
|
|
||||||
|
await unlinkPromise(physicalFile.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
processImage
|
||||||
|
}
|
|
@ -27,10 +27,14 @@ function badRequest (req: express.Request, res: express.Response, next: express.
|
||||||
return res.type('json').status(400).end()
|
return res.type('json').status(400).end()
|
||||||
}
|
}
|
||||||
|
|
||||||
function createReqFiles (fieldName: string, storageDir: string, mimeTypes: { [ id: string ]: string }) {
|
function createReqFiles (
|
||||||
|
fieldNames: string[],
|
||||||
|
mimeTypes: { [ id: string ]: string },
|
||||||
|
destinations: { [ fieldName: string ]: string }
|
||||||
|
) {
|
||||||
const storage = multer.diskStorage({
|
const storage = multer.diskStorage({
|
||||||
destination: (req, file, cb) => {
|
destination: (req, file, cb) => {
|
||||||
cb(null, storageDir)
|
cb(null, destinations[file.fieldname])
|
||||||
},
|
},
|
||||||
|
|
||||||
filename: async (req, file, cb) => {
|
filename: async (req, file, cb) => {
|
||||||
|
@ -48,7 +52,15 @@ function createReqFiles (fieldName: string, storageDir: string, mimeTypes: { [ i
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return multer({ storage }).fields([{ name: fieldName, maxCount: 1 }])
|
const fields = []
|
||||||
|
for (const fieldName of fieldNames) {
|
||||||
|
fields.push({
|
||||||
|
name: fieldName,
|
||||||
|
maxCount: 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return multer({ storage }).fields(fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateRandomString (size: number) {
|
async function generateRandomString (size: number) {
|
||||||
|
|
|
@ -182,6 +182,12 @@ const CONSTRAINTS_FIELDS = {
|
||||||
NAME: { min: 3, max: 120 }, // Length
|
NAME: { min: 3, max: 120 }, // Length
|
||||||
TRUNCATED_DESCRIPTION: { min: 3, max: 250 }, // Length
|
TRUNCATED_DESCRIPTION: { min: 3, max: 250 }, // Length
|
||||||
DESCRIPTION: { min: 3, max: 3000 }, // Length
|
DESCRIPTION: { min: 3, max: 3000 }, // Length
|
||||||
|
IMAGE: {
|
||||||
|
EXTNAME: [ '.jpg', '.jpeg' ],
|
||||||
|
FILE_SIZE: {
|
||||||
|
max: 2 * 1024 * 1024 // 2MB
|
||||||
|
}
|
||||||
|
},
|
||||||
EXTNAME: [ '.mp4', '.ogv', '.webm' ],
|
EXTNAME: [ '.mp4', '.ogv', '.webm' ],
|
||||||
INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2
|
INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2
|
||||||
DURATION: { min: 1 }, // Number
|
DURATION: { min: 1 }, // Number
|
||||||
|
@ -285,7 +291,7 @@ const VIDEO_MIMETYPE_EXT = {
|
||||||
'video/mp4': '.mp4'
|
'video/mp4': '.mp4'
|
||||||
}
|
}
|
||||||
|
|
||||||
const AVATAR_MIMETYPE_EXT = {
|
const IMAGE_MIMETYPE_EXT = {
|
||||||
'image/png': '.png',
|
'image/png': '.png',
|
||||||
'image/jpg': '.jpg',
|
'image/jpg': '.jpg',
|
||||||
'image/jpeg': '.jpg'
|
'image/jpeg': '.jpg'
|
||||||
|
@ -427,7 +433,7 @@ export {
|
||||||
VIDEO_RATE_TYPES,
|
VIDEO_RATE_TYPES,
|
||||||
VIDEO_MIMETYPE_EXT,
|
VIDEO_MIMETYPE_EXT,
|
||||||
USER_PASSWORD_RESET_LIFETIME,
|
USER_PASSWORD_RESET_LIFETIME,
|
||||||
AVATAR_MIMETYPE_EXT,
|
IMAGE_MIMETYPE_EXT,
|
||||||
SCHEDULER_INTERVAL,
|
SCHEDULER_INTERVAL,
|
||||||
JOB_COMPLETED_LIFETIME
|
JOB_COMPLETED_LIFETIME
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { logger } from '../../helpers/logger'
|
||||||
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
|
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
|
||||||
import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
|
import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
|
||||||
import { getUrlFromWebfinger } from '../../helpers/webfinger'
|
import { getUrlFromWebfinger } from '../../helpers/webfinger'
|
||||||
import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers'
|
import { IMAGE_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers'
|
||||||
import { AccountModel } from '../../models/account/account'
|
import { AccountModel } from '../../models/account/account'
|
||||||
import { ActorModel } from '../../models/activitypub/actor'
|
import { ActorModel } from '../../models/activitypub/actor'
|
||||||
import { AvatarModel } from '../../models/avatar/avatar'
|
import { AvatarModel } from '../../models/avatar/avatar'
|
||||||
|
@ -147,10 +147,10 @@ async function fetchActorTotalItems (url: string) {
|
||||||
|
|
||||||
async function fetchAvatarIfExists (actorJSON: ActivityPubActor) {
|
async function fetchAvatarIfExists (actorJSON: ActivityPubActor) {
|
||||||
if (
|
if (
|
||||||
actorJSON.icon && actorJSON.icon.type === 'Image' && AVATAR_MIMETYPE_EXT[actorJSON.icon.mediaType] !== undefined &&
|
actorJSON.icon && actorJSON.icon.type === 'Image' && IMAGE_MIMETYPE_EXT[actorJSON.icon.mediaType] !== undefined &&
|
||||||
isActivityPubUrlValid(actorJSON.icon.url)
|
isActivityPubUrlValid(actorJSON.icon.url)
|
||||||
) {
|
) {
|
||||||
const extension = AVATAR_MIMETYPE_EXT[actorJSON.icon.mediaType]
|
const extension = IMAGE_MIMETYPE_EXT[actorJSON.icon.mediaType]
|
||||||
|
|
||||||
const avatarName = uuidv4() + extension
|
const avatarName = uuidv4() + extension
|
||||||
const destPath = join(CONFIG.STORAGE.AVATARS_DIR, avatarName)
|
const destPath = join(CONFIG.STORAGE.AVATARS_DIR, avatarName)
|
||||||
|
|
|
@ -4,8 +4,18 @@ import { body, param, query } from 'express-validator/check'
|
||||||
import { UserRight, VideoPrivacy } from '../../../shared'
|
import { UserRight, VideoPrivacy } from '../../../shared'
|
||||||
import { isBooleanValid, isIdOrUUIDValid, isIdValid, isUUIDValid } from '../../helpers/custom-validators/misc'
|
import { isBooleanValid, isIdOrUUIDValid, isIdValid, isUUIDValid } from '../../helpers/custom-validators/misc'
|
||||||
import {
|
import {
|
||||||
isVideoAbuseReasonValid, isVideoCategoryValid, isVideoDescriptionValid, isVideoExist, isVideoFile, isVideoLanguageValid,
|
isVideoAbuseReasonValid,
|
||||||
isVideoLicenceValid, isVideoNameValid, isVideoPrivacyValid, isVideoRatingTypeValid, isVideoTagsValid
|
isVideoCategoryValid,
|
||||||
|
isVideoDescriptionValid,
|
||||||
|
isVideoExist,
|
||||||
|
isVideoFile,
|
||||||
|
isVideoImage,
|
||||||
|
isVideoLanguageValid,
|
||||||
|
isVideoLicenceValid,
|
||||||
|
isVideoNameValid,
|
||||||
|
isVideoPrivacyValid,
|
||||||
|
isVideoRatingTypeValid,
|
||||||
|
isVideoTagsValid
|
||||||
} from '../../helpers/custom-validators/videos'
|
} from '../../helpers/custom-validators/videos'
|
||||||
import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
|
import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
|
@ -22,6 +32,14 @@ const videosAddValidator = [
|
||||||
'This file is not supported. Please, make sure it is of the following type : '
|
'This file is not supported. Please, make sure it is of the following type : '
|
||||||
+ CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ')
|
+ CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ')
|
||||||
),
|
),
|
||||||
|
body('thumbnailfile').custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage(
|
||||||
|
'This thumbnail file is not supported. Please, make sure it is of the following type : '
|
||||||
|
+ CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
|
||||||
|
),
|
||||||
|
body('previewfile').custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage(
|
||||||
|
'This preview file is not supported. Please, make sure it is of the following type : '
|
||||||
|
+ CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
|
||||||
|
),
|
||||||
body('name').custom(isVideoNameValid).withMessage('Should have a valid name'),
|
body('name').custom(isVideoNameValid).withMessage('Should have a valid name'),
|
||||||
body('category').optional().custom(isVideoCategoryValid).withMessage('Should have a valid category'),
|
body('category').optional().custom(isVideoCategoryValid).withMessage('Should have a valid category'),
|
||||||
body('licence').optional().custom(isVideoLicenceValid).withMessage('Should have a valid licence'),
|
body('licence').optional().custom(isVideoLicenceValid).withMessage('Should have a valid licence'),
|
||||||
|
@ -37,6 +55,7 @@ const videosAddValidator = [
|
||||||
logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files })
|
logger.debug('Checking videosAdd parameters', { parameters: req.body, files: req.files })
|
||||||
|
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
if (areErrorsInVideoImageFiles(req, res)) return
|
||||||
|
|
||||||
const videoFile: Express.Multer.File = req.files['videofile'][0]
|
const videoFile: Express.Multer.File = req.files['videofile'][0]
|
||||||
const user = res.locals.oauth.token.User
|
const user = res.locals.oauth.token.User
|
||||||
|
@ -82,6 +101,14 @@ const videosAddValidator = [
|
||||||
|
|
||||||
const videosUpdateValidator = [
|
const videosUpdateValidator = [
|
||||||
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
|
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
|
||||||
|
body('thumbnailfile').custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage(
|
||||||
|
'This thumbnail file is not supported. Please, make sure it is of the following type : '
|
||||||
|
+ CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
|
||||||
|
),
|
||||||
|
body('previewfile').custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage(
|
||||||
|
'This preview file is not supported. Please, make sure it is of the following type : '
|
||||||
|
+ CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
|
||||||
|
),
|
||||||
body('name').optional().custom(isVideoNameValid).withMessage('Should have a valid name'),
|
body('name').optional().custom(isVideoNameValid).withMessage('Should have a valid name'),
|
||||||
body('category').optional().custom(isVideoCategoryValid).withMessage('Should have a valid category'),
|
body('category').optional().custom(isVideoCategoryValid).withMessage('Should have a valid category'),
|
||||||
body('licence').optional().custom(isVideoLicenceValid).withMessage('Should have a valid licence'),
|
body('licence').optional().custom(isVideoLicenceValid).withMessage('Should have a valid licence'),
|
||||||
|
@ -96,6 +123,7 @@ const videosUpdateValidator = [
|
||||||
logger.debug('Checking videosUpdate parameters', { parameters: req.body })
|
logger.debug('Checking videosUpdate parameters', { parameters: req.body })
|
||||||
|
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
if (areErrorsInVideoImageFiles(req, res)) return
|
||||||
if (!await isVideoExist(req.params.id, res)) return
|
if (!await isVideoExist(req.params.id, res)) return
|
||||||
|
|
||||||
const video = res.locals.video
|
const video = res.locals.video
|
||||||
|
@ -274,3 +302,22 @@ function checkUserCanDeleteVideo (user: UserModel, video: VideoModel, res: expre
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function areErrorsInVideoImageFiles (req: express.Request, res: express.Response) {
|
||||||
|
// Files are optional
|
||||||
|
if (!req.files) return false
|
||||||
|
|
||||||
|
for (const imageField of [ 'thumbnail', 'preview' ]) {
|
||||||
|
if (!req.files[ imageField ]) continue
|
||||||
|
|
||||||
|
const imageFile = req.files[ imageField ][ 0 ] as Express.Multer.File
|
||||||
|
if (imageFile.size > CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max) {
|
||||||
|
res.status(400)
|
||||||
|
.send({ error: `The size of the ${imageField} is too big (>${CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max}).` })
|
||||||
|
.end()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { UserRole } from '../../../../shared'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createUser, flushTests, getMyUserInformation, getMyUserVideoRating, getUsersList, immutableAssign, killallServers, makeGetRequest,
|
createUser, flushTests, getMyUserInformation, getMyUserVideoRating, getUsersList, immutableAssign, killallServers, makeGetRequest,
|
||||||
makePostBodyRequest, makePostUploadRequest, makePutBodyRequest, registerUser, removeUser, runServer, ServerInfo, setAccessTokensToServers,
|
makePostBodyRequest, makeUploadRequest, makePutBodyRequest, registerUser, removeUser, runServer, ServerInfo, setAccessTokensToServers,
|
||||||
updateUser, uploadVideo, userLogin
|
updateUser, uploadVideo, userLogin
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
|
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
|
||||||
|
@ -273,7 +273,7 @@ describe('Test users API validators', function () {
|
||||||
const attaches = {
|
const attaches = {
|
||||||
'avatarfile': join(__dirname, '..', 'fixtures', 'video_short.mp4')
|
'avatarfile': join(__dirname, '..', 'fixtures', 'video_short.mp4')
|
||||||
}
|
}
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a big file', async function () {
|
it('Should fail with a big file', async function () {
|
||||||
|
@ -281,7 +281,7 @@ describe('Test users API validators', function () {
|
||||||
const attaches = {
|
const attaches = {
|
||||||
'avatarfile': join(__dirname, '..', 'fixtures', 'avatar-big.png')
|
'avatarfile': join(__dirname, '..', 'fixtures', 'avatar-big.png')
|
||||||
}
|
}
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should succeed with the correct params', async function () {
|
it('Should succeed with the correct params', async function () {
|
||||||
|
@ -289,7 +289,7 @@ describe('Test users API validators', function () {
|
||||||
const attaches = {
|
const attaches = {
|
||||||
'avatarfile': join(__dirname, '..', 'fixtures', 'avatar.png')
|
'avatarfile': join(__dirname, '..', 'fixtures', 'avatar.png')
|
||||||
}
|
}
|
||||||
await makePostUploadRequest({
|
await makeUploadRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
path: path + '/me/avatar/pick',
|
path: path + '/me/avatar/pick',
|
||||||
token: server.accessToken,
|
token: server.accessToken,
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { join } from 'path'
|
||||||
import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
|
import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
|
||||||
import {
|
import {
|
||||||
createUser, flushTests, getMyUserInformation, getVideo, getVideosList, immutableAssign, killallServers, makeDeleteRequest,
|
createUser, flushTests, getMyUserInformation, getVideo, getVideosList, immutableAssign, killallServers, makeDeleteRequest,
|
||||||
makeGetRequest, makePostUploadRequest, makePutBodyRequest, removeVideo, runServer, ServerInfo, setAccessTokensToServers, userLogin
|
makeGetRequest, makeUploadRequest, makePutBodyRequest, removeVideo, runServer, ServerInfo, setAccessTokensToServers, userLogin
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
|
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
|
||||||
|
|
||||||
|
@ -111,91 +111,91 @@ describe('Test videos API validator', function () {
|
||||||
it('Should fail with nothing', async function () {
|
it('Should fail with nothing', async function () {
|
||||||
const fields = {}
|
const fields = {}
|
||||||
const attaches = {}
|
const attaches = {}
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail without name', async function () {
|
it('Should fail without name', async function () {
|
||||||
const fields = omit(baseCorrectParams, 'name')
|
const fields = omit(baseCorrectParams, 'name')
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a long name', async function () {
|
it('Should fail with a long name', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
|
const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a bad category', async function () {
|
it('Should fail with a bad category', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { category: 125 })
|
const fields = immutableAssign(baseCorrectParams, { category: 125 })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a bad licence', async function () {
|
it('Should fail with a bad licence', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { licence: 125 })
|
const fields = immutableAssign(baseCorrectParams, { licence: 125 })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a bad language', async function () {
|
it('Should fail with a bad language', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { language: 125 })
|
const fields = immutableAssign(baseCorrectParams, { language: 125 })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail without nsfw attribute', async function () {
|
it('Should fail without nsfw attribute', async function () {
|
||||||
const fields = omit(baseCorrectParams, 'nsfw')
|
const fields = omit(baseCorrectParams, 'nsfw')
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a bad nsfw attribute', async function () {
|
it('Should fail with a bad nsfw attribute', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { nsfw: 2 })
|
const fields = immutableAssign(baseCorrectParams, { nsfw: 2 })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail without commentsEnabled attribute', async function () {
|
it('Should fail without commentsEnabled attribute', async function () {
|
||||||
const fields = omit(baseCorrectParams, 'commentsEnabled')
|
const fields = omit(baseCorrectParams, 'commentsEnabled')
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a bad commentsEnabled attribute', async function () {
|
it('Should fail with a bad commentsEnabled attribute', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { commentsEnabled: 2 })
|
const fields = immutableAssign(baseCorrectParams, { commentsEnabled: 2 })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a long description', async function () {
|
it('Should fail with a long description', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(1500) })
|
const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(1500) })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail without a channel', async function () {
|
it('Should fail without a channel', async function () {
|
||||||
const fields = omit(baseCorrectParams, 'channelId')
|
const fields = omit(baseCorrectParams, 'channelId')
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a bad channel', async function () {
|
it('Should fail with a bad channel', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { channelId: 545454 })
|
const fields = immutableAssign(baseCorrectParams, { channelId: 545454 })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with another user channel', async function () {
|
it('Should fail with another user channel', async function () {
|
||||||
|
@ -212,34 +212,34 @@ describe('Test videos API validator', function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { channelId: customChannelId })
|
const fields = immutableAssign(baseCorrectParams, { channelId: customChannelId })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with too many tags', async function () {
|
it('Should fail with too many tags', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] })
|
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a tag length too low', async function () {
|
it('Should fail with a tag length too low', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] })
|
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a tag length too big', async function () {
|
it('Should fail with a tag length too big', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] })
|
const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail without an input file', async function () {
|
it('Should fail without an input file', async function () {
|
||||||
const fields = baseCorrectParams
|
const fields = baseCorrectParams
|
||||||
const attaches = {}
|
const attaches = {}
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail without an incorrect input file', async function () {
|
it('Should fail without an incorrect input file', async function () {
|
||||||
|
@ -247,7 +247,47 @@ describe('Test videos API validator', function () {
|
||||||
const attaches = {
|
const attaches = {
|
||||||
'videofile': join(__dirname, '..', 'fixtures', 'video_short_fake.webm')
|
'videofile': join(__dirname, '..', 'fixtures', 'video_short_fake.webm')
|
||||||
}
|
}
|
||||||
await makePostUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with an incorrect thumbnail file', async function () {
|
||||||
|
const fields = baseCorrectParams
|
||||||
|
const attaches = {
|
||||||
|
'thumbnailfile': join(__dirname, '..', 'fixtures', 'avatar.png'),
|
||||||
|
'videofile': join(__dirname, '..', 'fixtures', 'video_short_fake.webm')
|
||||||
|
}
|
||||||
|
|
||||||
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with a big thumbnail file', async function () {
|
||||||
|
const fields = baseCorrectParams
|
||||||
|
const attaches = {
|
||||||
|
'thumbnailfile': join(__dirname, '..', 'fixtures', 'avatar-big.png'),
|
||||||
|
'videofile': join(__dirname, '..', 'fixtures', 'video_short_fake.webm')
|
||||||
|
}
|
||||||
|
|
||||||
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with an incorrect preview file', async function () {
|
||||||
|
const fields = baseCorrectParams
|
||||||
|
const attaches = {
|
||||||
|
'previewfile': join(__dirname, '..', 'fixtures', 'avatar.png'),
|
||||||
|
'videofile': join(__dirname, '..', 'fixtures', 'video_short_fake.webm')
|
||||||
|
}
|
||||||
|
|
||||||
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with a big preview file', async function () {
|
||||||
|
const fields = baseCorrectParams
|
||||||
|
const attaches = {
|
||||||
|
'previewfile': join(__dirname, '..', 'fixtures', 'avatar-big.png'),
|
||||||
|
'videofile': join(__dirname, '..', 'fixtures', 'video_short_fake.webm')
|
||||||
|
}
|
||||||
|
|
||||||
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should succeed with the correct parameters', async function () {
|
it('Should succeed with the correct parameters', async function () {
|
||||||
|
@ -257,7 +297,7 @@ describe('Test videos API validator', function () {
|
||||||
|
|
||||||
{
|
{
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
await makePostUploadRequest({
|
await makeUploadRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
path: path + '/upload',
|
path: path + '/upload',
|
||||||
token: server.accessToken,
|
token: server.accessToken,
|
||||||
|
@ -272,7 +312,7 @@ describe('Test videos API validator', function () {
|
||||||
videofile: join(__dirname, '..', 'fixtures', 'video_short.mp4')
|
videofile: join(__dirname, '..', 'fixtures', 'video_short.mp4')
|
||||||
})
|
})
|
||||||
|
|
||||||
await makePostUploadRequest({
|
await makeUploadRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
path: path + '/upload',
|
path: path + '/upload',
|
||||||
token: server.accessToken,
|
token: server.accessToken,
|
||||||
|
@ -287,7 +327,7 @@ describe('Test videos API validator', function () {
|
||||||
videofile: join(__dirname, '..', 'fixtures', 'video_short.ogv')
|
videofile: join(__dirname, '..', 'fixtures', 'video_short.ogv')
|
||||||
})
|
})
|
||||||
|
|
||||||
await makePostUploadRequest({
|
await makeUploadRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
path: path + '/upload',
|
path: path + '/upload',
|
||||||
token: server.accessToken,
|
token: server.accessToken,
|
||||||
|
@ -400,6 +440,70 @@ describe('Test videos API validator', function () {
|
||||||
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
|
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should fail with an incorrect thumbnail file', async function () {
|
||||||
|
const fields = baseCorrectParams
|
||||||
|
const attaches = {
|
||||||
|
'thumbnailfile': join(__dirname, '..', 'fixtures', 'avatar.png')
|
||||||
|
}
|
||||||
|
|
||||||
|
await makeUploadRequest({
|
||||||
|
url: server.url,
|
||||||
|
method: 'PUT',
|
||||||
|
path: path + videoId,
|
||||||
|
token: server.accessToken,
|
||||||
|
fields,
|
||||||
|
attaches
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with a big thumbnail file', async function () {
|
||||||
|
const fields = baseCorrectParams
|
||||||
|
const attaches = {
|
||||||
|
'thumbnailfile': join(__dirname, '..', 'fixtures', 'avatar-big.png')
|
||||||
|
}
|
||||||
|
|
||||||
|
await makeUploadRequest({
|
||||||
|
url: server.url,
|
||||||
|
method: 'PUT',
|
||||||
|
path: path + videoId,
|
||||||
|
token: server.accessToken,
|
||||||
|
fields,
|
||||||
|
attaches
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with an incorrect preview file', async function () {
|
||||||
|
const fields = baseCorrectParams
|
||||||
|
const attaches = {
|
||||||
|
'previewfile': join(__dirname, '..', 'fixtures', 'avatar.png')
|
||||||
|
}
|
||||||
|
|
||||||
|
await makeUploadRequest({
|
||||||
|
url: server.url,
|
||||||
|
method: 'PUT',
|
||||||
|
path: path + videoId,
|
||||||
|
token: server.accessToken,
|
||||||
|
fields,
|
||||||
|
attaches
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with a big preview file', async function () {
|
||||||
|
const fields = baseCorrectParams
|
||||||
|
const attaches = {
|
||||||
|
'previewfile': join(__dirname, '..', 'fixtures', 'avatar-big.png')
|
||||||
|
}
|
||||||
|
|
||||||
|
await makeUploadRequest({
|
||||||
|
url: server.url,
|
||||||
|
method: 'PUT',
|
||||||
|
path: path + videoId,
|
||||||
|
token: server.accessToken,
|
||||||
|
fields,
|
||||||
|
attaches
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('Should fail with a video of another user')
|
it('Should fail with a video of another user')
|
||||||
|
|
||||||
it('Should fail with a video of another server')
|
it('Should fail with a video of another server')
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -137,7 +137,9 @@ describe('Test multiple servers', function () {
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description for server 2',
|
description: 'my super description for server 2',
|
||||||
tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
|
tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
|
||||||
fixture: 'video_short2.webm'
|
fixture: 'video_short2.webm',
|
||||||
|
thumbnailfile: 'thumbnail.jpg',
|
||||||
|
previewfile: 'preview.jpg'
|
||||||
}
|
}
|
||||||
await uploadVideo(servers[1].url, userAccessToken, videoAttributes)
|
await uploadVideo(servers[1].url, userAccessToken, videoAttributes)
|
||||||
|
|
||||||
|
@ -184,7 +186,9 @@ describe('Test multiple servers', function () {
|
||||||
resolution: 720,
|
resolution: 720,
|
||||||
size: 710000
|
size: 710000
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
thumbnailfile: 'thumbnail',
|
||||||
|
previewfile: 'preview'
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await getVideosList(server.url)
|
const res = await getVideosList(server.url)
|
||||||
|
@ -521,7 +525,9 @@ describe('Test multiple servers', function () {
|
||||||
language: 13,
|
language: 13,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description updated',
|
description: 'my super description updated',
|
||||||
tags: [ 'tag_up_1', 'tag_up_2' ]
|
tags: [ 'tag_up_1', 'tag_up_2' ],
|
||||||
|
thumbnailfile: 'thumbnail.jpg',
|
||||||
|
previewfile: 'preview.jpg'
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, attributes)
|
await updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, attributes)
|
||||||
|
@ -565,7 +571,9 @@ describe('Test multiple servers', function () {
|
||||||
resolution: 720,
|
resolution: 720,
|
||||||
size: 292677
|
size: 292677
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
thumbnailfile: 'thumbnail',
|
||||||
|
previewfile: 'preview'
|
||||||
}
|
}
|
||||||
await completeVideoCheck(server.url, videoUpdated, checkAttributes)
|
await completeVideoCheck(server.url, videoUpdated, checkAttributes)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* tslint:disable:no-unused-expression */
|
/* tslint:disable:no-unused-expression */
|
||||||
|
|
||||||
import { join } from 'path'
|
import { isAbsolute, join } from 'path'
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
import * as WebTorrent from 'webtorrent'
|
import * as WebTorrent from 'webtorrent'
|
||||||
import { readFileBufferPromise } from '../../../helpers/core-utils'
|
import { readFileBufferPromise } from '../../../helpers/core-utils'
|
||||||
|
@ -45,8 +45,8 @@ async function testImage (url: string, imageName: string, imagePath: string, ext
|
||||||
const body = res.body
|
const body = res.body
|
||||||
|
|
||||||
const data = await readFileBufferPromise(join(__dirname, '..', '..', 'api', 'fixtures', imageName + extension))
|
const data = await readFileBufferPromise(join(__dirname, '..', '..', 'api', 'fixtures', imageName + extension))
|
||||||
const minLength = body.length - ((50 * body.length) / 100)
|
const minLength = body.length - ((20 * body.length) / 100)
|
||||||
const maxLength = body.length + ((50 * body.length) / 100)
|
const maxLength = body.length + ((20 * body.length) / 100)
|
||||||
|
|
||||||
return data.length > minLength && data.length < maxLength
|
return data.length > minLength && data.length < maxLength
|
||||||
} else {
|
} else {
|
||||||
|
@ -55,6 +55,14 @@ async function testImage (url: string, imageName: string, imagePath: string, ext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildAbsoluteFixturePath (path: string) {
|
||||||
|
if (isAbsolute(path)) {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
return join(__dirname, '..', '..', 'api', 'fixtures', path)
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -63,5 +71,6 @@ export {
|
||||||
webtorrentAdd,
|
webtorrentAdd,
|
||||||
immutableAssign,
|
immutableAssign,
|
||||||
testImage,
|
testImage,
|
||||||
|
buildAbsoluteFixturePath,
|
||||||
root
|
root
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
|
import { buildAbsoluteFixturePath } from '../'
|
||||||
|
|
||||||
function makeGetRequest (options: {
|
function makeGetRequest (options: {
|
||||||
url: string,
|
url: string,
|
||||||
|
@ -40,8 +41,9 @@ function makeDeleteRequest (options: {
|
||||||
.expect(options.statusCodeExpected)
|
.expect(options.statusCodeExpected)
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePostUploadRequest (options: {
|
function makeUploadRequest (options: {
|
||||||
url: string,
|
url: string,
|
||||||
|
method?: 'POST' | 'PUT',
|
||||||
path: string,
|
path: string,
|
||||||
token: string,
|
token: string,
|
||||||
fields: { [ fieldName: string ]: any },
|
fields: { [ fieldName: string ]: any },
|
||||||
|
@ -50,9 +52,14 @@ function makePostUploadRequest (options: {
|
||||||
}) {
|
}) {
|
||||||
if (!options.statusCodeExpected) options.statusCodeExpected = 400
|
if (!options.statusCodeExpected) options.statusCodeExpected = 400
|
||||||
|
|
||||||
const req = request(options.url)
|
let req: request.Test
|
||||||
.post(options.path)
|
if (options.method === 'PUT') {
|
||||||
.set('Accept', 'application/json')
|
req = request(options.url).put(options.path)
|
||||||
|
} else {
|
||||||
|
req = request(options.url).post(options.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.set('Accept', 'application/json')
|
||||||
|
|
||||||
if (options.token) req.set('Authorization', 'Bearer ' + options.token)
|
if (options.token) req.set('Authorization', 'Bearer ' + options.token)
|
||||||
|
|
||||||
|
@ -70,7 +77,7 @@ function makePostUploadRequest (options: {
|
||||||
|
|
||||||
Object.keys(options.attaches).forEach(attach => {
|
Object.keys(options.attaches).forEach(attach => {
|
||||||
const value = options.attaches[attach]
|
const value = options.attaches[attach]
|
||||||
req.attach(attach, value)
|
req.attach(attach, buildAbsoluteFixturePath(value))
|
||||||
})
|
})
|
||||||
|
|
||||||
return req.expect(options.statusCodeExpected)
|
return req.expect(options.statusCodeExpected)
|
||||||
|
@ -119,7 +126,7 @@ function makePutBodyRequest (options: {
|
||||||
|
|
||||||
export {
|
export {
|
||||||
makeGetRequest,
|
makeGetRequest,
|
||||||
makePostUploadRequest,
|
makeUploadRequest,
|
||||||
makePostBodyRequest,
|
makePostBodyRequest,
|
||||||
makePutBodyRequest,
|
makePutBodyRequest,
|
||||||
makeDeleteRequest
|
makeDeleteRequest
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { isAbsolute, join } from 'path'
|
import { isAbsolute, join } from 'path'
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
import { makePostBodyRequest, makePostUploadRequest, makePutBodyRequest } from '../'
|
import { makePostBodyRequest, makeUploadRequest, makePutBodyRequest } from '../'
|
||||||
|
|
||||||
import { UserRole } from '../../../../shared/index'
|
import { UserRole } from '../../../../shared/index'
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ function updateMyAvatar (options: {
|
||||||
filePath = join(__dirname, '..', '..', 'api', 'fixtures', options.fixture)
|
filePath = join(__dirname, '..', '..', 'api', 'fixtures', options.fixture)
|
||||||
}
|
}
|
||||||
|
|
||||||
return makePostUploadRequest({
|
return makeUploadRequest({
|
||||||
url: options.url,
|
url: options.url,
|
||||||
path,
|
path,
|
||||||
token: options.accessToken,
|
token: options.accessToken,
|
||||||
|
|
|
@ -5,7 +5,16 @@ import { existsSync, readFile } from 'fs'
|
||||||
import * as parseTorrent from 'parse-torrent'
|
import * as parseTorrent from 'parse-torrent'
|
||||||
import { extname, isAbsolute, join } from 'path'
|
import { extname, isAbsolute, join } from 'path'
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
import { getMyUserInformation, makeGetRequest, root, ServerInfo, testImage } from '../'
|
import {
|
||||||
|
buildAbsoluteFixturePath,
|
||||||
|
getMyUserInformation,
|
||||||
|
makeGetRequest,
|
||||||
|
makePutBodyRequest,
|
||||||
|
makeUploadRequest,
|
||||||
|
root,
|
||||||
|
ServerInfo,
|
||||||
|
testImage
|
||||||
|
} from '../'
|
||||||
import { VideoPrivacy } from '../../../../shared/models/videos'
|
import { VideoPrivacy } from '../../../../shared/models/videos'
|
||||||
import { readdirPromise } from '../../../helpers/core-utils'
|
import { readdirPromise } from '../../../helpers/core-utils'
|
||||||
import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers'
|
import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers'
|
||||||
|
@ -23,6 +32,8 @@ type VideoAttributes = {
|
||||||
channelId?: number
|
channelId?: number
|
||||||
privacy?: VideoPrivacy
|
privacy?: VideoPrivacy
|
||||||
fixture?: string
|
fixture?: string
|
||||||
|
thumbnailfile?: string
|
||||||
|
previewfile?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVideoCategories (url: string) {
|
function getVideoCategories (url: string) {
|
||||||
|
@ -228,8 +239,8 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
|
||||||
defaultChannelId = res.body.videoChannels[0].id
|
defaultChannelId = res.body.videoChannels[0].id
|
||||||
} catch (e) { /* empty */ }
|
} catch (e) { /* empty */ }
|
||||||
|
|
||||||
// Default attributes
|
// Override default attributes
|
||||||
let attributes = {
|
const attributes = Object.assign({
|
||||||
name: 'my super video',
|
name: 'my super video',
|
||||||
category: 5,
|
category: 5,
|
||||||
licence: 4,
|
licence: 4,
|
||||||
|
@ -241,8 +252,7 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
|
||||||
privacy: VideoPrivacy.PUBLIC,
|
privacy: VideoPrivacy.PUBLIC,
|
||||||
commentsEnabled: true,
|
commentsEnabled: true,
|
||||||
fixture: 'video_short.webm'
|
fixture: 'video_short.webm'
|
||||||
}
|
}, videoAttributesArg)
|
||||||
attributes = Object.assign(attributes, videoAttributesArg)
|
|
||||||
|
|
||||||
const req = request(url)
|
const req = request(url)
|
||||||
.post(path)
|
.post(path)
|
||||||
|
@ -267,22 +277,22 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
|
||||||
req.field('licence', attributes.licence.toString())
|
req.field('licence', attributes.licence.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attributes.thumbnailfile !== undefined) {
|
||||||
|
req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile))
|
||||||
|
}
|
||||||
|
if (attributes.previewfile !== undefined) {
|
||||||
|
req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < attributes.tags.length; i++) {
|
for (let i = 0; i < attributes.tags.length; i++) {
|
||||||
req.field('tags[' + i + ']', attributes.tags[i])
|
req.field('tags[' + i + ']', attributes.tags[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
let filePath = ''
|
return req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
|
||||||
if (isAbsolute(attributes.fixture)) {
|
|
||||||
filePath = attributes.fixture
|
|
||||||
} else {
|
|
||||||
filePath = join(__dirname, '..', '..', 'api', 'fixtures', attributes.fixture)
|
|
||||||
}
|
|
||||||
|
|
||||||
return req.attach('videofile', filePath)
|
|
||||||
.expect(specialStatus)
|
.expect(specialStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVideo (url: string, accessToken: string, id: number | string, attributes: VideoAttributes, specialStatus = 204) {
|
function updateVideo (url: string, accessToken: string, id: number | string, attributes: VideoAttributes, statusCodeExpected = 204) {
|
||||||
const path = '/api/v1/videos/' + id
|
const path = '/api/v1/videos/' + id
|
||||||
const body = {}
|
const body = {}
|
||||||
|
|
||||||
|
@ -296,12 +306,30 @@ function updateVideo (url: string, accessToken: string, id: number | string, att
|
||||||
if (attributes.tags) body['tags'] = attributes.tags
|
if (attributes.tags) body['tags'] = attributes.tags
|
||||||
if (attributes.privacy) body['privacy'] = attributes.privacy
|
if (attributes.privacy) body['privacy'] = attributes.privacy
|
||||||
|
|
||||||
return request(url)
|
// Upload request
|
||||||
.put(path)
|
if (attributes.thumbnailfile || attributes.previewfile) {
|
||||||
.send(body)
|
const attaches: any = {}
|
||||||
.set('Accept', 'application/json')
|
if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile
|
||||||
.set('Authorization', 'Bearer ' + accessToken)
|
if (attributes.previewfile) attaches.previewfile = attributes.previewfile
|
||||||
.expect(specialStatus)
|
|
||||||
|
return makeUploadRequest({
|
||||||
|
url,
|
||||||
|
method: 'PUT',
|
||||||
|
path,
|
||||||
|
token: accessToken,
|
||||||
|
fields: body,
|
||||||
|
attaches,
|
||||||
|
statusCodeExpected
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return makePutBodyRequest({
|
||||||
|
url,
|
||||||
|
path,
|
||||||
|
fields: body,
|
||||||
|
token: accessToken,
|
||||||
|
statusCodeExpected
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = 204) {
|
function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = 204) {
|
||||||
|
@ -355,7 +383,9 @@ async function completeVideoCheck (
|
||||||
files: {
|
files: {
|
||||||
resolution: number
|
resolution: number
|
||||||
size: number
|
size: number
|
||||||
}[]
|
}[],
|
||||||
|
thumbnailfile?: string
|
||||||
|
previewfile?: string
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (!attributes.likes) attributes.likes = 0
|
if (!attributes.likes) attributes.likes = 0
|
||||||
|
@ -414,8 +444,15 @@ async function completeVideoCheck (
|
||||||
const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
|
const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
|
||||||
expect(file.size).to.be.above(minSize).and.below(maxSize)
|
expect(file.size).to.be.above(minSize).and.below(maxSize)
|
||||||
|
|
||||||
const test = await testImage(url, attributes.fixture, videoDetails.thumbnailPath)
|
{
|
||||||
expect(test).to.equal(true)
|
const test = await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath)
|
||||||
|
expect(test).to.equal(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes.previewfile) {
|
||||||
|
const test = await testImage(url, attributes.previewfile, videoDetails.previewPath)
|
||||||
|
expect(test).to.equal(true)
|
||||||
|
}
|
||||||
|
|
||||||
const torrent = await webtorrentAdd(magnetUri, true)
|
const torrent = await webtorrentAdd(magnetUri, true)
|
||||||
expect(torrent.files).to.be.an('array')
|
expect(torrent.files).to.be.an('array')
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import * as program from 'commander'
|
import * as program from 'commander'
|
||||||
import { createWriteStream } from 'fs'
|
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { cursorTo } from 'readline'
|
|
||||||
import * as youtubeDL from 'youtube-dl'
|
import * as youtubeDL from 'youtube-dl'
|
||||||
import { VideoPrivacy } from '../../shared/models/videos'
|
import { VideoPrivacy } from '../../shared/models/videos'
|
||||||
import { unlinkPromise } from '../helpers/core-utils'
|
import { unlinkPromise } from '../helpers/core-utils'
|
||||||
|
|
Loading…
Reference in New Issue