aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api/videos/import.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-08-06 17:13:39 +0200
committerChocobozzz <me@florianbigard.com>2018-08-08 09:30:31 +0200
commitce33919c24e7402d92d81f3cd8e545df52d98240 (patch)
tree7e131a2f8df649899d0a71294665cf386ffb50d4 /server/controllers/api/videos/import.ts
parent788487140c500abeb69ca44daf3a9e26efa8d36f (diff)
downloadPeerTube-ce33919c24e7402d92d81f3cd8e545df52d98240.tar.gz
PeerTube-ce33919c24e7402d92d81f3cd8e545df52d98240.tar.zst
PeerTube-ce33919c24e7402d92d81f3cd8e545df52d98240.zip
Import magnets with webtorrent
Diffstat (limited to 'server/controllers/api/videos/import.ts')
-rw-r--r--server/controllers/api/videos/import.ts142
1 files changed, 105 insertions, 37 deletions
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts
index 30a7d816c..c16a254d2 100644
--- a/server/controllers/api/videos/import.ts
+++ b/server/controllers/api/videos/import.ts
@@ -1,3 +1,4 @@
1import * as magnetUtil from 'magnet-uri'
1import * as express from 'express' 2import * as express from 'express'
2import { auditLoggerFactory, VideoImportAuditView } from '../../../helpers/audit-logger' 3import { auditLoggerFactory, VideoImportAuditView } from '../../../helpers/audit-logger'
3import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares' 4import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares'
@@ -13,6 +14,10 @@ import { VideoImportModel } from '../../../models/video/video-import'
13import { JobQueue } from '../../../lib/job-queue/job-queue' 14import { JobQueue } from '../../../lib/job-queue/job-queue'
14import { processImage } from '../../../helpers/image-utils' 15import { processImage } from '../../../helpers/image-utils'
15import { join } from 'path' 16import { join } from 'path'
17import { isArray } from '../../../helpers/custom-validators/misc'
18import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model'
19import { VideoChannelModel } from '../../../models/video/video-channel'
20import * as Bluebird from 'bluebird'
16 21
17const auditLogger = auditLoggerFactory('video-imports') 22const auditLogger = auditLoggerFactory('video-imports')
18const videoImportsRouter = express.Router() 23const videoImportsRouter = express.Router()
@@ -41,7 +46,45 @@ export {
41 46
42// --------------------------------------------------------------------------- 47// ---------------------------------------------------------------------------
43 48
44async function addVideoImport (req: express.Request, res: express.Response) { 49function addVideoImport (req: express.Request, res: express.Response) {
50 if (req.body.targetUrl) return addYoutubeDLImport(req, res)
51
52 if (req.body.magnetUri) return addTorrentImport(req, res)
53}
54
55async function addTorrentImport (req: express.Request, res: express.Response) {
56 const body: VideoImportCreate = req.body
57 const magnetUri = body.magnetUri
58
59 const parsed = magnetUtil.decode(magnetUri)
60 const magnetName = isArray(parsed.name) ? parsed.name[0] : parsed.name as string
61
62 const video = buildVideo(res.locals.videoChannel.id, body, { name: magnetName })
63
64 await processThumbnail(req, video)
65 await processPreview(req, video)
66
67 const tags = null
68 const videoImportAttributes = {
69 magnetUri,
70 state: VideoImportState.PENDING
71 }
72 const videoImport: VideoImportModel = await insertIntoDB(video, res.locals.videoChannel, tags, videoImportAttributes)
73
74 // Create job to import the video
75 const payload = {
76 type: 'magnet-uri' as 'magnet-uri',
77 videoImportId: videoImport.id,
78 magnetUri
79 }
80 await JobQueue.Instance.createJob({ type: 'video-import', payload })
81
82 auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoImportAuditView(videoImport.toFormattedJSON()))
83
84 return res.json(videoImport.toFormattedJSON()).end()
85}
86
87async function addYoutubeDLImport (req: express.Request, res: express.Response) {
45 const body: VideoImportCreate = req.body 88 const body: VideoImportCreate = req.body
46 const targetUrl = body.targetUrl 89 const targetUrl = body.targetUrl
47 90
@@ -56,53 +99,94 @@ async function addVideoImport (req: express.Request, res: express.Response) {
56 }).end() 99 }).end()
57 } 100 }
58 101
59 // Create video DB object 102 const video = buildVideo(res.locals.videoChannel.id, body, youtubeDLInfo)
103
104 const downloadThumbnail = !await processThumbnail(req, video)
105 const downloadPreview = !await processPreview(req, video)
106
107 const tags = body.tags || youtubeDLInfo.tags
108 const videoImportAttributes = {
109 targetUrl,
110 state: VideoImportState.PENDING
111 }
112 const videoImport: VideoImportModel = await insertIntoDB(video, res.locals.videoChannel, tags, videoImportAttributes)
113
114 // Create job to import the video
115 const payload = {
116 type: 'youtube-dl' as 'youtube-dl',
117 videoImportId: videoImport.id,
118 thumbnailUrl: youtubeDLInfo.thumbnailUrl,
119 downloadThumbnail,
120 downloadPreview
121 }
122 await JobQueue.Instance.createJob({ type: 'video-import', payload })
123
124 auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoImportAuditView(videoImport.toFormattedJSON()))
125
126 return res.json(videoImport.toFormattedJSON()).end()
127}
128
129function buildVideo (channelId: number, body: VideoImportCreate, importData: YoutubeDLInfo) {
60 const videoData = { 130 const videoData = {
61 name: body.name || youtubeDLInfo.name, 131 name: body.name || importData.name || 'Unknown name',
62 remote: false, 132 remote: false,
63 category: body.category || youtubeDLInfo.category, 133 category: body.category || importData.category,
64 licence: body.licence || youtubeDLInfo.licence, 134 licence: body.licence || importData.licence,
65 language: body.language || undefined, 135 language: body.language || undefined,
66 commentsEnabled: body.commentsEnabled || true, 136 commentsEnabled: body.commentsEnabled || true,
67 waitTranscoding: body.waitTranscoding || false, 137 waitTranscoding: body.waitTranscoding || false,
68 state: VideoState.TO_IMPORT, 138 state: VideoState.TO_IMPORT,
69 nsfw: body.nsfw || youtubeDLInfo.nsfw || false, 139 nsfw: body.nsfw || importData.nsfw || false,
70 description: body.description || youtubeDLInfo.description, 140 description: body.description || importData.description,
71 support: body.support || null, 141 support: body.support || null,
72 privacy: body.privacy || VideoPrivacy.PRIVATE, 142 privacy: body.privacy || VideoPrivacy.PRIVATE,
73 duration: 0, // duration will be set by the import job 143 duration: 0, // duration will be set by the import job
74 channelId: res.locals.videoChannel.id 144 channelId: channelId
75 } 145 }
76 const video = new VideoModel(videoData) 146 const video = new VideoModel(videoData)
77 video.url = getVideoActivityPubUrl(video) 147 video.url = getVideoActivityPubUrl(video)
78 148
79 // Process thumbnail file? 149 return video
150}
151
152async function processThumbnail (req: express.Request, video: VideoModel) {
80 const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined 153 const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined
81 let downloadThumbnail = true
82 if (thumbnailField) { 154 if (thumbnailField) {
83 const thumbnailPhysicalFile = thumbnailField[ 0 ] 155 const thumbnailPhysicalFile = thumbnailField[ 0 ]
84 await processImage(thumbnailPhysicalFile, join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName()), THUMBNAILS_SIZE) 156 await processImage(thumbnailPhysicalFile, join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName()), THUMBNAILS_SIZE)
85 downloadThumbnail = false 157
158 return true
86 } 159 }
87 160
88 // Process preview file? 161 return false
162}
163
164async function processPreview (req: express.Request, video: VideoModel) {
89 const previewField = req.files ? req.files['previewfile'] : undefined 165 const previewField = req.files ? req.files['previewfile'] : undefined
90 let downloadPreview = true
91 if (previewField) { 166 if (previewField) {
92 const previewPhysicalFile = previewField[0] 167 const previewPhysicalFile = previewField[0]
93 await processImage(previewPhysicalFile, join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName()), PREVIEWS_SIZE) 168 await processImage(previewPhysicalFile, join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName()), PREVIEWS_SIZE)
94 downloadPreview = false 169
170 return true
95 } 171 }
96 172
97 const videoImport: VideoImportModel = await sequelizeTypescript.transaction(async t => { 173 return false
174}
175
176function insertIntoDB (
177 video: VideoModel,
178 videoChannel: VideoChannelModel,
179 tags: string[],
180 videoImportAttributes: FilteredModelAttributes<VideoImportModel>
181): Bluebird<VideoImportModel> {
182 return sequelizeTypescript.transaction(async t => {
98 const sequelizeOptions = { transaction: t } 183 const sequelizeOptions = { transaction: t }
99 184
100 // Save video object in database 185 // Save video object in database
101 const videoCreated = await video.save(sequelizeOptions) 186 const videoCreated = await video.save(sequelizeOptions)
102 videoCreated.VideoChannel = res.locals.videoChannel 187 videoCreated.VideoChannel = videoChannel
103 188
104 // Set tags to the video 189 // Set tags to the video
105 const tags = body.tags ? body.tags : youtubeDLInfo.tags
106 if (tags !== undefined) { 190 if (tags !== undefined) {
107 const tagInstances = await TagModel.findOrCreateTags(tags, t) 191 const tagInstances = await TagModel.findOrCreateTags(tags, t)
108 192
@@ -111,28 +195,12 @@ async function addVideoImport (req: express.Request, res: express.Response) {
111 } 195 }
112 196
113 // Create video import object in database 197 // Create video import object in database
114 const videoImport = await VideoImportModel.create({ 198 const videoImport = await VideoImportModel.create(
115 targetUrl, 199 Object.assign({ videoId: videoCreated.id }, videoImportAttributes),
116 state: VideoImportState.PENDING, 200 sequelizeOptions
117 videoId: videoCreated.id 201 )
118 }, sequelizeOptions)
119
120 videoImport.Video = videoCreated 202 videoImport.Video = videoCreated
121 203
122 return videoImport 204 return videoImport
123 }) 205 })
124
125 // Create job to import the video
126 const payload = {
127 type: 'youtube-dl' as 'youtube-dl',
128 videoImportId: videoImport.id,
129 thumbnailUrl: youtubeDLInfo.thumbnailUrl,
130 downloadThumbnail,
131 downloadPreview
132 }
133 await JobQueue.Instance.createJob({ type: 'video-import', payload })
134
135 auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoImportAuditView(videoImport.toFormattedJSON()))
136
137 return res.json(videoImport.toFormattedJSON()).end()
138} 206}