# Gemini Imagegen Browser

> Generate images (Nano Banana; Pro variant via per-message 'Recreate in Pro'), video and music with the mode picker in a logged-in gemini.google.com browser session (user's own Google AI subscription — the single account configured as ACCOUNT; other accounts forbidden, but SWITCHING between already-signed-in accounts to the configured one is allowed) via browser-harness CDP — no API key. Use when…

- **Type:** Skill
- **Install:** `agentstack add skill-prophetic-helgy-gemini-mediagen-automatizator-gemini-mediagen-automatizator`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Prophetic-Helgy](https://agentstack.voostack.com/s/prophetic-helgy)
- **Installs:** 0
- **Category:** [Web & Browser](https://agentstack.voostack.com/c/web-and-browser)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Prophetic-Helgy](https://github.com/Prophetic-Helgy)
- **Source:** https://github.com/Prophetic-Helgy/gemini-mediagen-automatizator

## Install

```sh
agentstack add skill-prophetic-helgy-gemini-mediagen-automatizator-gemini-mediagen-automatizator
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Генерация в gemini.google.com через залогиненный Chrome (без API-ключа)

Генерация картинок (web-модель Nano Banana; по запросу на особо высокое качество —
пересоздание в Nano Banana Pro, СМ. «Пересоздание в Pro»), видео и музыки режимами
выбора («Изображения / Видео / Музыка») в web-интерфейсе gemini.google.com на
подписке пользователя, без API-ключа (подписка кредиты API не даёт — API-бэкенд не
выдумывать).
Движок — публичный пакет `browser-harness` (pip): CLI читает python-скрипт из
stdin, хелперы уже импортированы:
`list_tabs switch_tab new_tab js cdp click_at_xy page_info wait_for_load`.

Референс-реализация в этом репозитории: `examples/gen_frames.py` (батч картинок:
кадр-рецепт, префлайт аккаунта, переключение, ожидание лимита, валидация,
реестр, идемпотентность). Если скрипт нужен «как есть» — берите его, а не
переписывайте с нуля; режимы Видео/Музыка — по аналогии (см. «Режимы»).

## Аккаунт (жёсткая привязка к НАСТРОЕННОМУ)

Единственный разрешённый аккаунт — тот, что настроен как `ACCOUNT`
(в `examples/gen_frames.py`; при работе «через агента» — спросите у пользователя
один раз и запоминайте в контекст/память). Правила:

- Перед генерацией проверить, что активный аккаунт на gemini.google.com — именно
  ACCOUNT: искомать адрес профиля в DOM (атрибуты avatar/profile-элемента,
  `aria-label`, `title`, textContent; заодно `` аватара с `title`/`src`).
  Надёжнее всего — `aria-label` родителя аватара («Аккаунт Google: NAME (e-mail)»);
  префикс URL `/u/N` аккаунт НЕ доказывает (индексы плавают) — при нескольких
  вкладках gemini брать ту, где скан даёт ACCOUNT.
- Активный аккаунт — ДРУГОЙ из уже залогиненных на машине — РАЗРЕШЕНО
  переключиться самостоятельно: `location.assign`
  `https://accounts.google.com/AccountChooser?continue=https%3A%2F%2Fgemini.google.com%2Fapp`,
  в chooser найти строку с точным текстом `ACCOUNT` (shadow-piercing обход,
  точное совпадение e-mail'а, не подстрока чужого). Строка chooser НЕ реагирует на
  trusted-клик и на клик по leaf — работает ТОЛЬКО JS `.click()` по предку
  `div[role=link]` (проверено 2026-09-15); дождаться возвращения на gemini/app и
  ПОВТОРИТЬ скан.
- **«Аккаунт-гарант» в батче**: скан аккаунта — ДО кадра и ПОСЛЕ любого
  переключения/навигации. Вкладка нужного аккаунта может быть закрыта пользователем —
  оставшиеся вкладки gemini окажутся на чужих аккаунтах, и молча «наследовать первую
  вкладку» нельзя; идти через AccountChooser способом выше.
- Иначе переключение запрещено: НЕ вводить пароль/коды за пользователя, НЕ
  выбирать иной аккаунт, НЕ «пробовать другой». После переключения скан снова не
  ACCOUNT, либо Google требует учётные данные (`login_wall`), либо e-mail не найден
  среди залогиненных — статус `account_mismatch` / `login_wall`: ОСТАНОВКА и доклад.

## Предусловия (проверять первыми)

1. `pip install browser-harness` установлен (`browser-harness --version`;
   FileNotFound → доложить; установка/подключение Chrome — install.md в
   github.com/browser-use/browser-harness).
2. В Chrome есть вкладка/сессия gemini.google.com, залогиненная на ACCOUNT
   (см. «Аккаунт»). Логин за пользователя не выполняется НИКОГДА.
3. Один кадр ≈ 90+ с. Дневной лимит подписки реален: темп ≥90 с + джиттер между
   кадрами. Маркеры: «вы достигли лимита», «вернитесь завтра»,
   «come back tomorrow», «reached your limit» … По маркеру — СМ. «Сброс лимита».
4. Ожидание кадра, лимиты таймаутов — щедрее, чем кажется: генерация видео/музыки
   занимает минуты.

## Рецепт кадра (отлажено на живом UI 2026-09-14; порядок и задержки — часть рецепта)

Весь кадр — ОДИН python-скрипт в stdin `browser-harness`, печатает
`###JSON###` в конце.

1. **Чистый диалог**: найти вкладку gemini.google.com (иначе new_tab),
   `location.assign('…/app')` — свежий лендинг, чтобы «появился img» означало НАШ кадр.
2. **Композер**: DOM-поллинг селектора `.ql-editor, div[contenteditable="true"][role="textbox"], textarea`
   до 90 с. Никаких фиксированных sleep-ов на ожидание.
3. **Режим (Изображения / Видео / Музыка)**: оверлей «Загрузка и инструменты»
   открывается JS-ом `el.click()` по кнопке (`aria-label` ~ /загрузка и инструмент/i).
   **Названия пунктов плавают от дня к дню: 2026-09-14 — «Изображения», «Видео», «Музыка»;
   вечер 2026-09-15 — «Создание изображений», «Создание видео», «Создание музыки»
   (DOM `.gem-menu-item-label`). Точный поиск по старому имени не находит пункт → режим
   не выбран → промпт уходит в режим по умолчанию и генерируется ФОТО вместо видео.**
   **Меню раскрывается ДВУМЯ волнами: сразу только «Загрузить файлы»/«Добавить с Google
   Диска»/«Другие варианты ›»; секция режимов дорисовывается асинхронно через 5–20 с —
   поллить текст нужного пункта, не кликать раньше (промах = дефолтный режим = фото вместо
   видео).** **Надёжнее входа в видео-режим — сайдбар-пункт «Видео»: стабильный селектор
   `[data-test-id="videos-side-nav-entry-button"]` (href /videos, прямой URL `…/videos`) —
   страница «Создание видео» с галереей шаблонов и УЖЕ активным режимом видео + выбор
   соотношения сторон (16:9); шаблоны трогать не нужно — печатать промпт и слать.**
   Поэтому: дамп пунктов открытого оверлея (shadow-piercing: `querySelectorAll('*')` +
   рекурсия в `shadowRoot`), матч подстрогом (нормализовать регистр/пробелы). Выбор —
   `el.click()` по leaf с поиском кликабельного предка
   /button|menuitem|list-item|action|mat-list-item|toolbox-item/i; если JS-клик не реагирует —
   trusted `click_at_xy` по координатам пункта. Верификация — чип режима **у композера**
   (нижняя половина экрана, x>250 — иначе ловится одноимённый пункт боковой навигации) или
   placeholder («Опишите видео»). Фолбэк (путь B): trusted-клик `click_at_xy`
   по кнопке + стрелки/Enter. Между путями — `location.assign('…/app')` (сброс
   состояния меню). 3 ретрая; после неудачи — скрин-дебаг и `mode_not_selected`.
   Каждый цикл: `Page.bringToFront` + Escape-сброс (оверлей Angular закрывается при blur).
4. **Промпт**: клик в композер, `Input.insertText`, ВЕРИФИКАЦИЯ textContent == промпт
   (`prompt_mismatch` иначе). Промпт = описание + «Ракурс: X» + стилевой блок; для
   картинок ещё «квадрат 1:1, ≥1024²» (для видео/музыки — длительность/формат по брифу).
5. **Отправка**: в режиме картинок Enter вставляет перевод строки, а НЕ отправляет —
   Enter НЕ жаловать НИКОГДА (фолбэк «подождать и нажать Enter» сжигает промпт переводом
   строки). Кнопка «Отправить сообщение» в режиме картинок принимает JS-клик **с задержкой
   30–90 с** (проверено 2026-09-15): PRIMARY — JS `.click()` по кнопке
   `aria-label` ~ /отправ|send/i (`scrollIntoView` + `.click()`; trusted-клик по её
   координатам НЕ работает), поллить «композер опустел» до **150 с, повторный `.click()`
   раз в ~12 с**; за 150 с не ушла — `send_failed` со скрин-дебагом.
   Регекспсы без `\b` (кириллица не `\w` в JS без unicode-флага).
6. **Ожидание**: картинки — DOM-поллинг `img` class~`image`, `complete`,
   `naturalWidth ≥ 512`; видео — `video` с `readyState ≥ 2`, `videoWidth > 0` и финальным
   `duration` (элемент виден и из главного документа). Скорость серверной очереди плавно
   меняется по дням: днём текст-без-референсов — 36 с, тем же вечером — >10 мин и не готова
   к 610 с. Таймаут ожидания ≥30 мин; карточка «Создание видео…» + «Вернитесь позже» при
   пустом «Ответ Gemini» = задача ЖИВАЯ (пустой ответ — норма для видео), ждать и НЕ
   перегенерировать; музыка — `audio` с ненулевым
   `duration`. Параллельно проверка текстов лимита; timeout → `timeout_or_no_media`.
7. **Выгрузка**: CSP режет fetch blob, кнопка «Скачать» — в скрытом overflow ⇒
   ПРОВЕРЕНО 2026-09-14: «Скачать изображение в полном размере» и «Ещё»→«Скачать»
   из автоматизации НЕ забираются (fetch(blob:) блокирует CSP; клик по скачиванию —
   JS и trusted — файл не создаёт; переоткрытие чата не помогает). Тупик — сразу
   canvas:
   картинка: canvas `drawImage(img)` + `toDataURL('image/png')` → base64 → файл;
   видео/музыка: `video.currentSrc` — https `contribution.usercontent.google.com/download?...`
   (генерация по тексту) или `blob:` (с референсами). Для https-URL PRIMARY:
   `fetch(url, {credentials:'include'})` из вкладки ЧАТА (fetch БЕЗ credentials — «Failed to
   fetch»: отсутствующая авторизационная кука, а не CSP; проверено 2026-09-15) → base64
   чанками; фолбэк — `cdp('Browser.setDownloadBehavior', behavior='allow', downloadPath=…)` +
   `new_tab(currentSrc)` → оригинальный mp4 без перекодирования кладётся в downloadPath
   (проверено 2026-09-15; размеры с fetch+credentials совпадают побайтово), вкладку закрыть.
   **Одно окно:** весь кадр — доступ, промпт, отправка, ожидание и выгрузка — в ОДНОЙ вкладке
   (той, где начата генерация); new_tab поднимает отдельное окно — только фолбэк при провале
   fetch+credentials. Выбор вкладки (скан аккаунта) — ДО начала кадра.
   Для `blob:` — `fetch(blobUrl)→arrayBuffer→base64`;
   фолбэк — CDP-перехват (`Network.responseReceived` → `Network.getResponseBody`,
   base64-флаг). Чанковать base64 наружу, целиком в одну печать не сувать.

## Режимы

- **Изображения** (Nano Banana Pro): рецепт выше целиком; валидация PIL — СМ. ниже.
- **Видео / Музыка**: тот же конвейер; отличается пункт меню (шаг 3), критерий
  готовности (шаг 6) и способ выгрузки (шаг 7). Скорость видео — от секунд до >10 мин
  (серверная очередь, зависит от дня); таймаут — ≥30 мин в обоих случаях.
  В реестре `kind` = image|video|music.

## Пересоздание в Pro (по запросу «особо высокое качество», проверено 2026-09-14)

Обычная генерация идёт Nano Banana (режим «Изображения»). Более качественный вариант
— **Nano Banana Pro** — доступен НЕ в меню «+», а на уже созданном изображении, как
наслоение на обычное создание:

- В тулбаре сообщения-картинки (ряд действий под изображением) — кнопка «Ещё»:
  `data-test-id="more-menu-button"`, `aria-label` ~ /показать другие варианты/i,
  тултип «Ещё». В композере/меню «+» Pro нет.
- Клик по «Ещё» (js `.click()` по ``, shadow-piercing обход) → меню с
  пунктами; нужен «Пересоздать в Pro» (текст искать /пересоздать в pro|recreate in
  pro/i, leaf + клик предку `[role=menuitem]`/`gem-menu-item`; меню может
  прокручиваться — листать при промахе).
- Соседняя кнопка «Повторить» (`data-test-id="regenerate-button"`) — обычное
  пересоздание: новый ВАРИАНТ того же режима (счётчик «2/2», «3/3» у тулбара).
  Pro-пункт создаёт вариант в Pro (детальнее по микрофактуре; на web разрешение
  1024², как у обычной).
- Ожидание: поллинг НОВОГО `img` (blob-URL отличается от прежних, `naturalWidth ≥
  512`); индикатор «генерации» может висеть и после готовности — не доверять.
  В реестр — отдельный ряд (name с суффиксом `_pro`). На Pro-пересоздание
  распространяется суточный лимит.

## Валидация кадра (для картинок — PIL, не «на глаз»)

- размер ≥ целевого (обычно 1024²);
- однотонный фон: разброс RGB 4 углов ≤ 30;
- объект по центру: bbox ненулевых пикселей (Δ>60 от фона) в ±0.16 от центра;
- доля объекта 4–95 % (мелкий/съевшийся кадр — реджект).

Провал → ретрай с **переразметкой** промпта (прогрессивно жёстче: «фон строго
однотонный, объект один, крупно, по центру, без теней и текста»), ≤3 попыток,
дальше `needs_human_review`. Принятый кадр на диске — идемпотентность: не
перегенерировать.

## Сброс лимита: ждать и продолжать

По маркеру лимита Gemini печатает сообщение со **датой и временем сброса**. Это не
конец очереди: распарсить, дождаться, продолжать.

- **Коррекция времени**: UI может показывать время сброса в поясе, отличном от
  системного. По умолчанию поправка НЕ применяется (OFFSET=0); проверьте смещение
  ОДИН раз по первому сообщению о лимите и, если оно ненулевое, зафиксируйте.
- **Дата** может быть другим днём («15 сентября», «Sep 15», «15.09») — брать её.
  Даты нет → сегодня; если после коррекции момент прошёл → завтра.
- Ждать до (скорректированный момент **+ 2 минуты** «для верности»), спать чанками
  с логом, затем ПРОДОЛЖИТЬ очередь с того же кадра (ретраям лимит не засчитывать;
  в реестр — строка `fail:limit_reached` с исходным текстом сообщения).
- Парсить из окна текста вокруг маркера: время `(\d{1,2}):(\d{2})`, дата — `дд.мм`
  или «число + месяц (род. падеж)». Время не нашлось → ОСТАНОВКА и доклад (не
  гадать). Ожидание > 26 ч → `needs_human_review`.

## Реестр (обязательно)

CSV-ряд на каждый кадр (успех И провал): kind, name, frame, **точный промпт**,
модель, UTC, файл, sha256, статус (`ok`/`fail:…`/`needs_human_review`),
длительность. Без реестра батч не воспроизводим. Внимание: реестр хранит промпты
— не допускайте в них персональных данных, если реестр куда-то коммитится.

## Типовые грабли

| Симптом | Причина / лечение |
|---|---|
| Оверлей закрылся до выбора пункта | вкладка не в фокусе → `Page.bringToFront` перед КАЖДОЙ попыткой, Escape-сброс |
| Довериться trusted-клику «+»/↓↓↓→Enter | UI с 2026-09 плоский, JS `.click()` открывает оверлей; trusted-путь — только фолбэк |
| Enter вместо отправки печатает перенос строки | жать `.click()` по кнопке отправки (`aria-label` ~ /отправ\|send/i), не Enter |
| `mode_not_selected` после trusted-ретрая | фокус меню засорён — `location.assign('…/app')` между путями |
| Чип не виден `querySelector` | Angular shadow-DOM — рекурсия в `shadowRoot` |
| `fetch(blob)` / скачивание не работает | CSP — canvas toDataURL для картинок; для media с https-src — fetch+credentials из вкладки чата (или `Browser.setDownloadBehavior`+`new_tab`), для blob — fetch/CDP-перехват. Кнопка «Скачать в полном размере» из автоматизации НЕ срабатывает — не пытаться |
| fetch mp4 с usercontent «Failed to fetch» | не хватает авторизационной куки: `{credentials:'include'}` из вкладки чата — проходит |
| Генерация «висит» неограниченно, пустые «Ответ Gemini», панель не монтируется | чаще всего канал доступа к сервису (зеркало/прокси устарел) — после смены канала тот же промпт готов за минуту; проверь вручную, прежде чем делать выводы о политике контента |
| `video_mode_not_selected`, а вместо видео вышло ФОТО | пункт меню переименован («Создание видео» вместо «Видео») — точный матч по старому имени не находит, промпт ушёл в режим по умолчанию; дамп пунктов + подстрочный матч, чип валиден только у композера |
| `timeout_or_no_video`, а в чате карточка «Создание видео…» | задача ЖИВАЯ в серверной очереди («Вернитесь позже»; пустой «Ответ Gemini» — норма для видео). Ждать ≥30 мин, один reload чата; ложный отказ = перегенерация = пустой расход дневного лимита |
| `timeout_or_no_video` при живом чате (текст-промт без референсов) | src у видео НЕ blob, а `contribution.usercontent.google.com/download?...`, и готово оно за ` — признак принятой отправки |
| На AccountChooser клик по строке аккаунта «не давит» | страница `accounts.google.com/.../accountchooser`: trusted `click_at_xy` и JS `.click()` по leaf бесполезны — работает только JS `.click()` по предку `div[role="link"]`; признак возврата — `href.startswith` с точного URL gemini (подстрока 'gemini.google.com' ложно светится в continue-параметре URL chooser'а) |
| Лимит «сбросится завтра» и очередь встала | читать дату+время из сообщения, +OFFSET, +2 мин, спать и продолжать |

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Prophetic-Helgy](https://github.com/Prophetic-Helgy)
- **Source:** [Prophetic-Helgy/gemini-mediagen-automatizator](https://github.com/Prophetic-Helgy/gemini-mediagen-automatizator)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-prophetic-helgy-gemini-mediagen-automatizator-gemini-mediagen-automatizator
- Seller: https://agentstack.voostack.com/s/prophetic-helgy
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
