Add getSubs to YoutubeDL video import

pull/2629/head
kimsible 2020-04-11 04:24:42 +02:00
parent 5def04e17f
commit 50ad0a1c16
3 changed files with 100 additions and 23 deletions

View File

@ -12,6 +12,7 @@ import { FormValidatorService } from '@app/shared'
import { VideoCaptionService } from '@app/shared/video-caption'
import { VideoImportService } from '@app/shared/video-import'
import { scrollToTop } from '@app/shared/misc/utils'
import { switchMap, map } from 'rxjs/operators'
@Component({
selector: 'my-video-import-url',
@ -76,31 +77,44 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
this.loadingBar.start()
this.videoImportService.importVideoUrl(this.targetUrl, videoUpdate).subscribe(
res => {
this.loadingBar.complete()
this.firstStepDone.emit(res.video.name)
this.isImportingVideo = false
this.hasImportedVideo = true
this.videoImportService
.importVideoUrl(this.targetUrl, videoUpdate)
.pipe(
switchMap(res => {
return this.videoCaptionService
.listCaptions(res.video.id)
.pipe(
map(result => ({ video: res.video, videoCaptions: result.data }))
)
})
)
.subscribe(
({ video, videoCaptions }) => {
this.loadingBar.complete()
this.firstStepDone.emit(video.name)
this.isImportingVideo = false
this.hasImportedVideo = true
this.video = new VideoEdit(Object.assign(res.video, {
commentsEnabled: videoUpdate.commentsEnabled,
downloadEnabled: videoUpdate.downloadEnabled,
support: null,
thumbnailUrl: null,
previewUrl: null
}))
this.video = new VideoEdit(Object.assign(video, {
commentsEnabled: videoUpdate.commentsEnabled,
downloadEnabled: videoUpdate.downloadEnabled,
support: null,
thumbnailUrl: null,
previewUrl: null
}))
this.hydrateFormFromVideo()
},
this.videoCaptions = videoCaptions
err => {
this.loadingBar.complete()
this.isImportingVideo = false
this.firstStepError.emit()
this.notifier.error(err.message)
}
)
this.hydrateFormFromVideo()
},
err => {
this.loadingBar.complete()
this.isImportingVideo = false
this.firstStepError.emit()
this.notifier.error(err.message)
}
)
}
updateSecondStep () {

View File

@ -3,11 +3,13 @@ import * as magnetUtil from 'magnet-uri'
import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger'
import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares'
import { MIMETYPES } from '../../../initializers/constants'
import { getYoutubeDLInfo, YoutubeDLInfo } from '../../../helpers/youtube-dl'
import { getYoutubeDLInfo, YoutubeDLInfo, getYoutubeDLSubs } 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 { VideoCaptionModel } from '../../../models/video/video-caption'
import { moveAndProcessCaptionFile } from '../../../helpers/captions-utils'
import { getVideoActivityPubUrl } from '../../../lib/activitypub'
import { TagModel } from '../../../models/video/tag'
import { VideoImportModel } from '../../../models/video/video-import'
@ -28,6 +30,7 @@ import {
MThumbnail,
MUser,
MVideoAccountDefault,
MVideoCaptionVideo,
MVideoTag,
MVideoThumbnailAccountDefault,
MVideoWithBlacklistLight
@ -136,6 +139,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response)
const targetUrl = body.targetUrl
const user = res.locals.oauth.token.User
// Get video infos
let youtubeDLInfo: YoutubeDLInfo
try {
youtubeDLInfo = await getYoutubeDLInfo(targetUrl)
@ -168,6 +172,29 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response)
user
})
// Get video subtitles
try {
const subtitles = await getYoutubeDLSubs(targetUrl)
for (const subtitle of subtitles) {
const videoCaption = new VideoCaptionModel({
videoId: video.id,
language: subtitle.language
}) as MVideoCaptionVideo
videoCaption.Video = video
// Move physical file
await moveAndProcessCaptionFile(subtitle, videoCaption)
await sequelizeTypescript.transaction(async t => {
await VideoCaptionModel.insertOrReplaceLanguage(video.id, subtitle.language, null, t)
})
}
} catch (err) {
logger.warn('Cannot get video subtitles.', { err })
}
// Create job to import the video
const payload = {
type: 'youtube-dl' as 'youtube-dl',

View File

@ -20,6 +20,12 @@ export type YoutubeDLInfo = {
originallyPublishedAt?: Date
}
export type YoutubeDLSubs = {
language: string,
filename: string,
path: string
}[]
const processOptions = {
maxBuffer: 1024 * 1024 * 10 // 10MB
}
@ -45,6 +51,35 @@ function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo>
})
}
function getYoutubeDLSubs (url: string, opts?: object): Promise<YoutubeDLSubs> {
return new Promise<YoutubeDLSubs>((res, rej) => {
const cwd = CONFIG.STORAGE.TMP_DIR
const options = opts || { all: true, format: 'vtt', cwd }
safeGetYoutubeDL()
.then(youtubeDL => {
youtubeDL.getSubs(url, options, (err, files) => {
if (err) return rej(err)
const subtitles = files.reduce((acc, filename) => {
const matched = filename.match(/\.([a-z]{2})\.(vtt|ttml)/i)
if (matched[1]) {
return [...acc, {
language: matched[1],
path: join(cwd, filename),
filename
}]
}
}, [])
return res(subtitles)
})
})
.catch(err => rej(err))
})
}
function downloadYoutubeDLVideo (url: string, extension: string, timeout: number) {
const path = generateVideoImportTmpPath(url, extension)
let timer
@ -185,6 +220,7 @@ function buildOriginallyPublishedAt (obj: any) {
export {
updateYoutubeDLBinary,
downloadYoutubeDLVideo,
getYoutubeDLSubs,
getYoutubeDLInfo,
safeGetYoutubeDL,
buildOriginallyPublishedAt