aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tools/peertube-import-videos.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/tools/peertube-import-videos.ts')
-rw-r--r--server/tools/peertube-import-videos.ts145
1 files changed, 89 insertions, 56 deletions
diff --git a/server/tools/peertube-import-videos.ts b/server/tools/peertube-import-videos.ts
index 9a366dbbd..f9cd3106a 100644
--- a/server/tools/peertube-import-videos.ts
+++ b/server/tools/peertube-import-videos.ts
@@ -14,8 +14,10 @@ import { sha256 } from '../helpers/core-utils'
14import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' 14import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl'
15import { getNetrc, getRemoteObjectOrDie, getSettings } from './cli' 15import { getNetrc, getRemoteObjectOrDie, getSettings } from './cli'
16 16
17let accessToken: string 17type UserInfo = {
18let client: { id: string, secret: string } 18 username: string
19 password: string
20}
19 21
20const processOptions = { 22const processOptions = {
21 cwd: __dirname, 23 cwd: __dirname,
@@ -28,13 +30,14 @@ program
28 .option('-U, --username <username>', 'Username') 30 .option('-U, --username <username>', 'Username')
29 .option('-p, --password <token>', 'Password') 31 .option('-p, --password <token>', 'Password')
30 .option('-t, --target-url <targetUrl>', 'Video target URL') 32 .option('-t, --target-url <targetUrl>', 'Video target URL')
33 .option('-C, --channel-id <channel_id>', 'Channel ID')
31 .option('-l, --language <languageCode>', 'Language ISO 639 code (fr or en...)') 34 .option('-l, --language <languageCode>', 'Language ISO 639 code (fr or en...)')
32 .option('-v, --verbose', 'Verbose mode') 35 .option('-v, --verbose', 'Verbose mode')
33 .parse(process.argv) 36 .parse(process.argv)
34 37
35Promise.all([ getSettings(), getNetrc() ]) 38Promise.all([ getSettings(), getNetrc() ])
36 .then(([ settings, netrc ]) => { 39 .then(([ settings, netrc ]) => {
37 const { url, username, password } = getRemoteObjectOrDie(program, settings) 40 const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc)
38 41
39 if (!program[ 'targetUrl' ]) { 42 if (!program[ 'targetUrl' ]) {
40 console.error('--targetUrl field is required.') 43 console.error('--targetUrl field is required.')
@@ -45,56 +48,20 @@ Promise.all([ getSettings(), getNetrc() ])
45 removeEndSlashes(url) 48 removeEndSlashes(url)
46 removeEndSlashes(program[ 'targetUrl' ]) 49 removeEndSlashes(program[ 'targetUrl' ])
47 50
48 const user = { 51 const user = { username, password }
49 username: username,
50 password: password
51 }
52 52
53 run(user, url) 53 run(url, user)
54 .catch(err => { 54 .catch(err => {
55 console.error(err) 55 console.error(err)
56 process.exit(-1) 56 process.exit(-1)
57 }) 57 })
58 }) 58 })
59 59
60async function promptPassword () { 60async function run (url: string, user: UserInfo) {
61 return new Promise((res, rej) => {
62 prompt.start()
63 const schema = {
64 properties: {
65 password: {
66 hidden: true,
67 required: true
68 }
69 }
70 }
71 prompt.get(schema, function (err, result) {
72 if (err) {
73 return rej(err)
74 }
75 return res(result.password)
76 })
77 })
78}
79
80async function run (user, url: string) {
81 if (!user.password) { 61 if (!user.password) {
82 user.password = await promptPassword() 62 user.password = await promptPassword()
83 } 63 }
84 64
85 const res = await getClient(url)
86 client = {
87 id: res.body.client_id,
88 secret: res.body.client_secret
89 }
90
91 try {
92 const res = await login(program[ 'url' ], client, user)
93 accessToken = res.body.access_token
94 } catch (err) {
95 throw new Error('Cannot authenticate. Please check your username/password.')
96 }
97
98 const youtubeDL = await safeGetYoutubeDL() 65 const youtubeDL = await safeGetYoutubeDL()
99 66
100 const options = [ '-j', '--flat-playlist', '--playlist-reverse' ] 67 const options = [ '-j', '--flat-playlist', '--playlist-reverse' ]
@@ -115,7 +82,12 @@ async function run (user, url: string) {
115 console.log('Will download and upload %d videos.\n', infoArray.length) 82 console.log('Will download and upload %d videos.\n', infoArray.length)
116 83
117 for (const info of infoArray) { 84 for (const info of infoArray) {
118 await processVideo(info, program[ 'language' ], processOptions.cwd, url, user) 85 await processVideo({
86 cwd: processOptions.cwd,
87 url,
88 user,
89 youtubeInfo: info
90 })
119 } 91 }
120 92
121 console.log('Video/s for user %s imported: %s', program[ 'username' ], program[ 'targetUrl' ]) 93 console.log('Video/s for user %s imported: %s', program[ 'username' ], program[ 'targetUrl' ])
@@ -123,11 +95,18 @@ async function run (user, url: string) {
123 }) 95 })
124} 96}
125 97
126function processVideo (info: any, languageCode: string, cwd: string, url: string, user) { 98function processVideo (parameters: {
99 cwd: string,
100 url: string,
101 user: { username: string, password: string },
102 youtubeInfo: any
103}) {
104 const { youtubeInfo, cwd, url, user } = parameters
105
127 return new Promise(async res => { 106 return new Promise(async res => {
128 if (program[ 'verbose' ]) console.log('Fetching object.', info) 107 if (program[ 'verbose' ]) console.log('Fetching object.', youtubeInfo)
129 108
130 const videoInfo = await fetchObject(info) 109 const videoInfo = await fetchObject(youtubeInfo)
131 if (program[ 'verbose' ]) console.log('Fetched object.', videoInfo) 110 if (program[ 'verbose' ]) console.log('Fetched object.', videoInfo)
132 111
133 const result = await searchVideoWithSort(url, videoInfo.title, '-match') 112 const result = await searchVideoWithSort(url, videoInfo.title, '-match')
@@ -153,7 +132,13 @@ function processVideo (info: any, languageCode: string, cwd: string, url: string
153 } 132 }
154 133
155 console.log(output.join('\n')) 134 console.log(output.join('\n'))
156 await uploadVideoOnPeerTube(normalizeObject(videoInfo), path, cwd, url, user, languageCode) 135 await uploadVideoOnPeerTube({
136 cwd,
137 url,
138 user,
139 videoInfo: normalizeObject(videoInfo),
140 videoPath: path
141 })
157 return res() 142 return res()
158 }) 143 })
159 } catch (err) { 144 } catch (err) {
@@ -163,7 +148,15 @@ function processVideo (info: any, languageCode: string, cwd: string, url: string
163 }) 148 })
164} 149}
165 150
166async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: string, url: string, user, language?: string) { 151async function uploadVideoOnPeerTube (parameters: {
152 videoInfo: any,
153 videoPath: string,
154 cwd: string,
155 url: string,
156 user: { username: string; password: string }
157}) {
158 const { videoInfo, videoPath, cwd, url, user } = parameters
159
167 const category = await getCategory(videoInfo.categories, url) 160 const category = await getCategory(videoInfo.categories, url)
168 const licence = getLicence(videoInfo.license) 161 const licence = getLicence(videoInfo.license)
169 let tags = [] 162 let tags = []
@@ -194,7 +187,7 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st
194 }), 187 }),
195 category, 188 category,
196 licence, 189 licence,
197 language, 190 language: program[ 'language' ],
198 nsfw: isNSFW(videoInfo), 191 nsfw: isNSFW(videoInfo),
199 waitTranscoding: true, 192 waitTranscoding: true,
200 commentsEnabled: true, 193 commentsEnabled: true,
@@ -209,15 +202,21 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st
209 originallyPublishedAt: originallyPublishedAt ? originallyPublishedAt.toISOString() : null 202 originallyPublishedAt: originallyPublishedAt ? originallyPublishedAt.toISOString() : null
210 } 203 }
211 204
205 if (program[ 'channelId' ]) {
206 Object.assign(videoAttributes, { channelId: program['channelId'] })
207 }
208
212 console.log('\nUploading on PeerTube video "%s".', videoAttributes.name) 209 console.log('\nUploading on PeerTube video "%s".', videoAttributes.name)
210
211 let accessToken = await getAccessTokenOrDie(url, user)
212
213 try { 213 try {
214 await uploadVideo(url, accessToken, videoAttributes) 214 await uploadVideo(url, accessToken, videoAttributes)
215 } catch (err) { 215 } catch (err) {
216 if (err.message.indexOf('401') !== -1) { 216 if (err.message.indexOf('401') !== -1) {
217 console.log('Got 401 Unauthorized, token may have expired, renewing token and retry.') 217 console.log('Got 401 Unauthorized, token may have expired, renewing token and retry.')
218 218
219 const res = await login(url, client, user) 219 accessToken = await getAccessTokenOrDie(url, user)
220 accessToken = res.body.access_token
221 220
222 await uploadVideo(url, accessToken, videoAttributes) 221 await uploadVideo(url, accessToken, videoAttributes)
223 } else { 222 } else {
@@ -232,6 +231,8 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st
232 console.log('Uploaded video "%s"!\n', videoAttributes.name) 231 console.log('Uploaded video "%s"!\n', videoAttributes.name)
233} 232}
234 233
234/* ---------------------------------------------------------- */
235
235async function getCategory (categories: string[], url: string) { 236async function getCategory (categories: string[], url: string) {
236 if (!categories) return undefined 237 if (!categories) return undefined
237 238
@@ -250,8 +251,6 @@ async function getCategory (categories: string[], url: string) {
250 return undefined 251 return undefined
251} 252}
252 253
253/* ---------------------------------------------------------- */
254
255function getLicence (licence: string) { 254function getLicence (licence: string) {
256 if (!licence) return undefined 255 if (!licence) return undefined
257 256
@@ -305,9 +304,7 @@ function buildUrl (info: any) {
305} 304}
306 305
307function isNSFW (info: any) { 306function isNSFW (info: any) {
308 if (info.age_limit && info.age_limit >= 16) return true 307 return info.age_limit && info.age_limit >= 16
309
310 return false
311} 308}
312 309
313function removeEndSlashes (url: string) { 310function removeEndSlashes (url: string) {
@@ -315,3 +312,39 @@ function removeEndSlashes (url: string) {
315 url.slice(0, -1) 312 url.slice(0, -1)
316 } 313 }
317} 314}
315
316async function promptPassword () {
317 return new Promise<string>((res, rej) => {
318 prompt.start()
319 const schema = {
320 properties: {
321 password: {
322 hidden: true,
323 required: true
324 }
325 }
326 }
327 prompt.get(schema, function (err, result) {
328 if (err) {
329 return rej(err)
330 }
331 return res(result.password)
332 })
333 })
334}
335
336async function getAccessTokenOrDie (url: string, user: UserInfo) {
337 const resClient = await getClient(url)
338 const client = {
339 id: resClient.body.client_id,
340 secret: resClient.body.client_secret
341 }
342
343 try {
344 const res = await login(url, client, user)
345 return res.body.access_token
346 } catch (err) {
347 console.error('Cannot authenticate. Please check your username/password.')
348 process.exit(-1)
349 }
350}