youtube-data-cli 0.0.1 → 1.0.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/README.md +326 -11
- package/dist/api.js +94 -12
- package/dist/commands/activities.js +42 -0
- package/dist/commands/captions.js +152 -0
- package/dist/commands/channel-banners.js +25 -0
- package/dist/commands/channel-sections.js +139 -0
- package/dist/commands/channels.js +46 -0
- package/dist/commands/comment-threads.js +1 -1
- package/dist/commands/comments.js +27 -0
- package/dist/commands/i18n.js +39 -0
- package/dist/commands/members.js +51 -0
- package/dist/commands/playlist-images.js +107 -0
- package/dist/commands/playlists.js +1 -1
- package/dist/commands/thumbnails.js +27 -0
- package/dist/commands/video-abuse-report-reasons.js +22 -0
- package/dist/commands/video-categories.js +32 -0
- package/dist/commands/videos.js +169 -1
- package/dist/commands/watermarks.js +56 -0
- package/dist/index.js +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { loadCredentials } from "../auth.js";
|
|
2
|
+
import { callApi } from "../api.js";
|
|
3
|
+
import { output, fatal } from "../utils.js";
|
|
4
|
+
export function registerVideoCategoryCommands(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("video-categories")
|
|
7
|
+
.description("List video categories")
|
|
8
|
+
.option("--region-code <code>", "ISO 3166-1 alpha-2 country code", "US")
|
|
9
|
+
.option("--id <id>", "Category ID(s), comma-separated")
|
|
10
|
+
.option("--hl <lang>", "Language for localized text (ISO 639-1)")
|
|
11
|
+
.action(async (opts) => {
|
|
12
|
+
try {
|
|
13
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
14
|
+
const params = {
|
|
15
|
+
part: "snippet",
|
|
16
|
+
};
|
|
17
|
+
if (opts.id) {
|
|
18
|
+
params.id = opts.id;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
params.regionCode = opts.regionCode;
|
|
22
|
+
}
|
|
23
|
+
if (opts.hl)
|
|
24
|
+
params.hl = opts.hl;
|
|
25
|
+
const data = await callApi("/videoCategories", { creds, params });
|
|
26
|
+
output(data, program.opts().format);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
fatal(err.message);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
package/dist/commands/videos.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadCredentials } from "../auth.js";
|
|
2
|
-
import { callApi } from "../api.js";
|
|
2
|
+
import { callApi, uploadFile } from "../api.js";
|
|
3
3
|
import { output, fatal } from "../utils.js";
|
|
4
4
|
export function registerVideoCommands(program) {
|
|
5
5
|
program
|
|
@@ -20,4 +20,172 @@ export function registerVideoCommands(program) {
|
|
|
20
20
|
fatal(err.message);
|
|
21
21
|
}
|
|
22
22
|
});
|
|
23
|
+
program
|
|
24
|
+
.command("videos-insert")
|
|
25
|
+
.description("Upload a video (OAuth required)")
|
|
26
|
+
.requiredOption("--file <path>", "Path to video file")
|
|
27
|
+
.requiredOption("--title <title>", "Video title")
|
|
28
|
+
.option("--description <desc>", "Video description")
|
|
29
|
+
.option("--tags <tags>", "Comma-separated tags")
|
|
30
|
+
.option("--category-id <id>", "Video category ID", "22")
|
|
31
|
+
.option("--privacy <status>", "Privacy status (public, private, unlisted)", "private")
|
|
32
|
+
.option("--content-type <type>", "Video MIME type", "video/mp4")
|
|
33
|
+
.action(async (opts) => {
|
|
34
|
+
try {
|
|
35
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
36
|
+
const snippet = {
|
|
37
|
+
title: opts.title,
|
|
38
|
+
categoryId: opts.categoryId,
|
|
39
|
+
};
|
|
40
|
+
if (opts.description)
|
|
41
|
+
snippet.description = opts.description;
|
|
42
|
+
if (opts.tags)
|
|
43
|
+
snippet.tags = opts.tags.split(",").map((t) => t.trim());
|
|
44
|
+
const data = await uploadFile({
|
|
45
|
+
creds,
|
|
46
|
+
endpoint: "/videos",
|
|
47
|
+
params: { part: "snippet,status" },
|
|
48
|
+
filePath: opts.file,
|
|
49
|
+
contentType: opts.contentType,
|
|
50
|
+
body: {
|
|
51
|
+
snippet,
|
|
52
|
+
status: { privacyStatus: opts.privacy },
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
output(data, program.opts().format);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
fatal(err.message);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
program
|
|
62
|
+
.command("videos-update")
|
|
63
|
+
.description("Update video metadata (OAuth required)")
|
|
64
|
+
.requiredOption("--id <id>", "Video ID")
|
|
65
|
+
.requiredOption("--title <title>", "Video title")
|
|
66
|
+
.requiredOption("--category-id <id>", "Video category ID (required by YouTube API when updating snippet)")
|
|
67
|
+
.option("--description <desc>", "Video description")
|
|
68
|
+
.option("--tags <tags>", "Comma-separated tags")
|
|
69
|
+
.option("--privacy <status>", "Privacy status (public, private, unlisted)")
|
|
70
|
+
.option("--default-language <lang>", "Default language (ISO 639-1)")
|
|
71
|
+
.action(async (opts) => {
|
|
72
|
+
try {
|
|
73
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
74
|
+
const snippet = {
|
|
75
|
+
title: opts.title,
|
|
76
|
+
categoryId: opts.categoryId,
|
|
77
|
+
};
|
|
78
|
+
if (opts.description !== undefined)
|
|
79
|
+
snippet.description = opts.description;
|
|
80
|
+
if (opts.tags)
|
|
81
|
+
snippet.tags = opts.tags.split(",").map((t) => t.trim());
|
|
82
|
+
if (opts.defaultLanguage)
|
|
83
|
+
snippet.defaultLanguage = opts.defaultLanguage;
|
|
84
|
+
const body = { id: opts.id, snippet };
|
|
85
|
+
const parts = ["snippet"];
|
|
86
|
+
if (opts.privacy) {
|
|
87
|
+
body.status = { privacyStatus: opts.privacy };
|
|
88
|
+
parts.push("status");
|
|
89
|
+
}
|
|
90
|
+
const data = await callApi("/videos", {
|
|
91
|
+
creds,
|
|
92
|
+
params: { part: parts.join(",") },
|
|
93
|
+
method: "PUT",
|
|
94
|
+
body,
|
|
95
|
+
});
|
|
96
|
+
output(data, program.opts().format);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
fatal(err.message);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
program
|
|
103
|
+
.command("videos-delete")
|
|
104
|
+
.description("Delete a video (OAuth required)")
|
|
105
|
+
.requiredOption("--id <id>", "Video ID")
|
|
106
|
+
.action(async (opts) => {
|
|
107
|
+
try {
|
|
108
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
109
|
+
const data = await callApi("/videos", {
|
|
110
|
+
creds,
|
|
111
|
+
params: { id: opts.id },
|
|
112
|
+
method: "DELETE",
|
|
113
|
+
});
|
|
114
|
+
output(data, program.opts().format);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
fatal(err.message);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
program
|
|
121
|
+
.command("videos-rate")
|
|
122
|
+
.description("Rate a video (OAuth required)")
|
|
123
|
+
.requiredOption("--id <id>", "Video ID")
|
|
124
|
+
.requiredOption("--rating <rating>", "Rating: like, dislike, or none")
|
|
125
|
+
.action(async (opts) => {
|
|
126
|
+
try {
|
|
127
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
128
|
+
const data = await callApi("/videos/rate", {
|
|
129
|
+
creds,
|
|
130
|
+
params: { id: opts.id, rating: opts.rating },
|
|
131
|
+
method: "POST",
|
|
132
|
+
requireOAuth: true,
|
|
133
|
+
});
|
|
134
|
+
output(data, program.opts().format);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
fatal(err.message);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
program
|
|
141
|
+
.command("videos-get-rating")
|
|
142
|
+
.description("Get your rating on videos (OAuth required)")
|
|
143
|
+
.requiredOption("--id <ids>", "Video ID(s), comma-separated")
|
|
144
|
+
.action(async (opts) => {
|
|
145
|
+
try {
|
|
146
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
147
|
+
const data = await callApi("/videos/getRating", {
|
|
148
|
+
creds,
|
|
149
|
+
params: { id: opts.id },
|
|
150
|
+
requireOAuth: true,
|
|
151
|
+
});
|
|
152
|
+
output(data, program.opts().format);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
fatal(err.message);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
program
|
|
159
|
+
.command("videos-report-abuse")
|
|
160
|
+
.description("Report a video for abuse (OAuth required)")
|
|
161
|
+
.requiredOption("--video-id <id>", "Video ID")
|
|
162
|
+
.requiredOption("--reason-id <id>", "Abuse reason ID")
|
|
163
|
+
.option("--secondary-reason-id <id>", "Secondary reason ID")
|
|
164
|
+
.option("--comments <text>", "Additional comments")
|
|
165
|
+
.option("--language <lang>", "Language the comment is written in")
|
|
166
|
+
.action(async (opts) => {
|
|
167
|
+
try {
|
|
168
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
169
|
+
const body = {
|
|
170
|
+
videoId: opts.videoId,
|
|
171
|
+
reasonId: opts.reasonId,
|
|
172
|
+
};
|
|
173
|
+
if (opts.secondaryReasonId)
|
|
174
|
+
body.secondaryReasonId = opts.secondaryReasonId;
|
|
175
|
+
if (opts.comments)
|
|
176
|
+
body.comments = opts.comments;
|
|
177
|
+
if (opts.language)
|
|
178
|
+
body.language = opts.language;
|
|
179
|
+
const data = await callApi("/videos/reportAbuse", {
|
|
180
|
+
creds,
|
|
181
|
+
method: "POST",
|
|
182
|
+
body,
|
|
183
|
+
requireOAuth: true,
|
|
184
|
+
});
|
|
185
|
+
output(data, program.opts().format);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
fatal(err.message);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
23
191
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { loadCredentials } from "../auth.js";
|
|
2
|
+
import { callApi, uploadFile } from "../api.js";
|
|
3
|
+
import { output, fatal } from "../utils.js";
|
|
4
|
+
export function registerWatermarkCommands(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("watermarks-set")
|
|
7
|
+
.description("Upload a channel watermark image (OAuth required)")
|
|
8
|
+
.requiredOption("--channel-id <id>", "Channel ID")
|
|
9
|
+
.requiredOption("--file <path>", "Path to image file (PNG, JPEG)")
|
|
10
|
+
.option("--content-type <type>", "Image MIME type", "image/png")
|
|
11
|
+
.option("--timing-type <type>", "Timing type (offsetFromStart, offsetFromEnd)", "offsetFromEnd")
|
|
12
|
+
.option("--offset-ms <ms>", "Offset in milliseconds", "0")
|
|
13
|
+
.option("--duration-ms <ms>", "Duration in milliseconds")
|
|
14
|
+
.action(async (opts) => {
|
|
15
|
+
try {
|
|
16
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
17
|
+
const timing = {
|
|
18
|
+
type: opts.timingType,
|
|
19
|
+
offsetMs: opts.offsetMs,
|
|
20
|
+
};
|
|
21
|
+
if (opts.durationMs)
|
|
22
|
+
timing.durationMs = opts.durationMs;
|
|
23
|
+
const data = await uploadFile({
|
|
24
|
+
creds,
|
|
25
|
+
endpoint: "/watermarks/set",
|
|
26
|
+
params: { channelId: opts.channelId },
|
|
27
|
+
filePath: opts.file,
|
|
28
|
+
contentType: opts.contentType,
|
|
29
|
+
body: { timing },
|
|
30
|
+
});
|
|
31
|
+
output(data, program.opts().format);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
fatal(err.message);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
program
|
|
38
|
+
.command("watermarks-unset")
|
|
39
|
+
.description("Remove a channel watermark (OAuth required)")
|
|
40
|
+
.requiredOption("--channel-id <id>", "Channel ID")
|
|
41
|
+
.action(async (opts) => {
|
|
42
|
+
try {
|
|
43
|
+
const creds = loadCredentials(program.opts().credentials);
|
|
44
|
+
const data = await callApi("/watermarks/unset", {
|
|
45
|
+
creds,
|
|
46
|
+
params: { channelId: opts.channelId },
|
|
47
|
+
method: "POST",
|
|
48
|
+
requireOAuth: true,
|
|
49
|
+
});
|
|
50
|
+
output(data, program.opts().format);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
fatal(err.message);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,17 @@ import { registerPlaylistItemCommands } from "./commands/playlist-items.js";
|
|
|
11
11
|
import { registerCommentThreadCommands } from "./commands/comment-threads.js";
|
|
12
12
|
import { registerCommentCommands } from "./commands/comments.js";
|
|
13
13
|
import { registerSubscriptionCommands } from "./commands/subscriptions.js";
|
|
14
|
+
import { registerActivityCommands } from "./commands/activities.js";
|
|
15
|
+
import { registerCaptionCommands } from "./commands/captions.js";
|
|
16
|
+
import { registerChannelBannerCommands } from "./commands/channel-banners.js";
|
|
17
|
+
import { registerChannelSectionCommands } from "./commands/channel-sections.js";
|
|
18
|
+
import { registerI18nCommands } from "./commands/i18n.js";
|
|
19
|
+
import { registerMemberCommands } from "./commands/members.js";
|
|
20
|
+
import { registerPlaylistImageCommands } from "./commands/playlist-images.js";
|
|
21
|
+
import { registerThumbnailCommands } from "./commands/thumbnails.js";
|
|
22
|
+
import { registerVideoCategoryCommands } from "./commands/video-categories.js";
|
|
23
|
+
import { registerVideoAbuseReportReasonCommands } from "./commands/video-abuse-report-reasons.js";
|
|
24
|
+
import { registerWatermarkCommands } from "./commands/watermarks.js";
|
|
14
25
|
const program = new Command();
|
|
15
26
|
program
|
|
16
27
|
.name("youtube-data-cli")
|
|
@@ -45,6 +56,17 @@ registerPlaylistItemCommands(program);
|
|
|
45
56
|
registerCommentThreadCommands(program);
|
|
46
57
|
registerCommentCommands(program);
|
|
47
58
|
registerSubscriptionCommands(program);
|
|
59
|
+
registerActivityCommands(program);
|
|
60
|
+
registerCaptionCommands(program);
|
|
61
|
+
registerChannelBannerCommands(program);
|
|
62
|
+
registerChannelSectionCommands(program);
|
|
63
|
+
registerI18nCommands(program);
|
|
64
|
+
registerMemberCommands(program);
|
|
65
|
+
registerPlaylistImageCommands(program);
|
|
66
|
+
registerThumbnailCommands(program);
|
|
67
|
+
registerVideoCategoryCommands(program);
|
|
68
|
+
registerVideoAbuseReportReasonCommands(program);
|
|
69
|
+
registerWatermarkCommands(program);
|
|
48
70
|
program.on("command:*", (operands) => {
|
|
49
71
|
process.stderr.write(JSON.stringify({ error: `Unknown command: ${operands[0]}. Run --help for available commands.` }) + "\n");
|
|
50
72
|
process.exit(1);
|