]>
Commit | Line | Data |
---|---|---|
26fcf2ef C |
1 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | registerTSPaths() | |
3 | ||
26fcf2ef | 4 | import * as CliTable3 from 'cli-table3' |
078f17e6 | 5 | import { Command, program } from 'commander' |
26fcf2ef | 6 | import { uniq } from 'lodash' |
078f17e6 C |
7 | import { URL } from 'url' |
8 | import validator from 'validator' | |
9 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | |
10 | import { VideoRedundanciesTarget } from '@shared/models' | |
11 | import { buildServer, getAdminTokenOrDie, getServerCredentials } from './cli' | |
26fcf2ef | 12 | |
a1587156 C |
13 | import bytes = require('bytes') |
14 | ||
26fcf2ef C |
15 | program |
16 | .name('plugins') | |
17 | .usage('[command] [options]') | |
18 | ||
19 | program | |
20 | .command('list-remote-redundancies') | |
21 | .description('List remote redundancies on your videos') | |
22 | .option('-u, --url <url>', 'Server url') | |
23 | .option('-U, --username <username>', 'Username') | |
24 | .option('-p, --password <token>', 'Password') | |
25 | .action(() => listRedundanciesCLI('my-videos')) | |
26 | ||
27 | program | |
28 | .command('list-my-redundancies') | |
29 | .description('List your redundancies of remote videos') | |
30 | .option('-u, --url <url>', 'Server url') | |
31 | .option('-U, --username <username>', 'Username') | |
32 | .option('-p, --password <token>', 'Password') | |
33 | .action(() => listRedundanciesCLI('remote-videos')) | |
34 | ||
35 | program | |
36 | .command('add') | |
37 | .description('Duplicate a video in your redundancy system') | |
38 | .option('-u, --url <url>', 'Server url') | |
39 | .option('-U, --username <username>', 'Username') | |
40 | .option('-p, --password <token>', 'Password') | |
41 | .option('-v, --video <videoId>', 'Video id to duplicate') | |
ba5a8d89 | 42 | .action((options, command) => addRedundancyCLI(options, command)) |
26fcf2ef C |
43 | |
44 | program | |
45 | .command('remove') | |
46 | .description('Remove a video from your redundancies') | |
47 | .option('-u, --url <url>', 'Server url') | |
48 | .option('-U, --username <username>', 'Username') | |
49 | .option('-p, --password <token>', 'Password') | |
50 | .option('-v, --video <videoId>', 'Video id to remove from redundancies') | |
ba5a8d89 | 51 | .action((options, command) => removeRedundancyCLI(options, command)) |
26fcf2ef C |
52 | |
53 | if (!process.argv.slice(2).length) { | |
54 | program.outputHelp() | |
55 | } | |
56 | ||
57 | program.parse(process.argv) | |
58 | ||
59 | // ---------------------------------------------------------------------------- | |
60 | ||
61 | async function listRedundanciesCLI (target: VideoRedundanciesTarget) { | |
62 | const { url, username, password } = await getServerCredentials(program) | |
078f17e6 C |
63 | const token = await getAdminTokenOrDie(url, username, password) |
64 | const server = buildServer(url, token) | |
26fcf2ef | 65 | |
078f17e6 | 66 | const { data } = await server.redundancyCommand.listVideos({ start: 0, count: 100, sort: 'name', target }) |
26fcf2ef C |
67 | |
68 | const table = new CliTable3({ | |
69 | head: [ 'video id', 'video name', 'video url', 'files', 'playlists', 'by instances', 'total size' ] | |
a1587156 | 70 | }) as any |
26fcf2ef | 71 | |
078f17e6 | 72 | for (const redundancy of data) { |
26fcf2ef C |
73 | const webtorrentFiles = redundancy.redundancies.files |
74 | const streamingPlaylists = redundancy.redundancies.streamingPlaylists | |
75 | ||
76 | let totalSize = '' | |
77 | if (target === 'remote-videos') { | |
78 | const tmp = webtorrentFiles.concat(streamingPlaylists) | |
79 | .reduce((a, b) => a + b.size, 0) | |
80 | ||
81 | totalSize = bytes(tmp) | |
82 | } | |
83 | ||
84 | const instances = uniq( | |
85 | webtorrentFiles.concat(streamingPlaylists) | |
86 | .map(r => r.fileUrl) | |
a1587156 | 87 | .map(u => new URL(u).host) |
26fcf2ef C |
88 | ) |
89 | ||
90 | table.push([ | |
91 | redundancy.id.toString(), | |
92 | redundancy.name, | |
93 | redundancy.url, | |
94 | webtorrentFiles.length, | |
95 | streamingPlaylists.length, | |
96 | instances.join('\n'), | |
97 | totalSize | |
98 | ]) | |
99 | } | |
100 | ||
101 | console.log(table.toString()) | |
102 | process.exit(0) | |
103 | } | |
104 | ||
12152aa0 | 105 | async function addRedundancyCLI (options: { video: number }, command: Command) { |
ba5a8d89 | 106 | const { url, username, password } = await getServerCredentials(command) |
078f17e6 C |
107 | const token = await getAdminTokenOrDie(url, username, password) |
108 | const server = buildServer(url, token) | |
26fcf2ef | 109 | |
ba5a8d89 | 110 | if (!options.video || validator.isInt('' + options.video) === false) { |
26fcf2ef | 111 | console.error('You need to specify the video id to duplicate and it should be a number.\n') |
ba5a8d89 | 112 | command.outputHelp() |
26fcf2ef C |
113 | process.exit(-1) |
114 | } | |
115 | ||
116 | try { | |
078f17e6 | 117 | await server.redundancyCommand.addVideo({ videoId: options.video }) |
26fcf2ef C |
118 | |
119 | console.log('Video will be duplicated by your instance!') | |
120 | ||
121 | process.exit(0) | |
122 | } catch (err) { | |
f2eb23cd | 123 | if (err.message.includes(HttpStatusCode.CONFLICT_409)) { |
26fcf2ef | 124 | console.error('This video is already duplicated by your instance.') |
f2eb23cd | 125 | } else if (err.message.includes(HttpStatusCode.NOT_FOUND_404)) { |
26fcf2ef C |
126 | console.error('This video id does not exist.') |
127 | } else { | |
128 | console.error(err) | |
129 | } | |
130 | ||
131 | process.exit(-1) | |
132 | } | |
133 | } | |
134 | ||
12152aa0 | 135 | async function removeRedundancyCLI (options: { video: number }, command: Command) { |
ba5a8d89 | 136 | const { url, username, password } = await getServerCredentials(command) |
078f17e6 C |
137 | const token = await getAdminTokenOrDie(url, username, password) |
138 | const server = buildServer(url, token) | |
26fcf2ef | 139 | |
ba5a8d89 | 140 | if (!options.video || validator.isInt('' + options.video) === false) { |
26fcf2ef | 141 | console.error('You need to specify the video id to remove from your redundancies.\n') |
ba5a8d89 | 142 | command.outputHelp() |
26fcf2ef C |
143 | process.exit(-1) |
144 | } | |
145 | ||
ba5a8d89 | 146 | const videoId = parseInt(options.video + '', 10) |
26fcf2ef | 147 | |
078f17e6 C |
148 | const myVideoRedundancies = await server.redundancyCommand.listVideos({ target: 'my-videos' }) |
149 | let videoRedundancy = myVideoRedundancies.data.find(r => videoId === r.id) | |
26fcf2ef C |
150 | |
151 | if (!videoRedundancy) { | |
078f17e6 C |
152 | const remoteVideoRedundancies = await server.redundancyCommand.listVideos({ target: 'remote-videos' }) |
153 | videoRedundancy = remoteVideoRedundancies.data.find(r => videoId === r.id) | |
26fcf2ef C |
154 | } |
155 | ||
156 | if (!videoRedundancy) { | |
157 | console.error('Video redundancy not found.') | |
158 | process.exit(-1) | |
159 | } | |
160 | ||
161 | try { | |
162 | const ids = videoRedundancy.redundancies.files | |
163 | .concat(videoRedundancy.redundancies.streamingPlaylists) | |
164 | .map(r => r.id) | |
165 | ||
166 | for (const id of ids) { | |
078f17e6 | 167 | await server.redundancyCommand.removeVideo({ redundancyId: id }) |
26fcf2ef C |
168 | } |
169 | ||
170 | console.log('Video redundancy removed!') | |
171 | ||
172 | process.exit(0) | |
173 | } catch (err) { | |
174 | console.error(err) | |
175 | process.exit(-1) | |
176 | } | |
177 | } |