1
0
Fork 0

Improve create import file job

Fix federation of .ogv videos
This commit is contained in:
Chocobozzz 2018-06-07 09:43:18 +02:00
parent 0138af9237
commit 28be89161a
No known key found for this signature in database
GPG key ID: 583A612D890159BE
7 changed files with 48 additions and 34 deletions

View file

@ -27,6 +27,7 @@ async function run () {
const video = await VideoModel.loadByUUID(program['video']) const video = await VideoModel.loadByUUID(program['video'])
if (!video) throw new Error('Video not found.') if (!video) throw new Error('Video not found.')
if (video.isOwned() === false) throw new Error('Cannot import files of a non owned video.')
const dataInput = { const dataInput = {
videoUUID: video.uuid, videoUUID: video.uuid,

View file

@ -7,8 +7,8 @@ import { UserRight, VideoRateType } from '../../../shared'
import { import {
CONSTRAINTS_FIELDS, CONSTRAINTS_FIELDS,
VIDEO_CATEGORIES, VIDEO_CATEGORIES,
VIDEO_LANGUAGES, VIDEO_LICENCES,
VIDEO_LICENCES, VIDEO_MIMETYPE_EXT, VIDEO_MIMETYPE_EXT,
VIDEO_PRIVACIES, VIDEO_PRIVACIES,
VIDEO_RATE_TYPES VIDEO_RATE_TYPES
} from '../../initializers' } from '../../initializers'

View file

@ -7,6 +7,7 @@ import { VideoPrivacy } from '../../shared/models/videos'
// Do not use barrels, remain constants as independent as possible // Do not use barrels, remain constants as independent as possible
import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils'
import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
import { invert } from 'lodash'
// Use a variable to reload the configuration if we need // Use a variable to reload the configuration if we need
let config: IConfig = require('config') let config: IConfig = require('config')
@ -330,6 +331,7 @@ const VIDEO_MIMETYPE_EXT = {
'video/ogg': '.ogv', 'video/ogg': '.ogv',
'video/mp4': '.mp4' 'video/mp4': '.mp4'
} }
const VIDEO_EXT_MIMETYPE = invert(VIDEO_MIMETYPE_EXT)
const IMAGE_MIMETYPE_EXT = { const IMAGE_MIMETYPE_EXT = {
'image/png': '.png', 'image/png': '.png',
@ -501,6 +503,7 @@ export {
SCHEDULER_INTERVAL, SCHEDULER_INTERVAL,
STATIC_DOWNLOAD_PATHS, STATIC_DOWNLOAD_PATHS,
RATES_LIMIT, RATES_LIMIT,
VIDEO_EXT_MIMETYPE,
JOB_COMPLETED_LIFETIME, JOB_COMPLETED_LIFETIME,
VIDEO_VIEW_LIFETIME, VIDEO_VIEW_LIFETIME,
buildLanguages buildLanguages

View file

@ -16,14 +16,14 @@ export type VideoFilePayload = {
isPortraitMode?: boolean isPortraitMode?: boolean
} }
export type VideoImportPayload = { export type VideoFileImportPayload = {
videoUUID: string, videoUUID: string,
filePath: string filePath: string
} }
async function processVideoImport (job: kue.Job) { async function processVideoFileImport (job: kue.Job) {
const payload = job.data as VideoImportPayload const payload = job.data as VideoFileImportPayload
logger.info('Processing video import in job %d.', job.id) logger.info('Processing video file import in job %d.', job.id)
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID) const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
// No video, maybe deleted? // No video, maybe deleted?
@ -132,5 +132,5 @@ async function onVideoFileOptimizerSuccess (video: VideoModel, isNewVideo: boole
export { export {
processVideoFile, processVideoFile,
processVideoImport processVideoFileImport
} }

View file

@ -7,7 +7,7 @@ import { ActivitypubHttpBroadcastPayload, processActivityPubHttpBroadcast } from
import { ActivitypubHttpFetcherPayload, processActivityPubHttpFetcher } from './handlers/activitypub-http-fetcher' import { ActivitypubHttpFetcherPayload, processActivityPubHttpFetcher } from './handlers/activitypub-http-fetcher'
import { ActivitypubHttpUnicastPayload, processActivityPubHttpUnicast } from './handlers/activitypub-http-unicast' import { ActivitypubHttpUnicastPayload, processActivityPubHttpUnicast } from './handlers/activitypub-http-unicast'
import { EmailPayload, processEmail } from './handlers/email' import { EmailPayload, processEmail } from './handlers/email'
import { processVideoFile, processVideoImport, VideoFilePayload, VideoImportPayload } from './handlers/video-file' import { processVideoFile, processVideoFileImport, VideoFilePayload, VideoFileImportPayload } from './handlers/video-file'
import { ActivitypubFollowPayload, processActivityPubFollow } from './handlers/activitypub-follow' import { ActivitypubFollowPayload, processActivityPubFollow } from './handlers/activitypub-follow'
type CreateJobArgument = type CreateJobArgument =
@ -15,7 +15,7 @@ type CreateJobArgument =
{ type: 'activitypub-http-unicast', payload: ActivitypubHttpUnicastPayload } | { type: 'activitypub-http-unicast', payload: ActivitypubHttpUnicastPayload } |
{ type: 'activitypub-http-fetcher', payload: ActivitypubHttpFetcherPayload } | { type: 'activitypub-http-fetcher', payload: ActivitypubHttpFetcherPayload } |
{ type: 'activitypub-follow', payload: ActivitypubFollowPayload } | { type: 'activitypub-follow', payload: ActivitypubFollowPayload } |
{ type: 'video-file-import', payload: VideoImportPayload } | { type: 'video-file-import', payload: VideoFileImportPayload } |
{ type: 'video-file', payload: VideoFilePayload } | { type: 'video-file', payload: VideoFilePayload } |
{ type: 'email', payload: EmailPayload } { type: 'email', payload: EmailPayload }
@ -24,7 +24,7 @@ const handlers: { [ id in JobType ]: (job: kue.Job) => Promise<any>} = {
'activitypub-http-unicast': processActivityPubHttpUnicast, 'activitypub-http-unicast': processActivityPubHttpUnicast,
'activitypub-http-fetcher': processActivityPubHttpFetcher, 'activitypub-http-fetcher': processActivityPubHttpFetcher,
'activitypub-follow': processActivityPubFollow, 'activitypub-follow': processActivityPubFollow,
'video-file-import': processVideoImport, 'video-file-import': processVideoFileImport,
'video-file': processVideoFile, 'video-file': processVideoFile,
'email': processEmail 'email': processEmail
} }

View file

@ -2,7 +2,7 @@ import * as Bluebird from 'bluebird'
import { map, maxBy } from 'lodash' import { map, maxBy } from 'lodash'
import * as magnetUtil from 'magnet-uri' import * as magnetUtil from 'magnet-uri'
import * as parseTorrent from 'parse-torrent' import * as parseTorrent from 'parse-torrent'
import { join, extname } from 'path' import { extname, join } from 'path'
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
import { import {
AllowNull, AllowNull,
@ -30,9 +30,9 @@ import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos'
import { VideoFilter } from '../../../shared/models/videos/video-query.type' import { VideoFilter } from '../../../shared/models/videos/video-query.type'
import { import {
copyFilePromise,
createTorrentPromise, createTorrentPromise,
peertubeTruncate, peertubeTruncate,
copyFilePromise,
renamePromise, renamePromise,
statPromise, statPromise,
unlinkPromise, unlinkPromise,
@ -63,6 +63,7 @@ import {
STATIC_PATHS, STATIC_PATHS,
THUMBNAILS_SIZE, THUMBNAILS_SIZE,
VIDEO_CATEGORIES, VIDEO_CATEGORIES,
VIDEO_EXT_MIMETYPE,
VIDEO_LANGUAGES, VIDEO_LANGUAGES,
VIDEO_LICENCES, VIDEO_LICENCES,
VIDEO_PRIVACIES VIDEO_PRIVACIES
@ -1166,7 +1167,7 @@ export class VideoModel extends Model<VideoModel> {
for (const file of this.VideoFiles) { for (const file of this.VideoFiles) {
url.push({ url.push({
type: 'Link', type: 'Link',
mimeType: 'video/' + file.extname.replace('.', ''), mimeType: VIDEO_EXT_MIMETYPE[file.extname],
href: this.getVideoFileUrl(file, baseUrlHttp), href: this.getVideoFileUrl(file, baseUrlHttp),
width: file.resolution, width: file.resolution,
size: file.size size: file.size
@ -1328,14 +1329,18 @@ export class VideoModel extends Model<VideoModel> {
await copyFilePromise(inputFilePath, outputPath) await copyFilePromise(inputFilePath, outputPath)
const currentVideoFile = this.VideoFiles.find(videoFile => videoFile.resolution === updatedVideoFile.resolution) const currentVideoFile = this.VideoFiles.find(videoFile => videoFile.resolution === updatedVideoFile.resolution)
const isNewVideoFile = !currentVideoFile
if (!isNewVideoFile) { if (currentVideoFile) {
if (currentVideoFile.extname !== updatedVideoFile.extname) { // Remove old file and old torrent
await this.removeFile(currentVideoFile) await this.removeFile(currentVideoFile)
await this.removeTorrent(currentVideoFile)
// Remove the old video file from the array
this.VideoFiles = this.VideoFiles.filter(f => f !== currentVideoFile)
// Update the database
currentVideoFile.set('extname', updatedVideoFile.extname) currentVideoFile.set('extname', updatedVideoFile.extname)
}
currentVideoFile.set('size', updatedVideoFile.size) currentVideoFile.set('size', updatedVideoFile.size)
updatedVideoFile = currentVideoFile updatedVideoFile = currentVideoFile
} }
@ -1343,10 +1348,8 @@ export class VideoModel extends Model<VideoModel> {
await updatedVideoFile.save() await updatedVideoFile.save()
if (isNewVideoFile) {
this.VideoFiles.push(updatedVideoFile) this.VideoFiles.push(updatedVideoFile)
} }
}
getOriginalFileResolution () { getOriginalFileResolution () {
const originalFilePath = this.getVideoFilePath(this.getOriginalFile()) const originalFilePath = this.getVideoFilePath(this.getOriginalFile())

View file

@ -3,29 +3,31 @@
import 'mocha' import 'mocha'
import * as chai from 'chai' import * as chai from 'chai'
import { VideoDetails, VideoFile } from '../../../shared/models/videos' import { VideoDetails, VideoFile } from '../../../shared/models/videos'
const expect = chai.expect
import { import {
doubleFollow,
execCLI, execCLI,
flushAndRunMultipleServers,
flushTests, flushTests,
getEnvCli, getEnvCli,
getVideo,
getVideosList, getVideosList,
killallServers, killallServers,
parseTorrentVideo,
runServer,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
uploadVideo, uploadVideo,
wait, wait
getVideo, flushAndRunMultipleServers, doubleFollow
} from '../utils' } from '../utils'
function assertVideoProperties (video: VideoFile, resolution: number, extname: string) { const expect = chai.expect
function assertVideoProperties (video: VideoFile, resolution: number, extname: string, size?: number) {
expect(video).to.have.nested.property('resolution.id', resolution) expect(video).to.have.nested.property('resolution.id', resolution)
expect(video).to.have.property('magnetUri').that.includes(`.${extname}`) expect(video).to.have.property('magnetUri').that.includes(`.${extname}`)
expect(video).to.have.property('torrentUrl').that.includes(`-${resolution}.torrent`) expect(video).to.have.property('torrentUrl').that.includes(`-${resolution}.torrent`)
expect(video).to.have.property('fileUrl').that.includes(`.${extname}`) expect(video).to.have.property('fileUrl').that.includes(`.${extname}`)
expect(video).to.have.property('size').that.is.above(0) expect(video).to.have.property('size').that.is.above(0)
if (size) expect(video.size).to.equal(size)
} }
describe('Test create import video jobs', function () { describe('Test create import video jobs', function () {
@ -51,6 +53,7 @@ describe('Test create import video jobs', function () {
const res2 = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video2' }) const res2 = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video2' })
video2UUID = res2.body.video.uuid video2UUID = res2.body.video.uuid
// Transcoding
await wait(40000) await wait(40000)
}) })
@ -60,12 +63,11 @@ describe('Test create import video jobs', function () {
await wait(30000) await wait(30000)
let magnetUri: string
for (const server of servers) { for (const server of servers) {
const { data: videos } = (await getVideosList(server.url)).body const { data: videos } = (await getVideosList(server.url)).body
expect(videos).to.have.lengthOf(2) expect(videos).to.have.lengthOf(2)
let infoHashes: { [ id: number ]: string } = {}
const video = videos.find(({ uuid }) => uuid === video1UUID) const video = videos.find(({ uuid }) => uuid === video1UUID)
const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body
@ -73,6 +75,9 @@ describe('Test create import video jobs', function () {
const [originalVideo, transcodedVideo] = videoDetail.files const [originalVideo, transcodedVideo] = videoDetail.files
assertVideoProperties(originalVideo, 720, 'webm') assertVideoProperties(originalVideo, 720, 'webm')
assertVideoProperties(transcodedVideo, 480, 'webm') assertVideoProperties(transcodedVideo, 480, 'webm')
if (!magnetUri) magnetUri = transcodedVideo.magnetUri
else expect(transcodedVideo.magnetUri).to.equal(magnetUri)
} }
}) })
@ -82,21 +87,23 @@ describe('Test create import video jobs', function () {
await wait(30000) await wait(30000)
let magnetUri: string
for (const server of servers.reverse()) { for (const server of servers.reverse()) {
const { data: videos } = (await getVideosList(server.url)).body const { data: videos } = (await getVideosList(server.url)).body
expect(videos).to.have.lengthOf(2) expect(videos).to.have.lengthOf(2)
let infoHashes: { [ id: number ]: string }
const video = videos.find(({ uuid }) => uuid === video2UUID) const video = videos.find(({ uuid }) => uuid === video2UUID)
const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body
expect(videoDetail.files).to.have.lengthOf(4) expect(videoDetail.files).to.have.lengthOf(4)
const [originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240] = videoDetail.files const [originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240] = videoDetail.files
assertVideoProperties(originalVideo, 720, 'ogv') assertVideoProperties(originalVideo, 720, 'ogv', 140849)
assertVideoProperties(transcodedVideo420, 480, 'mp4') assertVideoProperties(transcodedVideo420, 480, 'mp4')
assertVideoProperties(transcodedVideo320, 360, 'mp4') assertVideoProperties(transcodedVideo320, 360, 'mp4')
assertVideoProperties(transcodedVideo240, 240, 'mp4') assertVideoProperties(transcodedVideo240, 240, 'mp4')
if (!magnetUri) magnetUri = originalVideo.magnetUri
else expect(originalVideo.magnetUri).to.equal(magnetUri)
} }
}) })