O que wechat-channels-video faz?
Use a sessão do Ego Lite para salvar rascunhos de vídeo no 视频号助手. Não clique em "Publicar" — a publicação via QR é feita apenas por humanos.
Save a WeChat Channels draft through Ego Lite. Never click Publish — QR publish is human-only.
Instalação do Ego
Primeiro, instale o Ego Lite e certifique-se de que ego-browser está no PATH. Se estiver ausente, falhe suavemente / informe o usuário para instalá-lo. Não use um navegador comum.
Antes de cada publicação: Verificação de Login (Obrigatório)
O estado de login do WeChat Channels expira rapidamente. O agente deve executar o seguinte antes de fazer upload ou preencher formulários:
node scripts/check-login.mjs
# Para manter a janela aberta para o usuário escanear o QR:
node scripts/check-login.mjs --keep
| Código de saída | Significado | Ação do Agente |
|---|---|---|
0 | Logado | Informe login_tip ao usuário e prossiga com o fluxo |
2 | Não logado / ego-browser ausente | Exiba how_to_login / how_to_login_zh, pare. Peça ao usuário para escanear o QR no Ego e depois execute check-login novamente |
1 | Outro erro | Reporte o erro JSON, não finja que foi publicado |
Consulte references/login.md para mais detalhes. Não implemente uma skill separada de verificação de cookies.
Entrada (Genérica, sem caminhos de produto locais)
A parte chamadora fornece os campos de vídeo e texto. Consulte references/inputs.md. Esta skill não fixa nenhum diretório de negócios ~/….
Mínimo necessário: caminho local do video, description, short_title. Opcionais: tags, cover, localização/original/atividade.
Scripts Leves via CLI (Parte Estável)
ego-browser nodejs não repassa argumentos de shell; check-login já está encapsulado usando um entry temporário + ego-browser nodejs -e.
# Na raiz do repositório
node skills/wechat-channels-video/scripts/check-login.mjs
node skills/wechat-channels-video/scripts/check-login.mjs --keep
node skills/wechat-channels-video/scripts/serve-file.mjs --file /caminho/absoluto/para/video.mp4 --port 18765
# No diretório da skill instalada, também pode usar caminhos relativos
node scripts/check-login.mjs
node scripts/serve-file.mjs --file /caminho/absoluto/para/video.mp4 --port 18765
- check-login: Única barreira de login; termina com
finish({ keep: [] })por padrão (exceto com--keep). - serve-file: Servidor de arquivos local com CORS para
fetchda página; imprime{ url, bytes, port }, termina com SIGINT. Para vídeos grandes, não use base64.
Não transforme toda a interface de publicação em um script gigante: wujie, cliques em coordenadas, waitForFileChooser para capa exigem que o agente veja snapshots/screenshots. Os scripts cuidam de tarefas determinísticas (login e upload de arquivos); o preenchimento do formulário segue os passos do agente abaixo.
Referência Rápida da API ego-browser
Cada ego-browser nodejs é um novo processo; TaskSpace / Page persistem entre chamadas, mas variáveis JS não.
| API | Descrição |
|---|---|
taskSpace(name|id) | Um espaço por objetivo do usuário; anote o spaceId para reutilizar |
task.page("p1") | Reuse a página inicial com goto, não abra páginas desnecessariamente |
page.snapshot() | Observação (consegue ver através do shadow DOM do wujie); cliques dentro do wujie são frequentemente bloqueados |
page.evaluate(fn, arg) | Aceita apenas um argumento serializável em JSON (textos longos vão aqui) |
page.mouse.click(x, y) | Útil para modais dentro do wujie |
page.waitForFileChooser() | Único caminho confiável para upload de capa |
task.handOff() | Passa o controle para o humano (publicação via QR / login presencial) |
task.finish({ keep: [] }) | Finaliza e fecha o espaço; use handOff se o humano precisar continuar, não ocupe a máquina por muito tempo |
Importante: snapshot enxerga o shadow DOM do wujie; cliques em texto/referência disparam "intercepts pointer events". Ações dentro do wujie usem .click() dentro de evaluate ou cliques por coordenada mouse.click.
Fluxo do Agente (Após Login Bem-sucedido)
0. Navegar para a Página de Publicação
Não vá diretamente para /platform/post/create (carregamento preguiçoso causa tela branca). Siga o caminho pela UI:
Página inicial → Coluna esquerda "Gestão de Conteúdo" → "Vídeos" → Botão "Publicar Vídeo" à direita
Pronto: dentro do wujie, aparecem os textos "Descrição do vídeo" e "Título curto", além de um input[type=file][accept*="video"] oculto e o botão "Salvar rascunho".
const state = await page.evaluate(() => {
const app = document.querySelector('wujie-app');
if (!app?.shadowRoot) return { wujie: false };
const t = app.shadowRoot.textContent || '';
return {
wujie: true,
hasDesc: t.includes('视频描述'),
hasShort: t.includes('短标题'),
hasUpload: !!app.shadowRoot.querySelector('input[type=file][accept*="video"]'),
hasSave: t.includes('保存草稿'),
};
});
1. Upload do Vídeo
Primeiro, inicie serve-file (porta padrão 18765). Depois, na página, use fetch + DataTransfer para injetar no input de arquivo oculto (o componente de vídeo não reforça isTrusted; a capa, sim):
const r = await page.evaluate(async (p) => {
const root = document.querySelector('wujie-app').shadowRoot;
const input = root.querySelector('input[type=file][accept*="video"]');
const resp = await fetch(p.url);
const dt = new DataTransfer();
dt.items.add(new File([await resp.blob()], p.name, { type: 'video/mp4' }));
input.files = dt.files;
input.dispatchEvent(new Event('input', { bubbles: true }));
input.dispatchEvent(new Event('change', { bubbles: true }));
return 'injected ' + dt.files[0].size;
}, { url: 'http://127.0.0.1:18765/video.mp4', name: 'video.mp4' });
Verificação apenas pelo DOM: deve aparecer o card de prévia "Compartilhar/Curtir/Comentar" e a barra de progresso em 100%. O recurso de performance não captura o POST de upload. Durante o upload, não preencha formulários; se o wujie ficar null momentaneamente, aguarde e tente novamente, não recarregue.
1.5 Ponto de Verificação: Salvar Rascunho Primeiro
Assim que o upload terminar, imediatamente clique em "Salvar rascunho" uma vez. Depois preencha descrição/título curto/localização e salve novamente. Isso evita refazer o upload de arquivos grandes se algo der errado.
2. Descrição + Tópicos
A descrição é um .input-editor (não contenteditable). Use execCommand; o texto é passado como segundo argumento do evaluate:
await page.evaluate((p) => {
const ed = document.querySelector('wujie-app').shadowRoot.querySelector('.input-editor');
ed.focus();
document.execCommand('selectAll', false, null);
document.execCommand('delete', false, null);
document.execCommand('insertText', false, p.desc);
}, { desc });
await page.evaluate((p) => {
const ed = document.querySelector('wujie-app').shadowRoot.querySelector('.input-editor');
ed.focus();
document.execCommand('insertParagraph');
document.execCommand('insertText', false, p.tags);
ed.blur();
}, { tags });
3. Título Curto
É um <input> verdadeiro, deve usar setter nativo; verifique lendo input.value (innerText não contém o valor do input).
4. Localização
Normalmente já vem com a cidade. Abordagem segura: mouse.click para abrir o seletor → snapshot/screenshot → clique em "Não mostrar localização" → releia o campo para confirmar. Coordenadas no evaluate podem clicar em camadas ocultas.
5. Salvar Rascunho (Ponto Final)
Clique em "Salvar rascunho". Sinal de sucesso: texto "Salvo" aparece + botão inferior fica cinza. Depois, navegue para a lista de rascunhos para verificar. Não saia do editor antes de o rascunho aparecer na lista.
Opcional: declarar como original, pesquisa de atividade (use setter nativo para escrever o termo de busca; se não encontrar, escolha "Não participar da atividade").
6. Capa (Opcional)
Único caminho confiável: waitForFileChooser() + clique confiável em "Enviar capa" + chooser.setFiles(<caminho absoluto>). A abordagem de sintetizar input.files / usar caixa de diálogo do sistema já foi testada e falhou. Após o botão de confirmação parar de girar e a prévia não voltar ao quadro padrão, salve o rascunho.
7. Finalização
- Pare o
serve-file(libere a porta). - Se o humano precisar publicar: use
handOff()na lista de rascunhos. - Caso contrário,
finish({ keep: [] }), não ocupe o espaço por muito tempo.
Lista de Armadilhas
- Shadow DOM do wujie: consultas a partir de
wujie-app.shadowRoot. - URL direta
createcausa tela branca: entre pela UI na página de publicação. - Cliques em texto/referência dentro do wujie são bloqueados → use
evaluateou clique por coordenada. - Textos longos devem ser passados apenas como parâmetro do
evaluate. - Descrição use
execCommand; título curto use setter nativo. - Localização: clique por coordenada em duas etapas + releitura para verificar.
- Capa: apenas
waitForFileChooser. - Verificação de upload: apenas pelo DOM; após upload, salve rascunho primeiro.
- Não navegue para fora antes de o rascunho ser salvo.
- A página de login "falha ao carregar" é um falso positivo; use
handOffpara o humano escanear o QR. - Execute check-login antes de cada publicação; código de saída 2 exige parada.
- Publicação é ponto final humano; esta skill só vai até o rascunho.
Testes
npm test