Skip to content
Back to skills

Racegow Youtube

ASecurity

Upload a verified best-3-consecutive-laps clip (from the fpv-best-laps skill) to the pilot's YouTube channel, with the title, description and tags built from the run - track, 3-lap time and splits, pilot, current RaceGOW leaderboard rank, quad, date flown, sponsor, deadline and the organiser's demo flythrough link - then record the video URL in result.json and the track README. Use whenever someone wants to upload, post, publish or share a best-laps / RaceGOW / whoop race clip on YouTube, or ...

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 16, 2026
ai-agentspythongobashtestingapi

Works with

  • cli
  • api

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 3 files and shows the line behind each finding

Scanned November 11, 2026

npx -y skills add irom77/Racegow --skill racegow-youtube --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Racegow Youtube?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Racegow Youtube
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/irom77-racegow-youtube/badge)](https://www.skillsdirectory.com/skills/irom77-racegow-youtube)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: racegow-youtube
description: Upload a verified best-3-consecutive-laps clip (from the fpv-best-laps skill) to the pilot's YouTube channel, with the title, description and tags built from the run - track, 3-lap time and splits, pilot, current RaceGOW leaderboard rank, quad, date flown, sponsor, deadline and the organiser's demo flythrough link - then record the video URL in result.json and the track README. Use whenever someone wants to upload, post, publish or share a best-laps / RaceGOW / whoop race clip on YouTube, or asks for a YouTube title or description for one.
compatibility: Python 3.9+. Building the description needs only the standard library; uploading needs google-api-python-client and google-auth-oauthlib (scripts/requirements.txt), or `uv run --with`. Needs a Google Cloud OAuth desktop client with YouTube Data API v3 enabled.
---

# Upload a best-laps clip to YouTube

Pilot **PAPFPV**. `<skill-dir>` is the folder with this SKILL.md, `<work>` the fpv-best-laps work
folder (has `result.json` and `export/render_rank<N>.json`). Only upload a clip whose laps were
verified against the demo flythrough (see the fpv-best-laps skill).

Run the script with the Google libraries available, for example:

```bash
YT="uv run -q --no-project --with google-api-python-client --with google-auth-oauthlib python <skill-dir>/scripts/yt_upload.py"
```

(or `pip install -r <skill-dir>/scripts/requirements.txt` into a venv). `meta` and `record` work
with plain `python3`.

## 1. Sign in (once per machine)

The token is in `~/.config/racegow-youtube/token.json` (mode 600, never in a repo) and refreshes by
itself. If it's missing or revoked:

```bash
$YT auth --client /path/to/client_secret_XXXX.json    # first time
$YT auth                                             # again: reuses the client stored in token.json
```

It prints `AUTH_URL ...` (run it in the background with `PYTHONUNBUFFERED=1`, or the URL sits in
the output buffer). There's no browser on WSL, so give the pilot that URL to open; it times out
after a few minutes, so start a new one if they come back later. Signing in again needs no client
file: `auth` without `--client` takes `client_id` and `client_secret` from the existing `token.json`. Google
redirects to `http://localhost:8765`, which the script is listening on. Then the pilot picks the
**channel** to upload to at the Google sign-in. Setup in the Google Cloud project, once:
enable **YouTube Data API v3**, create an OAuth client of type **Desktop app**, and while the app is
in testing mode add the pilot's Google account as a **test user**. Scopes: `youtube.upload`,
`youtube.readonly` (to read the channel name) and `youtube` (playlists: fpv-highlights adds each
Short to its playlist). Tokens are loaded with the scopes they were granted, so an older upload-only
token still uploads.

## 2. Build the title and description

```bash
python3 <skill-dir>/scripts/yt_upload.py meta --work <work> --rank 1
```

It writes `<work>/export/youtube_rank1.json` and prints the title, description, tags and clip.
Where each part comes from:

| Part | Source (override) |
|---|---|
| Time and lap splits, clip | `result.json` best rank N, `export/render_rankN.json` (`--rank`) |
| RaceGOW and track number | folder names such as `RaceeGow6/Track2/1st` (`--race`, `--track`) |
| Demo link + flythrough start | track README: `**Demo video:** <url> ("title")`, `**Flythrough starts at:** 1:00` (`--readme`) |
| Sponsor/designer sentence, deadline | the demo video's description, read with `yt-dlp` (or `uvx yt-dlp`): "RaceGOW6 Track2 is sponsored by ...", "DEADLINE = ..." (`--about-line`, `--deadline`; `--offline` skips it) |
| Sponsor, designer (fallback, tags) | the demo title in the README, "sponsored by X and designed by Y" (`--sponsor`, `--designer`) |
| Leaderboard rank | runs the **racegow-leaderboard** skill now (`--leaderboard file.json`, `--no-rank`) |
| Quad, video system | `--quad` (default Air65, the OSD craft name); system from file names, `hdz_` = HDZero (`--video-system`) |
| Date flown | container `creation_time`, else the file time (`--date`) |

Title format: `RaceGOW6 Track 2 | 41.43s best 3 consecutive laps | PAPFPV`. Category 17 (Sports),
not made for kids. The rank is per track: if the track being uploaded isn't on the leaderboard yet,
the description gives the rank on the latest track that is, and says which track. The
description never says top or bottom half; that's only for the leaderboard report. The Reg#
(300) is never a rank.

Fix every `WARNING` line (pass the missing flag) before going on. If the deadline is missing, read
the demo description yourself (`uvx yt-dlp --skip-download --print description <demo url>`).

## 3. Get approval, then upload

1. **Show the pilot the full title, description and tags** and get an OK. Edit the JSON if they
   want wording changes.
2. **Channel: always https://www.youtube.com/@niuk9290** (papfpv, `UCJeJajoMrXyvZQP2-tKLT8A`),
   never youtube.com/irom77. The pilot settled this; don't ask. Run `$YT channel` to check the
   token points there. If it doesn't, run `auth` again: at sign-in the pilot must pick the
   **papfpv** brand account on Google's "choose an account or brand account" page.
3. **Privacy: public.** The pilot settled this too; don't ask, unless they say otherwise for a
   particular clip.

```bash
$YT upload --meta <work>/export/youtube_rank1.json
```

Both are the script's defaults (`--privacy public`, `--expect-channel @niuk9290`); pass them only to
override. `--expect-channel` takes an id, title or @handle. The upload is refused if the token
points to a different channel, or if this meta JSON was already uploaded (`--again` to override).
The upload is resumable, in 8 MB chunks, with progress.

## 4. Record the URL

`upload` saves the URL by itself, in:

- the meta JSON (`youtube`),
- `<work>/result.json` (`uploads`: rank, video, total, url, privacy, channel, uploaded_at),
- the track README's results table: the YouTube column of the row with this video and total. If
  there's no such row, it says so; add the row by hand (batch, time and splits, video and time
  range, clip, YouTube).

For a video uploaded some other way: `python3 <skill-dir>/scripts/yt_upload.py record --meta ... --url ...`.

Report the URL, privacy and channel to the pilot.

Files in this skill

  • SKILL.md5.5 KB
  • scripts/requirements.txt58 B
  • scripts/yt_upload.py20.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in ai-agents →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.