Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature additions #122

Merged
merged 11 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/ilyakaznacheev/cleanenv v1.5.0
github.com/magefile/mage v1.15.0
github.com/smartystreets/goconvey v1.8.1
google.golang.org/api v0.168.0
google.golang.org/api v0.169.0
)

require (
Expand All @@ -25,7 +25,7 @@ require (
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 // indirect
google.golang.org/grpc v1.62.1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -191,17 +191,17 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.168.0 h1:MBRe+Ki4mMN93jhDDbpuRLjRddooArz4FeSObvUMmjY=
google.golang.org/api v0.168.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY=
google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8 h1:IR+hp6ypxjH24bkMfEJ0yHR21+gwPWdV+/IBrPQyn3k=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7 h1:em/y72n4XlYRtayY/cVj6pnVzHa//BDA1BdoO+z9mdE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240308144416-29370a3891b7/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
Expand Down
24 changes: 12 additions & 12 deletions pkg/cmd/grafana-kiosk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type Args struct {
UseMFA bool
Audience string
KeyFile string
Apikey string
APIKey string
LXDEHome string
ConfigPath string
Mode string
Expand Down Expand Up @@ -68,7 +68,7 @@ func ProcessArgs(cfg interface{}) Args {
flagSettings.StringVar(&processedArgs.PasswordField, "field-password", "password", "Fieldname for the password")
flagSettings.StringVar(&processedArgs.Audience, "audience", "", "idtoken audience")
flagSettings.StringVar(&processedArgs.KeyFile, "keyfile", "key.json", "idtoken json credentials")
flagSettings.StringVar(&processedArgs.Apikey, "apikey", "", "apikey")
flagSettings.StringVar(&processedArgs.APIKey, "apikey", "", "apikey")

fu := flagSettings.Usage
flagSettings.Usage = func() {
Expand Down Expand Up @@ -134,9 +134,9 @@ func summary(cfg *kiosk.Config) {
log.Println("IsPlayList:", cfg.Target.IsPlayList)
log.Println("UseMFA:", cfg.Target.UseMFA)
// goauth
log.Println("Fieldname AutoLogin:", cfg.GOAUTH.AutoLogin)
log.Println("Fieldname Username:", cfg.GOAUTH.UsernameField)
log.Println("Fieldname Password:", cfg.GOAUTH.PasswordField)
log.Println("Fieldname AutoLogin:", cfg.GoAuth.AutoLogin)
log.Println("Fieldname Username:", cfg.GoAuth.UsernameField)
log.Println("Fieldname Password:", cfg.GoAuth.PasswordField)
}

func main() {
Expand Down Expand Up @@ -186,14 +186,14 @@ func main() {
cfg.General.WindowPosition = args.WindowPosition
cfg.General.WindowSize = args.WindowSize
//
cfg.GOAUTH.AutoLogin = args.OauthAutoLogin
cfg.GOAUTH.UsernameField = args.UsernameField
cfg.GOAUTH.PasswordField = args.PasswordField
cfg.GoAuth.AutoLogin = args.OauthAutoLogin
cfg.GoAuth.UsernameField = args.UsernameField
cfg.GoAuth.PasswordField = args.PasswordField

cfg.IDTOKEN.Audience = args.Audience
cfg.IDTOKEN.KeyFile = args.KeyFile
cfg.IDToken.Audience = args.Audience
cfg.IDToken.KeyFile = args.KeyFile

cfg.APIKEY.Apikey = args.Apikey
cfg.APIKey.APIKey = args.APIKey
}

// make sure the url has content
Expand Down Expand Up @@ -232,7 +232,7 @@ func main() {
kiosk.GrafanaKioskIDToken(&cfg, messages)
case "apikey":
log.Printf("Launching apikey kiosk")
kiosk.GrafanaKioskApikey(&cfg, messages)
kiosk.GrafanaKioskAPIKey(&cfg, messages)
case "aws":
log.Printf("Launcing AWS SSO kiosk")
kiosk.GrafanaKioskAWSLogin(&cfg, messages)
Expand Down
93 changes: 89 additions & 4 deletions pkg/cmd/grafana-kiosk/main_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,101 @@
package main

import (
"log"
"os"
"testing"

"github.com/grafana/grafana-kiosk/pkg/kiosk"
"github.com/ilyakaznacheev/cleanenv"
. "github.com/smartystreets/goconvey/convey"
)

// TestKiosk checks kiosk command.
func TestKioskCommand(t *testing.T) {
Convey("Given Kiosk CMD", t, func() {
Convey("cmd should...", func() {
So(true, ShouldBeTrue)
func TestMain(t *testing.T) {
Convey("Given Default Configuration", t, func() {
cfg := kiosk.Config{
BuildInfo: kiosk.BuildInfo{
Version: "1.0.0",
},
General: kiosk.General{
AutoFit: true,
LXDEEnabled: true,
LXDEHome: "/home/pi",
Mode: "full",
WindowPosition: "0,0",
WindowSize: "1920,1080",
ScaleFactor: "1.0",
},
Target: kiosk.Target{
IgnoreCertificateErrors: false,
IsPlayList: false,
UseMFA: false,
LoginMethod: "local",
Password: "admin",
URL: "http://localhost:3000",
Username: "admin",
},
GoAuth: kiosk.GoAuth{
AutoLogin: false,
UsernameField: "user",
PasswordField: "password",
},
IDToken: kiosk.IDToken{
KeyFile: "/tmp/key.json",
Audience: "clientid",
},
APIKey: kiosk.APIKey{
APIKey: "abc",
},
}
Convey("General Options", func() {
Convey("Parameter - autofit", func() {
oldArgs := os.Args
defer func() { os.Args = oldArgs }()
os.Args = []string{"grafana-kiosk", ""}
// starts out default true
result := ProcessArgs(cfg)
So(result.AutoFit, ShouldBeTrue)
// flag to set it false
os.Args = []string{
"grafana-kiosk",
"--autofit=false",
}
result = ProcessArgs(cfg)
So(result.AutoFit, ShouldBeFalse)
})

Convey("Environment - autofit", func() {
oldArgs := os.Args
defer func() { os.Args = oldArgs }()
os.Args = []string{"grafana-kiosk", ""}
os.Setenv("KIOSK_AUTOFIT", "false")
cfg := kiosk.Config{}
if err := cleanenv.ReadEnv(&cfg); err != nil {
log.Println("Error reading config from environment", err)
}
So(cfg.General.AutoFit, ShouldBeFalse)
})
})
// end of general options

Convey("Anonymous Login", func() {
oldArgs := os.Args
defer func() { os.Args = oldArgs }()
os.Args = []string{"grafana-kiosk", ""}
result := ProcessArgs(cfg)
So(result.LoginMethod, ShouldEqual, "anon")
So(result.URL, ShouldEqual, "https://play.grafana.org")
So(result.AutoFit, ShouldBeTrue)
})
Convey("Local Login", func() {
oldArgs := os.Args
defer func() { os.Args = oldArgs }()
os.Args = []string{"grafana-kiosk", "-login-method", "local"}
result := ProcessArgs(cfg)
So(result.LoginMethod, ShouldEqual, "local")
So(result.URL, ShouldEqual, "https://play.grafana.org")
So(result.AutoFit, ShouldBeTrue)
})
})
}
7 changes: 4 additions & 3 deletions pkg/kiosk/anonymous_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ func GrafanaKioskAnonymous(cfg *Config, messages chan string) {
taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
defer cancel()

listenChromeEvents(taskCtx, consoleAPICall|targetCrashed)
listenChromeEvents(taskCtx, cfg, consoleAPICall|targetCrashed)

// ensure that the browser process is started
if err := chromedp.Run(taskCtx); err != nil {
panic(err)
}

// Give browser time to load next page (this can be prone to failure, explore different options vs sleeping)
time.Sleep(2000 * time.Millisecond)
// Give browser time to load
log.Printf("Sleeping %d MS before navigating to url", cfg.General.PageLoadDelayMS)
time.Sleep(time.Duration(cfg.General.PageLoadDelayMS) * time.Millisecond)

var generatedURL = GenerateURL(cfg.Target.URL, cfg.General.Mode, cfg.General.AutoFit, cfg.Target.IsPlayList)

Expand Down
13 changes: 7 additions & 6 deletions pkg/kiosk/apikey_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"github.com/chromedp/chromedp"
)

// GrafanaKioskApikey creates a chrome-based kiosk using a grafana api key.
func GrafanaKioskApikey(cfg *Config, messages chan string) {
// GrafanaKioskAPIKey creates a chrome-based kiosk using a grafana api key.
func GrafanaKioskAPIKey(cfg *Config, messages chan string) {
dir, err := os.MkdirTemp(os.TempDir(), "chromedp-kiosk")
if err != nil {
panic(err)
Expand All @@ -29,15 +29,16 @@ func GrafanaKioskApikey(cfg *Config, messages chan string) {
taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
defer cancel()

listenChromeEvents(taskCtx, consoleAPICall|targetCrashed)
listenChromeEvents(taskCtx, cfg, consoleAPICall|targetCrashed)

// ensure that the browser process is started
if err := chromedp.Run(taskCtx); err != nil {
panic(err)
}

// Give browser time to load next page (this can be prone to failure, explore different options vs sleeping)
time.Sleep(2000 * time.Millisecond)
// Give browser time to load
log.Printf("Sleeping %d MS before navigating to url", cfg.General.PageLoadDelayMS)
time.Sleep(time.Duration(cfg.General.PageLoadDelayMS) * time.Millisecond)

var generatedURL = GenerateURL(cfg.Target.URL, cfg.General.Mode, cfg.General.AutoFit, cfg.Target.IsPlayList)

Expand All @@ -46,7 +47,7 @@ func GrafanaKioskApikey(cfg *Config, messages chan string) {
Launch chrome and look for main-view element
*/
headers := map[string]interface{}{
"Authorization": "Bearer " + cfg.APIKEY.Apikey,
"Authorization": "Bearer " + cfg.APIKey.APIKey,
}
if err := chromedp.Run(taskCtx,
network.Enable(),
Expand Down
5 changes: 4 additions & 1 deletion pkg/kiosk/aws_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ func GrafanaKioskAWSLogin(cfg *Config, messages chan string) {
taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
defer cancel()

listenChromeEvents(taskCtx, targetCrashed)
listenChromeEvents(taskCtx, cfg, targetCrashed)
// Give browser time to load
log.Printf("Sleeping %d MS before navigating to url", cfg.General.PageLoadDelayMS)
time.Sleep(time.Duration(cfg.General.PageLoadDelayMS) * time.Millisecond)

// ensure that the browser process is started
if err := chromedp.Run(taskCtx); err != nil {
Expand Down
88 changes: 55 additions & 33 deletions pkg/kiosk/config.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,60 @@
package kiosk

// BuildInfo contains the build version
type BuildInfo struct {
briangann marked this conversation as resolved.
Show resolved Hide resolved
Version string `yaml:"version,omitempty"`
}

// General non-site specific configuations
type General struct {
briangann marked this conversation as resolved.
Show resolved Hide resolved
AutoFit bool `yaml:"autofit" env:"KIOSK_AUTOFIT" env-default:"true" env-description:"fit panels to screen"`
DebugEnabled bool `yaml:"debug" env:"KIOSK_DEBUG" env-default:"false" env-description:"enables debug output"`
GPUEnabled bool `yaml:"gpu-enabled" env:"KIOSK_GPU_ENABLED" env-default:"false" env-description:"disable GPU support"`
LXDEEnabled bool `yaml:"lxde" env:"KIOSK_LXDE_ENABLED" env-default:"false" env-description:"initialize LXDE for kiosk mode"`
LXDEHome string `yaml:"lxde-home" env:"KIOSK_LXDE_HOME" env-default:"/home/pi" env-description:"path to home directory of LXDE user running X Server"`
Mode string `yaml:"kiosk-mode" env:"KIOSK_MODE" env-default:"full" env-description:"[full|tv|disabled]"`
OzonePlatform string `yaml:"ozone-platform" env:"KIOSK_OZONE_PLATFORM" env-default:"" env-description:"Set ozone-platform option (wayland|cast|drm|wayland|x11)"`
PageLoadDelayMS int64 `yaml:"page-load-delay-ms" env:"KIOSK_PAGE_LOAD_DELAY_MS" env-default:"2000" env-description:"milliseconds to wait before expecting page load"`
ScaleFactor string `yaml:"scale-factor" env:"KIOSK_SCALE_FACTOR" env-default:"1.0" env-description:"Scale factor, like zoom"`
WindowPosition string `yaml:"window-position" env:"KIOSK_WINDOW_POSITION" env-default:"0,0" env-description:"Top Left Position of Kiosk"`
WindowSize string `yaml:"window-size" env:"KIOSK_WINDOW_SIZE" env-default:"" env-description:"Size of Kiosk in pixels (width,height)"`
}

// Target the dashboard/playlist details
type Target struct {
briangann marked this conversation as resolved.
Show resolved Hide resolved
IgnoreCertificateErrors bool `yaml:"ignore-certificate-errors" env:"KIOSK_IGNORE_CERTIFICATE_ERRORS" env-description:"ignore SSL/TLS certificate errors" env-default:"false"`
IsPlayList bool `yaml:"playlist" env:"KIOSK_IS_PLAYLIST" env-default:"false" env-description:"URL is a playlist"`
LoginMethod string `yaml:"login-method" env:"KIOSK_LOGIN_METHOD" env-default:"anon" env-description:"[anon|local|gcom|goauth|idtoken|apikey]"`
Password string `yaml:"password" env:"KIOSK_LOGIN_PASSWORD" env-default:"guest" env-description:"password"`
URL string `yaml:"URL" env:"KIOSK_URL" env-default:"https://play.grafana.org" env-description:"URL to Grafana server"`
Username string `yaml:"username" env:"KIOSK_LOGIN_USER" env-default:"guest" env-description:"username"`
UseMFA bool `yaml:"use-mfa" env:"KIOSK_USE_MFA" env-default:"false" env-description:"MFA is enabled for given account"`
}

// GoAuth OAuth
type GoAuth struct {
briangann marked this conversation as resolved.
Show resolved Hide resolved
AutoLogin bool `yaml:"auto-login" env:"KIOSK_GOAUTH_AUTO_LOGIN" env-description:"[false|true]"`
UsernameField string `yaml:"fieldname-username" env:"KIOSK_GOAUTH_FIELD_USER" env-description:"Username html input name value"`
PasswordField string `yaml:"fieldname-password" env:"KIOSK_GOAUTH_FIELD_PASSWORD" env-description:"Password html input name value"`
}

// IDToken token based login
type IDToken struct {
KeyFile string `yaml:"idtoken-keyfile" env:"KIOSK_IDTOKEN_KEYFILE" env-default:"key.json" env-description:"JSON Credentials for idtoken"`
Audience string `yaml:"idtoken-audience" env:"KIOSK_IDTOKEN_AUDIENCE" env-description:"Audience for idtoken, tpyically your oauth client id"`
}

// APIKey APIKey for login
type APIKey struct {
APIKey string `yaml:"apikey" env:"KIOSK_APIKEY_APIKEY" env-description:"APIKEY"`
}

// Config configuration for backend.
type Config struct {
BuildInfo struct {
Version string `yaml:"version,omitempty"`
}
General struct {
AutoFit bool `yaml:"autofit" env:"KIOSK_AUTOFIT" env-default:"true" env-description:"fit panels to screen"`
LXDEEnabled bool `yaml:"lxde" env:"KIOSK_LXDE_ENABLED" env-default:"false" env-description:"initialize LXDE for kiosk mode"`
LXDEHome string `yaml:"lxde-home" env:"KIOSK_LXDE_HOME" env-default:"/home/pi" env-description:"path to home directory of LXDE user running X Server"`
Mode string `yaml:"kiosk-mode" env:"KIOSK_MODE" env-default:"full" env-description:"[full|tv|disabled]"`
WindowPosition string `yaml:"window-position" env:"KIOSK_WINDOW_POSITION" env-default:"0,0" env-description:"Top Left Position of Kiosk"`
WindowSize string `yaml:"window-size" env:"KIOSK_WINDOW_SIZE" env-default:"" env-description:"Size of Kiosk in pixels (width,height)"`
ScaleFactor string `yaml:"scale-factor" env:"KIOSK_SCALE_FACTOR" env-default:"1.0" env-description:"Scale factor, like zoom"`
} `yaml:"general"`
Target struct {
IgnoreCertificateErrors bool `yaml:"ignore-certificate-errors" env:"KIOSK_IGNORE_CERTIFICATE_ERRORS" env-description:"ignore SSL/TLS certificate errors" env-default:"false"`
IsPlayList bool `yaml:"playlist" env:"KIOSK_IS_PLAYLIST" env-default:"false" env-description:"URL is a playlist"`
UseMFA bool `yaml:"use-mfa" env:"KIOSK_USE_MFA" env-default:"false" env-description:"MFA is enabled for given account"`
LoginMethod string `yaml:"login-method" env:"KIOSK_LOGIN_METHOD" env-default:"anon" env-description:"[anon|local|gcom|goauth|idtoken|apikey]"`
Password string `yaml:"password" env:"KIOSK_LOGIN_PASSWORD" env-default:"guest" env-description:"password"`
URL string `yaml:"URL" env:"KIOSK_URL" env-default:"https://play.grafana.org" env-description:"URL to Grafana server"`
Username string `yaml:"username" env:"KIOSK_LOGIN_USER" env-default:"guest" env-description:"username"`
} `yaml:"target"`
GOAUTH struct {
AutoLogin bool `yaml:"auto-login" env:"KIOSK_GOAUTH_AUTO_LOGIN" env-description:"[false|true]"`
UsernameField string `yaml:"fieldname-username" env:"KIOSK_GOAUTH_FIELD_USER" env-description:"Username html input name value"`
PasswordField string `yaml:"fieldname-password" env:"KIOSK_GOAUTH_FIELD_PASSWORD" env-description:"Password html input name value"`
} `yaml:"goauth"`
IDTOKEN struct {
KeyFile string `yaml:"idtoken-keyfile" env:"KIOSK_IDTOKEN_KEYFILE" env-default:"key.json" env-description:"JSON Credentials for idtoken"`
Audience string `yaml:"idtoken-audience" env:"KIOSK_IDTOKEN_AUDIENCE" env-description:"Audience for idtoken, tpyically your oauth client id"`
} `yaml:"idtoken"`
APIKEY struct {
Apikey string `yaml:"apikey" env:"KIOSK_APIKEY_APIKEY" env-description:"APIKEY"`
} `yaml:"apikey"`
BuildInfo BuildInfo `yaml:"buildinfo"`
General General `yaml:"general"`
Target Target `yaml:"target"`
GoAuth GoAuth `yaml:"goauth"`
IDToken IDToken `yaml:"idtoken"`
APIKey APIKey `yaml:"apikey"`
}
5 changes: 4 additions & 1 deletion pkg/kiosk/grafana_com_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ func GrafanaKioskGCOM(cfg *Config, messages chan string) {
taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
defer cancel()

listenChromeEvents(taskCtx, targetCrashed)
listenChromeEvents(taskCtx, cfg, targetCrashed)

// ensure that the browser process is started
if err := chromedp.Run(taskCtx); err != nil {
panic(err)
}
// Give browser time to load
log.Printf("Sleeping %d MS before navigating to url", cfg.General.PageLoadDelayMS)
time.Sleep(time.Duration(cfg.General.PageLoadDelayMS) * time.Millisecond)

var generatedURL = GenerateURL(cfg.Target.URL, cfg.General.Mode, cfg.General.AutoFit, cfg.Target.IsPlayList)

Expand Down
Loading
Loading