diff options
Diffstat (limited to 'server/helpers/youtube-dl/youtube-dl-wrapper.ts')
-rw-r--r-- | server/helpers/youtube-dl/youtube-dl-wrapper.ts | 154 |
1 files changed, 0 insertions, 154 deletions
diff --git a/server/helpers/youtube-dl/youtube-dl-wrapper.ts b/server/helpers/youtube-dl/youtube-dl-wrapper.ts deleted file mode 100644 index ac3cd190e..000000000 --- a/server/helpers/youtube-dl/youtube-dl-wrapper.ts +++ /dev/null | |||
@@ -1,154 +0,0 @@ | |||
1 | import { move, pathExists, readdir, remove } from 'fs-extra' | ||
2 | import { dirname, join } from 'path' | ||
3 | import { inspect } from 'util' | ||
4 | import { CONFIG } from '@server/initializers/config' | ||
5 | import { isVideoFileExtnameValid } from '../custom-validators/videos' | ||
6 | import { logger, loggerTagsFactory } from '../logger' | ||
7 | import { generateVideoImportTmpPath } from '../utils' | ||
8 | import { YoutubeDLCLI } from './youtube-dl-cli' | ||
9 | import { YoutubeDLInfo, YoutubeDLInfoBuilder } from './youtube-dl-info-builder' | ||
10 | |||
11 | const lTags = loggerTagsFactory('youtube-dl') | ||
12 | |||
13 | export type YoutubeDLSubs = { | ||
14 | language: string | ||
15 | filename: string | ||
16 | path: string | ||
17 | }[] | ||
18 | |||
19 | const processOptions = { | ||
20 | maxBuffer: 1024 * 1024 * 30 // 30MB | ||
21 | } | ||
22 | |||
23 | class YoutubeDLWrapper { | ||
24 | |||
25 | constructor ( | ||
26 | private readonly url: string, | ||
27 | private readonly enabledResolutions: number[], | ||
28 | private readonly useBestFormat: boolean | ||
29 | ) { | ||
30 | |||
31 | } | ||
32 | |||
33 | async getInfoForDownload (youtubeDLArgs: string[] = []): Promise<YoutubeDLInfo> { | ||
34 | const youtubeDL = await YoutubeDLCLI.safeGet() | ||
35 | |||
36 | const info = await youtubeDL.getInfo({ | ||
37 | url: this.url, | ||
38 | format: YoutubeDLCLI.getYoutubeDLVideoFormat(this.enabledResolutions, this.useBestFormat), | ||
39 | additionalYoutubeDLArgs: youtubeDLArgs, | ||
40 | processOptions | ||
41 | }) | ||
42 | |||
43 | if (!info) throw new Error(`YoutubeDL could not get info from ${this.url}`) | ||
44 | |||
45 | if (info.is_live === true) throw new Error('Cannot download a live streaming.') | ||
46 | |||
47 | const infoBuilder = new YoutubeDLInfoBuilder(info) | ||
48 | |||
49 | return infoBuilder.getInfo() | ||
50 | } | ||
51 | |||
52 | async getInfoForListImport (options: { | ||
53 | latestVideosCount?: number | ||
54 | }) { | ||
55 | const youtubeDL = await YoutubeDLCLI.safeGet() | ||
56 | |||
57 | const list = await youtubeDL.getListInfo({ | ||
58 | url: this.url, | ||
59 | latestVideosCount: options.latestVideosCount, | ||
60 | processOptions | ||
61 | }) | ||
62 | |||
63 | if (!Array.isArray(list)) throw new Error(`YoutubeDL could not get list info from ${this.url}: ${inspect(list)}`) | ||
64 | |||
65 | return list.map(info => info.webpage_url) | ||
66 | } | ||
67 | |||
68 | async getSubtitles (): Promise<YoutubeDLSubs> { | ||
69 | const cwd = CONFIG.STORAGE.TMP_DIR | ||
70 | |||
71 | const youtubeDL = await YoutubeDLCLI.safeGet() | ||
72 | |||
73 | const files = await youtubeDL.getSubs({ url: this.url, format: 'vtt', processOptions: { cwd } }) | ||
74 | if (!files) return [] | ||
75 | |||
76 | logger.debug('Get subtitles from youtube dl.', { url: this.url, files, ...lTags() }) | ||
77 | |||
78 | const subtitles = files.reduce((acc, filename) => { | ||
79 | const matched = filename.match(/\.([a-z]{2})(-[a-z]+)?\.(vtt|ttml)/i) | ||
80 | if (!matched?.[1]) return acc | ||
81 | |||
82 | return [ | ||
83 | ...acc, | ||
84 | { | ||
85 | language: matched[1], | ||
86 | path: join(cwd, filename), | ||
87 | filename | ||
88 | } | ||
89 | ] | ||
90 | }, []) | ||
91 | |||
92 | return subtitles | ||
93 | } | ||
94 | |||
95 | async downloadVideo (fileExt: string, timeout: number): Promise<string> { | ||
96 | // Leave empty the extension, youtube-dl will add it | ||
97 | const pathWithoutExtension = generateVideoImportTmpPath(this.url, '') | ||
98 | |||
99 | logger.info('Importing youtubeDL video %s to %s', this.url, pathWithoutExtension, lTags()) | ||
100 | |||
101 | const youtubeDL = await YoutubeDLCLI.safeGet() | ||
102 | |||
103 | try { | ||
104 | await youtubeDL.download({ | ||
105 | url: this.url, | ||
106 | format: YoutubeDLCLI.getYoutubeDLVideoFormat(this.enabledResolutions, this.useBestFormat), | ||
107 | output: pathWithoutExtension, | ||
108 | timeout, | ||
109 | processOptions | ||
110 | }) | ||
111 | |||
112 | // If youtube-dl did not guess an extension for our file, just use .mp4 as default | ||
113 | if (await pathExists(pathWithoutExtension)) { | ||
114 | await move(pathWithoutExtension, pathWithoutExtension + '.mp4') | ||
115 | } | ||
116 | |||
117 | return this.guessVideoPathWithExtension(pathWithoutExtension, fileExt) | ||
118 | } catch (err) { | ||
119 | this.guessVideoPathWithExtension(pathWithoutExtension, fileExt) | ||
120 | .then(path => { | ||
121 | logger.debug('Error in youtube-dl import, deleting file %s.', path, { err, ...lTags() }) | ||
122 | |||
123 | return remove(path) | ||
124 | }) | ||
125 | .catch(innerErr => logger.error('Cannot remove file in youtubeDL error.', { innerErr, ...lTags() })) | ||
126 | |||
127 | throw err | ||
128 | } | ||
129 | } | ||
130 | |||
131 | private async guessVideoPathWithExtension (tmpPath: string, sourceExt: string) { | ||
132 | if (!isVideoFileExtnameValid(sourceExt)) { | ||
133 | throw new Error('Invalid video extension ' + sourceExt) | ||
134 | } | ||
135 | |||
136 | const extensions = [ sourceExt, '.mp4', '.mkv', '.webm' ] | ||
137 | |||
138 | for (const extension of extensions) { | ||
139 | const path = tmpPath + extension | ||
140 | |||
141 | if (await pathExists(path)) return path | ||
142 | } | ||
143 | |||
144 | const directoryContent = await readdir(dirname(tmpPath)) | ||
145 | |||
146 | throw new Error(`Cannot guess path of ${tmpPath}. Directory content: ${directoryContent.join(', ')}`) | ||
147 | } | ||
148 | } | ||
149 | |||
150 | // --------------------------------------------------------------------------- | ||
151 | |||
152 | export { | ||
153 | YoutubeDLWrapper | ||
154 | } | ||