]>
Commit | Line | Data |
---|---|---|
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 | } |