Skip to content

Commit 05ced34

Browse files
committed
Add support for Fingerprint Chromium and a screenshot endpoint
Updated the browser manager to support Fingerprint Chromium configuration. Introduced a new API endpoint for taking screenshots with thread-safe handling. Minor improvements and adjustments in element handling within the mouse interaction method.
1 parent 6716356 commit 05ced34

File tree

5 files changed

+44
-9
lines changed

5 files changed

+44
-9
lines changed

internal/api/handlers.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
)
1818

1919
var RequestMutex sync.Mutex
20+
var ScreenshotMutex sync.Mutex
2021

2122
// APIHandlers contains the handlers for API endpoints
2223
type APIHandlers struct {
@@ -36,6 +37,29 @@ func NewAPIHandlers(appConfig *config.AppConfig, queue *RequestQueue, pages map[
3637
}
3738
}
3839

40+
func (h *APIHandlers) TakeScreenshot(c *gin.Context) {
41+
defer ScreenshotMutex.Unlock()
42+
ScreenshotMutex.Lock()
43+
instanceName, ok := c.GetQuery("name")
44+
if !ok {
45+
c.Status(http.StatusNotFound)
46+
return
47+
}
48+
if page, hasKey := h.pages[instanceName]; hasKey {
49+
c.Header("Content-Type", "image/png")
50+
c.Header("Cache-Control", "no-cache")
51+
c.Header("Connection", "keep-alive")
52+
c.Header("Access-Control-Allow-Origin", "*")
53+
screenshot, err := page.Screenshot()
54+
if err != nil {
55+
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid request: %v", err), "code": 500})
56+
}
57+
_, _ = c.Writer.Write(screenshot)
58+
} else {
59+
c.Status(http.StatusNotFound)
60+
}
61+
}
62+
3963
// ChatCompletions handles the /v1/chat/completions endpoint
4064
func (h *APIHandlers) ChatCompletions(c *gin.Context) {
4165
defer RequestMutex.Unlock()

internal/api/server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ func (s *Server) setupRoutes() {
9191
},
9292
})
9393
})
94+
95+
s.engine.GET("/screenshot", s.handlers.TakeScreenshot)
9496
}
9597

9698
// Start starts the API server

internal/browser/manager.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,24 @@ func NewManager(cfg *config.AppConfig, cfgIndex int) (*Manager, error) {
3434

3535
// LaunchBrowserAndContext launches the configured browser and creates a new context with storage state.
3636
func (m *Manager) LaunchBrowserAndContext() error {
37+
var browser playwright.Browser
38+
var err error
3739
launchOptions := playwright.BrowserTypeLaunchOptions{
3840
Headless: playwright.Bool(m.Cfg.Headless),
3941
}
40-
if m.Cfg.CamoufoxPath != "" {
42+
if m.Cfg.FingerprintChromiumPath != "" {
43+
launchOptions.ExecutablePath = playwright.String(m.Cfg.FingerprintChromiumPath)
44+
launchOptions.Args = []string{"--fingerprint=1000", "--timezone='America/Los_Angeles'", "--ignore-certificate-errors"}
45+
log.Debugf("Attempting to launch Fingerprint Chromium from: %s", m.Cfg.CamoufoxPath)
46+
browser, err = m.pw.Chromium.Launch(launchOptions)
47+
} else if m.Cfg.CamoufoxPath != "" {
4148
launchOptions.ExecutablePath = playwright.String(m.Cfg.CamoufoxPath)
4249
log.Debugf("Attempting to launch Camoufox from: %s", m.Cfg.CamoufoxPath)
50+
browser, err = m.pw.Firefox.Launch(launchOptions)
4351
} else {
4452
log.Debug("Camoufox path not specified, launching default Playwright Firefox.")
4553
}
4654

47-
browser, err := m.pw.Firefox.Launch(launchOptions)
4855
if err != nil {
4956
return err
5057
}

internal/config/config.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ import (
77

88
// AppConfig holds the application configuration.
99
type AppConfig struct {
10-
Version string `yaml:"version"`
11-
Debug bool `yaml:"debug"`
12-
CamoufoxPath string `yaml:"camoufox-path"`
13-
Headless bool `yaml:"headless"`
14-
ApiPort string `yaml:"api-port"`
15-
Instance []AppConfigInstance `yaml:"instance"`
10+
Version string `yaml:"version"`
11+
Debug bool `yaml:"debug"`
12+
CamoufoxPath string `yaml:"camoufox-path"`
13+
FingerprintChromiumPath string `yaml:"fingerprint-chromium-path"`
14+
Headless bool `yaml:"headless"`
15+
ApiPort string `yaml:"api-port"`
16+
Instance []AppConfigInstance `yaml:"instance"`
1617
}
1718
type AppConfigRunner struct {
1819
Init string `yaml:"init"`

internal/method/mouse.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import (
88

99
func (m *Method) Click(elementSelector string, timeout float64) error {
1010
log.Debugf("Attempting to find and click element with selector: %s", elementSelector)
11-
element := m.page.Locator(elementSelector).First() // Use First() to get the first match if multiple
11+
element := m.page.Locator(elementSelector) // Use First() to get the first match if multiple
1212
count, err := element.Count()
1313
if err != nil {
1414
return fmt.Errorf("error counting elements with selector '%s': %v", elementSelector, err)
1515
}
1616
if count > 0 {
17+
element = element.First()
1718
isVisible, errIsVisible := element.IsVisible()
1819
if errIsVisible != nil {
1920
return fmt.Errorf("error checking visibility of element '%s': %v", elementSelector, errIsVisible)

0 commit comments

Comments
 (0)