Skip to content

Commit 6718e9a

Browse files
committed
Scrape: Modularize scraping into interface and single steps
1 parent a94706d commit 6718e9a

4 files changed

Lines changed: 124 additions & 56 deletions

File tree

cmd/run.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,6 @@ var runCmd = &cobra.Command{
3232
manual = true
3333
}
3434

35-
var scraper scrape.Scraper
36-
if !manual {
37-
// Checking optional force_jitsi flag first
38-
switch {
39-
case forceJitsi || strings.Contains(url, "meet.jit.si"):
40-
scraper = scrape.GetParticipantsJitsi
41-
case strings.Contains(url, "zoom"):
42-
scraper = scrape.GetParticipantsZoom
43-
default:
44-
return fmt.Errorf("Provided url does not contain known domain")
45-
}
46-
}
47-
4835
// We declare data here because it's consumed by both the `tui` and
4936
// `scrape` packages.
5037
var data tui.Data
@@ -56,10 +43,26 @@ var runCmd = &cobra.Command{
5643
return err
5744
}
5845

46+
// Checking optional force_jitsi flag first
47+
var meetingImpl scrape.MeetingImpl
48+
switch {
49+
case forceJitsi || strings.Contains(url, "meet.jit.si"):
50+
meetingImpl = scrape.NewJitsi(url, pw)
51+
case strings.Contains(url, "zoom"):
52+
meetingImpl = scrape.NewZoom(url, pw)
53+
default:
54+
return fmt.Errorf("Provided url does not contain known domain")
55+
}
56+
5957
log.Info("Initializing TUI.")
60-
url, err := cmd.Flags().GetString("url")
6158
go func() {
62-
err = scraper(url, 1, &data, pw)
59+
meetingImpl.VisitMeetingUrl()
60+
meetingImpl.FillBotName("clockwise-bot")
61+
meetingImpl.JoinMeeting()
62+
// FIXME: Deactivated until ffmpeg vcam gets implemented
63+
// meetingImpl.ActivateVirtualWebcam("")
64+
65+
err = meetingImpl.GetParticipants(1, &data)
6366
if err != nil {
6467
log.Fatal(err)
6568
}

internal/scrape/common.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ package scrape
33
import (
44
"fmt"
55

6-
"github.com/syncfast/clockwise/internal/tui"
76
"github.com/mxschmitt/playwright-go"
7+
"github.com/syncfast/clockwise/internal/tui"
88
)
99

10-
// Function prototype for per-platform participant count scraping
11-
type Scraper func(url string, refreshInterval int, data *tui.Data, pw *playwright.Playwright) error
10+
type MeetingImpl interface {
11+
VisitMeetingUrl() error
12+
FillBotName(botName string) error
13+
JoinMeeting() error
14+
ActivateVirtualWebcam(camName string) error
15+
GetParticipants(refreshInterval int, data *tui.Data) error
16+
}
1217

1318
// initializePlaywright starts playwright in a standalone function to circumvent
1419
// some flaws in the upstream in terms of how it prints logs.

internal/scrape/jitsi.go

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,94 @@ package scrape
22

33
import (
44
"fmt"
5+
"regexp"
56
"strconv"
67
"time"
7-
"regexp"
88

99
"github.com/mxschmitt/playwright-go"
1010
"github.com/syncfast/clockwise/internal/tui"
1111
)
1212

13-
// GetParticipantsJitsi retrieves the total participant count from a specified
14-
// Jitsi URL. It runs in a loop and updates the passed in `Data` struct every
15-
// `refreshInterval` seconds.
16-
func GetParticipantsJitsi(url string, refreshInterval int, data *tui.Data, pw *playwright.Playwright) error {
17-
var timeout float64 = 5000
13+
type Jitsi struct {
14+
url string
15+
pw *playwright.Playwright
16+
page playwright.Page
17+
timeout float64
18+
}
1819

19-
browser, err := pw.Chromium.Launch()
20+
func NewJitsi(url string, pw *playwright.Playwright) *Jitsi {
21+
return &Jitsi{
22+
url: url,
23+
pw: pw,
24+
page: nil,
25+
timeout: 5000,
26+
}
27+
}
28+
29+
func (j *Jitsi) VisitMeetingUrl() error {
30+
browser, err := j.pw.Chromium.Launch()
2031
if err != nil {
2132
return fmt.Errorf("could not launch browser: %w", err)
2233
}
2334

24-
page, err := browser.NewPage()
35+
j.page, err = browser.NewPage()
2536
if err != nil {
2637
return fmt.Errorf("could not create page: %w", err)
2738
}
2839

29-
if _, err = page.Goto(url, playwright.PageGotoOptions{
40+
if _, err = j.page.Goto(j.url, playwright.PageGotoOptions{
3041
WaitUntil: playwright.WaitUntilStateLoad,
3142
}); err != nil {
3243
return fmt.Errorf("could not goto: %w", err)
3344
}
3445

46+
return nil
47+
}
48+
49+
func (j *Jitsi) FillBotName(botName string) error {
3550
selector := "#Prejoin-input-field-id"
36-
if err := page.Fill(selector, "clockwise-bot", playwright.FrameFillOptions{
37-
Timeout: &timeout,
51+
if err := j.page.Fill(selector, botName, playwright.FrameFillOptions{
52+
Timeout: &j.timeout,
3853
}); err != nil {
3954
return err
4055
}
4156

57+
return nil
58+
}
59+
60+
func (j *Jitsi) JoinMeeting() error {
4261
// Wait for and click Join button
43-
page.WaitForSelector("#lobby-screen > div.content > div.prejoin-input-area-container > div > div > div")
62+
j.page.WaitForSelector("#lobby-screen > div.content > div.prejoin-input-area-container > div > div > div")
4463

45-
if err := page.Click("#lobby-screen > div.content > div.prejoin-input-area-container > div > div > div", playwright.PageClickOptions{
46-
Timeout: &timeout,
64+
if err := j.page.Click("#lobby-screen > div.content > div.prejoin-input-area-container > div > div > div", playwright.PageClickOptions{
65+
Timeout: &j.timeout,
4766
}); err != nil {
4867
return err
4968
}
5069

70+
return nil
71+
}
72+
73+
func (j *Jitsi) ActivateVirtualWebcam(camName string) error {
74+
return nil
75+
}
76+
77+
// GetParticipants retrieves the total participant count from a specified
78+
// Jitsi URL. It runs in a loop and updates the passed in `Data` struct every
79+
// `refreshInterval` seconds.
80+
func (j *Jitsi) GetParticipants(refreshInterval int, data *tui.Data) error {
5181
// Wait for and click participants sidebar
52-
page.WaitForSelector("#new-toolbox > div > div > div > div:nth-child(6)")
53-
if err := page.Click("#new-toolbox > div > div > div > div:nth-child(6)", playwright.PageClickOptions{
54-
Timeout: &timeout,
82+
j.page.WaitForSelector("#new-toolbox > div > div > div > div:nth-child(6)")
83+
if err := j.page.Click("#new-toolbox > div > div > div > div:nth-child(6)", playwright.PageClickOptions{
84+
Timeout: &j.timeout,
5585
}); err != nil {
5686
return err
5787
}
5888

59-
page.WaitForSelector("#layout_wrapper > div.participants_pane > div")
89+
j.page.WaitForSelector("#layout_wrapper > div.participants_pane > div")
6090

6191
for {
62-
res, err := page.QuerySelector("#layout_wrapper > div.participants_pane > div")
92+
res, err := j.page.QuerySelector("#layout_wrapper > div.participants_pane > div")
6393
if err != nil {
6494
return err
6595
}

internal/scrape/zoom.go

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,32 @@ import (
1010
"github.com/syncfast/clockwise/internal/tui"
1111
)
1212

13-
// GetParticipantsZoom retrieves the total participant count from a specified
14-
// zoom URL. It runs in a loop and updates the passed in `Data` struct every
15-
// `refreshInterval` seconds.
16-
func GetParticipantsZoom(url string, refreshInterval int, data *tui.Data, pw *playwright.Playwright) error {
17-
if strings.Contains(url, "zoom.us/my/") {
18-
return fmt.Errorf(`Error: clockwise is not compatible with Zoom Personal Meeting IDs at the moment.
19-
Disabling your PMI is as as simple as clicking a checkbox.
20-
Please visit https://support.zoom.us/hc/en-us/articles/203276937-Using-Personal-Meeting-ID-PMI- for more info.`)
13+
type Zoom struct {
14+
url string
15+
pw *playwright.Playwright
16+
page playwright.Page
17+
timeout float64
18+
}
19+
20+
func NewZoom(url string, pw *playwright.Playwright) *Zoom {
21+
return &Zoom{
22+
url: url,
23+
pw: pw,
24+
page: nil,
25+
timeout: 5000,
2126
}
27+
}
2228

23-
var timeout float64 = 5000
29+
func (z *Zoom) VisitMeetingUrl() error {
30+
if strings.Contains(z.url, "zoom.us/my/") {
31+
return fmt.Errorf(`Error: clockwise is not compatible with Zoom Personal Meeting IDs at the moment.
32+
Disabling your PMI is as as simple as clicking a checkbox.
33+
Please visit https://support.zoom.us/hc/en-us/articles/203276937-Using-Personal-Meeting-ID-PMI- for more info.`)
34+
}
2435

25-
url = mutateURL(url)
36+
z.url = mutateURL(z.url)
2637

27-
browser, err := pw.Chromium.Launch()
38+
browser, err := z.pw.Chromium.Launch()
2839
if err != nil {
2940
return fmt.Errorf("could not launch browser: %w", err)
3041
}
@@ -34,31 +45,50 @@ Please visit https://support.zoom.us/hc/en-us/articles/203276937-Using-Personal-
3445
return fmt.Errorf("could not create page: %w", err)
3546
}
3647

37-
if _, err = page.Goto(url, playwright.PageGotoOptions{
48+
if _, err = page.Goto(z.url, playwright.PageGotoOptions{
3849
WaitUntil: playwright.WaitUntilStateLoad,
3950
}); err != nil {
4051
return fmt.Errorf("could not goto: %w", err)
4152
}
4253

54+
return nil
55+
}
56+
57+
func (z *Zoom) FillBotName(botName string) error {
4358
selector := "text=Your Name"
44-
if err := page.Fill(selector, "clockwise-bot", playwright.FrameFillOptions{
45-
Timeout: &timeout,
59+
if err := z.page.Fill(selector, "clockwise-bot", playwright.FrameFillOptions{
60+
Timeout: &z.timeout,
4661
}); err != nil {
4762
return err
4863
}
4964

50-
page.WaitForSelector("button#joinBtn")
65+
return nil
66+
}
67+
68+
func (z *Zoom) JoinMeeting() error {
69+
z.page.WaitForSelector("button#joinBtn")
5170

52-
if err := page.Click("button#joinBtn", playwright.PageClickOptions{
53-
Timeout: &timeout,
71+
if err := z.page.Click("button#joinBtn", playwright.PageClickOptions{
72+
Timeout: &z.timeout,
5473
}); err != nil {
5574
return err
5675
}
5776

58-
page.WaitForSelector(".footer-button__number-counter")
77+
return nil
78+
}
79+
80+
func (z *Zoom) ActivateVirtualWebcam(camName string) error {
81+
return nil
82+
}
83+
84+
// GetParticipants retrieves the total participant count from a specified
85+
// zoom URL. It runs in a loop and updates the passed in `Data` struct every
86+
// `refreshInterval` seconds.
87+
func (z *Zoom) GetParticipants(refreshInterval int, data *tui.Data) error {
88+
z.page.WaitForSelector(".footer-button__number-counter")
5989

6090
for {
61-
res, err := page.QuerySelector(".footer-button__number-counter")
91+
res, err := z.page.QuerySelector(".footer-button__number-counter")
6292
if err != nil {
6393
return err
6494
}

0 commit comments

Comments
 (0)