-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Add domain skills: youtube/upload, dev-to/publish, google-search-console/check #476
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
engmsaleh
wants to merge
4
commits into
browser-use:main
Choose a base branch
from
engmsaleh:skill/youtube-upload
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
4b7a3f4
Add youtube/upload domain skill (battle-tested Studio flow)
engmsaleh afa309d
Add devto/publish domain skill (instant dofollow backlink flow)
engmsaleh 322f3e7
Address cubic review: rename devto->dev-to, quote YAML, import json, …
engmsaleh 6f99dc8
Add google-search-console/check domain skill (indexing + sitemap flow)
engmsaleh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # devto/publish — publish an article to DEV.to via the markdown editor (battle-tested 2026-06-28) | ||
|
|
||
| Driving `dev.to/new` with browser-harness against the user's logged-in Chrome. DEV.to gives an **instant, no-queue, high-DR dofollow backlink** in the article body — ideal for cross-posting an existing technical article. Far simpler than rich editors: it's one markdown textarea with Jekyll front matter. | ||
|
|
||
| ## Pre-flight | ||
| - User logged into dev.to in Chrome. `new_tab("https://dev.to/new")` → if the editor (`textarea#article_body_markdown`) is present you're in; if you see a login wall, pause and ask. | ||
| - The "basic markdown editor" puts **everything in one textarea** — title/tags/description go in YAML front matter at the top, body below. | ||
|
|
||
| ## The flow | ||
|
|
||
| ### 1. Build the content (front matter + markdown body) | ||
| ``` | ||
| --- | ||
| title: <Title, plain text> | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
|
||
| published: true # true = publish now; false = save as draft | ||
| description: <≤ ~150 chars> | ||
| tags: programming, ai, webdev, saas # comma-separated, MAX 4, lowercase, no spaces/hyphens inside a tag | ||
| canonical_url: <optional — set to the original if cross-posting, to avoid duplicate-content> | ||
| --- | ||
|
|
||
| <markdown body> | ||
| ``` | ||
| - **YouTube / Tweet embeds:** liquid tag on its own line — `{% embed https://youtu.be/<id> %}`. | ||
| - Body links are normal markdown `[text](https://...)` and render **dofollow**. | ||
|
|
||
| ### 2. Insert it (React-safe native setter — don't type) | ||
| The editor is one big controlled textarea. Set the value via the native setter + fire input/change (typing char-by-char is slow and flaky): | ||
| ```python | ||
| md = open("/path/post.md").read() | ||
| js("""(function(){ | ||
| var t=document.querySelector('textarea#article_body_markdown')|| | ||
| [].slice.call(document.querySelectorAll('textarea')).sort((a,b)=>b.getBoundingClientRect().height-a.getBoundingClientRect().height)[0]; | ||
| var setter=Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype,'value').set; | ||
| setter.call(t, %s); t.dispatchEvent(new Event('input',{bubbles:true})); t.dispatchEvent(new Event('change',{bubbles:true})); | ||
| return 'set:'+t.value.length; | ||
| })()""" % json.dumps(md)) | ||
| ``` | ||
|
|
||
| ### 3. Publish | ||
| - Scroll to the bottom; the button is **"Save changes"** (there is no separate "Publish" button in this editor). With `published: true` in the front matter, clicking **Save changes publishes**; with `published: false` it saves a draft. | ||
| - Success = the URL changes to `https://dev.to/<user>/<slug>`. | ||
|
|
||
| ## Gotchas (field-tested) | ||
| - **"Invalid authenticity token" (CSRF) on save** — the #1 failure. The Rails CSRF token goes stale if the page sat open a while (or across a failed submit). **Fix: `goto("https://dev.to/new")` to reload (fresh token), re-insert the content, save again.** Don't dwell between loading the editor and submitting. | ||
| - **No "Publish" button** — it's "Save changes"; the `published:` front-matter flag decides draft vs live. Don't hunt for a Publish button. | ||
| - **Tags:** max 4, lowercase, each a single token (e.g. `webdev`, not `web-dev`); invalid tags can block the save. | ||
| - **Cover image** is optional but boosts the home-feed; drag-drop only (skip in automation, the user can add later). | ||
| - Cross-posting the same article to multiple sites (HackerNoon, Hashnode, dev.to): set `canonical_url` to the original on the secondary copies if you care about duplicate-content; for pure-backlink plays it's optional. | ||
|
|
||
| ## Why it's worth it | ||
| Instant publish, no moderator queue, DEV.to is high domain authority, and body links are dofollow — so a single cross-post of an existing article = one of the "5 backlinks that matter," in ~3 minutes. Hashnode works the same way (markdown editor + instant publish). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # youtube/upload — publish a video to YouTube via Studio (battle-tested 2026-06-28) | ||
|
|
||
| Driving `studio.youtube.com` with browser-harness against the user's logged-in Chrome. This is the durable map of the upload flow — follow it and the first try works. The whole flow is ~5 steps but several controls resist JS selectors and need **coordinate clicks** (noted below). | ||
|
|
||
| ## Pre-flight | ||
| - User must be logged into the target channel in Chrome. Confirm: `page_info()` on `studio.youtube.com` returns `.../channel/<CHANNEL_ID>` and title contains "YouTube Studio". | ||
| - **Check for an existing video first.** The channel dashboard "Latest video performance" card shows the most recent upload — don't create a duplicate. To reuse an existing video's URL instead of uploading: go to `.../videos/upload`, scrape `a[href*="/video/"]` → `/video/(<id>)/` and build `https://youtu.be/<id>`. | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
|
||
| - Have the absolute path to the local `.mp4` ready. | ||
|
|
||
| ## The flow | ||
|
|
||
| ### 1. Open the upload dialog | ||
| - Click **Create** (top-right): match `aria-label === "Create"` (an `<button>`/`ytcp-button`). Get rect, `click(cx,cy)`. | ||
| - Menu appears with: Create post / **Upload videos** / Go live. Click the element whose trimmed innerText is exactly `Upload videos` (`children.length<=1`, width>0). | ||
|
|
||
| ### 2. Set the file (this triggers the upload immediately) | ||
| - After the dialog opens, find file inputs via CDP and set the **last** one: | ||
| ```python | ||
| doc=cdp("DOM.getDocument", depth=-1, pierce=True) | ||
| nodes=cdp("DOM.querySelectorAll", nodeId=doc["root"]["nodeId"], selector='input[type=file]')["nodeIds"] | ||
| cdp("DOM.setFileInputFiles", files=[ABS_MP4_PATH], nodeId=nodes[-1]) | ||
| ``` | ||
| - Wait ~8s. The dialog shows "Upload complete … Processing will begin shortly". The **public URL is available immediately** in the "Video link" anchor: scrape `a[href*="youtu.be"]` → e.g. `https://youtu.be/qm3aVsWDARY`. Capture it now. | ||
|
|
||
| ### 3. Details — title + description | ||
| - Title and description are **contenteditable `#textbox` divs** (NOT inputs). There are two large ones; sort by `y`: first = Title (pre-filled from filename), second = Description. | ||
| - Replace the title: `click()` it → `document.execCommand('selectAll',false,null)` → `cdp("Input.insertText", text=TITLE)`. | ||
| - Description: `click()` it → `cdp("Input.insertText", text=DESC)`. | ||
| - **Trap:** external links in the description are NOT clickable until the channel completes a one-off verification ("To make external links clickable, first complete a one-off verification"). The link text still shows; fine for a backlink mention. | ||
|
|
||
| ### 4. Audience — "Made for Kids" (REQUIRED, or Next is blocked) | ||
| - Radios are `tp-yt-paper-radio-button`. The "no" option's text is literally **`No, it's not 'Made for Kids'`** (curly quotes around Made for Kids — do NOT match `/not made for kids/`; match `/no,/i` AND `/made for kids/i`). | ||
| - `scrollIntoView({block:'center'})` then `click` its left edge (`rect.x+18, rect.y+height/2`). Verify `aria-checked === "true"`. | ||
|
|
||
| ### 5. Advance + Visibility + Publish | ||
| - Click **Next** (trimmed innerText `Next`, width>0) **3×** with ~3s waits: Details → Video elements → Checks → Visibility. Confirm you're on Visibility (`document.body.innerText` contains "Save or publish"). | ||
| - **Visibility radios resist JS selectors — use COORDINATE clicks.** The three options stack: Private, Unlisted, **Public** (3rd). Selecting any visibility enables the bottom-right button and relabels it `Save`→`Publish`. | ||
| - If a JS query for the radio returns null, click by coordinate. (See coordinate-conversion note below.) | ||
| - Verify selection worked by checking that a `Publish`/`Save` button with `aria-disabled!=="true"` now exists near the bottom (`rect.y>700`). | ||
| - Click **Publish**. Success = a **"Video published"** dialog appears with the share link (`youtu.be/<id>`) + Promote button. | ||
|
|
||
| ## Gotchas (field-tested) | ||
| - **Visibility radios: coordinate clicks only.** `[role=radio]`/`tp-yt-paper-radio-button` text matches fail because the label/description live in sibling nodes. Locate the Public row from a screenshot and click it. | ||
| - **Coordinate conversion:** screenshots come back at 2× retina (e.g. 3840 wide shown at 2000). For `click(x,y)` (CSS px on a ~1920 viewport): `css = displayed_screenshot_coord × 0.96`. | ||
| - **Clicking Publish/Save with no visibility chosen is safely blocked** — a "You need to choose a visibility setting" tooltip shows and the Visibility step turns red; nothing publishes. So a mis-fire here is harmless; just select Public and retry. | ||
| - **Auto-save:** the dialog header reads "Saved as private" / "Saving…" throughout — the video exists as private from the moment of upload; publishing flips it to the chosen visibility. | ||
| - **Don't re-upload an existing video** — check the dashboard card first. | ||
|
|
||
| ## Content best-practices (for the human filling fields) | ||
| - **Title** ≤100 chars, keyword-first. **Description**: 1–2 line hook + links (with timestamps if long). **Tags** in Show More. **Custom thumbnail** beats auto-generated for CTR. Add **end screens / cards** in the "Video elements" step if you skipped it. | ||
| - For embedding in an article (HackerNoon, etc.): paste the `youtu.be/<id>` URL on its own line — most editors auto-embed the player. Public or Unlisted both embed. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.