@acedatacloud/skills 2026.606.1 → 2026.613.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/package.json +1 -1
- package/skills/youtube/SKILL.md +152 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acedatacloud/skills",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.613.0",
|
|
4
4
|
"description": "Agent Skills for AceDataCloud AI services — music, image, video generation, LLM chat, web search. Compatible with Claude Code, GitHub Copilot, Gemini CLI, OpenAI Codex, and 30+ AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: youtube
|
|
3
|
+
description: Search YouTube, read your own channel and uploaded videos (stats, comments), and upload new videos via the YouTube Data API v3. Use when the user mentions YouTube, "my channel", "my videos", searching YouTube, video views / likes / stats, uploading a video to YouTube, or checking how a published video is doing.
|
|
4
|
+
when_to_use: |
|
|
5
|
+
Trigger when the user wants to search YouTube, inspect their own
|
|
6
|
+
channel / uploaded videos (views, likes, comments), look up a
|
|
7
|
+
video's stats, or upload a new video to their channel. The
|
|
8
|
+
installed connector always grants `youtube.readonly` (search + read
|
|
9
|
+
your channel and videos); the user opts in to `youtube.upload` at
|
|
10
|
+
install time to publish videos — confirm before uploading and
|
|
11
|
+
re-prompt to re-install if the upload scope is missing.
|
|
12
|
+
connections: [google/youtube]
|
|
13
|
+
allowed_tools: [Bash]
|
|
14
|
+
license: Apache-2.0
|
|
15
|
+
metadata:
|
|
16
|
+
author: acedatacloud
|
|
17
|
+
version: "1.0"
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
Call the **YouTube Data API v3** with `curl + jq`. The user's OAuth bearer
|
|
21
|
+
token is in `$GOOGLE_YOUTUBE_TOKEN`; every call needs it as
|
|
22
|
+
`Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN`. Base URL:
|
|
23
|
+
`https://www.googleapis.com/youtube/v3`.
|
|
24
|
+
|
|
25
|
+
The token always carries `youtube.readonly` plus identity scopes
|
|
26
|
+
(`openid email profile`); if the user opted in at install it also
|
|
27
|
+
carries `youtube.upload` (publish videos).
|
|
28
|
+
|
|
29
|
+
Responses are standard JSON; failures surface as
|
|
30
|
+
`{"error": {"code": 401|403|..., "message": "..."}}` — show that error
|
|
31
|
+
verbatim. `401` → token expired, the user must re-connect the YouTube
|
|
32
|
+
connector. `403 insufficientPermissions` on an upload → the user did
|
|
33
|
+
not grant `youtube.upload`; ask them to re-connect with the upload box
|
|
34
|
+
checked.
|
|
35
|
+
|
|
36
|
+
**Always start with the channel check** to confirm the connection works
|
|
37
|
+
and learn which channel you're operating against.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
curl -sS -H "Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN" \
|
|
41
|
+
"https://www.googleapis.com/youtube/v3/channels?part=snippet,statistics,contentDetails&mine=true" \
|
|
42
|
+
| jq '.items[0] | {title: .snippet.title, subs: .statistics.subscriberCount, views: .statistics.viewCount, uploads: .contentDetails.relatedPlaylists.uploads}'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Search YouTube
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Public search (any video). type can be video|channel|playlist.
|
|
49
|
+
curl -sS -H "Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN" \
|
|
50
|
+
--data-urlencode "q=ai video automation" \
|
|
51
|
+
--data-urlencode "part=snippet" \
|
|
52
|
+
--data-urlencode "type=video" \
|
|
53
|
+
--data-urlencode "maxResults=10" \
|
|
54
|
+
-G "https://www.googleapis.com/youtube/v3/search" \
|
|
55
|
+
| jq '.items[] | {videoId: .id.videoId, title: .snippet.title, channel: .snippet.channelTitle, published: .snippet.publishedAt}'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Add `--data-urlencode "order=date|viewCount|rating|relevance"` to sort,
|
|
59
|
+
or `--data-urlencode "publishedAfter=2026-01-01T00:00:00Z"` to window.
|
|
60
|
+
|
|
61
|
+
## See my uploaded videos
|
|
62
|
+
|
|
63
|
+
YouTube has no "list my videos" call directly — read the channel's
|
|
64
|
+
**uploads playlist**, then page its items.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# 1. Get the uploads playlist id (UU... ) — same as channels call above.
|
|
68
|
+
UPLOADS=$(curl -sS -H "Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN" \
|
|
69
|
+
"https://www.googleapis.com/youtube/v3/channels?part=contentDetails&mine=true" \
|
|
70
|
+
| jq -r '.items[0].contentDetails.relatedPlaylists.uploads')
|
|
71
|
+
|
|
72
|
+
# 2. List recent uploads (50/page; follow .nextPageToken for more).
|
|
73
|
+
curl -sS -H "Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN" \
|
|
74
|
+
-G "https://www.googleapis.com/youtube/v3/playlistItems" \
|
|
75
|
+
--data-urlencode "part=snippet,contentDetails" \
|
|
76
|
+
--data-urlencode "playlistId=$UPLOADS" \
|
|
77
|
+
--data-urlencode "maxResults=50" \
|
|
78
|
+
| jq '.items[] | {videoId: .contentDetails.videoId, title: .snippet.title, published: .snippet.publishedAt}'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Paginate by passing `--data-urlencode "pageToken=$PAGE_TOKEN"` with the
|
|
82
|
+
`.nextPageToken` from the previous response.
|
|
83
|
+
|
|
84
|
+
## Video stats (views / likes / comments)
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Accepts a comma-separated id list.
|
|
88
|
+
curl -sS -H "Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN" \
|
|
89
|
+
-G "https://www.googleapis.com/youtube/v3/videos" \
|
|
90
|
+
--data-urlencode "part=snippet,statistics,status" \
|
|
91
|
+
--data-urlencode "id=VIDEO_ID_1,VIDEO_ID_2" \
|
|
92
|
+
| jq '.items[] | {title: .snippet.title, views: .statistics.viewCount, likes: .statistics.likeCount, comments: .statistics.commentCount, privacy: .status.privacyStatus}'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Read comments on a video
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
curl -sS -H "Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN" \
|
|
99
|
+
-G "https://www.googleapis.com/youtube/v3/commentThreads" \
|
|
100
|
+
--data-urlencode "part=snippet" \
|
|
101
|
+
--data-urlencode "videoId=VIDEO_ID" \
|
|
102
|
+
--data-urlencode "maxResults=20" \
|
|
103
|
+
--data-urlencode "order=relevance" \
|
|
104
|
+
| jq '.items[] | .snippet.topLevelComment.snippet | {author: .authorDisplayName, text: .textDisplay, likes: .likeCount}'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Upload a video (needs `youtube.upload`)
|
|
108
|
+
|
|
109
|
+
**Confirm with the user before publishing** — show the title, privacy and
|
|
110
|
+
file you're about to upload. Uploads are a two-step *resumable* flow:
|
|
111
|
+
init with metadata → PUT the bytes.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
FILE="/path/to/video.mp4"
|
|
115
|
+
TITLE="My title"
|
|
116
|
+
DESC="My description"
|
|
117
|
+
# privacyStatus: public | unlisted | private
|
|
118
|
+
read -r -d '' META <<JSON
|
|
119
|
+
{"snippet":{"title":"$TITLE","description":"$DESC","categoryId":"22"},
|
|
120
|
+
"status":{"privacyStatus":"unlisted","selfDeclaredMadeForKids":false}}
|
|
121
|
+
JSON
|
|
122
|
+
|
|
123
|
+
# 1. Init resumable session -> capture the upload URL from the Location header.
|
|
124
|
+
UPLOAD_URL=$(curl -sS -D - -o /dev/null \
|
|
125
|
+
-H "Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN" \
|
|
126
|
+
-H "Content-Type: application/json; charset=UTF-8" \
|
|
127
|
+
-H "X-Upload-Content-Type: video/*" \
|
|
128
|
+
-X POST "https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status" \
|
|
129
|
+
-d "$META" | tr -d '\r' | awk '/^[Ll]ocation:/{print $2}')
|
|
130
|
+
|
|
131
|
+
# 2. Upload the bytes -> returns the created video resource (has .id).
|
|
132
|
+
curl -sS -H "Authorization: Bearer $GOOGLE_YOUTUBE_TOKEN" \
|
|
133
|
+
-H "Content-Type: video/*" \
|
|
134
|
+
-X PUT --upload-file "$FILE" "$UPLOAD_URL" \
|
|
135
|
+
| jq '{id: .id, url: ("https://www.youtube.com/watch?v=" + .id), privacy: .status.privacyStatus}'
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`categoryId` `22` = "People & Blogs" (a safe default). To set a custom
|
|
139
|
+
thumbnail (needs the file to be processed first), call
|
|
140
|
+
`POST /upload/youtube/v3/thumbnails/set?videoId=VIDEO_ID` with the image.
|
|
141
|
+
|
|
142
|
+
## Gotchas
|
|
143
|
+
|
|
144
|
+
- **Quota:** the Data API is quota-metered (default 10,000 units/day). A
|
|
145
|
+
`search` costs 100 units; an `upload` costs ~1,600. A burst of searches
|
|
146
|
+
can exhaust the daily quota → `403 quotaExceeded`; surface it plainly.
|
|
147
|
+
- **No "my videos" endpoint** — always go via the uploads playlist.
|
|
148
|
+
- **`search` results are eventually-consistent** — a freshly uploaded
|
|
149
|
+
video may not appear in `search` for minutes/hours; read it via the
|
|
150
|
+
uploads playlist or by id instead.
|
|
151
|
+
- Uploaded videos start in `uploaded`/`processing` state; stats are `0`
|
|
152
|
+
until processing completes.
|