Que fait wechat-channels-video ?
Utilisez une session Ego Lite dans l'assistant Channels pour enregistrer un brouillon vidéo. Ne cliquez pas sur « Publier » (la publication par QR est réservée à l'humain).
Save a WeChat Channels draft through Ego Lite. Never click Publish — QR publish is human-only.
Installation préalable : Ego
Installez d'abord Ego Lite et assurez-vous que ego-browser est dans le PATH. En cas d'absence, faites un soft-fail / informez l'utilisateur de l'installer, n'utilisez pas un navigateur classique.
Avant chaque publication : vérification de connexion (obligatoire)
La session de connexion à Channels expire très rapidement. L'agent doit exécuter la commande suivante avant toute opération d'upload ou de remplissage de formulaire :
node scripts/check-login.mjs
# Si la fenêtre doit être laissée à l'utilisateur pour scanner le QR :
node scripts/check-login.mjs --keep
| Code de sortie | Signification | Action de l'agent |
|---|---|---|
0 | Connecté | Informe l'utilisateur du login_tip, continue le processus. |
2 | Non connecté / ego-browser absent | Affiche how_to_login / how_to_login_zh, s'arrête. Demande à l'utilisateur de scanner le QR dans Ego, puis de relancer check-login. |
1 | Autre erreur | Signale l'error JSON, ne fait pas comme si la publication avait eu lieu. |
Voir les détails dans references/login.md. N'utilisez pas une autre compétence de vérification de cookies.
Entrées (génériques, sans chemin produit local)
L'appelant fournit le chemin de la vidéo et les champs de texte, voir references/inputs.md. Cette compétence n'utilise pas de répertoire métier en dur de type ~/….
Minimum requis : chemin local video, description, short_title. Optionnels : tags, cover, emplacement/original/activité.
Scripts CLI fins (partie stable)
ego-browser nodejs ne transmet pas les arguments shell ; check-login est déjà encapsulé avec une entrée temporaire + ego-browser nodejs -e.
# Depuis la racine du dépôt
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 /chemin/absolu/vers/video.mp4 --port 18765
# Depuis le répertoire de la compétence installée, vous pouvez aussi utiliser le chemin relatif
node scripts/check-login.mjs
node scripts/serve-file.mjs --file /chemin/absolu/vers/video.mp4 --port 18765
- check-login : unique porte de vérification de connexion ; se termine par défaut par
finish({ keep: [] })(sauf si--keepest utilisé). - serve-file : service de fichiers CORS local pour les
fetchde la page ; imprime{ url, bytes, port }, se termine par SIGINT. N'utilisez pas base64 pour les vidéos volumineuses.
Ne pas regrouper toute l'interface de publication en un seul script monolithique : wujie, les clics par coordonnées, le téléchargement de couverture avec waitForFileChooser nécessitent que l'agent observe les snapshots/captures d'écran. Les scripts gèrent les parties déterministes (connexion, transfert de fichier) ; le formulaire est traité par les étapes de l'agent ci-dessous.
Aide-mémoire de l'API ego-browser
Chaque appel à ego-browser nodejs crée un nouveau processus ; TaskSpace / Page persistent entre les appels, mais les variables JavaScript ne persistent pas.
| API | Description |
|---|---|
| `taskSpace(name | id)` |
task.page("p1") | Réutilisez la page initiale avec goto, n'ouvrez pas de nouvelles pages inutilement. |
page.snapshot() | Observabilité (voit à travers l'ombre ouverte) ; les clics sont souvent interceptés dans wujie. |
page.evaluate(fn, arg) | Accepte un seul argument sérialisable JSON (les longs textes passent par ici). |
page.mouse.click(x, y) | Utile pour les popups dans wujie. |
page.waitForFileChooser() | Seule méthode fiable pour le téléchargement de couverture. |
task.handOff() | Passe la main à l'humain pour publier par QR / se connecter en direct. |
task.finish({ keep: [] }) | Ferme l'espace à la fin ; utilisez handOff si l'humain doit continuer, n'occupez pas la machine longtemps. |
Point clé : le snapshot voit le shadow wujie ; les clics par ref/texte échouent avec une interception des événements pointeur. Dans wujie, utilisez .click() dans evaluate ou mouse.click par coordonnées.
Processus de l'agent (après connexion réussie)
0. Naviguer vers la page de publication
N'utilisez pas directement goto /platform/post/create (page blanche due au lazy loading). Suivez le parcours UI :
Accueil → barre de gauche « Gestion du contenu » → « Vidéo » → bouton droit « Publier une vidéo »
État attendu : les textes « Description de la vidéo », « Titre court » apparaissent dans wujie, ainsi qu'un input[type=file][accept*="video"] caché et un bouton « Enregistrer le brouillon ».
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. Télécharger la vidéo
Lancez d'abord serve-file (port par défaut 18765), puis dans la page, effectuez un fetch + injection via DataTransfer dans l'input file caché (le composant vidéo n'est pas renforcé par isTrusted ; la couverture, oui) :
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' });
Vérification : observez uniquement le DOM (apparition de la carte de prévisualisation « Transmettre/J'aime/Commenter », progression stable à 100%). Les ressources performance ne capturent pas la requête POST d'upload. Ne remplissez pas le formulaire pendant l'upload ; si wujie devient temporairement null, attendez un moment, ne rafraîchissez pas.
1.5 Point de contrôle : enregistrer d'abord le brouillon
Après l'upload, cliquez immédiatement une fois sur « Enregistrer le brouillon », puis remplissez la description/titre court/localisation, et enfin enregistrez à nouveau. Cela évite de devoir retélécharger un gros fichier en cas d'échec en cours de route.
2. Description + sujets
La description utilise .input-editor (non contenteditable). Utilisez execCommand ; le texte est passé via le second paramètre de 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. Titre court
C'est un vrai <input>, doit utiliser le native setter ; vérifiez en lisant input.value (innerText ne contient pas la valeur de l'input).
4. Localisation
Par défaut, une ville est souvent présente. Méthode fiable : mouse.click pour ouvrir → snapshot/capture → cliquez sur « Ne pas afficher la localisation » → relisez le champ pour confirmer. Les coordonnées dans evaluate peuvent cliquer sur une couche cachée.
5. Enregistrer le brouillon (point final)
Cliquez sur « Enregistrer le brouillon ». Signal de succès : « Enregistré » + le bouton en bas devient gris. Ensuite, allez dans la boîte de brouillons pour vérifier. Ne quittez pas l'éditeur avant que le brouillon ne soit visible dans la boîte.
Optionnel : déclarer original, recherche d'activité (native setter pour écrire le terme de recherche ; si aucun résultat, « Ne pas participer à l'activité »).
6. Couverture (optionnel)
Seule méthode fiable : waitForFileChooser() + clic de confiance sur « Télécharger la couverture » + chooser.setFiles(<chemin absolu>). La méthode de synthèse input.files / boîte de dialogue OS a été testée et a échoué. Attendez que le bouton de confirmation cesse de tourner et que l'aperçu ne revienne plus à l'image par défaut avant de sauvegarder le brouillon.
7. Finalisation
- Arrêtez
serve-file(libération du port). - Si l'humain doit publier :
handOff()dans la boîte de brouillons. - Sinon,
finish({ keep: [] }), n'occupez pas l'espace longtemps.
Liste des pièges à éviter
- Shadow wujie : les requêtes partent de
wujie-app.shadowRoot. - Lien direct create → page blanche : utilisez le parcours UI pour accéder à la page de publication.
- Dans wujie, les clics par ref/texte sont interceptés → utilisez evaluate ou clic par coordonnées.
- Les longs textes passent uniquement par le paramètre de evaluate.
- Description : utilisez execCommand ; titre court : native setter.
- Localisation : deux étapes (coordonnées + relecture de vérification).
- Couverture : uniquement waitForFileChooser.
- Vérification de l'upload : uniquement le DOM ; après l'upload, enregistrez d'abord le brouillon.
- Ne naviguez pas avant que le brouillon ne soit enregistré.
- « Échec du chargement » de la page de connexion est un faux problème ; handOff laisse l'humain scanner le QR.
- Vérifiez la connexion avant chaque publication ; code de sortie 2 = arrêt obligatoire.
- La publication est un point final humain ; cette compétence ne va que jusqu'au brouillon.
Tests
npm test