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.
@@ -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
+ }
@@ -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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "youtube-data-cli",
3
- "version": "0.0.1",
3
+ "version": "1.0.0",
4
4
  "description": "YouTube Data API CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {