Skip to content

Commit 84bc41c

Browse files
committed
feat: support language type list
1 parent 57752fd commit 84bc41c

File tree

4 files changed

+137
-0
lines changed

4 files changed

+137
-0
lines changed
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package handles
2+
3+
import (
4+
"sync"
5+
"time"
6+
7+
"github.com/lessapidev/lessapi-duckduckgo/internal/searchs"
8+
"github.com/lessapidev/lessapi-duckduckgo/internal/types"
9+
"github.com/lessapidev/lessapi-duckduckgo/internal/utils"
10+
11+
"github.com/gin-gonic/gin"
12+
)
13+
14+
type languagesCache struct {
15+
languages []types.LanguageType
16+
ttl time.Duration
17+
lock sync.RWMutex
18+
}
19+
20+
// ListLanguageHandle list all language types
21+
func ListLanguageHandle(c *gin.Context) {
22+
// parse request params
23+
var payload types.ListLanguagePayload
24+
if err := c.ShouldBindQuery(&payload); err != nil {
25+
c.JSON(200, utils.BuildApiError("invalid_params", "invalid request params"))
26+
return
27+
}
28+
29+
// search text
30+
resp, err := searchs.ListLanguage(payload)
31+
if err != nil {
32+
c.JSON(200, utils.BuildApiError("search_error", err.Error()))
33+
return
34+
}
35+
36+
// return response
37+
c.JSON(200, utils.BuildApiSuccessData(resp))
38+
}

internal/searchs/list_language.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package searchs
2+
3+
import (
4+
"fmt"
5+
"github.com/lessapidev/lessapi-duckduckgo/internal/types"
6+
"github.com/playwright-community/playwright-go"
7+
)
8+
9+
func ListLanguage(param types.ListLanguagePayload) (*types.ListLanguageResponse, error) {
10+
11+
// -----------------------------------------------------------
12+
// open browser
13+
// -----------------------------------------------------------
14+
15+
// create new browser context
16+
browserOpt := BrowserOptions{
17+
ProxyServer: &param.ViaProxyUrl,
18+
EnableStealthJs: playwright.Bool(true),
19+
viewportWidth: playwright.Int(1920),
20+
viewportHeight: playwright.Int(1080 - 35),
21+
}
22+
browserCtx, browserClose, err := NewBrowserContextWithOptions(browserOpt)
23+
if err != nil {
24+
return nil, fmt.Errorf("could not create virtual browser context: %w", err)
25+
}
26+
defer (func() {
27+
_ = browserClose()
28+
})()
29+
30+
// create new page
31+
page, err := browserCtx.NewPage()
32+
if err != nil {
33+
return nil, fmt.Errorf("could not create page: %w", err)
34+
}
35+
36+
// open search page
37+
if _, err = page.Goto("https://duckduckgo.com/?q=duckduckgo", playwright.PageGotoOptions{Timeout: playwright.Float(10 * 1000)}); err != nil {
38+
return nil, fmt.Errorf("could not goto: %w", err)
39+
}
40+
if err = page.WaitForLoadState(playwright.PageWaitForLoadStateOptions{Timeout: playwright.Float(10 * 1000)}); err != nil {
41+
return nil, fmt.Errorf("could not wait for load: %w", err)
42+
}
43+
44+
// click settings
45+
settingLocator := page.Locator("div[class='dropdown dropdown--settings'] a")
46+
if err := settingLocator.WaitFor(playwright.LocatorWaitForOptions{Timeout: playwright.Float(5 * 1000)}); err != nil {
47+
return nil, fmt.Errorf("could not locate setting: %w", err)
48+
}
49+
if err := settingLocator.Click(); err != nil {
50+
return nil, fmt.Errorf("could not click: %w", err)
51+
}
52+
53+
// find language select
54+
selectLocator := page.Locator("select[id=setting_kad]")
55+
if err := selectLocator.WaitFor(playwright.LocatorWaitForOptions{Timeout: playwright.Float(5 * 1000)}); err != nil {
56+
return nil, fmt.Errorf("could not locate select: %w", err)
57+
}
58+
59+
// get languages
60+
optionLocator := selectLocator.Locator("option")
61+
options, err := optionLocator.All()
62+
if err != nil {
63+
return nil, fmt.Errorf("could not get options: %w", err)
64+
}
65+
l := make([]types.LanguageType, 0)
66+
for _, option := range options {
67+
code, err := option.GetAttribute("value")
68+
if err != nil {
69+
return nil, fmt.Errorf("could not get value: %w", err)
70+
}
71+
name, err := option.TextContent()
72+
if err != nil {
73+
return nil, fmt.Errorf("could not get text content: %w", err)
74+
}
75+
l = append(l, types.LanguageType{
76+
Code: code,
77+
Name: name,
78+
})
79+
}
80+
81+
return &types.ListLanguageResponse{
82+
Languages: l,
83+
}, nil
84+
}

internal/server.go

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ func Run() {
1616
r.GET("/", handles.IndexHandle)
1717
r.GET("/openapi/openapi.json", handles.OpenAPIHandle)
1818
r.GET("/search/text", handles.SearchTextHandle)
19+
r.GET("/base/list-language", handles.ListLanguageHandle)
1920

2021
err := r.Run(":8080")
2122
if err != nil {

internal/types/types.go

+14
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,17 @@ type SearchTextResultItem struct {
2929
Url string `json:"url"` // url of the result
3030
Description string `json:"description"` // description of the result
3131
}
32+
33+
type LanguageType struct {
34+
Code string `json:"code"`
35+
Name string `json:"name"`
36+
}
37+
38+
type ListLanguagePayload struct {
39+
// Proxy url to use (optional)
40+
ViaProxyUrl string `json:"viaProxyUrl" form:"viaProxyUrl"`
41+
}
42+
43+
type ListLanguageResponse struct {
44+
Languages []LanguageType `json:"languages"`
45+
}

0 commit comments

Comments
 (0)