package browser import "fmt" // CdpNewTabBackground abre una pestaña nueva via Target.createTarget con el // parametro "background": true, de forma que la pestaña se crea SIN activarse y // SIN elevar la ventana del navegador (no roba el foco del WM). // // Es el drop-in sin-foco de CdpNewTab: misma firma, mismo CdpTab de retorno. // La diferencia tecnica es el mecanismo: // - CdpNewTab usa el endpoint HTTP PUT /json/new, que NO admite background y // por tanto SIEMPRE eleva la ventana (roba foco al usuario). // - Aqui usamos el comando CDP browser-level Target.createTarget con // "background": true, que en Linux/Chromium crea la pestaña en segundo plano. // // host vacio = "localhost". startURL vacio = "about:blank". func CdpNewTabBackground(host string, port int, startURL string) (CdpTab, error) { if host == "" { host = "localhost" } if startURL == "" { startURL = "about:blank" } // Target.createTarget debe ejecutarse contra el browser target (no una page), // por eso resolvemos el webSocketDebuggerUrl browser-level via /json/version. wsURL, err := cdpGetWSURL(port) if err != nil { return CdpTab{}, fmt.Errorf("cdp new tab background: %w", err) } conn, err := cdpConnectWS(wsURL, port) if err != nil { return CdpTab{}, fmt.Errorf("cdp new tab background: conectar: %w", err) } // Soltar solo el WebSocket; dejar el navegador vivo. defer CdpDisconnect(conn) res, err := conn.sendCDP("Target.createTarget", map[string]any{ "url": startURL, "background": true, }) if err != nil { return CdpTab{}, fmt.Errorf("cdp new tab background: createTarget: %w", err) } targetID, _ := res["targetId"].(string) if targetID == "" { return CdpTab{}, fmt.Errorf("cdp new tab background: createTarget no devolvio targetId") } // Resolver el CdpTab completo (con webSocketDebuggerUrl, title, etc.) buscando // el target recien creado en /json. tabs, err := CdpListTabs(host, port) if err == nil { for _, t := range tabs { if t.ID == targetID { return t, nil } } } // Fallback en caso de carrera (el target aun no aparece en /json): devolvemos // un CdpTab minimo con el id, tipo y URL inicial conocidos. return CdpTab{ID: targetID, Type: "page", URL: startURL}, nil }