diff --git a/go.mod b/go.mod index 9f7bd1e62..574e222d2 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,8 @@ require ( github.com/99designs/gqlgen v0.9.0 github.com/antchfx/htmlquery v1.2.3 github.com/bmatcuk/doublestar v1.3.1 + github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c + github.com/chromedp/chromedp v0.5.3 github.com/disintegration/imaging v1.6.0 github.com/go-chi/chi v4.0.2+incompatible github.com/gobuffalo/packr/v2 v2.0.2 diff --git a/go.sum b/go.sum index 9f08814d4..f63a9672e 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,11 @@ github.com/bmatcuk/doublestar v1.3.1/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chromedp/cdproto v0.0.0-20200116234248-4da64dd111ac/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g= +github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c h1:qM1xzKK8kc93zKPkxK4iqtjksqDDrU6g9wGnr30jyLo= +github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c/go.mod h1:E6LPWRdIJc11h/di5p0rwvRmUYbhGpBEH7ZbPfzDIOE= +github.com/chromedp/chromedp v0.5.3 h1:F9LafxmYpsQhWQBdCs+6Sret1zzeeFyHS5LkRF//Ffg= +github.com/chromedp/chromedp v0.5.3/go.mod h1:YLdPtndaHQ4rCpSpBG+IPpy9JvX0VD+7aaLxYgYj28w= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= @@ -310,6 +315,12 @@ github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM= github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc= github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -408,6 +419,8 @@ github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46s github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 h1:V0an7KRw92wmJysvFvtqtKMAPmvS5O0jtB0nYo6t+gs= +github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08/go.mod h1:dFWs1zEqDjFtnBXsd1vPOZaLsESovai349994nHx3e0= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -425,6 +438,9 @@ github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= +github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c= @@ -722,6 +738,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae h1:mQLHiymj/JXKnnjc62tb7nD5pZLs940/sXJu+Xp3DBA= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= diff --git a/graphql/documents/data/config.graphql b/graphql/documents/data/config.graphql index 71f7b9ef3..2a19709c4 100644 --- a/graphql/documents/data/config.graphql +++ b/graphql/documents/data/config.graphql @@ -19,6 +19,7 @@ fragment ConfigGeneralData on ConfigGeneralResult { logAccess excludes scraperUserAgent + scraperCDPPath } fragment ConfigInterfaceData on ConfigInterfaceResult { diff --git a/graphql/schema/types/config.graphql b/graphql/schema/types/config.graphql index ff7e3f845..27ae24236 100644 --- a/graphql/schema/types/config.graphql +++ b/graphql/schema/types/config.graphql @@ -58,6 +58,8 @@ input ConfigGeneralInput { excludes: [String!] """Scraper user agent string""" scraperUserAgent: String + """Scraper CDP path. Path to chrome executable or remote address""" + scraperCDPPath: String } type ConfigGeneralResult { @@ -101,6 +103,8 @@ type ConfigGeneralResult { excludes: [String!]! """Scraper user agent string""" scraperUserAgent: String + """Scraper CDP path. Path to chrome executable or remote address""" + scraperCDPPath: String } input ConfigInterfaceInput { diff --git a/pkg/api/resolver_mutation_configure.go b/pkg/api/resolver_mutation_configure.go index 45f0826ef..30c7ee63b 100644 --- a/pkg/api/resolver_mutation_configure.go +++ b/pkg/api/resolver_mutation_configure.go @@ -103,8 +103,15 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co config.Set(config.Exclude, input.Excludes) } + refreshScraperCache := false if input.ScraperUserAgent != nil { config.Set(config.ScraperUserAgent, input.ScraperUserAgent) + refreshScraperCache = true + } + + if input.ScraperCDPPath != nil { + config.Set(config.ScraperCDPPath, input.ScraperCDPPath) + refreshScraperCache = true } if err := config.Write(); err != nil { @@ -112,6 +119,9 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co } manager.GetInstance().RefreshConfig() + if refreshScraperCache { + manager.GetInstance().RefreshScraperCache() + } return makeConfigGeneralResult(), nil } diff --git a/pkg/api/resolver_query_configuration.go b/pkg/api/resolver_query_configuration.go index 759400eed..065fc4485 100644 --- a/pkg/api/resolver_query_configuration.go +++ b/pkg/api/resolver_query_configuration.go @@ -40,6 +40,7 @@ func makeConfigGeneralResult() *models.ConfigGeneralResult { maxStreamingTranscodeSize := config.GetMaxStreamingTranscodeSize() scraperUserAgent := config.GetScraperUserAgent() + scraperCDPPath := config.GetScraperCDPPath() return &models.ConfigGeneralResult{ Stashes: config.GetStashPaths(), @@ -62,6 +63,7 @@ func makeConfigGeneralResult() *models.ConfigGeneralResult { LogAccess: config.GetLogAccess(), Excludes: config.GetExcludes(), ScraperUserAgent: &scraperUserAgent, + ScraperCDPPath: &scraperCDPPath, } } diff --git a/pkg/manager/config/config.go b/pkg/manager/config/config.go index a3ebb48e5..025ec5ed4 100644 --- a/pkg/manager/config/config.go +++ b/pkg/manager/config/config.go @@ -57,6 +57,7 @@ const SessionStoreKey = "session_store_key" // scraping options const ScrapersPath = "scrapers_path" const ScraperUserAgent = "scraper_user_agent" +const ScraperCDPPath = "scraper_cdp_path" // i18n const Language = "language" @@ -158,6 +159,12 @@ func GetScraperUserAgent() string { return viper.GetString(ScraperUserAgent) } +// GetScraperCDPPath gets the path to the Chrome executable or remote address +// to an instance of Chrome. +func GetScraperCDPPath() string { + return viper.GetString(ScraperCDPPath) +} + func GetHost() string { return viper.GetString(Host) } diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index a98d32b27..7cbd536f8 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -153,10 +153,12 @@ func initLog() { logger.Init(config.GetLogFile(), config.GetLogOut(), config.GetLogLevel()) } +// initScraperCache initializes a new scraper cache and returns it. func initScraperCache() *scraper.Cache { scraperConfig := scraper.GlobalConfig{ Path: config.GetScrapersPath(), UserAgent: config.GetScraperUserAgent(), + CDPPath: config.GetScraperCDPPath(), } ret, err := scraper.NewCache(scraperConfig) @@ -178,3 +180,9 @@ func (s *singleton) RefreshConfig() { paths.EnsureJSONDirs() } } + +// RefreshScraperCache refreshes the scraper cache. Call this when scraper +// configuration changes. +func (s *singleton) RefreshScraperCache() { + s.ScraperCache = initScraperCache() +} diff --git a/pkg/scraper/config.go b/pkg/scraper/config.go index ab5b648ac..811459692 100644 --- a/pkg/scraper/config.go +++ b/pkg/scraper/config.go @@ -43,6 +43,9 @@ type config struct { // Xpath scraping configurations XPathScrapers mappedScrapers `yaml:"xPathScrapers"` + + // Scraping driver options + DriverOptions *scraperDriverOptions `yaml:"driver"` } func (c config) validate() error { @@ -135,6 +138,11 @@ type scraperDebugOptions struct { PrintHTML bool `yaml:"printHTML"` } +type scraperDriverOptions struct { + UseCDP bool `yaml:"useCDP"` + Sleep int `yaml:"sleep"` +} + func loadScraperFromYAML(id string, reader io.Reader) (*config, error) { ret := &config{} diff --git a/pkg/scraper/scrapers.go b/pkg/scraper/scrapers.go index a1b5b9f21..864c09a66 100644 --- a/pkg/scraper/scrapers.go +++ b/pkg/scraper/scrapers.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/models" @@ -14,7 +15,18 @@ import ( type GlobalConfig struct { // User Agent used when scraping using http. UserAgent string - Path string + + // Path (file or remote address) to a Chrome CDP instance. + CDPPath string + Path string +} + +func (c GlobalConfig) isCDPPathHTTP() bool { + return strings.HasPrefix(c.CDPPath, "http://") || strings.HasPrefix(c.CDPPath, "https://") +} + +func (c GlobalConfig) isCDPPathWS() bool { + return strings.HasPrefix(c.CDPPath, "ws://") } // Cache stores scraper details. diff --git a/pkg/scraper/url.go b/pkg/scraper/url.go new file mode 100644 index 000000000..391f1fd46 --- /dev/null +++ b/pkg/scraper/url.go @@ -0,0 +1,175 @@ +package scraper + +import ( + "context" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/cookiejar" + "os" + "strings" + "time" + + "github.com/chromedp/cdproto/dom" + "github.com/chromedp/cdproto/network" + "github.com/chromedp/chromedp" + jsoniter "github.com/json-iterator/go" + "github.com/stashapp/stash/pkg/logger" + "golang.org/x/net/html/charset" + "golang.org/x/net/publicsuffix" +) + +func loadURL(url string, scraperConfig config, globalConfig GlobalConfig) (io.Reader, error) { + driverOptions := scraperConfig.DriverOptions + if driverOptions != nil && driverOptions.UseCDP { + // get the page using chrome dp + return urlFromCDP(url, *driverOptions, globalConfig) + } + + // get the page using http.Client + options := cookiejar.Options{ + PublicSuffixList: publicsuffix.List, + } + jar, er := cookiejar.New(&options) + if er != nil { + return nil, er + } + + client := &http.Client{ + Timeout: scrapeGetTimeout, + // defaultCheckRedirect code with max changed from 10 to 20 + CheckRedirect: func(req *http.Request, via []*http.Request) error { + if len(via) >= 20 { + return errors.New("stopped after 20 redirects") + } + return nil + }, + Jar: jar, + } + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + userAgent := globalConfig.UserAgent + if userAgent != "" { + req.Header.Set("User-Agent", userAgent) + } + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return charset.NewReader(resp.Body, resp.Header.Get("Content-Type")) +} + +// func urlFromCDP uses chrome cdp and DOM to load and process the url +// if remote is set as true in the scraperConfig it will try to use localhost:9222 +// else it will look for google-chrome in path +func urlFromCDP(url string, driverOptions scraperDriverOptions, globalConfig GlobalConfig) (io.Reader, error) { + const defaultSleep = 2 + + if !driverOptions.UseCDP { + return nil, fmt.Errorf("Url shouldn't be feetched through CDP") + } + + sleep := defaultSleep + + if driverOptions.Sleep != 0 { + sleep = driverOptions.Sleep + } + + sleepDuration := time.Duration(sleep) * time.Second + act := context.Background() + + // if scraperCDPPath is a remote address, then allocate accordingly + if globalConfig.CDPPath != "" { + var cancelAct context.CancelFunc + + if globalConfig.isCDPPathHTTP() || globalConfig.isCDPPathWS() { + remote := globalConfig.CDPPath + + // if CDPPath is http(s) then we need to get the websocket URL + if globalConfig.isCDPPathHTTP() { + var err error + remote, err = getRemoteCDPWSAddress(remote) + if err != nil { + return nil, err + } + } + + act, cancelAct = chromedp.NewRemoteAllocator(context.Background(), remote) + } else { + // user a temporary user directory for chrome + dir, err := ioutil.TempDir("", "stash-chromedp") + if err != nil { + return nil, err + } + defer os.RemoveAll(dir) + + opts := append(chromedp.DefaultExecAllocatorOptions[:], + chromedp.UserDataDir(dir), + chromedp.ExecPath(globalConfig.CDPPath), + ) + act, cancelAct = chromedp.NewExecAllocator(act, opts...) + } + + defer cancelAct() + } + + ctx, cancel := chromedp.NewContext(act) + defer cancel() + + var res string + err := chromedp.Run(ctx, + network.Enable(), + chromedp.Navigate(url), + chromedp.Sleep(sleepDuration), + chromedp.ActionFunc(func(ctx context.Context) error { + node, err := dom.GetDocument().Do(ctx) + if err != nil { + return err + } + res, err = dom.GetOuterHTML().WithNodeID(node.NodeID).Do(ctx) + return err + }), + ) + if err != nil { + return nil, err + } + + return strings.NewReader(res), nil +} + +// getRemoteCDPWSAddress returns the complete remote address that is required to access the cdp instance +func getRemoteCDPWSAddress(address string) (string, error) { + resp, err := http.Get(address) + if err != nil { + return "", err + } + + var result map[string]interface{} + var json = jsoniter.ConfigCompatibleWithStandardLibrary + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", err + } + remote := result["webSocketDebuggerUrl"].(string) + logger.Debugf("Remote cdp instance found %s", remote) + return remote, err +} + +func cdpNetwork(enable bool) chromedp.Action { + return chromedp.ActionFunc(func(ctx context.Context) error { + if enable { + network.Enable().Do(ctx) + } else { + network.Disable().Do(ctx) + } + return nil + }) +} diff --git a/pkg/scraper/xpath.go b/pkg/scraper/xpath.go index a2b6bd655..406ef179b 100644 --- a/pkg/scraper/xpath.go +++ b/pkg/scraper/xpath.go @@ -3,17 +3,14 @@ package scraper import ( "bytes" "errors" - "net/http" - "net/http/cookiejar" "net/url" "regexp" "strings" "time" "github.com/antchfx/htmlquery" + "golang.org/x/net/html" - "golang.org/x/net/html/charset" - "golang.org/x/net/publicsuffix" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/models" @@ -111,42 +108,7 @@ func (s *xpathScraper) scrapeSceneByFragment(scene models.SceneUpdateInput) (*mo } func (s *xpathScraper) loadURL(url string) (*html.Node, error) { - options := cookiejar.Options{ - PublicSuffixList: publicsuffix.List, - } - jar, er := cookiejar.New(&options) - if er != nil { - return nil, er - } - - client := &http.Client{ - Timeout: scrapeGetTimeout, - // defaultCheckRedirect code with max changed from 10 to 20 - CheckRedirect: func(req *http.Request, via []*http.Request) error { - if len(via) >= 20 { - return errors.New("stopped after 20 redirects") - } - return nil - }, - Jar: jar, - } - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - - userAgent := s.globalConfig.UserAgent - if userAgent != "" { - req.Header.Set("User-Agent", userAgent) - } - - resp, err := client.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - r, err := charset.NewReader(resp.Body, resp.Header.Get("Content-Type")) + r, err := loadURL(url, s.config, s.globalConfig) if err != nil { return nil, err } diff --git a/scripts/test_oshash.go b/scripts/test_oshash.go new file mode 100644 index 000000000..221780167 --- /dev/null +++ b/scripts/test_oshash.go @@ -0,0 +1,20 @@ +// +build ignore + +package main + +import ( + "fmt" + "os" + + "github.com/stashapp/stash/pkg/utils" +) + +func main() { + hash, err := utils.OSHashFromFilePath(os.Args[1]) + + if err != nil { + panic(err) + } + + fmt.Println(hash) +} diff --git a/ui/v2.5/src/components/Changelog/versions/v030.tsx b/ui/v2.5/src/components/Changelog/versions/v030.tsx index 9f844167c..d6a34f92e 100644 --- a/ui/v2.5/src/components/Changelog/versions/v030.tsx +++ b/ui/v2.5/src/components/Changelog/versions/v030.tsx @@ -13,6 +13,7 @@ const markup = ` * Add support for parent/child studios. ### 🎨 Improvements +* Add support for chrome dp in xpath scrapers. * Allow customisation of preview video generation. * Add support for live transcoding in Safari. * Add mapped and fixed post-processing scraping options. diff --git a/ui/v2.5/src/components/Settings/SettingsConfigurationPanel.tsx b/ui/v2.5/src/components/Settings/SettingsConfigurationPanel.tsx index 814966275..b35936250 100644 --- a/ui/v2.5/src/components/Settings/SettingsConfigurationPanel.tsx +++ b/ui/v2.5/src/components/Settings/SettingsConfigurationPanel.tsx @@ -47,6 +47,9 @@ export const SettingsConfigurationPanel: React.FC = () => { const [scraperUserAgent, setScraperUserAgent] = useState( undefined ); + const [scraperCDPPath, setScraperCDPPath] = useState( + undefined + ); const { data, error, loading } = useConfiguration(); @@ -71,6 +74,7 @@ export const SettingsConfigurationPanel: React.FC = () => { logAccess, excludes, scraperUserAgent, + scraperCDPPath, }); useEffect(() => { @@ -100,6 +104,7 @@ export const SettingsConfigurationPanel: React.FC = () => { setLogAccess(conf.general.logAccess); setExcludes(conf.general.excludes); setScraperUserAgent(conf.general.scraperUserAgent ?? undefined); + setScraperCDPPath(conf.general.scraperCDPPath ?? undefined); } }, [data, error]); @@ -425,18 +430,37 @@ export const SettingsConfigurationPanel: React.FC = () => { - -
Scraping
- ) => - setScraperUserAgent(e.currentTarget.value) - } - /> - - User-Agent string used during scrape http requests - + +

Scraping

+ +
Scraper User Agent
+ ) => + setScraperUserAgent(e.currentTarget.value) + } + /> + + User-Agent string used during scrape http requests + +
+ + +
Chrome CDP path
+ ) => + setScraperCDPPath(e.currentTarget.value) + } + /> + + File path to the Chrome executable, or a remote address (starting + with http:// or https://, for example + http://localhost:9222/json/version) to a Chrome instance. + +

diff --git a/ui/v2.5/src/docs/en/Configuration.md b/ui/v2.5/src/docs/en/Configuration.md index 2d30c15e5..f605bfc91 100644 --- a/ui/v2.5/src/docs/en/Configuration.md +++ b/ui/v2.5/src/docs/en/Configuration.md @@ -34,10 +34,18 @@ exclude: _a useful [link](https://regex101.com/) to experiment with regexps_ -## Scraping User Agent string +## Scraping + +### User Agent string Some websites require a legitimate User-Agent string when receiving requests, or they will be rejected. If entered, this string will be applied as the `User-Agent` header value in http scrape requests. +### Chrome CDP path + +Some scrapers require a Chrome instance to function correctly. If left empty, stash will attempt to find the Chrome executable in the path environment, and will fail if it cannot find one. + +`Chrome CDP path` can be set to a path to the chrome executable, or an http(s) address to remote chrome instance (for example: `http://localhost:9222/json/version`). + ## Authentication By default, stash is not configured with any sort of password protection. To enable password protection, both `Username` and `Password` must be populated. Note that when entering a new username and password where none was set previously, the system will immediately request these credentials to log you in. diff --git a/ui/v2.5/src/docs/en/Scraping.md b/ui/v2.5/src/docs/en/Scraping.md index cdeca4bff..93bd1cd44 100644 --- a/ui/v2.5/src/docs/en/Scraping.md +++ b/ui/v2.5/src/docs/en/Scraping.md @@ -283,6 +283,22 @@ For backwards compatibility, `regex`, `subscraper` and `parseDate` are also allo Post-processing on attribute post-process is done in the following order: `concat`, `regex`, `subscraper`, `parseDate` and then `split`. +##### CDP support + +Some websites deliver content that cannot be scraped using the raw html file alone. These websites use javascript to dynamically load the content. As such, direct xpath scraping will not work on these websites. There is an option to use Chrome DevTools Protocol to load the webpage using an instance of Chrome, then scrape the result. + +Chrome CDP support can be enabled for a specific scraping configuration by adding the following to the root of the yml configuration: +``` +driver: + useCDP: true +``` + +Optionally, you can add a `sleep` value under the `driver` section. This specifies the amount of time (in seconds) that the scraper should wait after loading the website to perform the scrape. This is needed as some sites need more time for loading scripts to finish. If unset, this value defaults to 2 seconds. + +When `useCDP` is set to true, stash will execute or connect to an instance of Chrome. The behaviour is dictated by the `Chrome CDP path` setting in the user configuration. If left empty, stash will attempt to find the Chrome executable in the path environment, and will fail if it cannot find one. + +`Chrome CDP path` can be set to a path to the chrome executable, or an http(s) address to remote chrome instance (for example: `http://localhost:9222/json/version`). + ##### Example A performer and scene xpath scraper is shown as an example below: diff --git a/vendor/github.com/chromedp/cdproto/.gitignore b/vendor/github.com/chromedp/cdproto/.gitignore new file mode 100644 index 000000000..c456f5327 --- /dev/null +++ b/vendor/github.com/chromedp/cdproto/.gitignore @@ -0,0 +1,2 @@ +*.json +*.pdl diff --git a/vendor/github.com/chromedp/cdproto/.travis.yml b/vendor/github.com/chromedp/cdproto/.travis.yml new file mode 100644 index 000000000..1ee27956d --- /dev/null +++ b/vendor/github.com/chromedp/cdproto/.travis.yml @@ -0,0 +1,24 @@ +dist: bionic +language: go +go: + - 1.12.x + - 1.13.x +env: + - GO111MODULE=off +services: + - docker +addons: + apt: + chrome: stable +before_install: + - mkdir -p $GOPATH/src/github.com/chromedp + - git clone https://github.com/chromedp/chromedp.git $GOPATH/src/github.com/chromedp/chromedp + - cd $GOPATH/src/github.com/chromedp/chromedp + - go get -d -t +script: + - cd $GOPATH/src/github.com/chromedp/cdproto + - go install ./... + - cd $GOPATH/src/github.com/chromedp/chromedp + - go test -v + - go test -c + - docker run --rm --volume=$PWD:/chromedp --entrypoint=/chromedp/chromedp.test --workdir=/chromedp --env=PATH=/headless-shell chromedp/headless-shell:latest -test.v diff --git a/vendor/github.com/chromedp/cdproto/LICENSE b/vendor/github.com/chromedp/cdproto/LICENSE new file mode 100644 index 000000000..0b5be741b --- /dev/null +++ b/vendor/github.com/chromedp/cdproto/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016-2020 Kenneth Shaw + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/chromedp/cdproto/README.md b/vendor/github.com/chromedp/cdproto/README.md new file mode 100644 index 000000000..390b67704 --- /dev/null +++ b/vendor/github.com/chromedp/cdproto/README.md @@ -0,0 +1,23 @@ +# About cdproto + +Package `cdproto` contains the generated commands, types, and events for the +[Chrome DevTools Protocol domains][devtools-protocol]. + +This package is generated by the [`cdproto-gen`][cdproto-gen] command. Please +refer to that project and to the main [`chromedp`][chromedp] project for +information on using the commands, types, and events available here. + +## API + +Please see the [GoDoc listing][godoc]. + +## Contributing + +If you would like to submit a change to the code in this package, please submit +your Pull Request to the [`cdproto-gen`][cdproto-gen] project. Any Issues and +Pull Requests submitted to this project will be closed without being reviewed. + +[devtools-protocol]: https://chromedevtools.github.io/devtools-protocol/ +[cdproto-gen]: https://github.com/chromedp/cdproto-gen +[chromedp]: https://github.com/chromedp/chromedp +[godoc]: https://godoc.org/github.com/chromedp/cdproto diff --git a/vendor/github.com/chromedp/cdproto/accessibility/accessibility.go b/vendor/github.com/chromedp/cdproto/accessibility/accessibility.go new file mode 100644 index 000000000..f4a100506 --- /dev/null +++ b/vendor/github.com/chromedp/cdproto/accessibility/accessibility.go @@ -0,0 +1,153 @@ +// Package accessibility provides the Chrome DevTools Protocol +// commands, types, and events for the Accessibility domain. +// +// Generated by the cdproto-gen command. +package accessibility + +// Code generated by cdproto-gen. DO NOT EDIT. + +import ( + "context" + + "github.com/chromedp/cdproto/cdp" + "github.com/chromedp/cdproto/runtime" +) + +// DisableParams disables the accessibility domain. +type DisableParams struct{} + +// Disable disables the accessibility domain. +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-disable +func Disable() *DisableParams { + return &DisableParams{} +} + +// Do executes Accessibility.disable against the provided context. +func (p *DisableParams) Do(ctx context.Context) (err error) { + return cdp.Execute(ctx, CommandDisable, nil, nil) +} + +// EnableParams enables the accessibility domain which causes AXNodeIds to +// remain consistent between method calls. This turns on accessibility for the +// page, which can impact performance until accessibility is disabled. +type EnableParams struct{} + +// Enable enables the accessibility domain which causes AXNodeIds to remain +// consistent between method calls. This turns on accessibility for the page, +// which can impact performance until accessibility is disabled. +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-enable +func Enable() *EnableParams { + return &EnableParams{} +} + +// Do executes Accessibility.enable against the provided context. +func (p *EnableParams) Do(ctx context.Context) (err error) { + return cdp.Execute(ctx, CommandEnable, nil, nil) +} + +// GetPartialAXTreeParams fetches the accessibility node and partial +// accessibility tree for this DOM node, if it exists. +type GetPartialAXTreeParams struct { + NodeID cdp.NodeID `json:"nodeId,omitempty"` // Identifier of the node to get the partial accessibility tree for. + BackendNodeID cdp.BackendNodeID `json:"backendNodeId,omitempty"` // Identifier of the backend node to get the partial accessibility tree for. + ObjectID runtime.RemoteObjectID `json:"objectId,omitempty"` // JavaScript object id of the node wrapper to get the partial accessibility tree for. + FetchRelatives bool `json:"fetchRelatives,omitempty"` // Whether to fetch this nodes ancestors, siblings and children. Defaults to true. +} + +// GetPartialAXTree fetches the accessibility node and partial accessibility +// tree for this DOM node, if it exists. +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getPartialAXTree +// +// parameters: +func GetPartialAXTree() *GetPartialAXTreeParams { + return &GetPartialAXTreeParams{} +} + +// WithNodeID identifier of the node to get the partial accessibility tree +// for. +func (p GetPartialAXTreeParams) WithNodeID(nodeID cdp.NodeID) *GetPartialAXTreeParams { + p.NodeID = nodeID + return &p +} + +// WithBackendNodeID identifier of the backend node to get the partial +// accessibility tree for. +func (p GetPartialAXTreeParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *GetPartialAXTreeParams { + p.BackendNodeID = backendNodeID + return &p +} + +// WithObjectID JavaScript object id of the node wrapper to get the partial +// accessibility tree for. +func (p GetPartialAXTreeParams) WithObjectID(objectID runtime.RemoteObjectID) *GetPartialAXTreeParams { + p.ObjectID = objectID + return &p +} + +// WithFetchRelatives whether to fetch this nodes ancestors, siblings and +// children. Defaults to true. +func (p GetPartialAXTreeParams) WithFetchRelatives(fetchRelatives bool) *GetPartialAXTreeParams { + p.FetchRelatives = fetchRelatives + return &p +} + +// GetPartialAXTreeReturns return values. +type GetPartialAXTreeReturns struct { + Nodes []*Node `json:"nodes,omitempty"` // The Accessibility.AXNode for this DOM node, if it exists, plus its ancestors, siblings and children, if requested. +} + +// Do executes Accessibility.getPartialAXTree against the provided context. +// +// returns: +// nodes - The Accessibility.AXNode for this DOM node, if it exists, plus its ancestors, siblings and children, if requested. +func (p *GetPartialAXTreeParams) Do(ctx context.Context) (nodes []*Node, err error) { + // execute + var res GetPartialAXTreeReturns + err = cdp.Execute(ctx, CommandGetPartialAXTree, p, &res) + if err != nil { + return nil, err + } + + return res.Nodes, nil +} + +// GetFullAXTreeParams fetches the entire accessibility tree. +type GetFullAXTreeParams struct{} + +// GetFullAXTree fetches the entire accessibility tree. +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getFullAXTree +func GetFullAXTree() *GetFullAXTreeParams { + return &GetFullAXTreeParams{} +} + +// GetFullAXTreeReturns return values. +type GetFullAXTreeReturns struct { + Nodes []*Node `json:"nodes,omitempty"` +} + +// Do executes Accessibility.getFullAXTree against the provided context. +// +// returns: +// nodes +func (p *GetFullAXTreeParams) Do(ctx context.Context) (nodes []*Node, err error) { + // execute + var res GetFullAXTreeReturns + err = cdp.Execute(ctx, CommandGetFullAXTree, nil, &res) + if err != nil { + return nil, err + } + + return res.Nodes, nil +} + +// Command names. +const ( + CommandDisable = "Accessibility.disable" + CommandEnable = "Accessibility.enable" + CommandGetPartialAXTree = "Accessibility.getPartialAXTree" + CommandGetFullAXTree = "Accessibility.getFullAXTree" +) diff --git a/vendor/github.com/chromedp/cdproto/accessibility/easyjson.go b/vendor/github.com/chromedp/cdproto/accessibility/easyjson.go new file mode 100644 index 000000000..e2a01ec14 --- /dev/null +++ b/vendor/github.com/chromedp/cdproto/accessibility/easyjson.go @@ -0,0 +1,1275 @@ +// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. + +package accessibility + +import ( + json "encoding/json" + runtime "github.com/chromedp/cdproto/runtime" + easyjson "github.com/mailru/easyjson" + jlexer "github.com/mailru/easyjson/jlexer" + jwriter "github.com/mailru/easyjson/jwriter" +) + +// suppress unused package warning +var ( + _ *json.RawMessage + _ *jlexer.Lexer + _ *jwriter.Writer + _ easyjson.Marshaler +) + +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility(in *jlexer.Lexer, out *ValueSource) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "type": + (out.Type).UnmarshalEasyJSON(in) + case "value": + if in.IsNull() { + in.Skip() + out.Value = nil + } else { + if out.Value == nil { + out.Value = new(Value) + } + (*out.Value).UnmarshalEasyJSON(in) + } + case "attribute": + out.Attribute = string(in.String()) + case "attributeValue": + if in.IsNull() { + in.Skip() + out.AttributeValue = nil + } else { + if out.AttributeValue == nil { + out.AttributeValue = new(Value) + } + (*out.AttributeValue).UnmarshalEasyJSON(in) + } + case "superseded": + out.Superseded = bool(in.Bool()) + case "nativeSource": + (out.NativeSource).UnmarshalEasyJSON(in) + case "nativeSourceValue": + if in.IsNull() { + in.Skip() + out.NativeSourceValue = nil + } else { + if out.NativeSourceValue == nil { + out.NativeSourceValue = new(Value) + } + (*out.NativeSourceValue).UnmarshalEasyJSON(in) + } + case "invalid": + out.Invalid = bool(in.Bool()) + case "invalidReason": + out.InvalidReason = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility(out *jwriter.Writer, in ValueSource) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"type\":" + out.RawString(prefix[1:]) + (in.Type).MarshalEasyJSON(out) + } + if in.Value != nil { + const prefix string = ",\"value\":" + out.RawString(prefix) + (*in.Value).MarshalEasyJSON(out) + } + if in.Attribute != "" { + const prefix string = ",\"attribute\":" + out.RawString(prefix) + out.String(string(in.Attribute)) + } + if in.AttributeValue != nil { + const prefix string = ",\"attributeValue\":" + out.RawString(prefix) + (*in.AttributeValue).MarshalEasyJSON(out) + } + if in.Superseded { + const prefix string = ",\"superseded\":" + out.RawString(prefix) + out.Bool(bool(in.Superseded)) + } + if in.NativeSource != "" { + const prefix string = ",\"nativeSource\":" + out.RawString(prefix) + (in.NativeSource).MarshalEasyJSON(out) + } + if in.NativeSourceValue != nil { + const prefix string = ",\"nativeSourceValue\":" + out.RawString(prefix) + (*in.NativeSourceValue).MarshalEasyJSON(out) + } + if in.Invalid { + const prefix string = ",\"invalid\":" + out.RawString(prefix) + out.Bool(bool(in.Invalid)) + } + if in.InvalidReason != "" { + const prefix string = ",\"invalidReason\":" + out.RawString(prefix) + out.String(string(in.InvalidReason)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v ValueSource) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v ValueSource) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *ValueSource) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *ValueSource) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility1(in *jlexer.Lexer, out *Value) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "type": + (out.Type).UnmarshalEasyJSON(in) + case "value": + (out.Value).UnmarshalEasyJSON(in) + case "relatedNodes": + if in.IsNull() { + in.Skip() + out.RelatedNodes = nil + } else { + in.Delim('[') + if out.RelatedNodes == nil { + if !in.IsDelim(']') { + out.RelatedNodes = make([]*RelatedNode, 0, 8) + } else { + out.RelatedNodes = []*RelatedNode{} + } + } else { + out.RelatedNodes = (out.RelatedNodes)[:0] + } + for !in.IsDelim(']') { + var v1 *RelatedNode + if in.IsNull() { + in.Skip() + v1 = nil + } else { + if v1 == nil { + v1 = new(RelatedNode) + } + (*v1).UnmarshalEasyJSON(in) + } + out.RelatedNodes = append(out.RelatedNodes, v1) + in.WantComma() + } + in.Delim(']') + } + case "sources": + if in.IsNull() { + in.Skip() + out.Sources = nil + } else { + in.Delim('[') + if out.Sources == nil { + if !in.IsDelim(']') { + out.Sources = make([]*ValueSource, 0, 8) + } else { + out.Sources = []*ValueSource{} + } + } else { + out.Sources = (out.Sources)[:0] + } + for !in.IsDelim(']') { + var v2 *ValueSource + if in.IsNull() { + in.Skip() + v2 = nil + } else { + if v2 == nil { + v2 = new(ValueSource) + } + (*v2).UnmarshalEasyJSON(in) + } + out.Sources = append(out.Sources, v2) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility1(out *jwriter.Writer, in Value) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"type\":" + out.RawString(prefix[1:]) + (in.Type).MarshalEasyJSON(out) + } + if (in.Value).IsDefined() { + const prefix string = ",\"value\":" + out.RawString(prefix) + (in.Value).MarshalEasyJSON(out) + } + if len(in.RelatedNodes) != 0 { + const prefix string = ",\"relatedNodes\":" + out.RawString(prefix) + { + out.RawByte('[') + for v3, v4 := range in.RelatedNodes { + if v3 > 0 { + out.RawByte(',') + } + if v4 == nil { + out.RawString("null") + } else { + (*v4).MarshalEasyJSON(out) + } + } + out.RawByte(']') + } + } + if len(in.Sources) != 0 { + const prefix string = ",\"sources\":" + out.RawString(prefix) + { + out.RawByte('[') + for v5, v6 := range in.Sources { + if v5 > 0 { + out.RawByte(',') + } + if v6 == nil { + out.RawString("null") + } else { + (*v6).MarshalEasyJSON(out) + } + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v Value) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility1(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v Value) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility1(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *Value) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility1(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *Value) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility1(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility2(in *jlexer.Lexer, out *RelatedNode) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "backendDOMNodeId": + (out.BackendDOMNodeID).UnmarshalEasyJSON(in) + case "idref": + out.Idref = string(in.String()) + case "text": + out.Text = string(in.String()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility2(out *jwriter.Writer, in RelatedNode) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"backendDOMNodeId\":" + out.RawString(prefix[1:]) + out.Int64(int64(in.BackendDOMNodeID)) + } + if in.Idref != "" { + const prefix string = ",\"idref\":" + out.RawString(prefix) + out.String(string(in.Idref)) + } + if in.Text != "" { + const prefix string = ",\"text\":" + out.RawString(prefix) + out.String(string(in.Text)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v RelatedNode) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility2(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v RelatedNode) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility2(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *RelatedNode) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility2(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *RelatedNode) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility2(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility3(in *jlexer.Lexer, out *Property) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "name": + (out.Name).UnmarshalEasyJSON(in) + case "value": + if in.IsNull() { + in.Skip() + out.Value = nil + } else { + if out.Value == nil { + out.Value = new(Value) + } + (*out.Value).UnmarshalEasyJSON(in) + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility3(out *jwriter.Writer, in Property) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"name\":" + out.RawString(prefix[1:]) + (in.Name).MarshalEasyJSON(out) + } + { + const prefix string = ",\"value\":" + out.RawString(prefix) + if in.Value == nil { + out.RawString("null") + } else { + (*in.Value).MarshalEasyJSON(out) + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v Property) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility3(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v Property) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility3(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *Property) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility3(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *Property) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility3(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility4(in *jlexer.Lexer, out *Node) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "nodeId": + out.NodeID = NodeID(in.String()) + case "ignored": + out.Ignored = bool(in.Bool()) + case "ignoredReasons": + if in.IsNull() { + in.Skip() + out.IgnoredReasons = nil + } else { + in.Delim('[') + if out.IgnoredReasons == nil { + if !in.IsDelim(']') { + out.IgnoredReasons = make([]*Property, 0, 8) + } else { + out.IgnoredReasons = []*Property{} + } + } else { + out.IgnoredReasons = (out.IgnoredReasons)[:0] + } + for !in.IsDelim(']') { + var v7 *Property + if in.IsNull() { + in.Skip() + v7 = nil + } else { + if v7 == nil { + v7 = new(Property) + } + (*v7).UnmarshalEasyJSON(in) + } + out.IgnoredReasons = append(out.IgnoredReasons, v7) + in.WantComma() + } + in.Delim(']') + } + case "role": + if in.IsNull() { + in.Skip() + out.Role = nil + } else { + if out.Role == nil { + out.Role = new(Value) + } + (*out.Role).UnmarshalEasyJSON(in) + } + case "name": + if in.IsNull() { + in.Skip() + out.Name = nil + } else { + if out.Name == nil { + out.Name = new(Value) + } + (*out.Name).UnmarshalEasyJSON(in) + } + case "description": + if in.IsNull() { + in.Skip() + out.Description = nil + } else { + if out.Description == nil { + out.Description = new(Value) + } + (*out.Description).UnmarshalEasyJSON(in) + } + case "value": + if in.IsNull() { + in.Skip() + out.Value = nil + } else { + if out.Value == nil { + out.Value = new(Value) + } + (*out.Value).UnmarshalEasyJSON(in) + } + case "properties": + if in.IsNull() { + in.Skip() + out.Properties = nil + } else { + in.Delim('[') + if out.Properties == nil { + if !in.IsDelim(']') { + out.Properties = make([]*Property, 0, 8) + } else { + out.Properties = []*Property{} + } + } else { + out.Properties = (out.Properties)[:0] + } + for !in.IsDelim(']') { + var v8 *Property + if in.IsNull() { + in.Skip() + v8 = nil + } else { + if v8 == nil { + v8 = new(Property) + } + (*v8).UnmarshalEasyJSON(in) + } + out.Properties = append(out.Properties, v8) + in.WantComma() + } + in.Delim(']') + } + case "childIds": + if in.IsNull() { + in.Skip() + out.ChildIds = nil + } else { + in.Delim('[') + if out.ChildIds == nil { + if !in.IsDelim(']') { + out.ChildIds = make([]NodeID, 0, 4) + } else { + out.ChildIds = []NodeID{} + } + } else { + out.ChildIds = (out.ChildIds)[:0] + } + for !in.IsDelim(']') { + var v9 NodeID + v9 = NodeID(in.String()) + out.ChildIds = append(out.ChildIds, v9) + in.WantComma() + } + in.Delim(']') + } + case "backendDOMNodeId": + (out.BackendDOMNodeID).UnmarshalEasyJSON(in) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility4(out *jwriter.Writer, in Node) { + out.RawByte('{') + first := true + _ = first + { + const prefix string = ",\"nodeId\":" + out.RawString(prefix[1:]) + out.String(string(in.NodeID)) + } + { + const prefix string = ",\"ignored\":" + out.RawString(prefix) + out.Bool(bool(in.Ignored)) + } + if len(in.IgnoredReasons) != 0 { + const prefix string = ",\"ignoredReasons\":" + out.RawString(prefix) + { + out.RawByte('[') + for v10, v11 := range in.IgnoredReasons { + if v10 > 0 { + out.RawByte(',') + } + if v11 == nil { + out.RawString("null") + } else { + (*v11).MarshalEasyJSON(out) + } + } + out.RawByte(']') + } + } + if in.Role != nil { + const prefix string = ",\"role\":" + out.RawString(prefix) + (*in.Role).MarshalEasyJSON(out) + } + if in.Name != nil { + const prefix string = ",\"name\":" + out.RawString(prefix) + (*in.Name).MarshalEasyJSON(out) + } + if in.Description != nil { + const prefix string = ",\"description\":" + out.RawString(prefix) + (*in.Description).MarshalEasyJSON(out) + } + if in.Value != nil { + const prefix string = ",\"value\":" + out.RawString(prefix) + (*in.Value).MarshalEasyJSON(out) + } + if len(in.Properties) != 0 { + const prefix string = ",\"properties\":" + out.RawString(prefix) + { + out.RawByte('[') + for v12, v13 := range in.Properties { + if v12 > 0 { + out.RawByte(',') + } + if v13 == nil { + out.RawString("null") + } else { + (*v13).MarshalEasyJSON(out) + } + } + out.RawByte(']') + } + } + if len(in.ChildIds) != 0 { + const prefix string = ",\"childIds\":" + out.RawString(prefix) + { + out.RawByte('[') + for v14, v15 := range in.ChildIds { + if v14 > 0 { + out.RawByte(',') + } + out.String(string(v15)) + } + out.RawByte(']') + } + } + if in.BackendDOMNodeID != 0 { + const prefix string = ",\"backendDOMNodeId\":" + out.RawString(prefix) + out.Int64(int64(in.BackendDOMNodeID)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v Node) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility4(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v Node) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility4(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *Node) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility4(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *Node) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility4(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility5(in *jlexer.Lexer, out *GetPartialAXTreeReturns) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "nodes": + if in.IsNull() { + in.Skip() + out.Nodes = nil + } else { + in.Delim('[') + if out.Nodes == nil { + if !in.IsDelim(']') { + out.Nodes = make([]*Node, 0, 8) + } else { + out.Nodes = []*Node{} + } + } else { + out.Nodes = (out.Nodes)[:0] + } + for !in.IsDelim(']') { + var v16 *Node + if in.IsNull() { + in.Skip() + v16 = nil + } else { + if v16 == nil { + v16 = new(Node) + } + (*v16).UnmarshalEasyJSON(in) + } + out.Nodes = append(out.Nodes, v16) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility5(out *jwriter.Writer, in GetPartialAXTreeReturns) { + out.RawByte('{') + first := true + _ = first + if len(in.Nodes) != 0 { + const prefix string = ",\"nodes\":" + first = false + out.RawString(prefix[1:]) + { + out.RawByte('[') + for v17, v18 := range in.Nodes { + if v17 > 0 { + out.RawByte(',') + } + if v18 == nil { + out.RawString("null") + } else { + (*v18).MarshalEasyJSON(out) + } + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v GetPartialAXTreeReturns) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility5(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v GetPartialAXTreeReturns) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility5(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *GetPartialAXTreeReturns) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility5(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *GetPartialAXTreeReturns) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility5(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility6(in *jlexer.Lexer, out *GetPartialAXTreeParams) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "nodeId": + (out.NodeID).UnmarshalEasyJSON(in) + case "backendNodeId": + (out.BackendNodeID).UnmarshalEasyJSON(in) + case "objectId": + out.ObjectID = runtime.RemoteObjectID(in.String()) + case "fetchRelatives": + out.FetchRelatives = bool(in.Bool()) + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility6(out *jwriter.Writer, in GetPartialAXTreeParams) { + out.RawByte('{') + first := true + _ = first + if in.NodeID != 0 { + const prefix string = ",\"nodeId\":" + first = false + out.RawString(prefix[1:]) + out.Int64(int64(in.NodeID)) + } + if in.BackendNodeID != 0 { + const prefix string = ",\"backendNodeId\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.Int64(int64(in.BackendNodeID)) + } + if in.ObjectID != "" { + const prefix string = ",\"objectId\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.String(string(in.ObjectID)) + } + if in.FetchRelatives { + const prefix string = ",\"fetchRelatives\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + out.Bool(bool(in.FetchRelatives)) + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v GetPartialAXTreeParams) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility6(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v GetPartialAXTreeParams) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility6(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *GetPartialAXTreeParams) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility6(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *GetPartialAXTreeParams) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility6(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility7(in *jlexer.Lexer, out *GetFullAXTreeReturns) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "nodes": + if in.IsNull() { + in.Skip() + out.Nodes = nil + } else { + in.Delim('[') + if out.Nodes == nil { + if !in.IsDelim(']') { + out.Nodes = make([]*Node, 0, 8) + } else { + out.Nodes = []*Node{} + } + } else { + out.Nodes = (out.Nodes)[:0] + } + for !in.IsDelim(']') { + var v19 *Node + if in.IsNull() { + in.Skip() + v19 = nil + } else { + if v19 == nil { + v19 = new(Node) + } + (*v19).UnmarshalEasyJSON(in) + } + out.Nodes = append(out.Nodes, v19) + in.WantComma() + } + in.Delim(']') + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility7(out *jwriter.Writer, in GetFullAXTreeReturns) { + out.RawByte('{') + first := true + _ = first + if len(in.Nodes) != 0 { + const prefix string = ",\"nodes\":" + first = false + out.RawString(prefix[1:]) + { + out.RawByte('[') + for v20, v21 := range in.Nodes { + if v20 > 0 { + out.RawByte(',') + } + if v21 == nil { + out.RawString("null") + } else { + (*v21).MarshalEasyJSON(out) + } + } + out.RawByte(']') + } + } + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v GetFullAXTreeReturns) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility7(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v GetFullAXTreeReturns) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility7(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *GetFullAXTreeReturns) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility7(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *GetFullAXTreeReturns) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility7(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility8(in *jlexer.Lexer, out *GetFullAXTreeParams) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility8(out *jwriter.Writer, in GetFullAXTreeParams) { + out.RawByte('{') + first := true + _ = first + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v GetFullAXTreeParams) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility8(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v GetFullAXTreeParams) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility8(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *GetFullAXTreeParams) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility8(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *GetFullAXTreeParams) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility8(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility9(in *jlexer.Lexer, out *EnableParams) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility9(out *jwriter.Writer, in EnableParams) { + out.RawByte('{') + first := true + _ = first + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v EnableParams) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility9(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v EnableParams) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility9(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *EnableParams) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility9(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *EnableParams) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility9(l, v) +} +func easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility10(in *jlexer.Lexer, out *DisableParams) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeString() + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility10(out *jwriter.Writer, in DisableParams) { + out.RawByte('{') + first := true + _ = first + out.RawByte('}') +} + +// MarshalJSON supports json.Marshaler interface +func (v DisableParams) MarshalJSON() ([]byte, error) { + w := jwriter.Writer{} + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility10(&w, v) + return w.Buffer.BuildBytes(), w.Error +} + +// MarshalEasyJSON supports easyjson.Marshaler interface +func (v DisableParams) MarshalEasyJSON(w *jwriter.Writer) { + easyjsonC5a4559bEncodeGithubComChromedpCdprotoAccessibility10(w, v) +} + +// UnmarshalJSON supports json.Unmarshaler interface +func (v *DisableParams) UnmarshalJSON(data []byte) error { + r := jlexer.Lexer{Data: data} + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility10(&r, v) + return r.Error() +} + +// UnmarshalEasyJSON supports easyjson.Unmarshaler interface +func (v *DisableParams) UnmarshalEasyJSON(l *jlexer.Lexer) { + easyjsonC5a4559bDecodeGithubComChromedpCdprotoAccessibility10(l, v) +} diff --git a/vendor/github.com/chromedp/cdproto/accessibility/types.go b/vendor/github.com/chromedp/cdproto/accessibility/types.go new file mode 100644 index 000000000..bb2bf7e22 --- /dev/null +++ b/vendor/github.com/chromedp/cdproto/accessibility/types.go @@ -0,0 +1,448 @@ +package accessibility + +// Code generated by cdproto-gen. DO NOT EDIT. + +import ( + "errors" + + "github.com/chromedp/cdproto/cdp" + "github.com/mailru/easyjson" + "github.com/mailru/easyjson/jlexer" + "github.com/mailru/easyjson/jwriter" +) + +// NodeID unique accessibility node identifier. +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXNodeId +type NodeID string + +// String returns the NodeID as string value. +func (t NodeID) String() string { + return string(t) +} + +// ValueType enum of possible property types. +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueType +type ValueType string + +// String returns the ValueType as string value. +func (t ValueType) String() string { + return string(t) +} + +// ValueType values. +const ( + ValueTypeBoolean ValueType = "boolean" + ValueTypeTristate ValueType = "tristate" + ValueTypeBooleanOrUndefined ValueType = "booleanOrUndefined" + ValueTypeIdref ValueType = "idref" + ValueTypeIdrefList ValueType = "idrefList" + ValueTypeInteger ValueType = "integer" + ValueTypeNode ValueType = "node" + ValueTypeNodeList ValueType = "nodeList" + ValueTypeNumber ValueType = "number" + ValueTypeString ValueType = "string" + ValueTypeComputedString ValueType = "computedString" + ValueTypeToken ValueType = "token" + ValueTypeTokenList ValueType = "tokenList" + ValueTypeDomRelation ValueType = "domRelation" + ValueTypeRole ValueType = "role" + ValueTypeInternalRole ValueType = "internalRole" + ValueTypeValueUndefined ValueType = "valueUndefined" +) + +// MarshalEasyJSON satisfies easyjson.Marshaler. +func (t ValueType) MarshalEasyJSON(out *jwriter.Writer) { + out.String(string(t)) +} + +// MarshalJSON satisfies json.Marshaler. +func (t ValueType) MarshalJSON() ([]byte, error) { + return easyjson.Marshal(t) +} + +// UnmarshalEasyJSON satisfies easyjson.Unmarshaler. +func (t *ValueType) UnmarshalEasyJSON(in *jlexer.Lexer) { + switch ValueType(in.String()) { + case ValueTypeBoolean: + *t = ValueTypeBoolean + case ValueTypeTristate: + *t = ValueTypeTristate + case ValueTypeBooleanOrUndefined: + *t = ValueTypeBooleanOrUndefined + case ValueTypeIdref: + *t = ValueTypeIdref + case ValueTypeIdrefList: + *t = ValueTypeIdrefList + case ValueTypeInteger: + *t = ValueTypeInteger + case ValueTypeNode: + *t = ValueTypeNode + case ValueTypeNodeList: + *t = ValueTypeNodeList + case ValueTypeNumber: + *t = ValueTypeNumber + case ValueTypeString: + *t = ValueTypeString + case ValueTypeComputedString: + *t = ValueTypeComputedString + case ValueTypeToken: + *t = ValueTypeToken + case ValueTypeTokenList: + *t = ValueTypeTokenList + case ValueTypeDomRelation: + *t = ValueTypeDomRelation + case ValueTypeRole: + *t = ValueTypeRole + case ValueTypeInternalRole: + *t = ValueTypeInternalRole + case ValueTypeValueUndefined: + *t = ValueTypeValueUndefined + + default: + in.AddError(errors.New("unknown ValueType value")) + } +} + +// UnmarshalJSON satisfies json.Unmarshaler. +func (t *ValueType) UnmarshalJSON(buf []byte) error { + return easyjson.Unmarshal(buf, t) +} + +// ValueSourceType enum of possible property sources. +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueSourceType +type ValueSourceType string + +// String returns the ValueSourceType as string value. +func (t ValueSourceType) String() string { + return string(t) +} + +// ValueSourceType values. +const ( + ValueSourceTypeAttribute ValueSourceType = "attribute" + ValueSourceTypeImplicit ValueSourceType = "implicit" + ValueSourceTypeStyle ValueSourceType = "style" + ValueSourceTypeContents ValueSourceType = "contents" + ValueSourceTypePlaceholder ValueSourceType = "placeholder" + ValueSourceTypeRelatedElement ValueSourceType = "relatedElement" +) + +// MarshalEasyJSON satisfies easyjson.Marshaler. +func (t ValueSourceType) MarshalEasyJSON(out *jwriter.Writer) { + out.String(string(t)) +} + +// MarshalJSON satisfies json.Marshaler. +func (t ValueSourceType) MarshalJSON() ([]byte, error) { + return easyjson.Marshal(t) +} + +// UnmarshalEasyJSON satisfies easyjson.Unmarshaler. +func (t *ValueSourceType) UnmarshalEasyJSON(in *jlexer.Lexer) { + switch ValueSourceType(in.String()) { + case ValueSourceTypeAttribute: + *t = ValueSourceTypeAttribute + case ValueSourceTypeImplicit: + *t = ValueSourceTypeImplicit + case ValueSourceTypeStyle: + *t = ValueSourceTypeStyle + case ValueSourceTypeContents: + *t = ValueSourceTypeContents + case ValueSourceTypePlaceholder: + *t = ValueSourceTypePlaceholder + case ValueSourceTypeRelatedElement: + *t = ValueSourceTypeRelatedElement + + default: + in.AddError(errors.New("unknown ValueSourceType value")) + } +} + +// UnmarshalJSON satisfies json.Unmarshaler. +func (t *ValueSourceType) UnmarshalJSON(buf []byte) error { + return easyjson.Unmarshal(buf, t) +} + +// ValueNativeSourceType enum of possible native property sources (as a +// subtype of a particular AXValueSourceType). +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueNativeSourceType +type ValueNativeSourceType string + +// String returns the ValueNativeSourceType as string value. +func (t ValueNativeSourceType) String() string { + return string(t) +} + +// ValueNativeSourceType values. +const ( + ValueNativeSourceTypeFigcaption ValueNativeSourceType = "figcaption" + ValueNativeSourceTypeLabel ValueNativeSourceType = "label" + ValueNativeSourceTypeLabelfor ValueNativeSourceType = "labelfor" + ValueNativeSourceTypeLabelwrapped ValueNativeSourceType = "labelwrapped" + ValueNativeSourceTypeLegend ValueNativeSourceType = "legend" + ValueNativeSourceTypeTablecaption ValueNativeSourceType = "tablecaption" + ValueNativeSourceTypeTitle ValueNativeSourceType = "title" + ValueNativeSourceTypeOther ValueNativeSourceType = "other" +) + +// MarshalEasyJSON satisfies easyjson.Marshaler. +func (t ValueNativeSourceType) MarshalEasyJSON(out *jwriter.Writer) { + out.String(string(t)) +} + +// MarshalJSON satisfies json.Marshaler. +func (t ValueNativeSourceType) MarshalJSON() ([]byte, error) { + return easyjson.Marshal(t) +} + +// UnmarshalEasyJSON satisfies easyjson.Unmarshaler. +func (t *ValueNativeSourceType) UnmarshalEasyJSON(in *jlexer.Lexer) { + switch ValueNativeSourceType(in.String()) { + case ValueNativeSourceTypeFigcaption: + *t = ValueNativeSourceTypeFigcaption + case ValueNativeSourceTypeLabel: + *t = ValueNativeSourceTypeLabel + case ValueNativeSourceTypeLabelfor: + *t = ValueNativeSourceTypeLabelfor + case ValueNativeSourceTypeLabelwrapped: + *t = ValueNativeSourceTypeLabelwrapped + case ValueNativeSourceTypeLegend: + *t = ValueNativeSourceTypeLegend + case ValueNativeSourceTypeTablecaption: + *t = ValueNativeSourceTypeTablecaption + case ValueNativeSourceTypeTitle: + *t = ValueNativeSourceTypeTitle + case ValueNativeSourceTypeOther: + *t = ValueNativeSourceTypeOther + + default: + in.AddError(errors.New("unknown ValueNativeSourceType value")) + } +} + +// UnmarshalJSON satisfies json.Unmarshaler. +func (t *ValueNativeSourceType) UnmarshalJSON(buf []byte) error { + return easyjson.Unmarshal(buf, t) +} + +// ValueSource a single source for a computed AX property. +// +// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueSource +type ValueSource struct { + Type ValueSourceType `json:"type"` // What type of source this is. + Value *Value `json:"value,omitempty"` // The value of this property source. + Attribute string `json:"attribute,omitempty"` // The name of the relevant attribute, if any. + AttributeValue *Value `json:"attributeValue,omitempty"` // The value of the relevant attribute, if any. + Superseded bool `json:"superseded,omitempty"` // Whether this source is superseded by a higher priority source. + NativeSource ValueNativeSourceType `json:"nativeSource,omitempty"` // The native markup source for this value, e.g. a