1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
import * as express from 'express'
import { auditLoggerFactory, VideoImportAuditView } from '../../../helpers/audit-logger'
import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares'
import { CONFIG, IMAGE_MIMETYPE_EXT, PREVIEWS_SIZE, sequelizeTypescript, THUMBNAILS_SIZE } from '../../../initializers'
import { getYoutubeDLInfo, YoutubeDLInfo } from '../../../helpers/youtube-dl'
import { createReqFiles } from '../../../helpers/express-utils'
import { logger } from '../../../helpers/logger'
import { VideoImportCreate, VideoImportState, VideoPrivacy, VideoState } from '../../../../shared'
import { VideoModel } from '../../../models/video/video'
import { getVideoActivityPubUrl } from '../../../lib/activitypub'
import { TagModel } from '../../../models/video/tag'
import { VideoImportModel } from '../../../models/video/video-import'
import { JobQueue } from '../../../lib/job-queue/job-queue'
import { processImage } from '../../../helpers/image-utils'
import { join } from 'path'
const auditLogger = auditLoggerFactory('video-imports')
const videoImportsRouter = express.Router()
const reqVideoFileImport = createReqFiles(
[ 'thumbnailfile', 'previewfile' ],
IMAGE_MIMETYPE_EXT,
{
thumbnailfile: CONFIG.STORAGE.THUMBNAILS_DIR,
previewfile: CONFIG.STORAGE.PREVIEWS_DIR
}
)
videoImportsRouter.post('/imports',
authenticate,
reqVideoFileImport,
asyncMiddleware(videoImportAddValidator),
asyncRetryTransactionMiddleware(addVideoImport)
)
// ---------------------------------------------------------------------------
export {
videoImportsRouter
}
// ---------------------------------------------------------------------------
async function addVideoImport (req: express.Request, res: express.Response) {
const body: VideoImportCreate = req.body
const targetUrl = body.targetUrl
let youtubeDLInfo: YoutubeDLInfo
try {
youtubeDLInfo = await getYoutubeDLInfo(targetUrl)
} catch (err) {
logger.info('Cannot fetch information from import for URL %s.', targetUrl, { err })
return res.status(400).json({
error: 'Cannot fetch remote information of this URL.'
}).end()
}
// Create video DB object
const videoData = {
name: body.name || youtubeDLInfo.name,
remote: false,
category: body.category || youtubeDLInfo.category,
licence: body.licence || youtubeDLInfo.licence,
language: body.language || undefined,
commentsEnabled: body.commentsEnabled || true,
waitTranscoding: body.waitTranscoding || false,
state: VideoState.TO_IMPORT,
nsfw: body.nsfw || youtubeDLInfo.nsfw || false,
description: body.description || youtubeDLInfo.description,
support: body.support || null,
privacy: body.privacy || VideoPrivacy.PRIVATE,
duration: 0, // duration will be set by the import job
channelId: res.locals.videoChannel.id
}
const video = new VideoModel(videoData)
video.url = getVideoActivityPubUrl(video)
// Process thumbnail file?
const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined
let downloadThumbnail = true
if (thumbnailField) {
const thumbnailPhysicalFile = thumbnailField[ 0 ]
await processImage(thumbnailPhysicalFile, join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName()), THUMBNAILS_SIZE)
downloadThumbnail = false
}
// Process preview file?
const previewField = req.files ? req.files['previewfile'] : undefined
let downloadPreview = true
if (previewField) {
const previewPhysicalFile = previewField[0]
await processImage(previewPhysicalFile, join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName()), PREVIEWS_SIZE)
downloadPreview = false
}
const videoImport: VideoImportModel = await sequelizeTypescript.transaction(async t => {
const sequelizeOptions = { transaction: t }
// Save video object in database
const videoCreated = await video.save(sequelizeOptions)
videoCreated.VideoChannel = res.locals.videoChannel
// Set tags to the video
const tags = body.tags ? body.tags : youtubeDLInfo.tags
if (tags !== undefined) {
const tagInstances = await TagModel.findOrCreateTags(tags, t)
await videoCreated.$set('Tags', tagInstances, sequelizeOptions)
videoCreated.Tags = tagInstances
}
// Create video import object in database
const videoImport = await VideoImportModel.create({
targetUrl,
state: VideoImportState.PENDING,
videoId: videoCreated.id
}, sequelizeOptions)
videoImport.Video = videoCreated
return videoImport
})
// Create job to import the video
const payload = {
type: 'youtube-dl' as 'youtube-dl',
videoImportId: videoImport.id,
thumbnailUrl: youtubeDLInfo.thumbnailUrl,
downloadThumbnail,
downloadPreview
}
await JobQueue.Instance.createJob({ type: 'video-import', payload })
auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoImportAuditView(videoImport.toFormattedJSON()))
return res.json(videoImport.toFormattedJSON()).end()
}
|