aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tools
diff options
context:
space:
mode:
Diffstat (limited to 'server/tools')
-rw-r--r--server/tools/README.md82
-rw-r--r--server/tools/cli.ts2
-rw-r--r--server/tools/peertube-auth.ts113
-rw-r--r--server/tools/peertube-get-access-token.ts2
-rw-r--r--server/tools/peertube-import-videos.ts34
-rw-r--r--server/tools/peertube-repl.ts76
-rw-r--r--server/tools/peertube-upload.ts4
-rwxr-xr-xserver/tools/peertube.ts3
8 files changed, 244 insertions, 72 deletions
diff --git a/server/tools/README.md b/server/tools/README.md
new file mode 100644
index 000000000..6b94d74e5
--- /dev/null
+++ b/server/tools/README.md
@@ -0,0 +1,82 @@
1peertube(8) -- companion CLI for PeerTube
2=========================================
3
4SYNOPSIS
5--------
6
7```
8peertube [command] [options]
9```
10
11DESCRIPTION
12-----------
13
14`peertube` wraps various utilities around PeerTube that are used either on a running local, running remote, or cold local instance.
15
16COMMANDS
17--------
18
19Unless otherwise specified, every command can be queried for its own help or manual by passing its name to the `help` command, or by using the `--help` option.
20
21`auth [action]`: stores credentials for your accounts on remote instances so that you don't need to pass them at every command
22
23`upload|up`: upload a video to a remote instance
24
25 $ peertube upload \
26 -u "PEERTUBE_URL" \
27 -U "PEERTUBE_USER" \
28 --password "PEERTUBE_PASSWORD"
29
30`import-videos|import`: import a video from a streaming platform to a remote instance
31
32 $ peertube import \
33 -u "PEERTUBE_URL" \
34 -U "PEERTUBE_USER" \
35 --password "PEERTUBE_PASSWORD" \
36 -t "TARGET_URL"
37
38 The target URL can be directly the video file, or any of the supported sites of youtube-dl. The video is downloaded locally and then uploaded. Already downloaded videos will not be uploaded twice, so you can run and re-run the script in case of crash, disconnection…
39
40`watch|w`: watch a video in the terminal ✩°。⋆
41
42 -g, --gui <player> player type (default: ascii)
43 -i, --invert invert colors (ascii player only)
44 -r, --resolution <res> video resolution (default: 720)
45
46 It provides support for different players:
47
48 - ascii (default ; plays in ascii art in your terminal!)
49 - mpv
50 - mplayer
51 - vlc
52 - stdout
53 - xbmc
54 - airplay
55 - chromecast
56
57`repl`: interact with the application libraries and objects even when PeerTube is not running
58
59 Type .help to see the repl-only functions, or to see the available PeerTube core functions:
60
61 repl> lodash.keys(context)
62
63`help [cmd]`: display help for [cmd]
64
65EXAMPLES
66--------
67
68 $ peertube auth add -u "PEERTUBE_URL" -U "PEERTUBE_USER" --password "PEERTUBE_PASSWORD"
69 $ peertube up <videoFile>
70 $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10
71
72SEE ALSO
73--------
74
75[PeerTube Tools Documentation](https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/tools.md)
76
77[PeerTube Admin Documentation](https://docs.joinpeertube.org/lang/en/docs/)
78
79REPORTING BUGS
80--------------
81
82See [PeerTube repository](https://github.com/Chocobozzz/PeerTube).
diff --git a/server/tools/cli.ts b/server/tools/cli.ts
index 53b20964e..108c44218 100644
--- a/server/tools/cli.ts
+++ b/server/tools/cli.ts
@@ -23,7 +23,7 @@ async function getSettings () {
23 if (err) { 23 if (err) {
24 return rej(err) 24 return rej(err)
25 } 25 }
26 return res(data || settings) 26 return res(Object.keys(data).length === 0 ? settings : data)
27 }) 27 })
28 }) 28 })
29} 29}
diff --git a/server/tools/peertube-auth.ts b/server/tools/peertube-auth.ts
index 33438811e..a962944a4 100644
--- a/server/tools/peertube-auth.ts
+++ b/server/tools/peertube-auth.ts
@@ -5,34 +5,25 @@ import { getSettings, writeSettings, netrc } from './cli'
5import { isHostValid } from '../helpers/custom-validators/servers' 5import { isHostValid } from '../helpers/custom-validators/servers'
6import { isUserUsernameValid } from '../helpers/custom-validators/users' 6import { isUserUsernameValid } from '../helpers/custom-validators/users'
7 7
8function delInstance (url: string) { 8async function delInstance (url: string) {
9 return new Promise((res, rej): void => { 9 const settings = await getSettings()
10 getSettings() 10
11 .then(async (settings) => { 11 settings.remotes.splice(settings.remotes.indexOf(url))
12 settings.remotes.splice(settings.remotes.indexOf(url)) 12 await writeSettings(settings)
13 await writeSettings(settings) 13
14 delete netrc.machines[url] 14 delete netrc.machines[url]
15 netrc.save() 15 await netrc.save()
16 res()
17 })
18 .catch(err => rej(err))
19 })
20} 16}
21 17
22async function setInstance (url: string, username: string, password: string) { 18async function setInstance (url: string, username: string, password: string) {
23 return new Promise((res, rej): void => { 19 const settings = await getSettings()
24 getSettings() 20 if (settings.remotes.indexOf(url) === -1) {
25 .then(async settings => { 21 settings.remotes.push(url)
26 if (settings.remotes.indexOf(url) === -1) { 22 }
27 settings.remotes.push(url) 23 await writeSettings(settings)
28 } 24
29 await writeSettings(settings) 25 netrc.machines[url] = { login: username, password }
30 netrc.machines[url] = { login: username, password } 26 await netrc.save()
31 netrc.save()
32 res()
33 })
34 .catch(err => rej(err))
35 })
36} 27}
37 28
38function isURLaPeerTubeInstance (url: string) { 29function isURLaPeerTubeInstance (url: string) {
@@ -71,56 +62,60 @@ program
71 required: true 62 required: true
72 } 63 }
73 } 64 }
74 }, (_, result) => { 65 }, async (_, result) => {
75 setInstance(result.url, result.username, result.password) 66 await setInstance(result.url, result.username, result.password)
67
68 process.exit(0)
76 }) 69 })
77 }) 70 })
78 71
79program 72program
80 .command('del <url>') 73 .command('del <url>')
81 .description('unregisters a remote instance') 74 .description('unregisters a remote instance')
82 .action((url) => { 75 .action(async url => {
83 delInstance(url) 76 await delInstance(url)
77
78 process.exit(0)
84 }) 79 })
85 80
86program 81program
87 .command('list') 82 .command('list')
88 .description('lists registered remote instances') 83 .description('lists registered remote instances')
89 .action(() => { 84 .action(async () => {
90 getSettings() 85 const settings = await getSettings()
91 .then(settings => { 86 const table = new Table({
92 const table = new Table({ 87 head: ['instance', 'login'],
93 head: ['instance', 'login'], 88 colWidths: [30, 30]
94 colWidths: [30, 30] 89 })
95 }) 90 netrc.loadSync()
96 netrc.loadSync() 91 settings.remotes.forEach(element => {
97 settings.remotes.forEach(element => { 92 table.push([
98 table.push([ 93 element,
99 element, 94 netrc.machines[element].login
100 netrc.machines[element].login 95 ])
101 ]) 96 })
102 }) 97
103 98 console.log(table.toString())
104 console.log(table.toString()) 99
105 }) 100 process.exit(0)
106 }) 101 })
107 102
108program 103program
109 .command('set-default <url>') 104 .command('set-default <url>')
110 .description('set an existing entry as default') 105 .description('set an existing entry as default')
111 .action((url) => { 106 .action(async url => {
112 getSettings() 107 const settings = await getSettings()
113 .then(settings => { 108 const instanceExists = settings.remotes.indexOf(url) !== -1
114 const instanceExists = settings.remotes.indexOf(url) !== -1 109
115 110 if (instanceExists) {
116 if (instanceExists) { 111 settings.default = settings.remotes.indexOf(url)
117 settings.default = settings.remotes.indexOf(url) 112 await writeSettings(settings)
118 writeSettings(settings) 113
119 } else { 114 process.exit(0)
120 console.log('<url> is not a registered instance.') 115 } else {
121 process.exit(-1) 116 console.log('<url> is not a registered instance.')
122 } 117 process.exit(-1)
123 }) 118 }
124 }) 119 })
125 120
126program.on('--help', function () { 121program.on('--help', function () {
diff --git a/server/tools/peertube-get-access-token.ts b/server/tools/peertube-get-access-token.ts
index eb2571a03..a68665f5b 100644
--- a/server/tools/peertube-get-access-token.ts
+++ b/server/tools/peertube-get-access-token.ts
@@ -6,7 +6,7 @@ import {
6 Server, 6 Server,
7 Client, 7 Client,
8 User 8 User
9} from '../tests/utils/index' 9} from '../../shared/utils'
10 10
11program 11program
12 .option('-u, --url <url>', 'Server url') 12 .option('-u, --url <url>', 'Server url')
diff --git a/server/tools/peertube-import-videos.ts b/server/tools/peertube-import-videos.ts
index 15f517cab..151c5a989 100644
--- a/server/tools/peertube-import-videos.ts
+++ b/server/tools/peertube-import-videos.ts
@@ -6,10 +6,11 @@ import { join } from 'path'
6import { VideoPrivacy } from '../../shared/models/videos' 6import { VideoPrivacy } from '../../shared/models/videos'
7import { doRequestAndSaveToFile } from '../helpers/requests' 7import { doRequestAndSaveToFile } from '../helpers/requests'
8import { CONSTRAINTS_FIELDS } from '../initializers' 8import { CONSTRAINTS_FIELDS } from '../initializers'
9import { getClient, getVideoCategories, login, searchVideoWithSort, uploadVideo } from '../tests/utils' 9import { getClient, getVideoCategories, login, searchVideoWithSort, uploadVideo } from '../../shared/utils/index'
10import { truncate } from 'lodash' 10import { truncate } from 'lodash'
11import * as prompt from 'prompt' 11import * as prompt from 'prompt'
12import { remove } from 'fs-extra' 12import { remove } from 'fs-extra'
13import { sha256 } from '../helpers/core-utils'
13import { safeGetYoutubeDL } from '../helpers/youtube-dl' 14import { safeGetYoutubeDL } from '../helpers/youtube-dl'
14import { getSettings, netrc } from './cli' 15import { getSettings, netrc } from './cli'
15 16
@@ -57,6 +58,7 @@ getSettings()
57 settings.remotes[settings.default] : 58 settings.remotes[settings.default] :
58 settings.remotes[0] 59 settings.remotes[0]
59 } 60 }
61
60 if (!program['username']) program['username'] = netrc.machines[program['url']].login 62 if (!program['username']) program['username'] = netrc.machines[program['url']].login
61 if (!program['password']) program['password'] = netrc.machines[program['url']].password 63 if (!program['password']) program['password'] = netrc.machines[program['url']].password
62 } 64 }
@@ -68,12 +70,19 @@ getSettings()
68 process.exit(-1) 70 process.exit(-1)
69 } 71 }
70 72
73 removeEndSlashes(program['url'])
74 removeEndSlashes(program['targetUrl'])
75
71 const user = { 76 const user = {
72 username: program['username'], 77 username: program['username'],
73 password: program['password'] 78 password: program['password']
74 } 79 }
75 80
76 run(user, program['url']).catch(err => console.error(err)) 81 run(user, program['url'])
82 .catch(err => {
83 console.error(err)
84 process.exit(-1)
85 })
77}) 86})
78 87
79async function promptPassword () { 88async function promptPassword () {
@@ -107,8 +116,12 @@ async function run (user, url: string) {
107 secret: res.body.client_secret 116 secret: res.body.client_secret
108 } 117 }
109 118
110 const res2 = await login(url, client, user) 119 try {
111 accessToken = res2.body.access_token 120 const res = await login(program[ 'url' ], client, user)
121 accessToken = res.body.access_token
122 } catch (err) {
123 throw new Error('Cannot authenticate. Please check your username/password.')
124 }
112 125
113 const youtubeDL = await safeGetYoutubeDL() 126 const youtubeDL = await safeGetYoutubeDL()
114 127
@@ -133,8 +146,7 @@ async function run (user, url: string) {
133 await processVideo(info, program['language'], processOptions.cwd, url, user) 146 await processVideo(info, program['language'], processOptions.cwd, url, user)
134 } 147 }
135 148
136 // https://www.youtube.com/watch?v=2Upx39TBc1s 149 console.log('Video/s for user %s imported: %s', program['username'], program['targetUrl'])
137 console.log('I\'m finished!')
138 process.exit(0) 150 process.exit(0)
139 }) 151 })
140} 152}
@@ -155,7 +167,7 @@ function processVideo (info: any, languageCode: string, cwd: string, url: string
155 return res() 167 return res()
156 } 168 }
157 169
158 const path = join(cwd, new Date().getTime() + '.mp4') 170 const path = join(cwd, sha256(videoInfo.url) + '.mp4')
159 171
160 console.log('Downloading video "%s"...', videoInfo.title) 172 console.log('Downloading video "%s"...', videoInfo.title)
161 173
@@ -192,7 +204,7 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st
192 204
193 let thumbnailfile 205 let thumbnailfile
194 if (videoInfo.thumbnail) { 206 if (videoInfo.thumbnail) {
195 thumbnailfile = join(cwd, 'thumbnail.jpg') 207 thumbnailfile = join(cwd, sha256(videoInfo.thumbnail) + '.jpg')
196 208
197 await doRequestAndSaveToFile({ 209 await doRequestAndSaveToFile({
198 method: 'GET', 210 method: 'GET',
@@ -322,3 +334,9 @@ function isNSFW (info: any) {
322 334
323 return false 335 return false
324} 336}
337
338function removeEndSlashes (url: string) {
339 while (url.endsWith('/')) {
340 url.slice(0, -1)
341 }
342}
diff --git a/server/tools/peertube-repl.ts b/server/tools/peertube-repl.ts
new file mode 100644
index 000000000..04d8b95a3
--- /dev/null
+++ b/server/tools/peertube-repl.ts
@@ -0,0 +1,76 @@
1import * as repl from 'repl'
2import * as path from 'path'
3import * as _ from 'lodash'
4import * as uuidv1 from 'uuid/v1'
5import * as uuidv3 from 'uuid/v3'
6import * as uuidv4 from 'uuid/v4'
7import * as uuidv5 from 'uuid/v5'
8import * as Sequelize from 'sequelize'
9import * as YoutubeDL from 'youtube-dl'
10
11import { initDatabaseModels, sequelizeTypescript } from '../initializers'
12import * as cli from '../tools/cli'
13import { logger } from '../helpers/logger'
14import * as constants from '../initializers/constants'
15import * as modelsUtils from '../models/utils'
16import * as coreUtils from '../helpers/core-utils'
17import * as ffmpegUtils from '../helpers/ffmpeg-utils'
18import * as peertubeCryptoUtils from '../helpers/peertube-crypto'
19import * as signupUtils from '../helpers/signup'
20import * as utils from '../helpers/utils'
21import * as YoutubeDLUtils from '../helpers/youtube-dl'
22
23const start = async () => {
24 await initDatabaseModels(true)
25
26 const versionCommitHash = await utils.getServerCommit()
27
28 const initContext = (replServer) => {
29 return (context) => {
30 const properties = {
31 context, repl: replServer, env: process.env,
32 lodash: _, path,
33 uuidv1, uuidv3, uuidv4, uuidv5,
34 cli, logger, constants,
35 Sequelize, sequelizeTypescript, modelsUtils,
36 models: sequelizeTypescript.models, transaction: sequelizeTypescript.transaction,
37 query: sequelizeTypescript.query, queryInterface: sequelizeTypescript.getQueryInterface(),
38 YoutubeDL,
39 coreUtils, ffmpegUtils, peertubeCryptoUtils, signupUtils, utils, YoutubeDLUtils
40 }
41
42 for (let prop in properties) {
43 Object.defineProperty(context, prop, {
44 configurable: false,
45 enumerable: true,
46 value: properties[prop]
47 })
48 }
49 }
50 }
51
52 const replServer = repl.start({
53 prompt: `PeerTube [${cli.version}] (${versionCommitHash})> `
54 })
55
56 initContext(replServer)(replServer.context)
57 replServer.on('reset', initContext(replServer))
58 replServer.on('exit', () => process.exit())
59
60 const resetCommand = {
61 help: 'Reset REPL',
62 action () {
63 this.write('.clear\n')
64 this.displayPrompt()
65 }
66 }
67 replServer.defineCommand('reset', resetCommand)
68 replServer.defineCommand('r', resetCommand)
69
70}
71
72start().then((data) => {
73 // do nothing
74}).catch((err) => {
75 console.error(err)
76})
diff --git a/server/tools/peertube-upload.ts b/server/tools/peertube-upload.ts
index b17bc4288..ebc62c965 100644
--- a/server/tools/peertube-upload.ts
+++ b/server/tools/peertube-upload.ts
@@ -1,8 +1,8 @@
1import * as program from 'commander' 1import * as program from 'commander'
2import { access, constants } from 'fs-extra' 2import { access, constants } from 'fs-extra'
3import { isAbsolute } from 'path' 3import { isAbsolute } from 'path'
4import { getClient, login } from '../tests/utils' 4import { getClient, login } from '../../shared/utils'
5import { uploadVideo } from '../tests/utils/index' 5import { uploadVideo } from '../../shared/utils/'
6import { VideoPrivacy } from '../../shared/models/videos' 6import { VideoPrivacy } from '../../shared/models/videos'
7import { netrc, getSettings } from './cli' 7import { netrc, getSettings } from './cli'
8 8
diff --git a/server/tools/peertube.ts b/server/tools/peertube.ts
index ad76bafb4..5d3ab2815 100755
--- a/server/tools/peertube.ts
+++ b/server/tools/peertube.ts
@@ -17,6 +17,7 @@ program
17 .command('import-videos', 'import a video from a streaming platform').alias('import') 17 .command('import-videos', 'import a video from a streaming platform').alias('import')
18 .command('get-access-token', 'get a peertube access token', { noHelp: true }).alias('token') 18 .command('get-access-token', 'get a peertube access token', { noHelp: true }).alias('token')
19 .command('watch', 'watch a video in the terminal ✩°。⋆').alias('w') 19 .command('watch', 'watch a video in the terminal ✩°。⋆').alias('w')
20 .command('repl', 'initiate a REPL to access internals')
20 21
21/* Not Yet Implemented */ 22/* Not Yet Implemented */
22program 23program
@@ -57,7 +58,7 @@ if (!process.argv.slice(2).length) {
57 ,"\\/ 58 ,"\\/
58 _,.__/"\\/_ (the CLI for red chocobos) 59 _,.__/"\\/_ (the CLI for red chocobos)
59 / \\) "./, ". 60 / \\) "./, ".
60 --/---"---" "-) )---- by Chocobozzz et al.`) 61 --/---"---" "-) )---- by Chocobozzz et al.\n`)
61} 62}
62 63
63getSettings() 64getSettings()