]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tools/peertube-redundancy.ts
Update translations
[github/Chocobozzz/PeerTube.git] / server / tools / peertube-redundancy.ts
1 // eslint-disable @typescript-eslint/no-unnecessary-type-assertion
2
3 import { registerTSPaths } from '../helpers/register-ts-paths'
4 registerTSPaths()
5
6 import * as program from 'commander'
7 import { getAdminTokenOrDie, getServerCredentials } from './cli'
8 import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models'
9 import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy } from '@shared/extra-utils/server/redundancy'
10 import validator from 'validator'
11 import * as CliTable3 from 'cli-table3'
12 import { URL } from 'url'
13 import { uniq } from 'lodash'
14
15 import bytes = require('bytes')
16
17 program
18 .name('plugins')
19 .usage('[command] [options]')
20
21 program
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
29 program
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
37 program
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
46 program
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
55 if (!process.argv.slice(2).length) {
56 program.outputHelp()
57 }
58
59 program.parse(process.argv)
60
61 // ----------------------------------------------------------------------------
62
63 async 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
106 async 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
139 async 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
186 async 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 }