@mux/cli 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { run } from '@oclif/command';
2
+ export { default as CommandBase } from './command-bases/base';
package/lib/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.run = void 0;
3
+ exports.CommandBase = exports.run = void 0;
4
4
  var command_1 = require("@oclif/command");
5
5
  Object.defineProperty(exports, "run", { enumerable: true, get: function () { return command_1.run; } });
6
+ var base_1 = require("./command-bases/base");
7
+ Object.defineProperty(exports, "CommandBase", { enumerable: true, get: function () { return base_1.default; } });
@@ -1 +1 @@
1
- {"version":"0.5.0","commands":{"init":{"id":"init","description":"set up a user-level config","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{},"args":[{"name":"envFile","description":"path to a Mux access token .env file","required":false}]},"sign":{"id":"sign","description":"Creates a new signed URL token for a playback ID","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"expiresIn":{"name":"expiresIn","type":"option","char":"e","description":"How long the signature is valid for. If no unit is specified, milliseconds is assumed.","default":"7d"},"type":{"name":"type","type":"option","char":"t","description":"What type of token this signature is for.","options":["video","thumbnail","gif"],"default":"video"}},"args":[{"name":"playback-id","description":"Playback ID to create a signed URL token for.","required":true}]},"assets:create":{"id":"assets:create","description":"Create a new asset in Mux using a file that's already available online","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"private":{"name":"private","type":"boolean","char":"p","description":"add a private playback policy to the created asset","allowNo":false}},"args":[{"name":"input","description":"input URL for the file you'd like to create this asset from","required":true}]},"assets:upload":{"id":"assets:upload","description":"Create a new asset in Mux via a local file","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"private":{"name":"private","type":"boolean","char":"p","description":"add a private playback policy to the created asset","allowNo":false},"filter":{"name":"filter","type":"option","char":"f","description":"regex that filters the selected destination if the provided path is a folder"},"concurrent":{"name":"concurrent","type":"option","char":"c","description":"max number of files to upload at once","default":3}},"args":[{"name":"path","description":"local path for the file (or folder) you'd like to upload","required":true}]},"live:complete":{"id":"live:complete","description":"Signal to Mux that a live stream has concluded and should be closed.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"},"disableAfterCompletion":{"name":"disableAfterCompletion","type":"boolean","char":"d","description":"If set, disables the stream upon completion.","allowNo":false}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]},"live:disable":{"id":"live:disable","description":"Disables a live stream and prevents encoders from streaming to it.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]},"live:enable":{"id":"live:enable","description":"Enables a live stream, allowing encoders to streaming to it.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]}}}
1
+ {"version":"0.7.0","commands":{"init":{"id":"init","description":"set up a user-level config","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"force":{"name":"force","type":"boolean","char":"f","description":"Will initialize a new file even if one already exists.","allowNo":false}},"args":[{"name":"envFile","description":"path to a Mux access token .env file","required":false}]},"sign":{"id":"sign","description":"Creates a new signed URL token for a playback ID","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"expiresIn":{"name":"expiresIn","type":"option","char":"e","description":"How long the signature is valid for. If no unit is specified, milliseconds is assumed.","default":"7d"},"type":{"name":"type","type":"option","char":"t","description":"What type of token this signature is for.","options":["video","thumbnail","gif"],"default":"video"}},"args":[{"name":"playback-id","description":"Playback ID to create a signed URL token for.","required":true}]},"assets:create":{"id":"assets:create","description":"Create a new asset in Mux using a file that's already available online","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"private":{"name":"private","type":"boolean","char":"p","description":"add a private playback policy to the created asset","allowNo":false}},"args":[{"name":"input","description":"input URL for the file you'd like to create this asset from","required":true}]},"assets:upload":{"id":"assets:upload","description":"Create a new asset in Mux via a local file","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"private":{"name":"private","type":"boolean","char":"p","allowNo":false},"filter":{"name":"filter","type":"option","char":"f","description":"regex that filters the selected destination if the provided path is a folder"},"concurrent":{"name":"concurrent","type":"option","char":"c","description":"max number of files to upload at once","default":3}},"args":[{"name":"path","description":"local path for the file (or folder) you'd like to upload","required":true}]},"live:complete":{"id":"live:complete","description":"Signal to Mux that a live stream has concluded and should be closed.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"},"disableAfterCompletion":{"name":"disableAfterCompletion","type":"boolean","char":"d","description":"If set, disables the stream upon completion.","allowNo":false}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]},"live:disable":{"id":"live:disable","description":"Disables a live stream and prevents encoders from streaming to it.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]},"live:enable":{"id":"live:enable","description":"Enables a live stream, allowing encoders to streaming to it.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mux/cli",
3
3
  "description": "Your friendly neighborhood Mux CLI tool!",
4
- "version": "0.5.0",
4
+ "version": "0.7.0",
5
5
  "author": {
6
6
  "name": "Mux",
7
7
  "email": "devex@mux.com",
@@ -16,52 +16,55 @@
16
16
  },
17
17
  "bugs": "https://github.com/muxinc/cli/issues",
18
18
  "dependencies": {
19
- "@mux/mux-node": "^3.1.0",
20
- "@oclif/command": "^1.8.0",
21
- "@oclif/config": "^1.17.0",
22
- "@oclif/plugin-autocomplete": "^0.2.0",
23
- "@oclif/plugin-commands": "^1.3.0",
24
- "@oclif/plugin-help": "^3.2.0",
25
- "@oclif/plugin-not-found": "^1.2.4",
26
- "@oclif/plugin-update": "^1.3.10",
27
- "@oclif/plugin-warn-if-update-available": "^1.7.0",
28
- "chalk": "^4.1.0",
19
+ "@mux/mux-node": "^4.0.0",
20
+ "@oclif/command": "^1.8.16",
21
+ "@oclif/config": "^1.18.2",
22
+ "@oclif/plugin-autocomplete": "^1.1.1",
23
+ "@oclif/plugin-commands": "^2.0.2",
24
+ "@oclif/plugin-help": "^5.1.10",
25
+ "@oclif/plugin-not-found": "^2.2.4",
26
+ "@oclif/plugin-plugins": "^2.0.12",
27
+ "@oclif/plugin-update": "^2.1.5",
28
+ "@oclif/plugin-warn-if-update-available": "^2.0.4",
29
+ "chalk": "4.1.2",
29
30
  "clipboardy": "^2.3.0",
30
31
  "dotenv": "^8.2.0",
31
- "fs-extra": "^9.0.1",
32
- "inquirer": "^7.3.3",
32
+ "fs-extra": "^10.0.0",
33
+ "inquirer": "^8.2.0",
33
34
  "listr": "^0.14.3",
34
35
  "request": "^2.88.2",
35
- "rxjs": "^6.6.3"
36
+ "runtypes": "^6.5.0",
37
+ "rxjs": "^7.5.2"
36
38
  },
37
39
  "devDependencies": {
38
- "@oclif/dev-cli": "^1.24.3",
39
- "@oclif/test": "^1.2.8",
40
+ "@oclif/dev-cli": "^1.26.10",
41
+ "@oclif/test": "^2.0.3",
40
42
  "@oclif/tslint": "^3",
41
- "@types/chai": "^4.2.14",
42
- "@types/fs-extra": "^9.0.4",
43
- "@types/inquirer": "^7.3.1",
44
- "@types/listr": "^0.14.2",
45
- "@types/mocha": "^8.0.4",
46
- "@types/node": "^10",
47
- "@types/request": "^2.48.5",
48
- "chai": "^4",
49
- "globby": "^11.0.1",
50
- "mocha": "^8.2.1",
43
+ "@types/chai": "^4.3.0",
44
+ "@types/fs-extra": "^9.0.13",
45
+ "@types/inquirer": "^8.1.3",
46
+ "@types/listr": "^0.14.4",
47
+ "@types/mocha": "^9.1.0",
48
+ "@types/node": "^17.0.12",
49
+ "@types/request": "^2.48.8",
50
+ "chai": "^4.3.6",
51
+ "globby": "11.0.4",
52
+ "mocha": "6.2.3",
51
53
  "nyc": "^15.1.0",
52
- "oclif": "^1.16.1",
53
- "ts-node": "^9.0.0",
54
+ "oclif": "^2.4.0",
55
+ "ts-node": "^10.4.0",
54
56
  "tslint": "^6.1.3",
55
57
  "tslint-config-prettier": "^1.18.0",
56
- "typescript": "^4.1.2"
58
+ "typescript": "^4.5.5"
57
59
  },
58
60
  "engines": {
59
- "node": ">=8.0.0"
61
+ "node": ">=14.0.0"
60
62
  },
61
63
  "files": [
62
64
  "/bin",
63
65
  "/lib",
64
- "/npm-shrinkwrap.json",
66
+ "/src",
67
+ "/yarn.lock",
65
68
  "/oclif.manifest.json"
66
69
  ],
67
70
  "homepage": "https://github.com/muxinc/cli",
@@ -79,7 +82,8 @@
79
82
  "@oclif/plugin-autocomplete",
80
83
  "@oclif/plugin-commands",
81
84
  "@oclif/plugin-update",
82
- "@oclif/plugin-warn-if-update-available"
85
+ "@oclif/plugin-warn-if-update-available",
86
+ "@oclif/plugin-plugins"
83
87
  ],
84
88
  "macos": {
85
89
  "identifier": "com.mux.cli"
@@ -95,14 +99,16 @@
95
99
  },
96
100
  "repository": "muxinc/cli",
97
101
  "scripts": {
102
+ "clean": "rm -rf lib && rm -rf tsconfig.tsbuildinfo",
103
+ "build": "tsc -b",
98
104
  "postpack": "rm -f oclif.manifest.json",
99
105
  "posttest": "tslint -p test -t stylish",
100
- "prepack": "rm -rf lib && tsc -b && oclif-dev manifest && oclif-dev readme",
106
+ "prepack": "yarn run -s clean && yarn run -s build && oclif-dev manifest && oclif-dev readme",
101
107
  "test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\"",
102
108
  "version": "oclif-dev readme && git add README.md"
103
109
  },
104
110
  "types": "lib/index.d.ts",
105
111
  "volta": {
106
- "node": "8.17.0"
112
+ "node": "14.16.1"
107
113
  }
108
114
  }
@@ -0,0 +1,52 @@
1
+ import { Asset } from '@mux/mux-node';
2
+ import { flags } from '@oclif/command';
3
+ import * as Parser from '@oclif/parser';
4
+ import CommandBase from './base';
5
+
6
+ export type AssetBaseFlags = {
7
+ private: Parser.flags.IBooleanFlag<boolean>;
8
+ };
9
+
10
+ export default abstract class AssetCommandBase extends CommandBase {
11
+ static flags: AssetBaseFlags = {
12
+ private: flags.boolean({
13
+ char: 'p',
14
+ description: 'add a private playback policy to the created asset',
15
+ }),
16
+ };
17
+
18
+ playbackUrl(asset: Asset) {
19
+ const publicPlaybackId = (asset.playback_ids ?? []).find(
20
+ p => p.policy === 'public'
21
+ );
22
+ if (!publicPlaybackId) {
23
+ return 'No public playback policies found!';
24
+ }
25
+
26
+ return `https://mux-playground.now.sh/videojs?playback_id=${
27
+ publicPlaybackId.id
28
+ }`;
29
+ }
30
+
31
+ pollAsset(assetId: string): Promise<Asset> {
32
+ return new Promise((resolve, reject) => {
33
+ const poll = () =>
34
+ setTimeout(async () => {
35
+ try {
36
+ const asset = await this.Video.Assets.get(assetId);
37
+ if (asset.status === 'ready') {
38
+ return resolve(asset);
39
+ } else if (asset.status === 'errored') {
40
+ return reject(asset);
41
+ }
42
+
43
+ poll();
44
+ } catch (err) {
45
+ reject(err);
46
+ }
47
+ }, 500);
48
+
49
+ poll();
50
+ });
51
+ }
52
+ }
@@ -0,0 +1,71 @@
1
+ import Mux, { Video as MuxVideo, Data as MuxData } from '@mux/mux-node';
2
+ import Command from '@oclif/command';
3
+ import * as chalk from 'chalk';
4
+ import * as fs from 'fs-extra';
5
+ import * as path from 'path';
6
+
7
+ import { MuxCliConfigV1 } from '../config';
8
+
9
+ export const MUX_API_BASE_URL = "https://api.mux.com";
10
+
11
+ export default abstract class CommandBase extends Command {
12
+ configFile = path.join(this.config.configDir, 'config.json');
13
+
14
+ MuxConfig!: MuxCliConfigV1;
15
+ Mux!: Mux;
16
+ Video!: MuxVideo;
17
+ Data!: MuxData;
18
+ JWT: any;
19
+
20
+ async readConfigV1(): Promise<MuxCliConfigV1 | null> {
21
+ const configAlreadyExists = await fs.pathExists(this.configFile);
22
+ try {
23
+ const configRaw =
24
+ configAlreadyExists
25
+ ? await fs.readJSON(this.configFile)
26
+ : {};
27
+
28
+ // Mux SDK configuration options
29
+ configRaw.tokenId = process.env.MUX_TOKEN_ID ?? configRaw.tokenId;
30
+ configRaw.tokenSecret = process.env.MUX_TOKEN_SECRET ?? configRaw.tokenSecret;
31
+ configRaw.signingKeyId = process.env.MUX_SIGNING_KEY ?? configRaw.signingKeyId;
32
+ configRaw.signingKeySecret = process.env.MUX_PRIVATE_KEY ?? configRaw.signingKeySecret;
33
+
34
+ // Mux CLI specific configuration options
35
+ configRaw.configVersion = configRaw.configVersion ?? 1;
36
+ configRaw.baseUrl = process.env.MUX_CLI_BASE_URL ?? configRaw.baseUrl ?? MUX_API_BASE_URL;
37
+ return MuxCliConfigV1.check(configRaw);
38
+ } catch (err) {
39
+ if (configAlreadyExists) {
40
+ // we have a bad config file, and should say so
41
+ this.log(
42
+ chalk`{bold.underline.red Invalid Mux configuration file found at {bold.underline.cyan ${this.configFile}}:}\n\n` +
43
+ Object.entries((err as any).details).map(tup => " - " + chalk`{cyan ${tup[0]}}` + `: ${tup[1]}`) +
44
+ chalk`\n\nPlease fix the file or run {bold.magenta mux init --force} to create a new one.`
45
+ )
46
+ } else {
47
+ this.log(
48
+ chalk`{bold.underline.red No Mux configuration file found!} If you'd like to create ` +
49
+ chalk`one, run the {bold.magenta init} command. Otherwise, make sure to have the ` +
50
+ chalk`{bold.yellow MUX_TOKEN_ID} and {bold.yellow MUX_TOKEN_SECRET} environment variables set. 👋`
51
+ );
52
+ }
53
+
54
+ process.exit(1);
55
+ }
56
+ }
57
+
58
+ async init() {
59
+ if (this.id === 'init') return; // If we're initing we don't want any of this!
60
+
61
+ const config = await this.readConfigV1();
62
+ const mux = new Mux(config?.tokenId, config?.tokenSecret, {
63
+ baseUrl: config?.baseUrl,
64
+ });
65
+
66
+ this.Mux = mux;
67
+ this.Video = this.Mux.Video;
68
+ this.Data = this.Mux.Data;
69
+ this.JWT = Mux.JWT;
70
+ }
71
+ }
@@ -0,0 +1,35 @@
1
+ import { flags } from '@oclif/command';
2
+ import { IFlag } from '@oclif/command/lib/flags';
3
+
4
+ import CommandBase from './base';
5
+
6
+ export default abstract class LiveCommandBase extends CommandBase {
7
+ static argsForSingleLiveStream = [
8
+ {
9
+ name: 'streamName',
10
+ description:
11
+ "the name (coupled with --reference-type) to look up in Mux to yield this livestream",
12
+ required: true,
13
+ },
14
+ ];
15
+
16
+ static flagsForSingleLiveStream: Record<string, IFlag<any>> = {
17
+ streamId: flags.string({
18
+ name: 'reference-type',
19
+ char: 't',
20
+ description: 'the type of the provided reference name',
21
+ options: ['stream-id'],
22
+ default: 'stream-id',
23
+ }),
24
+ }
25
+
26
+ protected getStreamId(flags: Record<string, any>, streamName: string): string {
27
+ switch (flags.streamId) {
28
+ case 'stream-id':
29
+ // just a pass-through
30
+ return streamName;
31
+ }
32
+
33
+ throw new Error("Could not derive a stream ID. Please pass one with --stream-id.");
34
+ }
35
+ }
@@ -0,0 +1,74 @@
1
+ import * as chalk from 'chalk';
2
+ import * as clipboard from 'clipboardy';
3
+ import * as Listr from 'listr';
4
+
5
+ import AssetCommandBase from '../../command-bases/asset-base';
6
+
7
+ export default class AssetsCreate extends AssetCommandBase {
8
+ static description =
9
+ "Create a new asset in Mux using a file that's already available online";
10
+
11
+ static args = [
12
+ {
13
+ name: 'input',
14
+ description:
15
+ "input URL for the file you'd like to create this asset from",
16
+ required: true,
17
+ },
18
+ ];
19
+
20
+ async run() {
21
+ const { args, flags } = this.parse(AssetsCreate);
22
+ let assetBodyParams = {
23
+ input: args.input,
24
+ playback_policies: flags.private ? ['signed'] : ['public'],
25
+ };
26
+
27
+ const tasks = new Listr([
28
+ {
29
+ title: 'Creating Mux Asset',
30
+ task: async ctx => {
31
+ const asset = await this.Video.Assets.create(assetBodyParams);
32
+ ctx.asset = asset;
33
+ },
34
+ },
35
+ {
36
+ title: 'Waiting for asset to be playable',
37
+ task: async ctx => {
38
+ const asset = await this.pollAsset(ctx.asset.id);
39
+ ctx.asset = asset;
40
+ },
41
+ },
42
+ ]);
43
+
44
+ try {
45
+ const ctx = await tasks.run();
46
+ const playbackUrl = this.playbackUrl(ctx.asset);
47
+
48
+ if (!process.env.WSL_DISTRO_NAME) {
49
+ await clipboard.write(playbackUrl);
50
+ }
51
+
52
+ this.log(
53
+ chalk`
54
+ 💫 {bold.blue Asset ready for your enjoyment!}
55
+
56
+ {bold.underline Playback URL}
57
+ ${playbackUrl}
58
+ `
59
+ );
60
+ } catch (err) {
61
+ console.log(
62
+ chalk.redBright('Error:') +
63
+ "\n\n" +
64
+ err
65
+ );
66
+
67
+ if (err instanceof Error) {
68
+ this.error(err);
69
+ } else {
70
+ throw err;
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,192 @@
1
+ import { CreateUploadParams, Upload } from '@mux/mux-node';
2
+ import { flags } from '@oclif/command';
3
+ import * as chalk from 'chalk';
4
+ import * as clipboard from 'clipboardy';
5
+ import * as fs from 'fs-extra';
6
+ import * as inquirer from 'inquirer';
7
+ import * as Listr from 'listr';
8
+ import * as path from 'path';
9
+ import * as request from 'request';
10
+
11
+ import AssetCommandBase, { AssetBaseFlags } from '../../command-bases/asset-base';
12
+
13
+ export type AssetCreateFlags = AssetBaseFlags & {
14
+ filter: flags.IOptionFlag<string | undefined>;
15
+ concurrent: flags.IOptionFlag<number>;
16
+ };
17
+
18
+ export default class AssetsCreate extends AssetCommandBase {
19
+ static description = 'Create a new asset in Mux via a local file';
20
+
21
+ static args = [
22
+ {
23
+ name: 'path',
24
+ description: "local path for the file (or folder) you'd like to upload",
25
+ required: true,
26
+ },
27
+ ];
28
+
29
+ static flags: AssetCreateFlags = {
30
+ ...AssetCommandBase.flags,
31
+ filter: flags.string({
32
+ char: 'f',
33
+ description:
34
+ 'regex that filters the selected destination if the provided path is a folder',
35
+ }),
36
+ concurrent: flags.integer({
37
+ char: 'c',
38
+ description: 'max number of files to upload at once',
39
+ default: 3,
40
+ }),
41
+ private: flags.boolean({
42
+ char: 'p',
43
+ default: false,
44
+ })
45
+ };
46
+
47
+ getFilePaths(filePath: string, filter = '') {
48
+ if (fs.lstatSync(filePath).isDirectory()) {
49
+ return fs.readdirSync(filePath).filter(file => file.match(filter));
50
+ }
51
+
52
+ return [filePath];
53
+ }
54
+
55
+ uploadFile(filePath: string, url: string) {
56
+ return new Promise((resolve, reject) => {
57
+ fs.createReadStream(path.resolve(process.cwd(), filePath)).pipe(
58
+ request
59
+ .put(url)
60
+ .on('response', resolve)
61
+ .on('error', reject)
62
+ );
63
+ });
64
+ }
65
+
66
+ pollUpload(uploadId: string): Promise<Upload> {
67
+ return new Promise((resolve, reject) => {
68
+ const poll = () =>
69
+ setTimeout(async () => {
70
+ try {
71
+ const upload = await this.Video.Uploads.get(uploadId);
72
+ if (upload.status === 'asset_created') {
73
+ return resolve(upload);
74
+ } else if (upload.status === 'errored') {
75
+ return reject(upload);
76
+ }
77
+
78
+ poll();
79
+ } catch (err) {
80
+ reject(err);
81
+ }
82
+ }, 500);
83
+
84
+ poll();
85
+ });
86
+ }
87
+
88
+ async run() {
89
+ const { args, flags } = this.parse(AssetsCreate);
90
+
91
+ let assetBodyParams: CreateUploadParams = {
92
+ new_asset_settings: {
93
+ playback_policy: flags.private ? ['signed'] : ['public'],
94
+ },
95
+ };
96
+
97
+ const regex = new RegExp(flags.filter || '', 'ig');
98
+ const files = this.getFilePaths(
99
+ path.resolve(process.cwd(), args.path)
100
+ ).filter(file => file.match(regex));
101
+
102
+ let prompt = { files };
103
+ if (files.length === 0) {
104
+ return this.log(
105
+ `We were unable to find any files. You might want to double check your path or make sure your filter isn't too strict`
106
+ );
107
+ } else if (files.length > 1) {
108
+ prompt = await inquirer.prompt([
109
+ {
110
+ type: 'checkbox',
111
+ name: 'files',
112
+ message: 'We found a few files! Do all of these look good?',
113
+ choices: files,
114
+ default: files,
115
+ },
116
+ ]);
117
+ }
118
+
119
+ const tasks = prompt.files.map((file: string) => ({
120
+ title: `${file}: getting direct upload URL`,
121
+ task: async (ctx: any, task: Listr.ListrTaskWrapper) => {
122
+ const upload = await this.Video.Uploads.create(assetBodyParams);
123
+
124
+ task.title = `${file}: uploading`;
125
+ await this.uploadFile(
126
+ path.resolve(process.cwd(), args.path, file),
127
+ upload.url
128
+ );
129
+
130
+ task.title = `${file}: waiting for asset to be playable`;
131
+ const { asset_id: assetId } = await this.pollUpload(upload.id);
132
+
133
+ if (!assetId) {
134
+ throw new Error(`Asset for upload '${upload.id}' failed to resolve.`);
135
+ }
136
+ const asset = await this.pollAsset(assetId);
137
+
138
+ const playbackUrl = this.playbackUrl(asset);
139
+ task.title = `${file}: ${playbackUrl}`;
140
+ ctx.assets = [
141
+ ...(ctx.assets || [['Filename', 'Asset ID', 'PlaybackURL']]),
142
+ [file, asset.id, playbackUrl],
143
+ ];
144
+ },
145
+ }));
146
+
147
+ // I hate this `any` here, but I'm running into a weird issue casting
148
+ // the `tasks` above to an array of `ListrTasks[]`.
149
+ try {
150
+ const finalCtx = await new Listr(tasks, {
151
+ concurrent: flags.concurrent,
152
+ }).run();
153
+
154
+ const tsv = finalCtx.assets
155
+ .map((row: string[]) => row.join('\t'))
156
+ .join('\n');
157
+ if (prompt.files.length > 1 && !process.env.WSL_DISTRO_NAME) {
158
+ await clipboard.write(tsv);
159
+
160
+ return this.log(
161
+ chalk`
162
+ 📹 {bold.underline Assets ready for your enjoyment:}
163
+ ${tsv}
164
+
165
+ {blue (copied to your clipboard)}`
166
+ );
167
+ }
168
+
169
+ await clipboard.write(finalCtx.assets[1][2]);
170
+ return this.log(
171
+ chalk`
172
+ 📹 {bold.underline Asset ready for your enjoyment:}
173
+ ${tsv}
174
+
175
+ {blue (since you only uploaded one asset, we just added the playback URL to your clipboard.)}`
176
+ );
177
+ } catch (err) {
178
+ // TODO: make this clearer / separate it out per video for more obvious debugging.
179
+ console.log(
180
+ chalk.redBright('Error:') +
181
+ "\n\n" +
182
+ err
183
+ );
184
+
185
+ if (err instanceof Error) {
186
+ this.error(err);
187
+ } else {
188
+ throw err;
189
+ }
190
+ }
191
+ }
192
+ }