aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tools/peertube-redundancy.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/tools/peertube-redundancy.ts')
-rw-r--r--server/tools/peertube-redundancy.ts197
1 files changed, 197 insertions, 0 deletions
diff --git a/server/tools/peertube-redundancy.ts b/server/tools/peertube-redundancy.ts
new file mode 100644
index 000000000..1ab58a438
--- /dev/null
+++ b/server/tools/peertube-redundancy.ts
@@ -0,0 +1,197 @@
1// eslint-disable @typescript-eslint/no-unnecessary-type-assertion
2
3import { registerTSPaths } from '../helpers/register-ts-paths'
4registerTSPaths()
5
6import * as program from 'commander'
7import { getAdminTokenOrDie, getServerCredentials } from './cli'
8import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models'
9import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy } from '@shared/extra-utils/server/redundancy'
10import validator from 'validator'
11import * as CliTable3 from 'cli-table3'
12import { URL } from 'url'
13import { uniq } from 'lodash'
14
15import bytes = require('bytes')
16
17program
18 .name('plugins')
19 .usage('[command] [options]')
20
21program
22 .command('list-remote-redundancies')
23 .description('List remote redundancies on your videos')
24 .option('-u, --url <url>', 'Server url')
25 .option('-U, --username <username>', 'Username')
26 .option('-p, --password <token>', 'Password')
27 .action(() => listRedundanciesCLI('my-videos'))
28
29program
30 .command('list-my-redundancies')
31 .description('List your redundancies of remote videos')
32 .option('-u, --url <url>', 'Server url')
33 .option('-U, --username <username>', 'Username')
34 .option('-p, --password <token>', 'Password')
35 .action(() => listRedundanciesCLI('remote-videos'))
36
37program
38 .command('add')
39 .description('Duplicate a video in your redundancy system')
40 .option('-u, --url <url>', 'Server url')
41 .option('-U, --username <username>', 'Username')
42 .option('-p, --password <token>', 'Password')
43 .option('-v, --video <videoId>', 'Video id to duplicate')
44 .action((options) => addRedundancyCLI(options))
45
46program
47 .command('remove')
48 .description('Remove a video from your redundancies')
49 .option('-u, --url <url>', 'Server url')
50 .option('-U, --username <username>', 'Username')
51 .option('-p, --password <token>', 'Password')
52 .option('-v, --video <videoId>', 'Video id to remove from redundancies')
53 .action((options) => removeRedundancyCLI(options))
54
55if (!process.argv.slice(2).length) {
56 program.outputHelp()
57}
58
59program.parse(process.argv)
60
61// ----------------------------------------------------------------------------
62
63async function listRedundanciesCLI (target: VideoRedundanciesTarget) {
64 const { url, username, password } = await getServerCredentials(program)
65 const accessToken = await getAdminTokenOrDie(url, username, password)
66
67 const redundancies = await listVideoRedundanciesData(url, accessToken, target)
68
69 const table = new CliTable3({
70 head: [ 'video id', 'video name', 'video url', 'files', 'playlists', 'by instances', 'total size' ]
71 }) as any
72
73 for (const redundancy of redundancies) {
74 const webtorrentFiles = redundancy.redundancies.files
75 const streamingPlaylists = redundancy.redundancies.streamingPlaylists
76
77 let totalSize = ''
78 if (target === 'remote-videos') {
79 const tmp = webtorrentFiles.concat(streamingPlaylists)
80 .reduce((a, b) => a + b.size, 0)
81
82 totalSize = bytes(tmp)
83 }
84
85 const instances = uniq(
86 webtorrentFiles.concat(streamingPlaylists)
87 .map(r => r.fileUrl)
88 .map(u => new URL(u).host)
89 )
90
91 table.push([
92 redundancy.id.toString(),
93 redundancy.name,
94 redundancy.url,
95 webtorrentFiles.length,
96 streamingPlaylists.length,
97 instances.join('\n'),
98 totalSize
99 ])
100 }
101
102 console.log(table.toString())
103 process.exit(0)
104}
105
106async function addRedundancyCLI (options: { videoId: number }) {
107 const { url, username, password } = await getServerCredentials(program)
108 const accessToken = await getAdminTokenOrDie(url, username, password)
109
110 if (!options['video'] || validator.isInt('' + options['video']) === false) {
111 console.error('You need to specify the video id to duplicate and it should be a number.\n')
112 program.outputHelp()
113 process.exit(-1)
114 }
115
116 try {
117 await addVideoRedundancy({
118 url,
119 accessToken,
120 videoId: options['video']
121 })
122
123 console.log('Video will be duplicated by your instance!')
124
125 process.exit(0)
126 } catch (err) {
127 if (err.message.includes(409)) {
128 console.error('This video is already duplicated by your instance.')
129 } else if (err.message.includes(404)) {
130 console.error('This video id does not exist.')
131 } else {
132 console.error(err)
133 }
134
135 process.exit(-1)
136 }
137}
138
139async function removeRedundancyCLI (options: { videoId: number }) {
140 const { url, username, password } = await getServerCredentials(program)
141 const accessToken = await getAdminTokenOrDie(url, username, password)
142
143 if (!options['video'] || validator.isInt('' + options['video']) === false) {
144 console.error('You need to specify the video id to remove from your redundancies.\n')
145 program.outputHelp()
146 process.exit(-1)
147 }
148
149 const videoId = parseInt(options['video'] + '', 10)
150
151 let redundancies = await listVideoRedundanciesData(url, accessToken, 'my-videos')
152 let videoRedundancy = redundancies.find(r => videoId === r.id)
153
154 if (!videoRedundancy) {
155 redundancies = await listVideoRedundanciesData(url, accessToken, 'remote-videos')
156 videoRedundancy = redundancies.find(r => videoId === r.id)
157 }
158
159 if (!videoRedundancy) {
160 console.error('Video redundancy not found.')
161 process.exit(-1)
162 }
163
164 try {
165 const ids = videoRedundancy.redundancies.files
166 .concat(videoRedundancy.redundancies.streamingPlaylists)
167 .map(r => r.id)
168
169 for (const id of ids) {
170 await removeVideoRedundancy({
171 url,
172 accessToken,
173 redundancyId: id
174 })
175 }
176
177 console.log('Video redundancy removed!')
178
179 process.exit(0)
180 } catch (err) {
181 console.error(err)
182 process.exit(-1)
183 }
184}
185
186async function listVideoRedundanciesData (url: string, accessToken: string, target: VideoRedundanciesTarget) {
187 const res = await listVideoRedundancies({
188 url,
189 accessToken,
190 start: 0,
191 count: 100,
192 sort: 'name',
193 target
194 })
195
196 return res.body.data as VideoRedundancy[]
197}