@acedatacloud/skills 2026.606.1 → 2026.613.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acedatacloud/skills",
3
- "version": "2026.606.1",
3
+ "version": "2026.613.1",
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,68 @@
1
+ ---
2
+ name: blogger
3
+ description: Publish posts to your Blogger blog and read your blogs / posts via the Blogger API v3. Use when the user mentions Blogger, blogspot, publishing a post to their blog, listing their blogs, or updating an existing Blogger post.
4
+ when_to_use: |
5
+ Trigger when the user wants to publish a post to their Blogger blog,
6
+ list their blogs, list / read posts on a blog, or update an existing
7
+ post. The connector grants the Blogger scope (read + write); confirm
8
+ before publishing publicly (you can insert as a draft first).
9
+ connections: [google/blogger]
10
+ allowed_tools: [Bash]
11
+ license: Apache-2.0
12
+ metadata:
13
+ author: acedatacloud
14
+ version: "1.0"
15
+ ---
16
+
17
+ Call the **Blogger API v3** with `curl + jq`. The user's OAuth bearer token is
18
+ in `$GOOGLE_BLOGGER_TOKEN`; every call needs
19
+ `Authorization: Bearer $GOOGLE_BLOGGER_TOKEN`. Base URL:
20
+ `https://www.googleapis.com/blogger/v3`.
21
+
22
+ Errors are `{"error": {"code": ..., "message": ...}}` — show them verbatim.
23
+ `401` → token expired, re-connect the Blogger connector.
24
+
25
+ **Always start by listing the user's blogs** to get a `blogId`:
26
+
27
+ ```bash
28
+ curl -sS -H "Authorization: Bearer $GOOGLE_BLOGGER_TOKEN" \
29
+ "https://www.googleapis.com/blogger/v3/users/self/blogs" \
30
+ | jq '.items[] | {id, name, url}'
31
+ ```
32
+
33
+ ## Publish a post
34
+
35
+ **Confirm before publishing publicly.** Use `?isDraft=true` to stage a draft.
36
+
37
+ ```bash
38
+ BLOG_ID="1234567890"
39
+ jq -n --arg t "My title" --arg c "<p>HTML content of the post…</p>" \
40
+ '{kind:"blogger#post", title:$t, content:$c, labels:["ai","video"]}' \
41
+ | curl -sS -X POST \
42
+ "https://www.googleapis.com/blogger/v3/blogs/$BLOG_ID/posts/?isDraft=false" \
43
+ -H "Authorization: Bearer $GOOGLE_BLOGGER_TOKEN" \
44
+ -H "Content-Type: application/json" \
45
+ -d @- \
46
+ | jq '{id, url, status}'
47
+ ```
48
+
49
+ `content` is **HTML** (not Markdown) — convert Markdown to HTML first
50
+ (e.g. with `pandoc -f markdown -t html` or a simple converter).
51
+
52
+ - Publish a staged draft: `POST /blogs/{blogId}/posts/{postId}/publish`.
53
+ - Update a post: `PUT /blogs/{blogId}/posts/{postId}` with the same shape.
54
+
55
+ ## List / read posts
56
+
57
+ ```bash
58
+ curl -sS -H "Authorization: Bearer $GOOGLE_BLOGGER_TOKEN" \
59
+ "https://www.googleapis.com/blogger/v3/blogs/$BLOG_ID/posts?maxResults=20&status=live" \
60
+ | jq '.items[] | {id, title, url, published}'
61
+ ```
62
+
63
+ ## Gotchas
64
+
65
+ - **Enable the Blogger API** on the Google Cloud project backing the OAuth
66
+ client, or calls 403 with `accessNotConfigured`.
67
+ - `content` must be HTML; passing raw Markdown will render literally.
68
+ - Paginate with `&pageToken=$PAGE_TOKEN` from the previous `.nextPageToken`.
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: devto
3
+ description: Publish, update and read articles on DEV (dev.to) via the Forem API v1. Use when the user mentions dev.to / DEV Community, publishing a blog post to dev.to, cross-posting an article, updating a published post, or listing their dev.to articles and stats.
4
+ when_to_use: |
5
+ Trigger when the user wants to publish a Markdown article to their
6
+ dev.to account, update a previously published article, or list /
7
+ inspect their own dev.to articles (views, reactions, comments). The
8
+ connector stores a DEV API Key with full account access — confirm
9
+ before publishing publicly (you can publish as a draft with
10
+ published=false first).
11
+ connections: [devto]
12
+ allowed_tools: [Bash]
13
+ license: Apache-2.0
14
+ metadata:
15
+ author: acedatacloud
16
+ version: "1.0"
17
+ ---
18
+
19
+ Call the **Forem API v1** (dev.to) with `curl + jq`. The user's API key is in
20
+ `$DEVTO_API_KEY`; every call needs the headers `api-key: $DEVTO_API_KEY` and
21
+ `Accept: application/vnd.forem.api-v1+json`. Base URL: `https://dev.to/api`.
22
+
23
+ Errors come back as JSON with an `error` / `status` field — show them verbatim.
24
+ `401` means the API key is invalid → the user must re-connect the DEV connector.
25
+
26
+ **Always start by confirming the key** and learning the account:
27
+
28
+ ```bash
29
+ curl -sS -H "api-key: $DEVTO_API_KEY" -H "Accept: application/vnd.forem.api-v1+json" \
30
+ "https://dev.to/api/users/me" | jq '{username, name}'
31
+ ```
32
+
33
+ ## Publish an article
34
+
35
+ **Confirm with the user before publishing publicly.** Default to a draft
36
+ (`published:false`) unless they explicitly say publish/now.
37
+
38
+ ```bash
39
+ TITLE="My title"
40
+ BODY_MD="$(cat article.md)" # full Markdown body
41
+ jq -n --arg t "$TITLE" --arg b "$BODY_MD" \
42
+ '{article:{title:$t, body_markdown:$b, published:false, tags:["ai","webdev"]}}' \
43
+ | curl -sS -X POST "https://dev.to/api/articles" \
44
+ -H "api-key: $DEVTO_API_KEY" \
45
+ -H "Accept: application/vnd.forem.api-v1+json" \
46
+ -H "Content-Type: application/json" \
47
+ -d @- \
48
+ | jq '{id, url, published}'
49
+ ```
50
+
51
+ To publish a draft later (or edit), `PUT /api/articles/{id}` with the same
52
+ shape (set `published:true`). Front-matter inside `body_markdown` (a `---`
53
+ block) can also carry `title`, `tags`, `series`, `canonical_url`, `cover_image`.
54
+
55
+ - **Canonical URL:** when cross-posting, set
56
+ `"canonical_url":"https://your-blog/original"` so DEV points SEO back to the
57
+ source — important for the article→video / cross-publishing flow.
58
+
59
+ ## List / inspect my articles
60
+
61
+ ```bash
62
+ # My published + draft articles (paginated; per_page max 1000).
63
+ curl -sS -H "api-key: $DEVTO_API_KEY" -H "Accept: application/vnd.forem.api-v1+json" \
64
+ "https://dev.to/api/articles/me/all?per_page=30" \
65
+ | jq '.[] | {id, title, published, page_views_count, public_reactions_count, comments_count}'
66
+
67
+ # A single article's full content + stats.
68
+ curl -sS -H "api-key: $DEVTO_API_KEY" -H "Accept: application/vnd.forem.api-v1+json" \
69
+ "https://dev.to/api/articles/ARTICLE_ID" | jq '{title, url, reactions: .public_reactions_count, views: .page_views_count}'
70
+ ```
71
+
72
+ ## Gotchas
73
+
74
+ - **Tags:** max 4, lowercase, no spaces (e.g. `webdev`, `machinelearning`).
75
+ - **Rate limit:** article create/update is throttled (a few per 30s); space out
76
+ bulk publishes or you'll get `429`.
77
+ - `body_markdown` is the source of truth — if you put a `---` front-matter block
78
+ at the top, its fields override the JSON `article` fields.
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: linkedin
3
+ description: Publish text / link posts to your LinkedIn personal feed via the LinkedIn Posts API. Use when the user mentions LinkedIn, sharing or posting an update to LinkedIn, or cross-posting an article / link to their LinkedIn feed.
4
+ when_to_use: |
5
+ Trigger when the user wants to publish a text or link share to their
6
+ own LinkedIn feed. Posting is public on their profile — confirm the
7
+ text (and link, if any) before publishing. Requires the
8
+ w_member_social scope (granted by the connector at install).
9
+ connections: [linkedin]
10
+ allowed_tools: [Bash]
11
+ license: Apache-2.0
12
+ metadata:
13
+ author: acedatacloud
14
+ version: "1.0"
15
+ ---
16
+
17
+ Call the **LinkedIn API** with `curl + jq`. The user's bearer token is in
18
+ `$LINKEDIN_TOKEN`; every call needs `Authorization: Bearer $LINKEDIN_TOKEN`.
19
+
20
+ LinkedIn posts must be authored by the member's URN. Get the member id from the
21
+ OpenID userinfo endpoint, then build `urn:li:person:{sub}`.
22
+
23
+ ```bash
24
+ SUB=$(curl -sS -H "Authorization: Bearer $LINKEDIN_TOKEN" \
25
+ "https://api.linkedin.com/v2/userinfo" | jq -r .sub)
26
+ AUTHOR="urn:li:person:$SUB"
27
+ echo "$AUTHOR"
28
+ ```
29
+
30
+ Errors are JSON with `message` / `serviceErrorCode` — show them verbatim.
31
+ `401` → token expired (tokens last ~60 days), re-connect the LinkedIn connector.
32
+
33
+ ## Publish a post (Posts API)
34
+
35
+ **Confirm the text with the user first.** Use the versioned Posts API; set the
36
+ `LinkedIn-Version` header to a recent `YYYYMM` (LinkedIn requires a valid recent
37
+ version — if you get `426`/version errors, bump to the current month).
38
+
39
+ ```bash
40
+ jq -n --arg a "$AUTHOR" --arg t "My update text. Check out https://studio.acedata.cloud" \
41
+ '{author:$a, commentary:$t, visibility:"PUBLIC",
42
+ distribution:{feedDistribution:"MAIN_FEED", targetEntities:[], thirdPartyDistributionChannels:[]},
43
+ lifecycleState:"PUBLISHED", isReshareDisabledByAuthor:false}' \
44
+ | curl -sS -X POST "https://api.linkedin.com/rest/posts" \
45
+ -H "Authorization: Bearer $LINKEDIN_TOKEN" \
46
+ -H "Content-Type: application/json" \
47
+ -H "LinkedIn-Version: 202401" \
48
+ -H "X-Restli-Protocol-Version: 2.0.0" \
49
+ -d @- -D - -o /dev/null | tr -d '\r' | awk '/^[Xx]-[Rr]estli-[Ii]d:|^[Ll]ocation:/{print}'
50
+ ```
51
+
52
+ A successful create returns `201` with the post URN in the `x-restli-id`
53
+ (or `Location`) response header — report that URN / the resulting post URL.
54
+
55
+ > Link posts: put the URL inline in `commentary` (LinkedIn auto-unfurls it).
56
+ > Rich article attachments need the assets/images API — out of scope for a
57
+ > simple text/link share; keep links inline.
58
+
59
+ ## Fallback: legacy ugcPosts
60
+
61
+ If the versioned endpoint is unavailable for the app, the older
62
+ `POST https://api.linkedin.com/v2/ugcPosts` with a
63
+ `specificContent."com.linkedin.ugc.ShareContent"` body also works with
64
+ `w_member_social`. Prefer `/rest/posts` above.
65
+
66
+ ## Gotchas
67
+
68
+ - **Author URN** must match the token's member (`urn:li:person:{sub}`) — you
69
+ can't post as someone else.
70
+ - `w_member_social` only allows posting to the **member's own feed**; company
71
+ Page posts need `w_organization_social` + an admin role (not in this connector).
72
+ - The `LinkedIn-Version` header is mandatory for `/rest/*`; a stale value
73
+ returns a version error — bump to the current `YYYYMM`.
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: reddit
3
+ description: Submit posts (link or text) to subreddits and read your Reddit identity / content via the Reddit API. Use when the user mentions Reddit, posting to a subreddit, submitting a link or self-post, or checking their Reddit profile / submissions.
4
+ when_to_use: |
5
+ Trigger when the user wants to submit a post to a subreddit (link or
6
+ self/text post), or read their own Reddit identity and submissions.
7
+ Posting to a subreddit is public and subject to that subreddit's rules
8
+ / karma requirements — confirm the target subreddit, title and body
9
+ before submitting.
10
+ connections: [reddit]
11
+ allowed_tools: [Bash]
12
+ license: Apache-2.0
13
+ metadata:
14
+ author: acedatacloud
15
+ version: "1.0"
16
+ ---
17
+
18
+ Call the **Reddit API** (OAuth endpoints) with `curl + jq`. The user's bearer
19
+ token is in `$REDDIT_TOKEN`. **Every call MUST send a `User-Agent` header** or
20
+ Reddit returns `429`. Use the OAuth host `https://oauth.reddit.com`.
21
+
22
+ ```bash
23
+ UA="web:cloud.acedata.connectors:v1.0 (by /u/acedatacloud)"
24
+ ```
25
+
26
+ Errors are JSON; a submit returns `{"json":{"errors":[...], "data":{...}}}` —
27
+ if `errors` is non-empty, show them verbatim. `401` → token expired, re-connect.
28
+
29
+ **Always start by confirming identity:**
30
+
31
+ ```bash
32
+ curl -sS -H "Authorization: Bearer $REDDIT_TOKEN" -H "User-Agent: $UA" \
33
+ "https://oauth.reddit.com/api/v1/me" | jq '{name, total_karma, link_karma}'
34
+ ```
35
+
36
+ ## Submit a post
37
+
38
+ **Confirm the subreddit + title + body with the user first.** `sr` is the
39
+ subreddit name WITHOUT the `r/` prefix.
40
+
41
+ ```bash
42
+ # Self (text) post: kind=self + text. Link post: kind=link + url.
43
+ curl -sS -X POST "https://oauth.reddit.com/api/submit" \
44
+ -H "Authorization: Bearer $REDDIT_TOKEN" -H "User-Agent: $UA" \
45
+ --data-urlencode "sr=test" \
46
+ --data-urlencode "kind=self" \
47
+ --data-urlencode "title=My title" \
48
+ --data-urlencode "text=My self-post body in markdown" \
49
+ --data-urlencode "api_type=json" \
50
+ | jq '.json | {errors, url: .data.url, id: .data.id}'
51
+ ```
52
+
53
+ For a link post:
54
+
55
+ ```bash
56
+ curl -sS -X POST "https://oauth.reddit.com/api/submit" \
57
+ -H "Authorization: Bearer $REDDIT_TOKEN" -H "User-Agent: $UA" \
58
+ --data-urlencode "sr=test" --data-urlencode "kind=link" \
59
+ --data-urlencode "title=My title" --data-urlencode "url=https://example.com" \
60
+ --data-urlencode "api_type=json" | jq '.json'
61
+ ```
62
+
63
+ ## Read my submissions
64
+
65
+ ```bash
66
+ curl -sS -H "Authorization: Bearer $REDDIT_TOKEN" -H "User-Agent: $UA" \
67
+ "https://oauth.reddit.com/user/USERNAME/submitted?limit=10" \
68
+ | jq '.data.children[] | .data | {title, subreddit, ups, num_comments, permalink}'
69
+ ```
70
+
71
+ ## Gotchas
72
+
73
+ - **User-Agent is mandatory** on every request — omitting it → `429`.
74
+ - Many subreddits gate posting on **account age / karma / flair**; a submit can
75
+ return `errors` like `[["SUBREDDIT_NOTALLOWED", ...]]` — surface it and try
76
+ `r/test` to validate the flow.
77
+ - Respect rate limits: read the `X-Ratelimit-Remaining` response header; space
78
+ out bulk submits.
79
+ - Use `r/test` as a safe target when validating that the connection works.
@@ -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.