Change how we handle resolution
It was an enum before, now we just use video height
This commit is contained in:
parent
aa8b6df4a5
commit
14d3270f36
|
@ -46,3 +46,9 @@ user:
|
||||||
transcoding:
|
transcoding:
|
||||||
enabled: false
|
enabled: false
|
||||||
threads: 2
|
threads: 2
|
||||||
|
resolutions: # Only created if the original video has a higher resolution
|
||||||
|
240p: true
|
||||||
|
360p: true
|
||||||
|
480p: true
|
||||||
|
720p: true
|
||||||
|
1080p: true
|
||||||
|
|
|
@ -37,10 +37,11 @@ import {
|
||||||
retryTransactionWrapper,
|
retryTransactionWrapper,
|
||||||
generateRandomString,
|
generateRandomString,
|
||||||
getFormattedObjects,
|
getFormattedObjects,
|
||||||
renamePromise
|
renamePromise,
|
||||||
|
getVideoFileHeight
|
||||||
} from '../../../helpers'
|
} from '../../../helpers'
|
||||||
import { TagInstance, VideoInstance } from '../../../models'
|
import { TagInstance, VideoInstance } from '../../../models'
|
||||||
import { VideoCreate, VideoUpdate, VideoResolution } from '../../../../shared'
|
import { VideoCreate, VideoUpdate } from '../../../../shared'
|
||||||
|
|
||||||
import { abuseVideoRouter } from './abuse'
|
import { abuseVideoRouter } from './abuse'
|
||||||
import { blacklistRouter } from './blacklist'
|
import { blacklistRouter } from './blacklist'
|
||||||
|
@ -192,9 +193,14 @@ function addVideo (req: express.Request, res: express.Response, videoPhysicalFil
|
||||||
return { author, tagInstances, video }
|
return { author, tagInstances, video }
|
||||||
})
|
})
|
||||||
.then(({ author, tagInstances, video }) => {
|
.then(({ author, tagInstances, video }) => {
|
||||||
|
const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename)
|
||||||
|
return getVideoFileHeight(videoFilePath)
|
||||||
|
.then(height => ({ author, tagInstances, video, videoFileHeight: height }))
|
||||||
|
})
|
||||||
|
.then(({ author, tagInstances, video, videoFileHeight }) => {
|
||||||
const videoFileData = {
|
const videoFileData = {
|
||||||
extname: extname(videoPhysicalFile.filename),
|
extname: extname(videoPhysicalFile.filename),
|
||||||
resolution: VideoResolution.ORIGINAL,
|
resolution: videoFileHeight,
|
||||||
size: videoPhysicalFile.size
|
size: videoPhysicalFile.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@ import {
|
||||||
VIDEO_CATEGORIES,
|
VIDEO_CATEGORIES,
|
||||||
VIDEO_LICENCES,
|
VIDEO_LICENCES,
|
||||||
VIDEO_LANGUAGES,
|
VIDEO_LANGUAGES,
|
||||||
VIDEO_RATE_TYPES,
|
VIDEO_RATE_TYPES
|
||||||
VIDEO_FILE_RESOLUTIONS
|
|
||||||
} from '../../initializers'
|
} from '../../initializers'
|
||||||
import { isUserUsernameValid } from './users'
|
import { isUserUsernameValid } from './users'
|
||||||
import { isArray, exists } from './misc'
|
import { isArray, exists } from './misc'
|
||||||
|
@ -128,7 +127,7 @@ function isVideoFileSizeValid (value: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoFileResolutionValid (value: string) {
|
function isVideoFileResolutionValid (value: string) {
|
||||||
return VIDEO_FILE_RESOLUTIONS[value] !== undefined
|
return exists(value) && validator.isInt(value + '')
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoFileExtnameValid (value: string) {
|
function isVideoFileExtnameValid (value: string) {
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import * as Promise from 'bluebird'
|
||||||
|
import * as ffmpeg from 'fluent-ffmpeg'
|
||||||
|
|
||||||
|
import { CONFIG } from '../initializers'
|
||||||
|
import { VideoResolution } from '../../shared/models/videos/video-resolution.enum'
|
||||||
|
|
||||||
|
function getVideoFileHeight (path: string) {
|
||||||
|
return new Promise<number>((res, rej) => {
|
||||||
|
ffmpeg.ffprobe(path, (err, metadata) => {
|
||||||
|
if (err) return rej(err)
|
||||||
|
|
||||||
|
const videoStream = metadata.streams.find(s => s.codec_type === 'video')
|
||||||
|
return res(videoStream.height)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDurationFromVideoFile (path: string) {
|
||||||
|
return new Promise<number>((res, rej) => {
|
||||||
|
ffmpeg.ffprobe(path, (err, metadata) => {
|
||||||
|
if (err) return rej(err)
|
||||||
|
|
||||||
|
return res(Math.floor(metadata.format.duration))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateImageFromVideoFile (fromPath: string, folder: string, imageName: string, size?: string) {
|
||||||
|
const options = {
|
||||||
|
filename: imageName,
|
||||||
|
count: 1,
|
||||||
|
folder
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size !== undefined) {
|
||||||
|
options['size'] = size
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise<string>((res, rej) => {
|
||||||
|
ffmpeg(fromPath)
|
||||||
|
.on('error', rej)
|
||||||
|
.on('end', () => res(imageName))
|
||||||
|
.thumbnail(options)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type TranscodeOptions = {
|
||||||
|
inputPath: string
|
||||||
|
outputPath: string
|
||||||
|
resolution?: VideoResolution
|
||||||
|
}
|
||||||
|
|
||||||
|
function transcode (options: TranscodeOptions) {
|
||||||
|
return new Promise<void>((res, rej) => {
|
||||||
|
let command = ffmpeg(options.inputPath)
|
||||||
|
.output(options.outputPath)
|
||||||
|
.videoCodec('libx264')
|
||||||
|
.outputOption('-threads ' + CONFIG.TRANSCODING.THREADS)
|
||||||
|
.outputOption('-movflags faststart')
|
||||||
|
|
||||||
|
if (options.resolution !== undefined) {
|
||||||
|
const size = `${options.resolution}x?` // '720x?' for example
|
||||||
|
command = command.size(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
command.on('error', rej)
|
||||||
|
.on('end', res)
|
||||||
|
.run()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export {
|
||||||
|
getVideoFileHeight,
|
||||||
|
getDurationFromVideoFile,
|
||||||
|
generateImageFromVideoFile,
|
||||||
|
transcode
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
export * from './core-utils'
|
export * from './core-utils'
|
||||||
export * from './logger'
|
export * from './logger'
|
||||||
export * from './custom-validators'
|
export * from './custom-validators'
|
||||||
|
export * from './ffmpeg-utils'
|
||||||
export * from './database-utils'
|
export * from './database-utils'
|
||||||
export * from './peertube-crypto'
|
export * from './peertube-crypto'
|
||||||
export * from './requests'
|
export * from './requests'
|
||||||
|
|
|
@ -61,7 +61,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
|
||||||
]
|
]
|
||||||
|
|
||||||
for (const resolution of resolutions) {
|
for (const resolution of resolutions) {
|
||||||
if (configResolutions[resolution.toString()] === true && videoFileHeight >= resolution) {
|
if (configResolutions[resolution.toString()] === true && videoFileHeight > resolution) {
|
||||||
resolutionsEnabled.push(resolution)
|
resolutionsEnabled.push(resolution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,16 +189,6 @@ const VIDEO_LANGUAGES = {
|
||||||
14: 'Italian'
|
14: 'Italian'
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use VideoResolution when https://github.com/Microsoft/TypeScript/issues/13042 is fixed
|
|
||||||
const VIDEO_FILE_RESOLUTIONS: { [ id: number ]: string } = {
|
|
||||||
0: 'original',
|
|
||||||
240: '240p',
|
|
||||||
360: '360p',
|
|
||||||
480: '480p',
|
|
||||||
720: '720p',
|
|
||||||
1080: '1080p'
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
// Score a pod has when we create it as a friend
|
// Score a pod has when we create it as a friend
|
||||||
|
@ -385,7 +375,6 @@ export {
|
||||||
THUMBNAILS_SIZE,
|
THUMBNAILS_SIZE,
|
||||||
USER_ROLES,
|
USER_ROLES,
|
||||||
VIDEO_CATEGORIES,
|
VIDEO_CATEGORIES,
|
||||||
VIDEO_FILE_RESOLUTIONS,
|
|
||||||
VIDEO_LANGUAGES,
|
VIDEO_LANGUAGES,
|
||||||
VIDEO_LICENCES,
|
VIDEO_LICENCES,
|
||||||
VIDEO_RATE_TYPES
|
VIDEO_RATE_TYPES
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { join } from 'path'
|
||||||
|
|
||||||
import { readdirPromise, renamePromise } from '../../helpers/core-utils'
|
import { readdirPromise, renamePromise } from '../../helpers/core-utils'
|
||||||
import { CONFIG } from '../../initializers/constants'
|
import { CONFIG } from '../../initializers/constants'
|
||||||
|
import { getVideoFileHeight } from '../../helpers/ffmpeg-utils'
|
||||||
|
|
||||||
function up (utils: {
|
function up (utils: {
|
||||||
transaction: Sequelize.Transaction,
|
transaction: Sequelize.Transaction,
|
||||||
|
@ -14,26 +15,7 @@ function up (utils: {
|
||||||
const torrentDir = CONFIG.STORAGE.TORRENTS_DIR
|
const torrentDir = CONFIG.STORAGE.TORRENTS_DIR
|
||||||
const videoFileDir = CONFIG.STORAGE.VIDEOS_DIR
|
const videoFileDir = CONFIG.STORAGE.VIDEOS_DIR
|
||||||
|
|
||||||
return readdirPromise(torrentDir)
|
|
||||||
.then(torrentFiles => {
|
|
||||||
const tasks: Promise<any>[] = []
|
|
||||||
for (const torrentFile of torrentFiles) {
|
|
||||||
const matches = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.torrent/.exec(torrentFile)
|
|
||||||
if (matches === null) {
|
|
||||||
console.log('Invalid torrent file name %s.', torrentFile)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTorrentName = matches[1] + '-original.torrent'
|
|
||||||
const p = renamePromise(join(torrentDir, torrentFile), join(torrentDir, newTorrentName))
|
|
||||||
tasks.push(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(tasks)
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
return readdirPromise(videoFileDir)
|
return readdirPromise(videoFileDir)
|
||||||
})
|
|
||||||
.then(videoFiles => {
|
.then(videoFiles => {
|
||||||
const tasks: Promise<any>[] = []
|
const tasks: Promise<any>[] = []
|
||||||
for (const videoFile of videoFiles) {
|
for (const videoFile of videoFiles) {
|
||||||
|
@ -43,8 +25,25 @@ function up (utils: {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const newVideoFileName = matches[1] + '-original.' + matches[2]
|
const uuid = matches[1]
|
||||||
const p = renamePromise(join(videoFileDir, videoFile), join(videoFileDir, newVideoFileName))
|
const ext = matches[2]
|
||||||
|
|
||||||
|
const p = getVideoFileHeight(join(videoFileDir, videoFile))
|
||||||
|
.then(height => {
|
||||||
|
const oldTorrentName = uuid + '.torrent'
|
||||||
|
const newTorrentName = uuid + '-' + height + '.torrent'
|
||||||
|
return renamePromise(join(torrentDir, oldTorrentName), join(torrentDir, newTorrentName)).then(() => height)
|
||||||
|
})
|
||||||
|
.then(height => {
|
||||||
|
const newVideoFileName = uuid + '-' + height + '.' + ext
|
||||||
|
return renamePromise(join(videoFileDir, videoFile), join(videoFileDir, newVideoFileName)).then(() => height)
|
||||||
|
})
|
||||||
|
.then(height => {
|
||||||
|
const query = 'UPDATE "VideoFiles" SET "resolution" = ' + height +
|
||||||
|
' WHERE "videoId" = (SELECT "id" FROM "Videos" WHERE "uuid" = \'' + uuid + '\')'
|
||||||
|
return utils.sequelize.query(query)
|
||||||
|
})
|
||||||
|
|
||||||
tasks.push(p)
|
tasks.push(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ import {
|
||||||
isVideoNSFWValid,
|
isVideoNSFWValid,
|
||||||
isVideoIdOrUUIDValid,
|
isVideoIdOrUUIDValid,
|
||||||
isVideoAbuseReasonValid,
|
isVideoAbuseReasonValid,
|
||||||
isVideoRatingTypeValid
|
isVideoRatingTypeValid,
|
||||||
|
getDurationFromVideoFile
|
||||||
} from '../../helpers'
|
} from '../../helpers'
|
||||||
import { VideoInstance } from '../../models'
|
import { VideoInstance } from '../../models'
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ const videosAddValidator = [
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.Video.getDurationFromFile(videoFile.path)
|
return getDurationFromVideoFile(videoFile.path)
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.error('Invalid input file in videosAddValidator.', err)
|
logger.error('Invalid input file in videosAddValidator.', err)
|
||||||
res.status(400)
|
res.status(400)
|
||||||
|
|
|
@ -12,7 +12,6 @@ import {
|
||||||
isUserDisplayNSFWValid,
|
isUserDisplayNSFWValid,
|
||||||
isUserVideoQuotaValid
|
isUserVideoQuotaValid
|
||||||
} from '../../helpers'
|
} from '../../helpers'
|
||||||
import { VideoResolution } from '../../../shared'
|
|
||||||
|
|
||||||
import { addMethodsToModel } from '../utils'
|
import { addMethodsToModel } from '../utils'
|
||||||
import {
|
import {
|
||||||
|
@ -243,33 +242,21 @@ loadByUsernameOrEmail = function (username: string, email: string) {
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function getOriginalVideoFileTotalFromUser (user: UserInstance) {
|
function getOriginalVideoFileTotalFromUser (user: UserInstance) {
|
||||||
// attributes = [] because we don't want other fields than the sum
|
// Don't use sequelize because we need to use a subquery
|
||||||
const query = {
|
const query = 'SELECT SUM("size") AS "total" FROM ' +
|
||||||
where: {
|
'(SELECT MAX("VideoFiles"."size") AS "size" FROM "VideoFiles" ' +
|
||||||
resolution: VideoResolution.ORIGINAL
|
'INNER JOIN "Videos" ON "VideoFiles"."videoId" = "Videos"."id" ' +
|
||||||
},
|
'INNER JOIN "Authors" ON "Videos"."authorId" = "Authors"."id" ' +
|
||||||
include: [
|
'INNER JOIN "Users" ON "Authors"."userId" = "Users"."id" ' +
|
||||||
{
|
'WHERE "Users"."id" = $userId GROUP BY "Videos"."id") t'
|
||||||
attributes: [],
|
|
||||||
model: User['sequelize'].models.Video,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
attributes: [],
|
|
||||||
model: User['sequelize'].models.Author,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
attributes: [],
|
|
||||||
model: User['sequelize'].models.User,
|
|
||||||
where: {
|
|
||||||
id: user.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
return User['sequelize'].models.VideoFile.sum('size', query)
|
const options = {
|
||||||
|
bind: { userId: user.id },
|
||||||
|
type: Sequelize.QueryTypes.SELECT
|
||||||
|
}
|
||||||
|
return User['sequelize'].query(query, options).then(([ { total } ]) => {
|
||||||
|
if (total === null) return 0
|
||||||
|
|
||||||
|
return parseInt(total, 10)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ export namespace VideoMethods {
|
||||||
|
|
||||||
// Return thumbnail name
|
// Return thumbnail name
|
||||||
export type GenerateThumbnailFromData = (video: VideoInstance, thumbnailData: string) => Promise<string>
|
export type GenerateThumbnailFromData = (video: VideoInstance, thumbnailData: string) => Promise<string>
|
||||||
export type GetDurationFromFile = (videoPath: string) => Promise<number>
|
|
||||||
|
|
||||||
export type List = () => Promise<VideoInstance[]>
|
export type List = () => Promise<VideoInstance[]>
|
||||||
export type ListOwnedAndPopulateAuthorAndTags = () => Promise<VideoInstance[]>
|
export type ListOwnedAndPopulateAuthorAndTags = () => Promise<VideoInstance[]>
|
||||||
|
@ -65,7 +64,6 @@ export namespace VideoMethods {
|
||||||
|
|
||||||
export interface VideoClass {
|
export interface VideoClass {
|
||||||
generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData
|
generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData
|
||||||
getDurationFromFile: VideoMethods.GetDurationFromFile
|
|
||||||
list: VideoMethods.List
|
list: VideoMethods.List
|
||||||
listForApi: VideoMethods.ListForApi
|
listForApi: VideoMethods.ListForApi
|
||||||
listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags
|
listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import * as safeBuffer from 'safe-buffer'
|
import * as safeBuffer from 'safe-buffer'
|
||||||
const Buffer = safeBuffer.Buffer
|
const Buffer = safeBuffer.Buffer
|
||||||
import * as ffmpeg from 'fluent-ffmpeg'
|
|
||||||
import * as magnetUtil from 'magnet-uri'
|
import * as magnetUtil from 'magnet-uri'
|
||||||
import { map } from 'lodash'
|
import { map } from 'lodash'
|
||||||
import * as parseTorrent from 'parse-torrent'
|
import * as parseTorrent from 'parse-torrent'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import * as Promise from 'bluebird'
|
import * as Promise from 'bluebird'
|
||||||
|
import { maxBy } from 'lodash'
|
||||||
|
|
||||||
import { TagInstance } from './tag-interface'
|
import { TagInstance } from './tag-interface'
|
||||||
import {
|
import {
|
||||||
|
@ -23,7 +23,10 @@ import {
|
||||||
renamePromise,
|
renamePromise,
|
||||||
writeFilePromise,
|
writeFilePromise,
|
||||||
createTorrentPromise,
|
createTorrentPromise,
|
||||||
statPromise
|
statPromise,
|
||||||
|
generateImageFromVideoFile,
|
||||||
|
transcode,
|
||||||
|
getVideoFileHeight
|
||||||
} from '../../helpers'
|
} from '../../helpers'
|
||||||
import {
|
import {
|
||||||
CONFIG,
|
CONFIG,
|
||||||
|
@ -32,8 +35,7 @@ import {
|
||||||
VIDEO_CATEGORIES,
|
VIDEO_CATEGORIES,
|
||||||
VIDEO_LICENCES,
|
VIDEO_LICENCES,
|
||||||
VIDEO_LANGUAGES,
|
VIDEO_LANGUAGES,
|
||||||
THUMBNAILS_SIZE,
|
THUMBNAILS_SIZE
|
||||||
VIDEO_FILE_RESOLUTIONS
|
|
||||||
} from '../../initializers'
|
} from '../../initializers'
|
||||||
import { removeVideoToFriends } from '../../lib'
|
import { removeVideoToFriends } from '../../lib'
|
||||||
import { VideoResolution } from '../../../shared'
|
import { VideoResolution } from '../../../shared'
|
||||||
|
@ -67,7 +69,6 @@ let createTorrentAndSetInfoHash: VideoMethods.CreateTorrentAndSetInfoHash
|
||||||
let getOriginalFileHeight: VideoMethods.GetOriginalFileHeight
|
let getOriginalFileHeight: VideoMethods.GetOriginalFileHeight
|
||||||
|
|
||||||
let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData
|
let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData
|
||||||
let getDurationFromFile: VideoMethods.GetDurationFromFile
|
|
||||||
let list: VideoMethods.List
|
let list: VideoMethods.List
|
||||||
let listForApi: VideoMethods.ListForApi
|
let listForApi: VideoMethods.ListForApi
|
||||||
let loadByHostAndUUID: VideoMethods.LoadByHostAndUUID
|
let loadByHostAndUUID: VideoMethods.LoadByHostAndUUID
|
||||||
|
@ -233,7 +234,6 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
|
||||||
associate,
|
associate,
|
||||||
|
|
||||||
generateThumbnailFromData,
|
generateThumbnailFromData,
|
||||||
getDurationFromFile,
|
|
||||||
list,
|
list,
|
||||||
listForApi,
|
listForApi,
|
||||||
listOwnedAndPopulateAuthorAndTags,
|
listOwnedAndPopulateAuthorAndTags,
|
||||||
|
@ -338,11 +338,12 @@ function afterDestroy (video: VideoInstance, options: { transaction: Sequelize.T
|
||||||
getOriginalFile = function (this: VideoInstance) {
|
getOriginalFile = function (this: VideoInstance) {
|
||||||
if (Array.isArray(this.VideoFiles) === false) return undefined
|
if (Array.isArray(this.VideoFiles) === false) return undefined
|
||||||
|
|
||||||
return this.VideoFiles.find(file => file.resolution === VideoResolution.ORIGINAL)
|
// The original file is the file that have the higher resolution
|
||||||
|
return maxBy(this.VideoFiles, file => file.resolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoFilename = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
getVideoFilename = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
||||||
return this.uuid + '-' + VIDEO_FILE_RESOLUTIONS[videoFile.resolution] + videoFile.extname
|
return this.uuid + '-' + videoFile.resolution + videoFile.extname
|
||||||
}
|
}
|
||||||
|
|
||||||
getThumbnailName = function (this: VideoInstance) {
|
getThumbnailName = function (this: VideoInstance) {
|
||||||
|
@ -358,7 +359,7 @@ getPreviewName = function (this: VideoInstance) {
|
||||||
|
|
||||||
getTorrentFileName = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
getTorrentFileName = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
||||||
const extension = '.torrent'
|
const extension = '.torrent'
|
||||||
return this.uuid + '-' + VIDEO_FILE_RESOLUTIONS[videoFile.resolution] + extension
|
return this.uuid + '-' + videoFile.resolution + extension
|
||||||
}
|
}
|
||||||
|
|
||||||
isOwned = function (this: VideoInstance) {
|
isOwned = function (this: VideoInstance) {
|
||||||
|
@ -366,11 +367,20 @@ isOwned = function (this: VideoInstance) {
|
||||||
}
|
}
|
||||||
|
|
||||||
createPreview = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
createPreview = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
||||||
return generateImage(this, this.getVideoFilePath(videoFile), CONFIG.STORAGE.PREVIEWS_DIR, this.getPreviewName(), null)
|
return generateImageFromVideoFile(
|
||||||
|
this.getVideoFilePath(videoFile),
|
||||||
|
CONFIG.STORAGE.PREVIEWS_DIR,
|
||||||
|
this.getPreviewName()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
createThumbnail = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
createThumbnail = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
||||||
return generateImage(this, this.getVideoFilePath(videoFile), CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName(), THUMBNAILS_SIZE)
|
return generateImageFromVideoFile(
|
||||||
|
this.getVideoFilePath(videoFile),
|
||||||
|
CONFIG.STORAGE.THUMBNAILS_DIR,
|
||||||
|
this.getThumbnailName(),
|
||||||
|
THUMBNAILS_SIZE
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoFilePath = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
getVideoFilePath = function (this: VideoInstance, videoFile: VideoFileInstance) {
|
||||||
|
@ -480,8 +490,7 @@ toFormattedJSON = function (this: VideoInstance) {
|
||||||
// Format and sort video files
|
// Format and sort video files
|
||||||
json.files = this.VideoFiles
|
json.files = this.VideoFiles
|
||||||
.map(videoFile => {
|
.map(videoFile => {
|
||||||
let resolutionLabel = VIDEO_FILE_RESOLUTIONS[videoFile.resolution]
|
let resolutionLabel = videoFile.resolution + 'p'
|
||||||
if (!resolutionLabel) resolutionLabel = 'Unknown'
|
|
||||||
|
|
||||||
const videoFileJson = {
|
const videoFileJson = {
|
||||||
resolution: videoFile.resolution,
|
resolution: videoFile.resolution,
|
||||||
|
@ -578,16 +587,15 @@ optimizeOriginalVideofile = function (this: VideoInstance) {
|
||||||
const videoInputPath = join(videosDirectory, this.getVideoFilename(inputVideoFile))
|
const videoInputPath = join(videosDirectory, this.getVideoFilename(inputVideoFile))
|
||||||
const videoOutputPath = join(videosDirectory, this.id + '-transcoded' + newExtname)
|
const videoOutputPath = join(videosDirectory, this.id + '-transcoded' + newExtname)
|
||||||
|
|
||||||
return new Promise<void>((res, rej) => {
|
const transcodeOptions = {
|
||||||
ffmpeg(videoInputPath)
|
inputPath: videoInputPath,
|
||||||
.output(videoOutputPath)
|
outputPath: videoOutputPath
|
||||||
.videoCodec('libx264')
|
}
|
||||||
.outputOption('-threads ' + CONFIG.TRANSCODING.THREADS)
|
|
||||||
.outputOption('-movflags faststart')
|
|
||||||
.on('error', rej)
|
|
||||||
.on('end', () => {
|
|
||||||
|
|
||||||
|
return transcode(transcodeOptions)
|
||||||
|
.then(() => {
|
||||||
return unlinkPromise(videoInputPath)
|
return unlinkPromise(videoInputPath)
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Important to do this before getVideoFilename() to take in account the new file extension
|
// Important to do this before getVideoFilename() to take in account the new file extension
|
||||||
inputVideoFile.set('extname', newExtname)
|
inputVideoFile.set('extname', newExtname)
|
||||||
|
@ -607,16 +615,13 @@ optimizeOriginalVideofile = function (this: VideoInstance) {
|
||||||
return inputVideoFile.save()
|
return inputVideoFile.save()
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return res()
|
return undefined
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
// Auto destruction...
|
// Auto destruction...
|
||||||
this.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', err))
|
this.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', err))
|
||||||
|
|
||||||
return rej(err)
|
throw err
|
||||||
})
|
|
||||||
})
|
|
||||||
.run()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,18 +639,16 @@ transcodeOriginalVideofile = function (this: VideoInstance, resolution: VideoRes
|
||||||
videoId: this.id
|
videoId: this.id
|
||||||
})
|
})
|
||||||
const videoOutputPath = join(videosDirectory, this.getVideoFilename(newVideoFile))
|
const videoOutputPath = join(videosDirectory, this.getVideoFilename(newVideoFile))
|
||||||
const resolutionOption = `${resolution}x?` // '720x?' for example
|
|
||||||
|
|
||||||
return new Promise<void>((res, rej) => {
|
const transcodeOptions = {
|
||||||
ffmpeg(videoInputPath)
|
inputPath: videoInputPath,
|
||||||
.output(videoOutputPath)
|
outputPath: videoOutputPath,
|
||||||
.videoCodec('libx264')
|
resolution
|
||||||
.size(resolutionOption)
|
}
|
||||||
.outputOption('-threads ' + CONFIG.TRANSCODING.THREADS)
|
return transcode(transcodeOptions)
|
||||||
.outputOption('-movflags faststart')
|
.then(() => {
|
||||||
.on('error', rej)
|
|
||||||
.on('end', () => {
|
|
||||||
return statPromise(videoOutputPath)
|
return statPromise(videoOutputPath)
|
||||||
|
})
|
||||||
.then(stats => {
|
.then(stats => {
|
||||||
newVideoFile.set('size', stats.size)
|
newVideoFile.set('size', stats.size)
|
||||||
|
|
||||||
|
@ -660,26 +663,13 @@ transcodeOriginalVideofile = function (this: VideoInstance, resolution: VideoRes
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return this.VideoFiles.push(newVideoFile)
|
return this.VideoFiles.push(newVideoFile)
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => undefined)
|
||||||
return res()
|
|
||||||
})
|
|
||||||
.catch(rej)
|
|
||||||
})
|
|
||||||
.run()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getOriginalFileHeight = function (this: VideoInstance) {
|
getOriginalFileHeight = function (this: VideoInstance) {
|
||||||
const originalFilePath = this.getVideoFilePath(this.getOriginalFile())
|
const originalFilePath = this.getVideoFilePath(this.getOriginalFile())
|
||||||
|
|
||||||
return new Promise<number>((res, rej) => {
|
return getVideoFileHeight(originalFilePath)
|
||||||
ffmpeg.ffprobe(originalFilePath, (err, metadata) => {
|
|
||||||
if (err) return rej(err)
|
|
||||||
|
|
||||||
const videoStream = metadata.streams.find(s => s.codec_type === 'video')
|
|
||||||
return res(videoStream.height)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeThumbnail = function (this: VideoInstance) {
|
removeThumbnail = function (this: VideoInstance) {
|
||||||
|
@ -714,16 +704,6 @@ generateThumbnailFromData = function (video: VideoInstance, thumbnailData: strin
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getDurationFromFile = function (videoPath: string) {
|
|
||||||
return new Promise<number>((res, rej) => {
|
|
||||||
ffmpeg.ffprobe(videoPath, (err, metadata) => {
|
|
||||||
if (err) return rej(err)
|
|
||||||
|
|
||||||
return res(Math.floor(metadata.format.duration))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
list = function () {
|
list = function () {
|
||||||
const query = {
|
const query = {
|
||||||
include: [ Video['sequelize'].models.VideoFile ]
|
include: [ Video['sequelize'].models.VideoFile ]
|
||||||
|
@ -964,22 +944,3 @@ function createBaseVideosWhere () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateImage (video: VideoInstance, videoPath: string, folder: string, imageName: string, size: string) {
|
|
||||||
const options = {
|
|
||||||
filename: imageName,
|
|
||||||
count: 1,
|
|
||||||
folder
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size) {
|
|
||||||
options['size'] = size
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise<string>((res, rej) => {
|
|
||||||
ffmpeg(videoPath)
|
|
||||||
.on('error', rej)
|
|
||||||
.on('end', () => res(imageName))
|
|
||||||
.thumbnail(options)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -106,8 +106,8 @@ describe('Test multiple pods', function () {
|
||||||
const file = video.files[0]
|
const file = video.files[0]
|
||||||
const magnetUri = file.magnetUri
|
const magnetUri = file.magnetUri
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(572456)
|
expect(file.size).to.equal(572456)
|
||||||
|
|
||||||
if (server.url !== 'http://localhost:9001') {
|
if (server.url !== 'http://localhost:9001') {
|
||||||
|
@ -172,7 +172,7 @@ describe('Test multiple pods', function () {
|
||||||
expect(dateIsValid(video.updatedAt)).to.be.true
|
expect(dateIsValid(video.updatedAt)).to.be.true
|
||||||
expect(video.author).to.equal('root')
|
expect(video.author).to.equal('root')
|
||||||
|
|
||||||
expect(video.files).to.have.lengthOf(5)
|
expect(video.files).to.have.lengthOf(4)
|
||||||
|
|
||||||
// Check common attributes
|
// Check common attributes
|
||||||
for (const file of video.files) {
|
for (const file of video.files) {
|
||||||
|
@ -192,11 +192,6 @@ describe('Test multiple pods', function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const originalFile = video.files.find(f => f.resolution === 0)
|
|
||||||
expect(originalFile).not.to.be.undefined
|
|
||||||
expect(originalFile.resolutionLabel).to.equal('original')
|
|
||||||
expect(originalFile.size).to.be.above(700000).and.below(720000)
|
|
||||||
|
|
||||||
const file240p = video.files.find(f => f.resolution === 240)
|
const file240p = video.files.find(f => f.resolution === 240)
|
||||||
expect(file240p).not.to.be.undefined
|
expect(file240p).not.to.be.undefined
|
||||||
expect(file240p.resolutionLabel).to.equal('240p')
|
expect(file240p.resolutionLabel).to.equal('240p')
|
||||||
|
@ -215,7 +210,7 @@ describe('Test multiple pods', function () {
|
||||||
const file720p = video.files.find(f => f.resolution === 720)
|
const file720p = video.files.find(f => f.resolution === 720)
|
||||||
expect(file720p).not.to.be.undefined
|
expect(file720p).not.to.be.undefined
|
||||||
expect(file720p.resolutionLabel).to.equal('720p')
|
expect(file720p.resolutionLabel).to.equal('720p')
|
||||||
expect(file720p.size).to.be.above(310000).and.below(320000)
|
expect(file720p.size).to.be.above(700000).and.below(7200000)
|
||||||
|
|
||||||
const test = await testVideoImage(server.url, 'video_short2.webm', video.thumbnailPath)
|
const test = await testVideoImage(server.url, 'video_short2.webm', video.thumbnailPath)
|
||||||
expect(test).to.equal(true)
|
expect(test).to.equal(true)
|
||||||
|
@ -291,8 +286,8 @@ describe('Test multiple pods', function () {
|
||||||
|
|
||||||
const file1 = video1.files[0]
|
const file1 = video1.files[0]
|
||||||
expect(file1.magnetUri).to.have.lengthOf.above(2)
|
expect(file1.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file1.resolution).to.equal(0)
|
expect(file1.resolution).to.equal(720)
|
||||||
expect(file1.resolutionLabel).to.equal('original')
|
expect(file1.resolutionLabel).to.equal('720p')
|
||||||
expect(file1.size).to.equal(292677)
|
expect(file1.size).to.equal(292677)
|
||||||
|
|
||||||
expect(video2.name).to.equal('my super name for pod 3-2')
|
expect(video2.name).to.equal('my super name for pod 3-2')
|
||||||
|
@ -316,8 +311,8 @@ describe('Test multiple pods', function () {
|
||||||
const file2 = video2.files[0]
|
const file2 = video2.files[0]
|
||||||
const magnetUri2 = file2.magnetUri
|
const magnetUri2 = file2.magnetUri
|
||||||
expect(file2.magnetUri).to.have.lengthOf.above(2)
|
expect(file2.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file2.resolution).to.equal(0)
|
expect(file2.resolution).to.equal(720)
|
||||||
expect(file2.resolutionLabel).to.equal('original')
|
expect(file2.resolutionLabel).to.equal('720p')
|
||||||
expect(file2.size).to.equal(218910)
|
expect(file2.size).to.equal(218910)
|
||||||
|
|
||||||
if (server.url !== 'http://localhost:9003') {
|
if (server.url !== 'http://localhost:9003') {
|
||||||
|
@ -402,6 +397,22 @@ describe('Test multiple pods', function () {
|
||||||
expect(torrent.files.length).to.equal(1)
|
expect(torrent.files.length).to.equal(1)
|
||||||
expect(torrent.files[0].path).to.exist.and.to.not.equal('')
|
expect(torrent.files[0].path).to.exist.and.to.not.equal('')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should add the file 2 in 360p by asking pod 1', async function () {
|
||||||
|
// Yes, this could be long
|
||||||
|
this.timeout(200000)
|
||||||
|
|
||||||
|
const res = await getVideosList(servers[0].url)
|
||||||
|
|
||||||
|
const video = res.body.data.find(v => v.name === 'my super name for pod 2')
|
||||||
|
const file = video.files.find(f => f.resolution === 360)
|
||||||
|
expect(file).not.to.be.undefined
|
||||||
|
|
||||||
|
const torrent = await webtorrentAdd(file.magnetUri)
|
||||||
|
expect(torrent.files).to.be.an('array')
|
||||||
|
expect(torrent.files.length).to.equal(1)
|
||||||
|
expect(torrent.files[0].path).to.exist.and.to.not.equal('')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Should update video views, likes and dislikes', function () {
|
describe('Should update video views, likes and dislikes', function () {
|
||||||
|
@ -562,8 +573,8 @@ describe('Test multiple pods', function () {
|
||||||
|
|
||||||
const file = videoUpdated.files[0]
|
const file = videoUpdated.files[0]
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(292677)
|
expect(file.size).to.equal(292677)
|
||||||
|
|
||||||
const test = await testVideoImage(server.url, 'video_short3.webm', videoUpdated.thumbnailPath)
|
const test = await testVideoImage(server.url, 'video_short3.webm', videoUpdated.thumbnailPath)
|
||||||
|
|
|
@ -127,8 +127,8 @@ describe('Test a single pod', function () {
|
||||||
const file = video.files[0]
|
const file = video.files[0]
|
||||||
const magnetUri = file.magnetUri
|
const magnetUri = file.magnetUri
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(218910)
|
expect(file.size).to.equal(218910)
|
||||||
|
|
||||||
const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
|
const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
|
||||||
|
@ -170,8 +170,8 @@ describe('Test a single pod', function () {
|
||||||
|
|
||||||
const file = video.files[0]
|
const file = video.files[0]
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(218910)
|
expect(file.size).to.equal(218910)
|
||||||
|
|
||||||
const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
|
const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
|
||||||
|
@ -229,8 +229,8 @@ describe('Test a single pod', function () {
|
||||||
|
|
||||||
const file = video.files[0]
|
const file = video.files[0]
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(218910)
|
expect(file.size).to.equal(218910)
|
||||||
|
|
||||||
const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
|
const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
|
||||||
|
@ -291,8 +291,8 @@ describe('Test a single pod', function () {
|
||||||
|
|
||||||
const file = video.files[0]
|
const file = video.files[0]
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(218910)
|
expect(file.size).to.equal(218910)
|
||||||
|
|
||||||
const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
|
const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
|
||||||
|
@ -569,8 +569,8 @@ describe('Test a single pod', function () {
|
||||||
const file = video.files[0]
|
const file = video.files[0]
|
||||||
const magnetUri = file.magnetUri
|
const magnetUri = file.magnetUri
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(292677)
|
expect(file.size).to.equal(292677)
|
||||||
|
|
||||||
const test = await testVideoImage(server.url, 'video_short3.webm', video.thumbnailPath)
|
const test = await testVideoImage(server.url, 'video_short3.webm', video.thumbnailPath)
|
||||||
|
@ -612,8 +612,8 @@ describe('Test a single pod', function () {
|
||||||
|
|
||||||
const file = video.files[0]
|
const file = video.files[0]
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(292677)
|
expect(file.size).to.equal(292677)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -647,8 +647,8 @@ describe('Test a single pod', function () {
|
||||||
|
|
||||||
const file = video.files[0]
|
const file = video.files[0]
|
||||||
expect(file.magnetUri).to.have.lengthOf.above(2)
|
expect(file.magnetUri).to.have.lengthOf.above(2)
|
||||||
expect(file.resolution).to.equal(0)
|
expect(file.resolution).to.equal(720)
|
||||||
expect(file.resolutionLabel).to.equal('original')
|
expect(file.resolutionLabel).to.equal('720p')
|
||||||
expect(file.size).to.equal(292677)
|
expect(file.size).to.equal(292677)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ describe('Test video transcoding', function () {
|
||||||
const res = await getVideosList(servers[1].url)
|
const res = await getVideosList(servers[1].url)
|
||||||
|
|
||||||
const video = res.body.data[0]
|
const video = res.body.data[0]
|
||||||
expect(video.files).to.have.lengthOf(5)
|
expect(video.files).to.have.lengthOf(4)
|
||||||
|
|
||||||
const magnetUri = video.files[0].magnetUri
|
const magnetUri = video.files[0].magnetUri
|
||||||
expect(magnetUri).to.match(/\.mp4/)
|
expect(magnetUri).to.match(/\.mp4/)
|
||||||
|
|
|
@ -55,13 +55,13 @@ describe('Test update host scripts', function () {
|
||||||
expect(videos).to.have.lengthOf(2)
|
expect(videos).to.have.lengthOf(2)
|
||||||
|
|
||||||
for (const video of videos) {
|
for (const video of videos) {
|
||||||
expect(video.files).to.have.lengthOf(5)
|
expect(video.files).to.have.lengthOf(4)
|
||||||
|
|
||||||
for (const file of video.files) {
|
for (const file of video.files) {
|
||||||
expect(file.magnetUri).to.contain('localhost%3A9002%2Ftracker%2Fsocket')
|
expect(file.magnetUri).to.contain('localhost%3A9002%2Ftracker%2Fsocket')
|
||||||
expect(file.magnetUri).to.contain('localhost%3A9002%2Fstatic%2Fwebseed%2F')
|
expect(file.magnetUri).to.contain('localhost%3A9002%2Fstatic%2Fwebseed%2F')
|
||||||
|
|
||||||
const torrent = await parseTorrentVideo(server, video.uuid, file.resolutionLabel)
|
const torrent = await parseTorrentVideo(server, video.uuid, file.resolution)
|
||||||
expect(torrent.announce[0]).to.equal('ws://localhost:9002/tracker/socket')
|
expect(torrent.announce[0]).to.equal('ws://localhost:9002/tracker/socket')
|
||||||
expect(torrent.urlList[0]).to.contain('http://localhost:9002/static/webseed')
|
expect(torrent.urlList[0]).to.contain('http://localhost:9002/static/webseed')
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,14 +196,14 @@ function uploadVideo (url: string, accessToken: string, videoAttributesArg: Vide
|
||||||
req.field('tags[' + i + ']', attributes.tags[i])
|
req.field('tags[' + i + ']', attributes.tags[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
let filepath = ''
|
let filePath = ''
|
||||||
if (isAbsolute(attributes.fixture)) {
|
if (isAbsolute(attributes.fixture)) {
|
||||||
filepath = attributes.fixture
|
filePath = attributes.fixture
|
||||||
} else {
|
} else {
|
||||||
filepath = join(__dirname, '..', 'api', 'fixtures', attributes.fixture)
|
filePath = join(__dirname, '..', 'api', 'fixtures', attributes.fixture)
|
||||||
}
|
}
|
||||||
|
|
||||||
return req.attach('videofile', filepath)
|
return req.attach('videofile', filePath)
|
||||||
.expect(specialStatus)
|
.expect(specialStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,9 +238,9 @@ function rateVideo (url: string, accessToken: string, id: number, rating: string
|
||||||
.expect(specialStatus)
|
.expect(specialStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolutionLabel: string) {
|
function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) {
|
||||||
return new Promise<any>((res, rej) => {
|
return new Promise<any>((res, rej) => {
|
||||||
const torrentName = videoUUID + '-' + resolutionLabel + '.torrent'
|
const torrentName = videoUUID + '-' + resolution + '.torrent'
|
||||||
const torrentPath = join(__dirname, '..', '..', '..', 'test' + server.serverNumber, 'torrents', torrentName)
|
const torrentPath = join(__dirname, '..', '..', '..', 'test' + server.serverNumber, 'torrents', torrentName)
|
||||||
readFile(torrentPath, (err, data) => {
|
readFile(torrentPath, (err, data) => {
|
||||||
if (err) return rej(err)
|
if (err) return rej(err)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export enum VideoResolution {
|
export enum VideoResolution {
|
||||||
ORIGINAL = 0,
|
|
||||||
H_240P = 240,
|
H_240P = 240,
|
||||||
H_360P = 360,
|
H_360P = 360,
|
||||||
H_480P = 480,
|
H_480P = 480,
|
||||||
|
|
Loading…
Reference in New Issue