diff --git a/.gitattributes b/.gitattributes index 4fea60b95..3b5c2ca77 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,6 @@ go.mod text eol=lf -go.sum text eol=lf \ No newline at end of file +go.sum text eol=lf +*.go text eol=lf +vendor/** -text +ui/v2.5/**/*.ts* text eol=lf +ui/v2.5/**/*.scss text eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 87bb80199..45fc209de 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -23,6 +23,8 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem please ensure that your screenshots are SFW or at least appropriately censored. +**Stash Version: (from Settings -> About):** + **Desktop (please complete the following information):** - OS: [e.g. iOS] - Browser [e.g. chrome, safari] diff --git a/.gitignore b/.gitignore index a54db8fb0..4f92a344f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ # GraphQL generated output pkg/models/generated_*.go ui/v2/src/core/generated-*.tsx +ui/v2.5/src/core/generated-*.tsx # packr generated files *-packr.go diff --git a/.idea/go.iml b/.idea/go.iml index ef3c3f44e..eddfcc6c3 100644 --- a/.idea/go.iml +++ b/.idea/go.iml @@ -4,11 +4,10 @@ - - - + + - \ No newline at end of file + diff --git a/.travis.yml b/.travis.yml index 8ffc58986..ca5eecc95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,8 @@ +if: tag != latest_develop # dont build for the latest_develop tagged version + dist: xenial +git: + depth: false language: go go: - 1.11.x @@ -9,14 +13,15 @@ env: - GO111MODULE=on before_install: - echo -e "machine github.com\n login $CI_USER_TOKEN" > ~/.netrc -- travis_retry yarn --cwd ui/v2 install --frozen-lockfile +- nvm install 12 +- travis_retry yarn --cwd ui/v2.5 install --frozen-lockfile - make generate -- CI=false yarn --cwd ui/v2 build # TODO: Fix warnings +- CI=false yarn --cwd ui/v2.5 build-ci #- go get -v github.com/mgechev/revive script: +# left lint off to avoid getting extra dependency #- make lint -#- make vet -- make it +- make fmt-check vet it after_success: - docker pull stashapp/compiler:develop - sh ./scripts/cross-compile.sh @@ -31,6 +36,8 @@ before_deploy: deploy: # latest develop release - provider: releases + # use the v2 release provider for proper release note setting + edge: true api_key: secure: tGJ2q62CfPdayid2qEtW2aGRhMgCl3lBXYYQqp3eH0vFgIIf6cs7IDX7YC/x3XKMEQ/iMLZmtCXZvSTqNrD6Sk7MSnt30GIs+4uxIZDnnd8mV5X3K4n4gjD+NAORc4DrQBvUGrYMKJsR5gtkH0nu6diWb1o1If7OiJEuCPRhrmQYcza7NUdABnA9Z2wn2RNUV9Ga33WUCqLMEU5GtNBlfQPiP/khCQrqn/ocR6wUjYut3J6YagzqH4wsfJi3glHyWtowcNIw1LZi5zFxHD/bRBT4Tln7yypkjWNq9eQILA6i6kRUGf7ggyTx26/k8n4tnu+QD0vVh4EcjlThpU/LGyUXzKrrxjRwaDZnM0oYxg5AfHcBuAiAdo0eWnV3lEWRfTJMIVb9MPf4qDmzR4RREfB5OXOxwq3ODeCcJE8sTIMD/wBPZrlqS/QrRpND2gn2X4snkVukN9t9F4CMTFMtVSzFV7TDJW5E5Lq6VEExulteQhs6kcK9NRPNAaLgRQAw7X9kVWfDtiGUP+fE2i8F9Bo8bm7sOT5O5VPMPykx3EgeNg1IqIgMTCsMlhMJT4xBJoQUgmd2wWyf3Ryw+P+sFgdb5Sd7+lFgJBjMUUoOxMxAOiEgdFvCXcr+/Udyz2RdtetU1/6VzXzLPcKOw0wubZeBkISqu7o9gpfdMP9Eq00= file: @@ -41,7 +48,7 @@ deploy: skip_cleanup: true overwrite: true name: "${STASH_VERSION}: Latest development build" - body: ${RELEASE_DATE}\n This is always the latest committed version on the develop branch. Use as your own risk! + release_notes: "**${RELEASE_DATE}**\n This is always the latest committed version on the develop branch. Use as your own risk!" prerelease: true on: repo: stashapp/stash diff --git a/Makefile b/Makefile index 2cb51b4af..659a80120 100644 --- a/Makefile +++ b/Makefile @@ -21,13 +21,18 @@ clean: .PHONY: generate generate: go generate -mod=vendor - cd ui/v2 && yarn run gqlgen + cd ui/v2.5 && yarn run gqlgen # Runs gofmt -w on the project's source code, modifying any files that do not match its style. .PHONY: fmt fmt: go fmt ./... +# Ensures that changed files have had gofmt run on them +.PHONY: fmt-check +fmt-check: + sh ./scripts/check-gofmt.sh + # Runs go vet on the project's source code. .PHONY: vet vet: @@ -47,7 +52,31 @@ test: it: go test -mod=vendor -tags=integration ./... +# installs UI dependencies. Run when first cloning repository, or if UI +# dependencies have changed +.PHONY: pre-ui +pre-ui: + cd ui/v2.5 && yarn install --frozen-lockfile + .PHONY: ui ui: - cd ui/v2 && yarn build + cd ui/v2.5 && yarn build packr2 + +fmt-ui: + cd ui/v2.5 && yarn format + +# runs tests and checks on the UI and builds it +.PHONY: ui-validate +ui-validate: + cd ui/v2.5 && yarn run validate + +# just repacks the packr files - use when updating migrations and packed files without +# rebuilding the UI +.PHONY: packr +packr: + packr2 + +# runs all of the tests and checks required for a PR to be accepted +.PHONY: validate +validate: ui-validate fmt-check vet lint it diff --git a/README.md b/README.md index 3e4a18582..b00c8c456 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Join the [Discord server](https://discord.gg/2TsNFKt). * Go Install: `go get github.com/gobuffalo/packr/v2/packr2@v2.0.2` * [Binary Download](https://github.com/gobuffalo/packr/releases) * [Yarn](https://yarnpkg.com/en/docs/install) - Yarn package manager - * Run `yarn install --frozen-lockfile` in the `stash/ui/v2` folder (before running make generate for first time). + * Run `yarn install --frozen-lockfile` in the `stash/ui/v2.5` folder (before running make generate for first time). NOTE: You may need to run the `go get` commands outside the project directory to avoid modifying the projects module file. @@ -92,11 +92,18 @@ NOTE: The `make` command in Windows will be `mingw32-make` with MingW. ## Commands -* `make generate` - Generate Go GraphQL and packr2 files +* `make generate` - Generate Go and UI GraphQL files * `make build` - Builds the binary (make sure to build the UI as well... see below) -* `make ui` - Builds the frontend +* `make pre-ui` - Installs the UI dependencies. Only needs to be run once before building the UI for the first time, or if the dependencies are updated +* `make fmt-ui` - Formats the UI source code. +* `make ui` - Builds the frontend and the packr2 files +* `make packr` - Generate packr2 files (sub-target of `ui`. Use to regenerate packr2 files without rebuilding UI) * `make vet` - Run `go vet` * `make lint` - Run the linter +* `make fmt` - Run `go fmt` +* `make fmt-check` - Ensure changed files are formatted correctly +* `make it` - Run the unit and integration tests +* `make validate` - Run all of the tests and checks required to submit a PR ## Building a release @@ -111,3 +118,10 @@ where the app can be cross-compiled. This process is kicked off by CI via the ` command to open a bash shell to the container to poke around: `docker run --rm --mount type=bind,source="$(pwd)",target=/stash -w /stash -i -t stashappdev/compiler:latest /bin/bash` + +## Customization + +You can make Stash interface fit your desired style with [Custom CSS snippets](https://github.com/stashapp/stash/wiki/Custom-CSS-snippets) and [CSS Tweaks](https://github.com/stashapp/stash/wiki/CSS-Tweaks). + +[Stash Plex Theme](https://github.com/stashapp/stash/wiki/Stash-Plex-Theme) is a community created theme inspired by popular Plex Interface. + diff --git a/docker/build/x86_64/Dockerfile b/docker/build/x86_64/Dockerfile index c2f8af444..8ac117647 100644 --- a/docker/build/x86_64/Dockerfile +++ b/docker/build/x86_64/Dockerfile @@ -32,10 +32,10 @@ RUN wget -O /ffmpeg.tar.xz https://johnvansickle.com/ffmpeg/releases/ffmpeg-rele mv /ffmpeg*/ /ffmpeg/ # copy the ui yarn stuff so that it doesn't get rebuilt every time -COPY ./ui/v2/package.json ./ui/v2/yarn.lock /stash/ui/v2/ +COPY ./ui/v2.5/package.json ./ui/v2.5/yarn.lock /stash/ui/v2.5/ WORKDIR /stash -RUN yarn --cwd ui/v2 install --frozen-lockfile +RUN yarn --cwd ui/v2.5 install --frozen-lockfile COPY . /stash/ ENV GO111MODULE=on diff --git a/go.mod b/go.mod index ae4aff41b..e4e407dd8 100644 --- a/go.mod +++ b/go.mod @@ -2,29 +2,30 @@ module github.com/stashapp/stash require ( github.com/99designs/gqlgen v0.9.0 - github.com/PuerkitoBio/goquery v1.5.0 - github.com/antchfx/htmlquery v1.2.0 - github.com/antchfx/xpath v1.1.2 // indirect - github.com/bmatcuk/doublestar v1.1.5 + github.com/antchfx/htmlquery v1.2.3 + github.com/bmatcuk/doublestar v1.3.1 github.com/disintegration/imaging v1.6.0 github.com/go-chi/chi v4.0.2+incompatible github.com/gobuffalo/packr/v2 v2.0.2 github.com/golang-migrate/migrate/v4 v4.3.1 + github.com/gorilla/sessions v1.2.0 github.com/gorilla/websocket v1.4.0 github.com/h2non/filetype v1.0.8 - // this is required for generate github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jmoiron/sqlx v1.2.0 - github.com/mattn/go-sqlite3 v1.10.0 + github.com/json-iterator/go v1.1.9 + github.com/mattn/go-sqlite3 v1.13.0 github.com/rs/cors v1.6.0 github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f github.com/sirupsen/logrus v1.4.2 github.com/spf13/pflag v1.0.3 github.com/spf13/viper v1.4.0 + github.com/stretchr/testify v1.5.1 github.com/vektah/gqlparser v1.1.2 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 - golang.org/x/image v0.0.0-20190118043309-183bebdce1b2 // indirect - golang.org/x/net v0.0.0-20190522155817-f3200d17e092 + golang.org/x/image v0.0.0-20190118043309-183bebdce1b2 + golang.org/x/net v0.0.0-20200421231249-e086a090c8fd gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index bf4e10dbe..d9ef0d5a2 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,6 @@ github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= -github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= @@ -27,13 +25,11 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= -github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/antchfx/htmlquery v1.2.0 h1:oKShnsGlnOHX6t4uj5OHgLKkABcJoqnXpqnscoi9Lpw= -github.com/antchfx/htmlquery v1.2.0/go.mod h1:MS9yksVSQXls00iXkiMqXr0J+umL/AmxXKuP28SUJM8= -github.com/antchfx/xpath v1.1.2 h1:YziPrtM0gEJBnhdUGxYcIVYXZ8FXbtbovxOi+UW/yWQ= -github.com/antchfx/xpath v1.1.2/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= +github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M= +github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0= +github.com/antchfx/xpath v1.1.6 h1:6sVh6hB5T6phw1pFpHRQ+C4bd8sNI+O58flqtg7h0R0= +github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= @@ -41,8 +37,8 @@ github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= -github.com/bmatcuk/doublestar v1.1.5 h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk= -github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= +github.com/bmatcuk/doublestar v1.3.1 h1:rT8rxDPsavp9G+4ZULzqhhUSaI/OPsTZNG88Z3i0xvY= +github.com/bmatcuk/doublestar v1.3.1/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= 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= @@ -81,6 +77,7 @@ github.com/docker/docker v0.7.3-0.20190108045446-77df18c24acf/go.mod h1:eEKB0N0r github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= @@ -325,6 +322,8 @@ github.com/golang-migrate/migrate/v4 v4.3.1/go.mod h1:mJ89KBgbXmM3P49BqOxRL3riNF github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -340,6 +339,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= @@ -352,9 +352,12 @@ github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= +github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= @@ -383,6 +386,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= @@ -391,6 +396,8 @@ github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= @@ -445,6 +452,8 @@ github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/ github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c= +github.com/mattn/go-sqlite3 v1.13.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= @@ -453,6 +462,10 @@ github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:F github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mongodb/mongo-go-driver v0.3.0/go.mod h1:NK/HWDIIZkaYsnYa0hmtP443T5ELr0KDecmIioVuuyU= github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -574,6 +587,8 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -633,7 +648,6 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -660,6 +674,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -703,6 +719,8 @@ 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-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= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/gqlgen.yml b/gqlgen.yml index b0f197084..29e794f31 100644 --- a/gqlgen.yml +++ b/gqlgen.yml @@ -26,6 +26,8 @@ models: model: github.com/stashapp/stash/pkg/models.ScrapedItem Studio: model: github.com/stashapp/stash/pkg/models.Studio + Movie: + model: github.com/stashapp/stash/pkg/models.Movie Tag: model: github.com/stashapp/stash/pkg/models.Tag ScrapedPerformer: @@ -36,6 +38,8 @@ models: model: github.com/stashapp/stash/pkg/models.ScrapedScenePerformer ScrapedSceneStudio: model: github.com/stashapp/stash/pkg/models.ScrapedSceneStudio + ScrapedSceneMovie: + model: github.com/stashapp/stash/pkg/models.ScrapedSceneMovie ScrapedSceneTag: model: github.com/stashapp/stash/pkg/models.ScrapedSceneTag SceneFileType: diff --git a/graphql/documents/data/config.graphql b/graphql/documents/data/config.graphql index 57cd64c94..e050bfdd1 100644 --- a/graphql/documents/data/config.graphql +++ b/graphql/documents/data/config.graphql @@ -2,25 +2,32 @@ fragment ConfigGeneralData on ConfigGeneralResult { stashes databasePath generatedPath + cachePath maxTranscodeSize maxStreamingTranscodeSize + forceMkv + forceHevc username password + maxSessionAge logFile logOut logLevel logAccess excludes + scraperUserAgent } fragment ConfigInterfaceData on ConfigInterfaceResult { soundOnPreview wallShowTitle + wallPlayback maximumLoopDuration autostartVideo showStudioAsText css cssEnabled + language } fragment ConfigData on ConfigResult { diff --git a/graphql/documents/data/movie-slim.graphql b/graphql/documents/data/movie-slim.graphql new file mode 100644 index 000000000..49f458921 --- /dev/null +++ b/graphql/documents/data/movie-slim.graphql @@ -0,0 +1,5 @@ +fragment SlimMovieData on Movie { + id + name + front_image_path +} \ No newline at end of file diff --git a/graphql/documents/data/movie.graphql b/graphql/documents/data/movie.graphql new file mode 100644 index 000000000..ef3ab3f9f --- /dev/null +++ b/graphql/documents/data/movie.graphql @@ -0,0 +1,20 @@ +fragment MovieData on Movie { + id + checksum + name + aliases + duration + date + rating + director + + studio { + ...StudioData + } + + synopsis + url + front_image_path + back_image_path + scene_count +} diff --git a/graphql/documents/data/performer-slim.graphql b/graphql/documents/data/performer-slim.graphql index fdfa6016b..c2abc6023 100644 --- a/graphql/documents/data/performer-slim.graphql +++ b/graphql/documents/data/performer-slim.graphql @@ -1,5 +1,6 @@ fragment SlimPerformerData on Performer { id name + gender image_path } diff --git a/graphql/documents/data/performer.graphql b/graphql/documents/data/performer.graphql index e2ce624ec..cc5e6d2f1 100644 --- a/graphql/documents/data/performer.graphql +++ b/graphql/documents/data/performer.graphql @@ -3,6 +3,7 @@ fragment PerformerData on Performer { checksum name url + gender twitter instagram birthdate diff --git a/graphql/documents/data/scene-slim.graphql b/graphql/documents/data/scene-slim.graphql index 60fa93fe6..6d6fb3b05 100644 --- a/graphql/documents/data/scene-slim.graphql +++ b/graphql/documents/data/scene-slim.graphql @@ -47,6 +47,15 @@ fragment SlimSceneData on Scene { image_path } + movies { + movie { + id + name + front_image_path + } + scene_index + } + tags { id name diff --git a/graphql/documents/data/scene.graphql b/graphql/documents/data/scene.graphql index 9157eb714..06a7cab5a 100644 --- a/graphql/documents/data/scene.graphql +++ b/graphql/documents/data/scene.graphql @@ -42,6 +42,13 @@ fragment SceneData on Scene { studio { ...StudioData } + + movies { + movie { + ...MovieData + } + scene_index + } tags { ...TagData diff --git a/graphql/documents/data/scrapers.graphql b/graphql/documents/data/scrapers.graphql index 616465d0d..e9c8f324b 100644 --- a/graphql/documents/data/scrapers.graphql +++ b/graphql/documents/data/scrapers.graphql @@ -1,5 +1,27 @@ fragment ScrapedPerformerData on ScrapedPerformer { name + gender + url + twitter + instagram + birthdate + ethnicity + country + eye_color + height + measurements + fake_tits + career_length + tattoos + piercings + aliases + image +} + +fragment ScrapedScenePerformerData on ScrapedScenePerformer { + id + name + gender url twitter instagram @@ -16,23 +38,27 @@ fragment ScrapedPerformerData on ScrapedPerformer { aliases } -fragment ScrapedScenePerformerData on ScrapedScenePerformer { +fragment ScrapedMovieData on ScrapedMovie { + name + aliases + duration + date + rating + director + url + synopsis +} + +fragment ScrapedSceneMovieData on ScrapedSceneMovie { id name - url - twitter - instagram - birthdate - ethnicity - country - eye_color - height - measurements - fake_tits - career_length - tattoos - piercings aliases + duration + date + rating + director + url + synopsis } fragment ScrapedSceneStudioData on ScrapedSceneStudio { @@ -51,6 +77,7 @@ fragment ScrapedSceneData on ScrapedScene { details url date + image file { size @@ -74,4 +101,8 @@ fragment ScrapedSceneData on ScrapedScene { performers { ...ScrapedScenePerformerData } + + movies { + ...ScrapedSceneMovieData + } } \ No newline at end of file diff --git a/graphql/documents/mutations/metadata.graphql b/graphql/documents/mutations/metadata.graphql new file mode 100644 index 000000000..d02f10b09 --- /dev/null +++ b/graphql/documents/mutations/metadata.graphql @@ -0,0 +1,27 @@ +mutation MetadataImport { + metadataImport +} + +mutation MetadataExport { + metadataExport +} + +mutation MetadataScan($input: ScanMetadataInput!) { + metadataScan(input: $input) +} + +mutation MetadataGenerate($input: GenerateMetadataInput!) { + metadataGenerate(input: $input) +} + +mutation MetadataAutoTag($input: AutoTagMetadataInput!) { + metadataAutoTag(input: $input) +} + +mutation MetadataClean { + metadataClean +} + +mutation StopJob { + stopJob +} \ No newline at end of file diff --git a/graphql/documents/mutations/movie.graphql b/graphql/documents/mutations/movie.graphql new file mode 100644 index 000000000..253d2f8ac --- /dev/null +++ b/graphql/documents/mutations/movie.graphql @@ -0,0 +1,40 @@ +mutation MovieCreate( + $name: String!, + $aliases: String, + $duration: Int, + $date: String, + $rating: Int, + $studio_id: ID, + $director: String, + $synopsis: String, + $url: String, + $front_image: String, + $back_image: String) { + + movieCreate(input: { name: $name, aliases: $aliases, duration: $duration, date: $date, rating: $rating, studio_id: $studio_id, director: $director, synopsis: $synopsis, url: $url, front_image: $front_image, back_image: $back_image }) { + ...MovieData + } +} + +mutation MovieUpdate( + $id: ID! + $name: String, + $aliases: String, + $duration: Int, + $date: String, + $rating: Int, + $studio_id: ID, + $director: String, + $synopsis: String, + $url: String, + $front_image: String, + $back_image: String) { + + movieUpdate(input: { id: $id, name: $name, aliases: $aliases, duration: $duration, date: $date, rating: $rating, studio_id: $studio_id, director: $director, synopsis: $synopsis, url: $url, front_image: $front_image, back_image: $back_image }) { + ...MovieData + } +} + +mutation MovieDestroy($id: ID!) { + movieDestroy(input: { id: $id }) +} \ No newline at end of file diff --git a/graphql/documents/mutations/performer.graphql b/graphql/documents/mutations/performer.graphql index ec785f5f2..ae0b5e17f 100644 --- a/graphql/documents/mutations/performer.graphql +++ b/graphql/documents/mutations/performer.graphql @@ -1,6 +1,7 @@ mutation PerformerCreate( $name: String, $url: String, + $gender: GenderEnum, $birthdate: String, $ethnicity: String, $country: String, @@ -20,6 +21,7 @@ mutation PerformerCreate( performerCreate(input: { name: $name, url: $url, + gender: $gender, birthdate: $birthdate, ethnicity: $ethnicity, country: $country, @@ -44,6 +46,7 @@ mutation PerformerUpdate( $id: ID!, $name: String, $url: String, + $gender: GenderEnum, $birthdate: String, $ethnicity: String, $country: String, @@ -64,6 +67,7 @@ mutation PerformerUpdate( id: $id, name: $name, url: $url, + gender: $gender, birthdate: $birthdate, ethnicity: $ethnicity, country: $country, diff --git a/graphql/documents/mutations/scene.graphql b/graphql/documents/mutations/scene.graphql index ad4076c81..80c38d109 100644 --- a/graphql/documents/mutations/scene.graphql +++ b/graphql/documents/mutations/scene.graphql @@ -8,6 +8,7 @@ mutation SceneUpdate( $studio_id: ID, $gallery_id: ID, $performer_ids: [ID!] = [], + $movies: [SceneMovieInput!] = [], $tag_ids: [ID!] = [], $cover_image: String) { @@ -21,6 +22,7 @@ mutation SceneUpdate( studio_id: $studio_id, gallery_id: $gallery_id, performer_ids: $performer_ids, + movies: $movies, tag_ids: $tag_ids, cover_image: $cover_image }) { @@ -37,8 +39,8 @@ mutation BulkSceneUpdate( $rating: Int, $studio_id: ID, $gallery_id: ID, - $performer_ids: [ID!], - $tag_ids: [ID!]) { + $performer_ids: BulkUpdateIds, + $tag_ids: BulkUpdateIds) { bulkSceneUpdate(input: { ids: $ids, @@ -76,4 +78,8 @@ mutation SceneResetO($id: ID!) { mutation SceneDestroy($id: ID!, $delete_file: Boolean, $delete_generated : Boolean) { sceneDestroy(input: {id: $id, delete_file: $delete_file, delete_generated: $delete_generated}) -} \ No newline at end of file +} + +mutation SceneGenerateScreenshot($id: ID!, $at: Float) { + sceneGenerateScreenshot(id: $id, at: $at) +} diff --git a/graphql/documents/queries/misc.graphql b/graphql/documents/queries/misc.graphql index 65b0a59e1..2786ca997 100644 --- a/graphql/documents/queries/misc.graphql +++ b/graphql/documents/queries/misc.graphql @@ -19,19 +19,24 @@ query AllTags { } query AllPerformersForFilter { - allPerformers { + allPerformersSlim { ...SlimPerformerData } } query AllStudiosForFilter { - allStudios { + allStudiosSlim { ...SlimStudioData } } +query AllMoviesForFilter { + allMoviesSlim { + ...SlimMovieData + } +} query AllTagsForFilter { - allTags { + allTagsSlim { id name } @@ -47,9 +52,11 @@ query ValidGalleriesForScene($scene_id: ID!) { query Stats { stats { scene_count, + scene_size_count, gallery_count, performer_count, studio_count, + movie_count, tag_count } } diff --git a/graphql/documents/queries/movie.graphql b/graphql/documents/queries/movie.graphql new file mode 100644 index 000000000..c22b61b5b --- /dev/null +++ b/graphql/documents/queries/movie.graphql @@ -0,0 +1,14 @@ +query FindMovies($filter: FindFilterType, $movie_filter: MovieFilterType) { + findMovies(filter: $filter, movie_filter: $movie_filter) { + count + movies { + ...MovieData + } + } +} + +query FindMovie($id: ID!) { + findMovie(id: $id) { + ...MovieData + } +} \ No newline at end of file diff --git a/graphql/documents/queries/scene.graphql b/graphql/documents/queries/scene.graphql index add95cca1..343335503 100644 --- a/graphql/documents/queries/scene.graphql +++ b/graphql/documents/queries/scene.graphql @@ -46,6 +46,9 @@ query ParseSceneFilenames($filter: FindFilterType!, $config: SceneParserInput!) rating studio_id gallery_id + movies { + movie_id + } performer_ids tag_ids } diff --git a/graphql/documents/queries/settings/config.graphql b/graphql/documents/queries/settings/config.graphql index f92b14b7a..4ee9d4ec6 100644 --- a/graphql/documents/queries/settings/config.graphql +++ b/graphql/documents/queries/settings/config.graphql @@ -4,6 +4,10 @@ query Configuration { } } -query Directories($path: String) { - directories(path: $path) -} \ No newline at end of file +query Directory($path: String) { + directory(path: $path) { + path + parent + directories + } +} diff --git a/graphql/documents/queries/settings/metadata.graphql b/graphql/documents/queries/settings/metadata.graphql index a9092b8ea..376f8e4a0 100644 --- a/graphql/documents/queries/settings/metadata.graphql +++ b/graphql/documents/queries/settings/metadata.graphql @@ -1,27 +1,3 @@ -query MetadataImport { - metadataImport -} - -query MetadataExport { - metadataExport -} - -query MetadataScan($input: ScanMetadataInput!) { - metadataScan(input: $input) -} - -query MetadataGenerate($input: GenerateMetadataInput!) { - metadataGenerate(input: $input) -} - -query MetadataAutoTag($input: AutoTagMetadataInput!) { - metadataAutoTag(input: $input) -} - -query MetadataClean { - metadataClean -} - query JobStatus { jobStatus { progress @@ -29,7 +5,3 @@ query JobStatus { message } } - -query StopJob { - stopJob -} \ No newline at end of file diff --git a/graphql/schema/schema.graphql b/graphql/schema/schema.graphql index 8feae6add..3a57a551e 100644 --- a/graphql/schema/schema.graphql +++ b/graphql/schema/schema.graphql @@ -22,6 +22,11 @@ type Query { """A function which queries Studio objects""" findStudios(filter: FindFilterType): FindStudiosResultType! + """Find a movie by ID""" + findMovie(id: ID!): Movie + """A function which queries Movie objects""" + findMovies(movie_filter: MovieFilterType, filter: FindFilterType): FindMoviesResultType! + findGallery(id: ID!): Gallery findGalleries(filter: FindFilterType): FindGalleriesResultType! @@ -68,32 +73,26 @@ type Query { """Returns the current, complete configuration""" configuration: ConfigResult! """Returns an array of paths for the given path""" - directories(path: String): [String!]! + directory(path: String): Directory! # Metadata - """Start an import. Returns the job ID""" - metadataImport: String! - """Start an export. Returns the job ID""" - metadataExport: String! - """Start a scan. Returns the job ID""" - metadataScan(input: ScanMetadataInput!): String! - """Start generating content. Returns the job ID""" - metadataGenerate(input: GenerateMetadataInput!): String! - """Start auto-tagging. Returns the job ID""" - metadataAutoTag(input: AutoTagMetadataInput!): String! - """Clean metadata. Returns the job ID""" - metadataClean: String! - jobStatus: MetadataUpdateStatus! - stopJob: Boolean! # Get everything allPerformers: [Performer!]! allStudios: [Studio!]! + allMovies: [Movie!]! allTags: [Tag!]! + # Get everything with minimal metadata + + allPerformersSlim: [Performer!]! + allStudiosSlim: [Studio!]! + allMoviesSlim: [Movie!]! + allTagsSlim: [Tag!]! + # Version version: Version! @@ -114,6 +113,9 @@ type Mutation { """Resets the o-counter for a scene to 0. Returns the new value""" sceneResetO(id: ID!): Int! + """Generates screenshot at specified time in seconds. Leave empty to generate default screenshot""" + sceneGenerateScreenshot(id: ID!, at: Float): String! + sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker sceneMarkerDestroy(id: ID!): Boolean! @@ -126,6 +128,10 @@ type Mutation { studioUpdate(input: StudioUpdateInput!): Studio studioDestroy(input: StudioDestroyInput!): Boolean! + movieCreate(input: MovieCreateInput!): Movie + movieUpdate(input: MovieUpdateInput!): Movie + movieDestroy(input: MovieDestroyInput!): Boolean! + tagCreate(input: TagCreateInput!): Tag tagUpdate(input: TagUpdateInput!): Tag tagDestroy(input: TagDestroyInput!): Boolean! @@ -133,6 +139,21 @@ type Mutation { """Change general configuration options""" configureGeneral(input: ConfigGeneralInput!): ConfigGeneralResult! configureInterface(input: ConfigInterfaceInput!): ConfigInterfaceResult! + + """Start an import. Returns the job ID""" + metadataImport: String! + """Start an export. Returns the job ID""" + metadataExport: String! + """Start a scan. Returns the job ID""" + metadataScan(input: ScanMetadataInput!): String! + """Start generating content. Returns the job ID""" + metadataGenerate(input: GenerateMetadataInput!): String! + """Start auto-tagging. Returns the job ID""" + metadataAutoTag(input: AutoTagMetadataInput!): String! + """Clean metadata. Returns the job ID""" + metadataClean: String! + + stopJob: Boolean! } type Subscription { diff --git a/graphql/schema/types/config.graphql b/graphql/schema/types/config.graphql index 2d90c24f4..0f65c97fb 100644 --- a/graphql/schema/types/config.graphql +++ b/graphql/schema/types/config.graphql @@ -14,14 +14,22 @@ input ConfigGeneralInput { databasePath: String """Path to generated files""" generatedPath: String + """Path to cache""" + cachePath: String """Max generated transcode size""" maxTranscodeSize: StreamingResolutionEnum """Max streaming transcode size""" maxStreamingTranscodeSize: StreamingResolutionEnum + """Force MKV as supported format""" + forceMkv: Boolean! + """Force HEVC as a supported codec""" + forceHevc: Boolean! """Username""" username: String """Password""" password: String + """Maximum session cookie age""" + maxSessionAge: Int """Name of the log file""" logFile: String """Whether to also output to stderr""" @@ -32,6 +40,8 @@ input ConfigGeneralInput { logAccess: Boolean! """Array of file regexp to exclude from Scan""" excludes: [String!] + """Scraper user agent string""" + scraperUserAgent: String } type ConfigGeneralResult { @@ -41,14 +51,22 @@ type ConfigGeneralResult { databasePath: String! """Path to generated files""" generatedPath: String! - """Max generated transcode size""" + """Path to cache""" + cachePath: String! + """Max generated transcode size""" maxTranscodeSize: StreamingResolutionEnum """Max streaming transcode size""" maxStreamingTranscodeSize: StreamingResolutionEnum + """Force MKV as supported format""" + forceMkv: Boolean! + """Force HEVC as a supported codec""" + forceHevc: Boolean! """Username""" username: String! """Password""" password: String! + """Maximum session cookie age""" + maxSessionAge: Int! """Name of the log file""" logFile: String """Whether to also output to stderr""" @@ -59,6 +77,8 @@ type ConfigGeneralResult { logAccess: Boolean! """Array of file regexp to exclude from Scan""" excludes: [String!]! + """Scraper user agent string""" + scraperUserAgent: String } input ConfigInterfaceInput { @@ -66,6 +86,8 @@ input ConfigInterfaceInput { soundOnPreview: Boolean """Show title and tags in wall view""" wallShowTitle: Boolean + """Wall playback type""" + wallPlayback: String """Maximum duration (in seconds) in which a scene video will loop in the scene player""" maximumLoopDuration: Int """If true, video will autostart on load in the scene player""" @@ -75,6 +97,7 @@ input ConfigInterfaceInput { """Custom CSS""" css: String cssEnabled: Boolean + language: String } type ConfigInterfaceResult { @@ -82,6 +105,8 @@ type ConfigInterfaceResult { soundOnPreview: Boolean """Show title and tags in wall view""" wallShowTitle: Boolean + """Wall playback type""" + wallPlayback: String """Maximum duration (in seconds) in which a scene video will loop in the scene player""" maximumLoopDuration: Int """If true, video will autostart on load in the scene player""" @@ -91,6 +116,8 @@ type ConfigInterfaceResult { """Custom CSS""" css: String cssEnabled: Boolean + """Interface language""" + language: String } """All configuration settings""" @@ -98,3 +125,10 @@ type ConfigResult { general: ConfigGeneralResult! interface: ConfigInterfaceResult! } + +"""Directory structure of a path""" +type Directory { + path: String! + parent: String + directories: [String!]! +} diff --git a/graphql/schema/types/filters.graphql b/graphql/schema/types/filters.graphql index 4849d2803..92ac58e2c 100644 --- a/graphql/schema/types/filters.graphql +++ b/graphql/schema/types/filters.graphql @@ -46,6 +46,10 @@ input PerformerFilterType { piercings: StringCriterionInput """Filter by aliases""" aliases: StringCriterionInput + """Filter by gender""" + gender: GenderCriterionInput + """Filter to only include performers missing this property""" + is_missing: String } input SceneMarkerFilterType { @@ -74,12 +78,19 @@ input SceneFilterType { is_missing: String """Filter to only include scenes with this studio""" studios: MultiCriterionInput + """Filter to only include scenes with this movie""" + movies: MultiCriterionInput """Filter to only include scenes with these tags""" tags: MultiCriterionInput """Filter to only include scenes with these performers""" performers: MultiCriterionInput } +input MovieFilterType { + """Filter to only include movies with this studio""" + studios: MultiCriterionInput +} + enum CriterionModifier { """=""" EQUALS, @@ -112,4 +123,9 @@ input IntCriterionInput { input MultiCriterionInput { value: [ID!] modifier: CriterionModifier! +} + +input GenderCriterionInput { + value: GenderEnum + modifier: CriterionModifier! } \ No newline at end of file diff --git a/graphql/schema/types/metadata.graphql b/graphql/schema/types/metadata.graphql index a603b56b5..dede131fc 100644 --- a/graphql/schema/types/metadata.graphql +++ b/graphql/schema/types/metadata.graphql @@ -1,8 +1,12 @@ input GenerateMetadataInput { sprites: Boolean! previews: Boolean! + previewPreset: PreviewPreset + imagePreviews: Boolean! markers: Boolean! transcodes: Boolean! + """gallery thumbnails for cache usage""" + thumbnails: Boolean! } input ScanMetadataInput { @@ -20,6 +24,16 @@ input AutoTagMetadataInput { type MetadataUpdateStatus { progress: Float! - status: String! + status: String! message: String! -} \ No newline at end of file +} + +enum PreviewPreset { + "X264_ULTRAFAST", ultrafast + "X264_VERYFAST", veryfast + "X264_FAST", fast + "X264_MEDIUM", medium + "X264_SLOW", slow + "X264_SLOWER", slower + "X264_VERYSLOW", veryslow +} diff --git a/graphql/schema/types/movie.graphql b/graphql/schema/types/movie.graphql new file mode 100644 index 000000000..0b41af0c8 --- /dev/null +++ b/graphql/schema/types/movie.graphql @@ -0,0 +1,59 @@ +type Movie { + id: ID! + checksum: String! + name: String! + aliases: String + """Duration in seconds""" + duration: Int + date: String + rating: Int + studio: Studio + director: String + synopsis: String + url: String + + front_image_path: String # Resolver + back_image_path: String # Resolver + scene_count: Int # Resolver +} + +input MovieCreateInput { + name: String! + aliases: String + """Duration in seconds""" + duration: Int + date: String + rating: Int + studio_id: ID + director: String + synopsis: String + url: String + """This should be base64 encoded""" + front_image: String + back_image: String +} + +input MovieUpdateInput { + id: ID! + name: String + aliases: String + duration: Int + date: String + rating: Int + studio_id: ID + director: String + synopsis: String + url: String + """This should be base64 encoded""" + front_image: String + back_image: String +} + +input MovieDestroyInput { + id: ID! +} + +type FindMoviesResultType { + count: Int! + movies: [Movie!]! +} \ No newline at end of file diff --git a/graphql/schema/types/performer.graphql b/graphql/schema/types/performer.graphql index a1ba8e6f7..621f23dd9 100644 --- a/graphql/schema/types/performer.graphql +++ b/graphql/schema/types/performer.graphql @@ -1,8 +1,17 @@ +enum GenderEnum { + MALE + FEMALE + TRANSGENDER_MALE + TRANSGENDER_FEMALE + INTERSEX +} + type Performer { id: ID! checksum: String! name: String url: String + gender: GenderEnum twitter: String instagram: String birthdate: String @@ -26,6 +35,7 @@ type Performer { input PerformerCreateInput { name: String url: String + gender: GenderEnum birthdate: String ethnicity: String country: String @@ -48,6 +58,7 @@ input PerformerUpdateInput { id: ID! name: String url: String + gender: GenderEnum birthdate: String ethnicity: String country: String diff --git a/graphql/schema/types/scene.graphql b/graphql/schema/types/scene.graphql index c0828dae4..8afdd4b43 100644 --- a/graphql/schema/types/scene.graphql +++ b/graphql/schema/types/scene.graphql @@ -18,6 +18,11 @@ type ScenePathsType { chapters_vtt: String # Resolver } +type SceneMovie { + movie: Movie! + scene_index: Int +} + type Scene { id: ID! checksum: String! @@ -36,10 +41,16 @@ type Scene { scene_markers: [SceneMarker!]! gallery: Gallery studio: Studio + movies: [SceneMovie!]! tags: [Tag!]! performers: [Performer!]! } +input SceneMovieInput { + movie_id: ID! + scene_index: Int +} + input SceneUpdateInput { clientMutationId: String id: ID! @@ -51,11 +62,23 @@ input SceneUpdateInput { studio_id: ID gallery_id: ID performer_ids: [ID!] + movies: [SceneMovieInput!] tag_ids: [ID!] """This should be base64 encoded""" cover_image: String } +enum BulkUpdateIdMode { + SET + ADD + REMOVE +} + +input BulkUpdateIds { + ids: [ID!] + mode: BulkUpdateIdMode! +} + input BulkSceneUpdateInput { clientMutationId: String ids: [ID!] @@ -66,8 +89,8 @@ input BulkSceneUpdateInput { rating: Int studio_id: ID gallery_id: ID - performer_ids: [ID!] - tag_ids: [ID!] + performer_ids: BulkUpdateIds + tag_ids: BulkUpdateIds } input SceneDestroyInput { @@ -87,6 +110,11 @@ input SceneParserInput { capitalizeTitle: Boolean } +type SceneMovieID { + movie_id: ID! + scene_index: String +} + type SceneParserResult { scene: Scene! title: String @@ -97,6 +125,7 @@ type SceneParserResult { studio_id: ID gallery_id: ID performer_ids: [ID!] + movies: [SceneMovieID!] tag_ids: [ID!] } diff --git a/graphql/schema/types/scraped-movie.graphql b/graphql/schema/types/scraped-movie.graphql new file mode 100644 index 000000000..7589de364 --- /dev/null +++ b/graphql/schema/types/scraped-movie.graphql @@ -0,0 +1,22 @@ +"""A movie from a scraping operation...""" +type ScrapedMovie { + name: String + aliases: String + duration: String + date: String + rating: String + director: String + url: String + synopsis: String +} + +input ScrapedMovieInput { + name: String + aliases: String + duration: String + date: String + rating: String + director: String + url: String + synopsis: String +} \ No newline at end of file diff --git a/graphql/schema/types/scraped-performer.graphql b/graphql/schema/types/scraped-performer.graphql index a16f3df23..d991ed327 100644 --- a/graphql/schema/types/scraped-performer.graphql +++ b/graphql/schema/types/scraped-performer.graphql @@ -1,6 +1,7 @@ """A performer from a scraping operation...""" type ScrapedPerformer { name: String + gender: String url: String twitter: String instagram: String @@ -15,10 +16,14 @@ type ScrapedPerformer { tattoos: String piercings: String aliases: String + + """This should be base64 encoded""" + image: String } input ScrapedPerformerInput { name: String + gender: String url: String twitter: String instagram: String @@ -33,4 +38,6 @@ input ScrapedPerformerInput { tattoos: String piercings: String aliases: String + + # not including image for the input } \ No newline at end of file diff --git a/graphql/schema/types/scraper.graphql b/graphql/schema/types/scraper.graphql index 1dc153eb1..69c050a63 100644 --- a/graphql/schema/types/scraper.graphql +++ b/graphql/schema/types/scraper.graphql @@ -27,6 +27,7 @@ type ScrapedScenePerformer { """Set if performer matched""" id: ID name: String! + gender: String url: String twitter: String instagram: String @@ -43,6 +44,19 @@ type ScrapedScenePerformer { aliases: String } +type ScrapedSceneMovie { + """Set if movie matched""" + id: ID + name: String! + aliases: String + duration: String + date: String + rating: String + director: String + synopsis: String + url: String +} + type ScrapedSceneStudio { """Set if studio matched""" id: ID @@ -62,9 +76,13 @@ type ScrapedScene { url: String date: String + """This should be base64 encoded""" + image: String + file: SceneFileType # Resolver studio: ScrapedSceneStudio tags: [ScrapedSceneTag!] performers: [ScrapedScenePerformer!] + movies: [ScrapedSceneMovie!] } diff --git a/graphql/schema/types/stats.graphql b/graphql/schema/types/stats.graphql index f091f1bd3..d94086308 100644 --- a/graphql/schema/types/stats.graphql +++ b/graphql/schema/types/stats.graphql @@ -1,7 +1,9 @@ type StatsResultType { scene_count: Int! + scene_size_count: String! gallery_count: Int! performer_count: Int! studio_count: Int! + movie_count: Int! tag_count: Int! -} \ No newline at end of file +} diff --git a/pkg/api/cache_thumbs.go b/pkg/api/cache_thumbs.go new file mode 100644 index 000000000..0bcbd616c --- /dev/null +++ b/pkg/api/cache_thumbs.go @@ -0,0 +1,72 @@ +package api + +import ( + "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/manager/paths" + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/utils" + "io/ioutil" +) + +type thumbBuffer struct { + path string + dir string + data []byte +} + +func newCacheThumb(dir string, path string, data []byte) *thumbBuffer { + t := thumbBuffer{dir: dir, path: path, data: data} + return &t +} + +var writeChan chan *thumbBuffer +var touchChan chan *string + +func startThumbCache() { // TODO add extra wait, close chan code if/when stash gets a stop mode + + writeChan = make(chan *thumbBuffer, 20) + go thumbnailCacheWriter() +} + +//serialize file writes to avoid race conditions +func thumbnailCacheWriter() { + + for thumb := range writeChan { + exists, _ := utils.FileExists(thumb.path) + if !exists { + err := utils.WriteFile(thumb.path, thumb.data) + if err != nil { + logger.Errorf("Write error for thumbnail %s: %s ", thumb.path, err) + } + } + } + +} + +// get thumbnail from cache, otherwise create it and store to cache +func cacheGthumb(gallery *models.Gallery, index int, width int) []byte { + thumbPath := paths.GetGthumbPath(gallery.Checksum, index, width) + exists, _ := utils.FileExists(thumbPath) + if exists { // if thumbnail exists in cache return that + content, err := ioutil.ReadFile(thumbPath) + if err == nil { + return content + } else { + logger.Errorf("Read Error for file %s : %s", thumbPath, err) + } + + } + data := gallery.GetThumbnail(index, width) + thumbDir := paths.GetGthumbDir(gallery.Checksum) + t := newCacheThumb(thumbDir, thumbPath, data) + writeChan <- t // write the file to cache + return data +} + +// create all thumbs for a given gallery +func CreateGthumbs(gallery *models.Gallery) { + count := gallery.ImageCount() + for i := 0; i < count; i++ { + cacheGthumb(gallery, i, models.DefaultGthumbWidth) + } +} diff --git a/pkg/api/check_version.go b/pkg/api/check_version.go index ca79170b4..7cd1bb573 100644 --- a/pkg/api/check_version.go +++ b/pkg/api/check_version.go @@ -2,6 +2,7 @@ package api import ( "encoding/json" + "errors" "fmt" "io/ioutil" "net/http" @@ -18,6 +19,10 @@ const apiTags string = "https://api.github.com/repos/stashapp/stash/tags" const apiAcceptHeader string = "application/vnd.github.v3+json" const developmentTag string = "latest_develop" +// ErrNoVersion indicates that no version information has been embedded in the +// stash binary +var ErrNoVersion = errors.New("no stash version") + var stashReleases = func() map[string]string { return map[string]string{ "windows/amd64": "stash-win.exe", @@ -140,7 +145,7 @@ func GetLatestVersion(shortHash bool) (latestVersion string, latestRelease strin version, _, _ := GetVersion() if version == "" { - return "", "", fmt.Errorf("Stash doesn't have a version. Version check not supported.") + return "", "", ErrNoVersion } // if the version is suffixed with -x-xxxx, then we are running a development build diff --git a/pkg/api/context_keys.go b/pkg/api/context_keys.go index ba58e761d..917e1c587 100644 --- a/pkg/api/context_keys.go +++ b/pkg/api/context_keys.go @@ -9,4 +9,6 @@ const ( performerKey key = 1 sceneKey key = 2 studioKey key = 3 + movieKey key = 4 + ContextUser key = 5 ) diff --git a/pkg/api/images.go b/pkg/api/images.go index 48b5d18d5..bec90eb82 100644 --- a/pkg/api/images.go +++ b/pkg/api/images.go @@ -2,18 +2,31 @@ package api import ( "math/rand" + "strings" "github.com/gobuffalo/packr/v2" ) var performerBox *packr.Box +var performerBoxMale *packr.Box func initialiseImages() { performerBox = packr.New("Performer Box", "../../static/performer") + performerBoxMale = packr.New("Male Performer Box", "../../static/performer_male") } -func getRandomPerformerImage() ([]byte, error) { - imageFiles := performerBox.List() +func getRandomPerformerImage(gender string) ([]byte, error) { + var box *packr.Box + switch strings.ToUpper(gender) { + case "FEMALE": + box = performerBox + case "MALE": + box = performerBoxMale + default: + box = performerBox + + } + imageFiles := box.List() index := rand.Intn(len(imageFiles)) - return performerBox.Find(imageFiles[index]) + return box.Find(imageFiles[index]) } diff --git a/pkg/api/migrate.go b/pkg/api/migrate.go new file mode 100644 index 000000000..6305f47f8 --- /dev/null +++ b/pkg/api/migrate.go @@ -0,0 +1,92 @@ +package api + +import ( + "fmt" + "html/template" + "net/http" + "os" + + "github.com/stashapp/stash/pkg/database" + "github.com/stashapp/stash/pkg/logger" +) + +type migrateData struct { + ExistingVersion uint + MigrateVersion uint + BackupPath string +} + +func getMigrateData() migrateData { + return migrateData{ + ExistingVersion: database.Version(), + MigrateVersion: database.AppSchemaVersion(), + BackupPath: database.DatabaseBackupPath(), + } +} + +func getMigrateHandler(w http.ResponseWriter, r *http.Request) { + if !database.NeedsMigration() { + http.Redirect(w, r, "/", 301) + return + } + + data, _ := setupUIBox.Find("migrate.html") + templ, err := template.New("Migrate").Parse(string(data)) + if err != nil { + http.Error(w, fmt.Sprintf("error: %s", err), 500) + return + } + + err = templ.Execute(w, getMigrateData()) + if err != nil { + http.Error(w, fmt.Sprintf("error: %s", err), 500) + } +} + +func doMigrateHandler(w http.ResponseWriter, r *http.Request) { + err := r.ParseForm() + if err != nil { + http.Error(w, fmt.Sprintf("error: %s", err), 500) + } + + formBackupPath := r.Form.Get("backuppath") + + // always backup so that we can roll back to the previous version if + // migration fails + backupPath := formBackupPath + if formBackupPath == "" { + backupPath = database.DatabaseBackupPath() + } + + // perform database backup + if err = database.Backup(backupPath); err != nil { + http.Error(w, fmt.Sprintf("error backing up database: %s", err), 500) + return + } + + err = database.RunMigrations() + if err != nil { + errStr := fmt.Sprintf("error performing migration: %s", err) + + // roll back to the backed up version + restoreErr := database.RestoreFromBackup(backupPath) + if restoreErr != nil { + errStr = fmt.Sprintf("ERROR: unable to restore database from backup after migration failure: %s\n%s", restoreErr.Error(), errStr) + } else { + errStr = "An error occurred migrating the database to the latest schema version. The backup database file was automatically renamed to restore the database.\n" + errStr + } + + http.Error(w, errStr, 500) + return + } + + // if no backup path was provided, then delete the created backup + if formBackupPath == "" { + err = os.Remove(backupPath) + if err != nil { + logger.Warnf("error removing unwanted database backup (%s): %s", backupPath, err.Error()) + } + } + + http.Redirect(w, r, "/", 301) +} diff --git a/pkg/api/resolver.go b/pkg/api/resolver.go index 126003a6f..5713e0b22 100644 --- a/pkg/api/resolver.go +++ b/pkg/api/resolver.go @@ -33,6 +33,9 @@ func (r *Resolver) SceneMarker() models.SceneMarkerResolver { func (r *Resolver) Studio() models.StudioResolver { return &studioResolver{r} } +func (r *Resolver) Movie() models.MovieResolver { + return &movieResolver{r} +} func (r *Resolver) Subscription() models.SubscriptionResolver { return &subscriptionResolver{r} } @@ -49,6 +52,7 @@ type performerResolver struct{ *Resolver } type sceneResolver struct{ *Resolver } type sceneMarkerResolver struct{ *Resolver } type studioResolver struct{ *Resolver } +type movieResolver struct{ *Resolver } type tagResolver struct{ *Resolver } func (r *queryResolver) MarkerWall(ctx context.Context, q *string) ([]*models.SceneMarker, error) { @@ -89,19 +93,24 @@ func (r *queryResolver) ValidGalleriesForScene(ctx context.Context, scene_id *st func (r *queryResolver) Stats(ctx context.Context) (*models.StatsResultType, error) { scenesQB := models.NewSceneQueryBuilder() scenesCount, _ := scenesQB.Count() + scenesSizeCount, _ := scenesQB.SizeCount() galleryQB := models.NewGalleryQueryBuilder() galleryCount, _ := galleryQB.Count() performersQB := models.NewPerformerQueryBuilder() performersCount, _ := performersQB.Count() studiosQB := models.NewStudioQueryBuilder() studiosCount, _ := studiosQB.Count() + moviesQB := models.NewMovieQueryBuilder() + moviesCount, _ := moviesQB.Count() tagsQB := models.NewTagQueryBuilder() tagsCount, _ := tagsQB.Count() return &models.StatsResultType{ SceneCount: scenesCount, + SceneSizeCount: scenesSizeCount, GalleryCount: galleryCount, PerformerCount: performersCount, StudioCount: studiosCount, + MovieCount: moviesCount, TagCount: tagsCount, }, nil } diff --git a/pkg/api/resolver_model_movie.go b/pkg/api/resolver_model_movie.go new file mode 100644 index 000000000..6ab444a64 --- /dev/null +++ b/pkg/api/resolver_model_movie.go @@ -0,0 +1,95 @@ +package api + +import ( + "context" + + "github.com/stashapp/stash/pkg/api/urlbuilders" + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/utils" +) + +func (r *movieResolver) Name(ctx context.Context, obj *models.Movie) (string, error) { + if obj.Name.Valid { + return obj.Name.String, nil + } + return "", nil +} + +func (r *movieResolver) URL(ctx context.Context, obj *models.Movie) (*string, error) { + if obj.URL.Valid { + return &obj.URL.String, nil + } + return nil, nil +} + +func (r *movieResolver) Aliases(ctx context.Context, obj *models.Movie) (*string, error) { + if obj.Aliases.Valid { + return &obj.Aliases.String, nil + } + return nil, nil +} + +func (r *movieResolver) Duration(ctx context.Context, obj *models.Movie) (*int, error) { + if obj.Duration.Valid { + rating := int(obj.Duration.Int64) + return &rating, nil + } + return nil, nil +} + +func (r *movieResolver) Date(ctx context.Context, obj *models.Movie) (*string, error) { + if obj.Date.Valid { + result := utils.GetYMDFromDatabaseDate(obj.Date.String) + return &result, nil + } + return nil, nil +} + +func (r *movieResolver) Rating(ctx context.Context, obj *models.Movie) (*int, error) { + if obj.Rating.Valid { + rating := int(obj.Rating.Int64) + return &rating, nil + } + return nil, nil +} + +func (r *movieResolver) Studio(ctx context.Context, obj *models.Movie) (*models.Studio, error) { + qb := models.NewStudioQueryBuilder() + if obj.StudioID.Valid { + return qb.Find(int(obj.StudioID.Int64), nil) + } + + return nil, nil +} + +func (r *movieResolver) Director(ctx context.Context, obj *models.Movie) (*string, error) { + if obj.Director.Valid { + return &obj.Director.String, nil + } + return nil, nil +} + +func (r *movieResolver) Synopsis(ctx context.Context, obj *models.Movie) (*string, error) { + if obj.Synopsis.Valid { + return &obj.Synopsis.String, nil + } + return nil, nil +} + +func (r *movieResolver) FrontImagePath(ctx context.Context, obj *models.Movie) (*string, error) { + baseURL, _ := ctx.Value(BaseURLCtxKey).(string) + frontimagePath := urlbuilders.NewMovieURLBuilder(baseURL, obj.ID).GetMovieFrontImageURL() + return &frontimagePath, nil +} + +func (r *movieResolver) BackImagePath(ctx context.Context, obj *models.Movie) (*string, error) { + baseURL, _ := ctx.Value(BaseURLCtxKey).(string) + backimagePath := urlbuilders.NewMovieURLBuilder(baseURL, obj.ID).GetMovieBackImageURL() + return &backimagePath, nil +} + +func (r *movieResolver) SceneCount(ctx context.Context, obj *models.Movie) (*int, error) { + qb := models.NewSceneQueryBuilder() + res, err := qb.CountByMovieID(obj.ID) + return &res, err +} diff --git a/pkg/api/resolver_model_performer.go b/pkg/api/resolver_model_performer.go index 94be0aeea..29a4d2d90 100644 --- a/pkg/api/resolver_model_performer.go +++ b/pkg/api/resolver_model_performer.go @@ -2,6 +2,7 @@ package api import ( "context" + "github.com/stashapp/stash/pkg/api/urlbuilders" "github.com/stashapp/stash/pkg/models" ) @@ -20,6 +21,19 @@ func (r *performerResolver) URL(ctx context.Context, obj *models.Performer) (*st return nil, nil } +func (r *performerResolver) Gender(ctx context.Context, obj *models.Performer) (*models.GenderEnum, error) { + var ret models.GenderEnum + + if obj.Gender.Valid { + ret = models.GenderEnum(obj.Gender.String) + if ret.IsValid() { + return &ret, nil + } + } + + return nil, nil +} + func (r *performerResolver) Twitter(ctx context.Context, obj *models.Performer) (*string, error) { if obj.Twitter.Valid { return &obj.Twitter.String, nil diff --git a/pkg/api/resolver_model_scene.go b/pkg/api/resolver_model_scene.go index 892fe6112..36e921052 100644 --- a/pkg/api/resolver_model_scene.go +++ b/pkg/api/resolver_model_scene.go @@ -82,7 +82,9 @@ func (r *sceneResolver) Paths(ctx context.Context, obj *models.Scene) (*models.S } func (r *sceneResolver) IsStreamable(ctx context.Context, obj *models.Scene) (bool, error) { - return manager.IsStreamable(obj) + // ignore error + ret, _ := manager.IsStreamable(obj) + return ret, nil } func (r *sceneResolver) SceneMarkers(ctx context.Context, obj *models.Scene) ([]*models.SceneMarker, error) { @@ -100,6 +102,38 @@ func (r *sceneResolver) Studio(ctx context.Context, obj *models.Scene) (*models. return qb.FindBySceneID(obj.ID) } +func (r *sceneResolver) Movies(ctx context.Context, obj *models.Scene) ([]*models.SceneMovie, error) { + joinQB := models.NewJoinsQueryBuilder() + qb := models.NewMovieQueryBuilder() + + sceneMovies, err := joinQB.GetSceneMovies(obj.ID, nil) + if err != nil { + return nil, err + } + + var ret []*models.SceneMovie + for _, sm := range sceneMovies { + movie, err := qb.Find(sm.MovieID, nil) + if err != nil { + return nil, err + } + + sceneIdx := sm.SceneIndex + sceneMovie := &models.SceneMovie{ + Movie: movie, + } + + if sceneIdx.Valid { + var idx int + idx = int(sceneIdx.Int64) + sceneMovie.SceneIndex = &idx + } + + ret = append(ret, sceneMovie) + } + return ret, nil +} + func (r *sceneResolver) Tags(ctx context.Context, obj *models.Scene) ([]*models.Tag, error) { qb := models.NewTagQueryBuilder() return qb.FindBySceneID(obj.ID, nil) diff --git a/pkg/api/resolver_mutation_configure.go b/pkg/api/resolver_mutation_configure.go index 2b9273caf..ab7deb743 100644 --- a/pkg/api/resolver_mutation_configure.go +++ b/pkg/api/resolver_mutation_configure.go @@ -38,6 +38,13 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co config.Set(config.Generated, input.GeneratedPath) } + if input.CachePath != nil { + if err := utils.EnsureDir(*input.CachePath); err != nil { + return makeConfigGeneralResult(), err + } + config.Set(config.Cache, input.CachePath) + } + if input.MaxTranscodeSize != nil { config.Set(config.MaxTranscodeSize, input.MaxTranscodeSize.String()) } @@ -45,6 +52,8 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co if input.MaxStreamingTranscodeSize != nil { config.Set(config.MaxStreamingTranscodeSize, input.MaxStreamingTranscodeSize.String()) } + config.Set(config.ForceMKV, input.ForceMkv) + config.Set(config.ForceHEVC, input.ForceHevc) if input.Username != nil { config.Set(config.Username, input.Username) @@ -60,6 +69,10 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co } } + if input.MaxSessionAge != nil { + config.Set(config.MaxSessionAge, *input.MaxSessionAge) + } + if input.LogFile != nil { config.Set(config.LogFile, input.LogFile) } @@ -76,6 +89,10 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co config.Set(config.Exclude, input.Excludes) } + if input.ScraperUserAgent != nil { + config.Set(config.ScraperUserAgent, input.ScraperUserAgent) + } + if err := config.Write(); err != nil { return makeConfigGeneralResult(), err } @@ -94,6 +111,10 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models. config.Set(config.WallShowTitle, *input.WallShowTitle) } + if input.WallPlayback != nil { + config.Set(config.WallPlayback, *input.WallPlayback) + } + if input.MaximumLoopDuration != nil { config.Set(config.MaximumLoopDuration, *input.MaximumLoopDuration) } @@ -106,6 +127,10 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models. config.Set(config.ShowStudioAsText, *input.ShowStudioAsText) } + if input.Language != nil { + config.Set(config.Language, *input.Language) + } + css := "" if input.CSS != nil { diff --git a/pkg/api/resolver_mutation_metadata.go b/pkg/api/resolver_mutation_metadata.go new file mode 100644 index 000000000..65a743af8 --- /dev/null +++ b/pkg/api/resolver_mutation_metadata.go @@ -0,0 +1,53 @@ +package api + +import ( + "context" + + "github.com/stashapp/stash/pkg/manager" + "github.com/stashapp/stash/pkg/models" +) + +func (r *mutationResolver) MetadataScan(ctx context.Context, input models.ScanMetadataInput) (string, error) { + manager.GetInstance().Scan(input.UseFileMetadata) + return "todo", nil +} + +func (r *mutationResolver) MetadataImport(ctx context.Context) (string, error) { + manager.GetInstance().Import() + return "todo", nil +} + +func (r *mutationResolver) MetadataExport(ctx context.Context) (string, error) { + manager.GetInstance().Export() + return "todo", nil +} + +func (r *mutationResolver) MetadataGenerate(ctx context.Context, input models.GenerateMetadataInput) (string, error) { + manager.GetInstance().Generate(input.Sprites, input.Previews, input.PreviewPreset, input.ImagePreviews, input.Markers, input.Transcodes, input.Thumbnails) + return "todo", nil +} + +func (r *mutationResolver) MetadataAutoTag(ctx context.Context, input models.AutoTagMetadataInput) (string, error) { + manager.GetInstance().AutoTag(input.Performers, input.Studios, input.Tags) + return "todo", nil +} + +func (r *mutationResolver) MetadataClean(ctx context.Context) (string, error) { + manager.GetInstance().Clean() + return "todo", nil +} + +func (r *mutationResolver) JobStatus(ctx context.Context) (*models.MetadataUpdateStatus, error) { + status := manager.GetInstance().Status + ret := models.MetadataUpdateStatus{ + Progress: status.Progress, + Status: status.Status.String(), + Message: "", + } + + return &ret, nil +} + +func (r *mutationResolver) StopJob(ctx context.Context) (bool, error) { + return manager.GetInstance().Status.Stop(), nil +} diff --git a/pkg/api/resolver_mutation_movie.go b/pkg/api/resolver_mutation_movie.go new file mode 100644 index 000000000..d52d0dabe --- /dev/null +++ b/pkg/api/resolver_mutation_movie.go @@ -0,0 +1,199 @@ +package api + +import ( + "context" + "database/sql" + "strconv" + "time" + + "github.com/stashapp/stash/pkg/database" + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/utils" +) + +func (r *mutationResolver) MovieCreate(ctx context.Context, input models.MovieCreateInput) (*models.Movie, error) { + // generate checksum from movie name rather than image + checksum := utils.MD5FromString(input.Name) + + var frontimageData []byte + var backimageData []byte + var err error + + if input.FrontImage == nil { + input.FrontImage = &models.DefaultMovieImage + } + if input.BackImage == nil { + input.BackImage = &models.DefaultMovieImage + } + // Process the base 64 encoded image string + _, frontimageData, err = utils.ProcessBase64Image(*input.FrontImage) + if err != nil { + return nil, err + } + // Process the base 64 encoded image string + _, backimageData, err = utils.ProcessBase64Image(*input.BackImage) + if err != nil { + return nil, err + } + + // Populate a new movie from the input + currentTime := time.Now() + newMovie := models.Movie{ + BackImage: backimageData, + FrontImage: frontimageData, + Checksum: checksum, + Name: sql.NullString{String: input.Name, Valid: true}, + CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime}, + UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime}, + } + + if input.Aliases != nil { + newMovie.Aliases = sql.NullString{String: *input.Aliases, Valid: true} + } + if input.Duration != nil { + duration := int64(*input.Duration) + newMovie.Duration = sql.NullInt64{Int64: duration, Valid: true} + } + + if input.Date != nil { + newMovie.Date = models.SQLiteDate{String: *input.Date, Valid: true} + } + + if input.Rating != nil { + rating := int64(*input.Rating) + newMovie.Rating = sql.NullInt64{Int64: rating, Valid: true} + } + + if input.StudioID != nil { + studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) + newMovie.StudioID = sql.NullInt64{Int64: studioID, Valid: true} + } + + if input.Director != nil { + newMovie.Director = sql.NullString{String: *input.Director, Valid: true} + } + + if input.Synopsis != nil { + newMovie.Synopsis = sql.NullString{String: *input.Synopsis, Valid: true} + } + + if input.URL != nil { + newMovie.URL = sql.NullString{String: *input.URL, Valid: true} + } + + // Start the transaction and save the movie + tx := database.DB.MustBeginTx(ctx, nil) + qb := models.NewMovieQueryBuilder() + movie, err := qb.Create(newMovie, tx) + if err != nil { + _ = tx.Rollback() + return nil, err + } + + // Commit + if err := tx.Commit(); err != nil { + return nil, err + } + + return movie, nil +} + +func (r *mutationResolver) MovieUpdate(ctx context.Context, input models.MovieUpdateInput) (*models.Movie, error) { + // Populate movie from the input + movieID, _ := strconv.Atoi(input.ID) + + updatedMovie := models.MoviePartial{ + ID: movieID, + UpdatedAt: &models.SQLiteTimestamp{Timestamp: time.Now()}, + } + if input.FrontImage != nil { + _, frontimageData, err := utils.ProcessBase64Image(*input.FrontImage) + if err != nil { + return nil, err + } + updatedMovie.FrontImage = &frontimageData + } + if input.BackImage != nil { + _, backimageData, err := utils.ProcessBase64Image(*input.BackImage) + if err != nil { + return nil, err + } + updatedMovie.BackImage = &backimageData + } + + if input.Name != nil { + // generate checksum from movie name rather than image + checksum := utils.MD5FromString(*input.Name) + updatedMovie.Name = &sql.NullString{String: *input.Name, Valid: true} + updatedMovie.Checksum = &checksum + } + + if input.Aliases != nil { + updatedMovie.Aliases = &sql.NullString{String: *input.Aliases, Valid: true} + } + if input.Duration != nil { + duration := int64(*input.Duration) + updatedMovie.Duration = &sql.NullInt64{Int64: duration, Valid: true} + } + + if input.Date != nil { + updatedMovie.Date = &models.SQLiteDate{String: *input.Date, Valid: true} + } + + if input.Rating != nil { + rating := int64(*input.Rating) + updatedMovie.Rating = &sql.NullInt64{Int64: rating, Valid: true} + } else { + // rating must be nullable + updatedMovie.Rating = &sql.NullInt64{Valid: false} + } + + if input.StudioID != nil { + studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) + updatedMovie.StudioID = &sql.NullInt64{Int64: studioID, Valid: true} + } else { + // studio must be nullable + updatedMovie.StudioID = &sql.NullInt64{Valid: false} + } + + if input.Director != nil { + updatedMovie.Director = &sql.NullString{String: *input.Director, Valid: true} + } + + if input.Synopsis != nil { + updatedMovie.Synopsis = &sql.NullString{String: *input.Synopsis, Valid: true} + } + + if input.URL != nil { + updatedMovie.URL = &sql.NullString{String: *input.URL, Valid: true} + } + + // Start the transaction and save the movie + tx := database.DB.MustBeginTx(ctx, nil) + qb := models.NewMovieQueryBuilder() + movie, err := qb.Update(updatedMovie, tx) + if err != nil { + _ = tx.Rollback() + return nil, err + } + + // Commit + if err := tx.Commit(); err != nil { + return nil, err + } + + return movie, nil +} + +func (r *mutationResolver) MovieDestroy(ctx context.Context, input models.MovieDestroyInput) (bool, error) { + qb := models.NewMovieQueryBuilder() + tx := database.DB.MustBeginTx(ctx, nil) + if err := qb.Destroy(input.ID, tx); err != nil { + _ = tx.Rollback() + return false, err + } + if err := tx.Commit(); err != nil { + return false, err + } + return true, nil +} diff --git a/pkg/api/resolver_mutation_performer.go b/pkg/api/resolver_mutation_performer.go index 65c089525..697192392 100644 --- a/pkg/api/resolver_mutation_performer.go +++ b/pkg/api/resolver_mutation_performer.go @@ -19,7 +19,11 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input models.Per var err error if input.Image == nil { - imageData, err = getRandomPerformerImage() + gender := "" + if input.Gender != nil { + gender = input.Gender.String() + } + imageData, err = getRandomPerformerImage(gender) } else { _, imageData, err = utils.ProcessBase64Image(*input.Image) } @@ -42,6 +46,9 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input models.Per if input.URL != nil { newPerformer.URL = sql.NullString{String: *input.URL, Valid: true} } + if input.Gender != nil { + newPerformer.Gender = sql.NullString{String: input.Gender.String(), Valid: true} + } if input.Birthdate != nil { newPerformer.Birthdate = models.SQLiteDate{String: *input.Birthdate, Valid: true} } @@ -128,6 +135,9 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input models.Per if input.URL != nil { updatedPerformer.URL = sql.NullString{String: *input.URL, Valid: true} } + if input.Gender != nil { + updatedPerformer.Gender = sql.NullString{String: input.Gender.String(), Valid: true} + } if input.Birthdate != nil { updatedPerformer.Birthdate = models.SQLiteDate{String: *input.Birthdate, Valid: true} } diff --git a/pkg/api/resolver_mutation_scene.go b/pkg/api/resolver_mutation_scene.go index 1d2564257..3cee12c11 100644 --- a/pkg/api/resolver_mutation_scene.go +++ b/pkg/api/resolver_mutation_scene.go @@ -147,6 +147,31 @@ func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, tx *sqlx.T return nil, err } + // Save the movies + var movieJoins []models.MoviesScenes + + for _, movie := range input.Movies { + + movieID, _ := strconv.Atoi(movie.MovieID) + + movieJoin := models.MoviesScenes{ + MovieID: movieID, + SceneID: sceneID, + } + + if movie.SceneIndex != nil { + movieJoin.SceneIndex = sql.NullInt64{ + Int64: int64(*movie.SceneIndex), + Valid: true, + } + } + + movieJoins = append(movieJoins, movieJoin) + } + if err := jqb.UpdateMoviesScenes(sceneID, movieJoins, tx); err != nil { + return nil, err + } + // Save the tags var tagJoins []models.ScenesTags for _, tid := range input.TagIds { @@ -247,9 +272,14 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul // Save the performers if wasFieldIncluded(ctx, "performer_ids") { + performerIDs, err := adjustScenePerformerIDs(tx, sceneID, *input.PerformerIds) + if err != nil { + _ = tx.Rollback() + return nil, err + } + var performerJoins []models.PerformersScenes - for _, pid := range input.PerformerIds { - performerID, _ := strconv.Atoi(pid) + for _, performerID := range performerIDs { performerJoin := models.PerformersScenes{ PerformerID: performerID, SceneID: sceneID, @@ -264,9 +294,14 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul // Save the tags if wasFieldIncluded(ctx, "tag_ids") { + tagIDs, err := adjustSceneTagIDs(tx, sceneID, *input.TagIds) + if err != nil { + _ = tx.Rollback() + return nil, err + } + var tagJoins []models.ScenesTags - for _, tid := range input.TagIds { - tagID, _ := strconv.Atoi(tid) + for _, tagID := range tagIDs { tagJoin := models.ScenesTags{ SceneID: sceneID, TagID: tagID, @@ -288,6 +323,72 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul return ret, nil } +func adjustIDs(existingIDs []int, updateIDs models.BulkUpdateIds) []int { + for _, idStr := range updateIDs.Ids { + id, _ := strconv.Atoi(idStr) + + // look for the id in the list + foundExisting := false + for idx, existingID := range existingIDs { + if existingID == id { + if updateIDs.Mode == models.BulkUpdateIDModeRemove { + // remove from the list + existingIDs = append(existingIDs[:idx], existingIDs[idx+1:]...) + } + + foundExisting = true + break + } + } + + if !foundExisting && updateIDs.Mode != models.BulkUpdateIDModeRemove { + existingIDs = append(existingIDs, id) + } + } + + return existingIDs +} + +func adjustScenePerformerIDs(tx *sqlx.Tx, sceneID int, ids models.BulkUpdateIds) ([]int, error) { + var ret []int + + jqb := models.NewJoinsQueryBuilder() + if ids.Mode == models.BulkUpdateIDModeAdd || ids.Mode == models.BulkUpdateIDModeRemove { + // adding to the joins + performerJoins, err := jqb.GetScenePerformers(sceneID, tx) + + if err != nil { + return nil, err + } + + for _, join := range performerJoins { + ret = append(ret, join.PerformerID) + } + } + + return adjustIDs(ret, ids), nil +} + +func adjustSceneTagIDs(tx *sqlx.Tx, sceneID int, ids models.BulkUpdateIds) ([]int, error) { + var ret []int + + jqb := models.NewJoinsQueryBuilder() + if ids.Mode == models.BulkUpdateIDModeAdd || ids.Mode == models.BulkUpdateIDModeRemove { + // adding to the joins + tagJoins, err := jqb.GetSceneTags(sceneID, tx) + + if err != nil { + return nil, err + } + + for _, join := range tagJoins { + ret = append(ret, join.TagID) + } + } + + return adjustIDs(ret, ids), nil +} + func (r *mutationResolver) SceneDestroy(ctx context.Context, input models.SceneDestroyInput) (bool, error) { qb := models.NewSceneQueryBuilder() tx := database.DB.MustBeginTx(ctx, nil) @@ -356,6 +457,14 @@ func (r *mutationResolver) SceneMarkerUpdate(ctx context.Context, input models.S func (r *mutationResolver) SceneMarkerDestroy(ctx context.Context, id string) (bool, error) { qb := models.NewSceneMarkerQueryBuilder() tx := database.DB.MustBeginTx(ctx, nil) + + markerID, _ := strconv.Atoi(id) + marker, err := qb.Find(markerID) + + if err != nil { + return false, err + } + if err := qb.Destroy(id, tx); err != nil { _ = tx.Rollback() return false, err @@ -363,6 +472,16 @@ func (r *mutationResolver) SceneMarkerDestroy(ctx context.Context, id string) (b if err := tx.Commit(); err != nil { return false, err } + + // delete the preview for the marker + sqb := models.NewSceneQueryBuilder() + scene, _ := sqb.Find(int(marker.SceneID.Int64)) + + if scene != nil { + seconds := int(marker.Seconds) + manager.DeleteSceneMarkerFiles(scene, seconds) + } + return true, nil } @@ -372,13 +491,18 @@ func changeMarker(ctx context.Context, changeType int, changedMarker models.Scen qb := models.NewSceneMarkerQueryBuilder() jqb := models.NewJoinsQueryBuilder() + var existingMarker *models.SceneMarker var sceneMarker *models.SceneMarker var err error switch changeType { case create: sceneMarker, err = qb.Create(changedMarker, tx) case update: - sceneMarker, err = qb.Update(changedMarker, tx) + // check to see if timestamp was changed + existingMarker, err = qb.Find(changedMarker.ID) + if err == nil { + sceneMarker, err = qb.Update(changedMarker, tx) + } } if err != nil { _ = tx.Rollback() @@ -416,6 +540,18 @@ func changeMarker(ctx context.Context, changeType int, changedMarker models.Scen return nil, err } + // remove the marker preview if the timestamp was changed + if existingMarker != nil && existingMarker.Seconds != changedMarker.Seconds { + sqb := models.NewSceneQueryBuilder() + + scene, _ := sqb.Find(int(existingMarker.SceneID.Int64)) + + if scene != nil { + seconds := int(existingMarker.Seconds) + manager.DeleteSceneMarkerFiles(scene, seconds) + } + } + return sceneMarker, nil } @@ -478,3 +614,13 @@ func (r *mutationResolver) SceneResetO(ctx context.Context, id string) (int, err return newVal, nil } + +func (r *mutationResolver) SceneGenerateScreenshot(ctx context.Context, id string, at *float64) (string, error) { + if at != nil { + manager.GetInstance().GenerateScreenshot(id, *at) + } else { + manager.GetInstance().GenerateDefaultScreenshot(id) + } + + return "todo", nil +} diff --git a/pkg/api/resolver_query_configuration.go b/pkg/api/resolver_query_configuration.go index 80ddf8bd2..da059de60 100644 --- a/pkg/api/resolver_query_configuration.go +++ b/pkg/api/resolver_query_configuration.go @@ -12,12 +12,18 @@ func (r *queryResolver) Configuration(ctx context.Context) (*models.ConfigResult return makeConfigResult(), nil } -func (r *queryResolver) Directories(ctx context.Context, path *string) ([]string, error) { +func (r *queryResolver) Directory(ctx context.Context, path *string) (*models.Directory, error) { var dirPath = "" if path != nil { dirPath = *path } - return utils.ListDir(dirPath), nil + currentDir := utils.GetDir(dirPath) + + return &models.Directory{ + Path: currentDir, + Parent: utils.GetParent(currentDir), + Directories: utils.ListDir(currentDir), + }, nil } func makeConfigResult() *models.ConfigResult { @@ -33,38 +39,49 @@ func makeConfigGeneralResult() *models.ConfigGeneralResult { maxTranscodeSize := config.GetMaxTranscodeSize() maxStreamingTranscodeSize := config.GetMaxStreamingTranscodeSize() + scraperUserAgent := config.GetScraperUserAgent() + return &models.ConfigGeneralResult{ Stashes: config.GetStashPaths(), DatabasePath: config.GetDatabasePath(), GeneratedPath: config.GetGeneratedPath(), + CachePath: config.GetCachePath(), MaxTranscodeSize: &maxTranscodeSize, MaxStreamingTranscodeSize: &maxStreamingTranscodeSize, + ForceMkv: config.GetForceMKV(), + ForceHevc: config.GetForceHEVC(), Username: config.GetUsername(), Password: config.GetPasswordHash(), + MaxSessionAge: config.GetMaxSessionAge(), LogFile: &logFile, LogOut: config.GetLogOut(), LogLevel: config.GetLogLevel(), LogAccess: config.GetLogAccess(), Excludes: config.GetExcludes(), + ScraperUserAgent: &scraperUserAgent, } } func makeConfigInterfaceResult() *models.ConfigInterfaceResult { soundOnPreview := config.GetSoundOnPreview() wallShowTitle := config.GetWallShowTitle() + wallPlayback := config.GetWallPlayback() maximumLoopDuration := config.GetMaximumLoopDuration() autostartVideo := config.GetAutostartVideo() showStudioAsText := config.GetShowStudioAsText() css := config.GetCSS() cssEnabled := config.GetCSSEnabled() + language := config.GetLanguage() return &models.ConfigInterfaceResult{ SoundOnPreview: &soundOnPreview, WallShowTitle: &wallShowTitle, + WallPlayback: &wallPlayback, MaximumLoopDuration: &maximumLoopDuration, AutostartVideo: &autostartVideo, ShowStudioAsText: &showStudioAsText, CSS: &css, CSSEnabled: &cssEnabled, + Language: &language, } } diff --git a/pkg/api/resolver_query_find_movie.go b/pkg/api/resolver_query_find_movie.go new file mode 100644 index 000000000..9d23eddfc --- /dev/null +++ b/pkg/api/resolver_query_find_movie.go @@ -0,0 +1,33 @@ +package api + +import ( + "context" + "strconv" + + "github.com/stashapp/stash/pkg/models" +) + +func (r *queryResolver) FindMovie(ctx context.Context, id string) (*models.Movie, error) { + qb := models.NewMovieQueryBuilder() + idInt, _ := strconv.Atoi(id) + return qb.Find(idInt, nil) +} + +func (r *queryResolver) FindMovies(ctx context.Context, movieFilter *models.MovieFilterType, filter *models.FindFilterType) (*models.FindMoviesResultType, error) { + qb := models.NewMovieQueryBuilder() + movies, total := qb.Query(movieFilter, filter) + return &models.FindMoviesResultType{ + Count: total, + Movies: movies, + }, nil +} + +func (r *queryResolver) AllMovies(ctx context.Context) ([]*models.Movie, error) { + qb := models.NewMovieQueryBuilder() + return qb.All() +} + +func (r *queryResolver) AllMoviesSlim(ctx context.Context) ([]*models.Movie, error) { + qb := models.NewMovieQueryBuilder() + return qb.AllSlim() +} diff --git a/pkg/api/resolver_query_find_performer.go b/pkg/api/resolver_query_find_performer.go index 33c29d6c5..efb694910 100644 --- a/pkg/api/resolver_query_find_performer.go +++ b/pkg/api/resolver_query_find_performer.go @@ -25,3 +25,8 @@ func (r *queryResolver) AllPerformers(ctx context.Context) ([]*models.Performer, qb := models.NewPerformerQueryBuilder() return qb.All() } + +func (r *queryResolver) AllPerformersSlim(ctx context.Context) ([]*models.Performer, error) { + qb := models.NewPerformerQueryBuilder() + return qb.AllSlim() +} diff --git a/pkg/api/resolver_query_find_studio.go b/pkg/api/resolver_query_find_studio.go index 3537254f8..4b39130f4 100644 --- a/pkg/api/resolver_query_find_studio.go +++ b/pkg/api/resolver_query_find_studio.go @@ -25,3 +25,8 @@ func (r *queryResolver) AllStudios(ctx context.Context) ([]*models.Studio, error qb := models.NewStudioQueryBuilder() return qb.All() } + +func (r *queryResolver) AllStudiosSlim(ctx context.Context) ([]*models.Studio, error) { + qb := models.NewStudioQueryBuilder() + return qb.AllSlim() +} diff --git a/pkg/api/resolver_query_find_tag.go b/pkg/api/resolver_query_find_tag.go index e5b6a5929..64fc866c9 100644 --- a/pkg/api/resolver_query_find_tag.go +++ b/pkg/api/resolver_query_find_tag.go @@ -16,3 +16,8 @@ func (r *queryResolver) AllTags(ctx context.Context) ([]*models.Tag, error) { qb := models.NewTagQueryBuilder() return qb.All() } + +func (r *queryResolver) AllTagsSlim(ctx context.Context) ([]*models.Tag, error) { + qb := models.NewTagQueryBuilder() + return qb.AllSlim() +} diff --git a/pkg/api/resolver_query_metadata.go b/pkg/api/resolver_query_metadata.go index ad8dcbf3e..862d91eae 100644 --- a/pkg/api/resolver_query_metadata.go +++ b/pkg/api/resolver_query_metadata.go @@ -7,36 +7,6 @@ import ( "github.com/stashapp/stash/pkg/models" ) -func (r *queryResolver) MetadataScan(ctx context.Context, input models.ScanMetadataInput) (string, error) { - manager.GetInstance().Scan(input.UseFileMetadata) - return "todo", nil -} - -func (r *queryResolver) MetadataImport(ctx context.Context) (string, error) { - manager.GetInstance().Import() - return "todo", nil -} - -func (r *queryResolver) MetadataExport(ctx context.Context) (string, error) { - manager.GetInstance().Export() - return "todo", nil -} - -func (r *queryResolver) MetadataGenerate(ctx context.Context, input models.GenerateMetadataInput) (string, error) { - manager.GetInstance().Generate(input.Sprites, input.Previews, input.Markers, input.Transcodes) - return "todo", nil -} - -func (r *queryResolver) MetadataAutoTag(ctx context.Context, input models.AutoTagMetadataInput) (string, error) { - manager.GetInstance().AutoTag(input.Performers, input.Studios, input.Tags) - return "todo", nil -} - -func (r *queryResolver) MetadataClean(ctx context.Context) (string, error) { - manager.GetInstance().Clean() - return "todo", nil -} - func (r *queryResolver) JobStatus(ctx context.Context) (*models.MetadataUpdateStatus, error) { status := manager.GetInstance().Status ret := models.MetadataUpdateStatus{ @@ -47,7 +17,3 @@ func (r *queryResolver) JobStatus(ctx context.Context) (*models.MetadataUpdateSt return &ret, nil } - -func (r *queryResolver) StopJob(ctx context.Context) (bool, error) { - return manager.GetInstance().Status.Stop(), nil -} diff --git a/pkg/api/routes_gallery.go b/pkg/api/routes_gallery.go index 0c53cf35c..4b5a7f4cd 100644 --- a/pkg/api/routes_gallery.go +++ b/pkg/api/routes_gallery.go @@ -23,11 +23,15 @@ func (rs galleryRoutes) Routes() chi.Router { func (rs galleryRoutes) File(w http.ResponseWriter, r *http.Request) { gallery := r.Context().Value(galleryKey).(*models.Gallery) + if gallery == nil { + http.Error(w, http.StatusText(404), 404) + return + } fileIndex, _ := strconv.Atoi(chi.URLParam(r, "fileIndex")) thumb := r.URL.Query().Get("thumb") w.Header().Add("Cache-Control", "max-age=604800000") // 1 Week if thumb == "true" { - _, _ = w.Write(gallery.GetThumbnail(fileIndex, 200)) + _, _ = w.Write(cacheGthumb(gallery, fileIndex, models.DefaultGthumbWidth)) } else if thumb == "" { _, _ = w.Write(gallery.GetImage(fileIndex)) } else { @@ -36,7 +40,7 @@ func (rs galleryRoutes) File(w http.ResponseWriter, r *http.Request) { http.Error(w, http.StatusText(400), 400) return } - _, _ = w.Write(gallery.GetThumbnail(fileIndex, int(width))) + _, _ = w.Write(cacheGthumb(gallery, fileIndex, int(width))) } } diff --git a/pkg/api/routes_movie.go b/pkg/api/routes_movie.go new file mode 100644 index 000000000..3c6659c59 --- /dev/null +++ b/pkg/api/routes_movie.go @@ -0,0 +1,54 @@ +package api + +import ( + "context" + "net/http" + "strconv" + + "github.com/go-chi/chi" + "github.com/stashapp/stash/pkg/models" +) + +type movieRoutes struct{} + +func (rs movieRoutes) Routes() chi.Router { + r := chi.NewRouter() + + r.Route("/{movieId}", func(r chi.Router) { + r.Use(MovieCtx) + r.Get("/frontimage", rs.FrontImage) + r.Get("/backimage", rs.BackImage) + }) + + return r +} + +func (rs movieRoutes) FrontImage(w http.ResponseWriter, r *http.Request) { + movie := r.Context().Value(movieKey).(*models.Movie) + _, _ = w.Write(movie.FrontImage) +} + +func (rs movieRoutes) BackImage(w http.ResponseWriter, r *http.Request) { + movie := r.Context().Value(movieKey).(*models.Movie) + _, _ = w.Write(movie.BackImage) +} + +func MovieCtx(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + movieID, err := strconv.Atoi(chi.URLParam(r, "movieId")) + if err != nil { + http.Error(w, http.StatusText(404), 404) + return + } + + qb := models.NewMovieQueryBuilder() + movie, err := qb.Find(movieID, nil) + if err != nil { + http.Error(w, http.StatusText(404), 404) + return + } + + ctx := context.WithValue(r.Context(), movieKey, movie) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} diff --git a/pkg/api/routes_scene.go b/pkg/api/routes_scene.go index b5cf8827e..171d868b4 100644 --- a/pkg/api/routes_scene.go +++ b/pkg/api/routes_scene.go @@ -4,6 +4,7 @@ import ( "context" "io" "net/http" + "os" "strconv" "strings" @@ -42,13 +43,32 @@ func (rs sceneRoutes) Routes() chi.Router { // region Handlers func (rs sceneRoutes) Stream(w http.ResponseWriter, r *http.Request) { + scene := r.Context().Value(sceneKey).(*models.Scene) + container := "" + if scene.Format.Valid { + container = scene.Format.String + } else { // container isn't in the DB + // shouldn't happen, fallback to ffprobe + tmpVideoFile, err := ffmpeg.NewVideoFile(manager.GetInstance().FFProbePath, scene.Path) + if err != nil { + logger.Errorf("[transcode] error reading video file: %s", err.Error()) + return + } + + container = string(ffmpeg.MatchContainer(tmpVideoFile.Container, scene.Path)) + } + // detect if not a streamable file and try to transcode it instead filepath := manager.GetInstance().Paths.Scene.GetStreamPath(scene.Path, scene.Checksum) videoCodec := scene.VideoCodec.String + audioCodec := ffmpeg.MissingUnsupported + if scene.AudioCodec.Valid { + audioCodec = ffmpeg.AudioCodec(scene.AudioCodec.String) + } hasTranscode, _ := manager.HasTranscode(scene) - if ffmpeg.IsValidCodec(videoCodec) || hasTranscode { + if ffmpeg.IsValidCodec(videoCodec) && ffmpeg.IsValidCombo(videoCodec, ffmpeg.Container(container)) && ffmpeg.IsValidAudioForContainer(audioCodec, ffmpeg.Container(container)) || hasTranscode { manager.RegisterStream(filepath, &w) http.ServeFile(w, r, filepath) manager.WaitAndDeregisterStream(filepath, &w, r) @@ -69,16 +89,50 @@ func (rs sceneRoutes) Stream(w http.ResponseWriter, r *http.Request) { encoder := ffmpeg.NewEncoder(manager.GetInstance().FFMPEGPath) - stream, process, err := encoder.StreamTranscode(*videoFile, startTime, config.GetMaxStreamingTranscodeSize()) + var stream io.ReadCloser + var process *os.Process + mimeType := ffmpeg.MimeWebm + + if audioCodec == ffmpeg.MissingUnsupported { + //ffmpeg fails if it trys to transcode a non supported audio codec + stream, process, err = encoder.StreamTranscodeVideo(*videoFile, startTime, config.GetMaxStreamingTranscodeSize()) + } else { + copyVideo := false // try to be smart if the video to be transcoded is in a Matroska container + // mp4 has always supported audio so it doesn't need to be checked + // while mpeg_ts has seeking issues if we don't reencode the video + + if config.GetForceMKV() { // If MKV is forced as supported and video codec is also supported then only transcode audio + if ffmpeg.Container(container) == ffmpeg.Matroska { + switch videoCodec { + case ffmpeg.H264, ffmpeg.Vp9, ffmpeg.Vp8: + copyVideo = true + case ffmpeg.Hevc: + if config.GetForceHEVC() { + copyVideo = true + } + + } + } + } + + if copyVideo { // copy video stream instead of transcoding it + stream, process, err = encoder.StreamMkvTranscodeAudio(*videoFile, startTime, config.GetMaxStreamingTranscodeSize()) + mimeType = ffmpeg.MimeMkv + + } else { + stream, process, err = encoder.StreamTranscode(*videoFile, startTime, config.GetMaxStreamingTranscodeSize()) + } + } + if err != nil { logger.Errorf("[stream] error transcoding video file: %s", err.Error()) return } w.WriteHeader(http.StatusOK) - w.Header().Set("Content-Type", "video/webm") + w.Header().Set("Content-Type", mimeType) - logger.Info("[stream] transcoding video file") + logger.Infof("[stream] transcoding video file to %s", mimeType) // handle if client closes the connection notify := r.Context().Done() diff --git a/pkg/api/routes_studio.go b/pkg/api/routes_studio.go index 8080a641a..22d0702c5 100644 --- a/pkg/api/routes_studio.go +++ b/pkg/api/routes_studio.go @@ -2,10 +2,13 @@ package api import ( "context" + "crypto/md5" + "fmt" "github.com/go-chi/chi" "github.com/stashapp/stash/pkg/models" "net/http" "strconv" + "strings" ) type studioRoutes struct{} @@ -23,6 +26,21 @@ func (rs studioRoutes) Routes() chi.Router { func (rs studioRoutes) Image(w http.ResponseWriter, r *http.Request) { studio := r.Context().Value(studioKey).(*models.Studio) + etag := fmt.Sprintf("%x", md5.Sum(studio.Image)) + if match := r.Header.Get("If-None-Match"); match != "" { + if strings.Contains(match, etag) { + w.WriteHeader(http.StatusNotModified) + return + } + } + + contentType := http.DetectContentType(studio.Image) + if contentType == "text/xml; charset=utf-8" || contentType == "text/plain; charset=utf-8" { + contentType = "image/svg+xml" + } + + w.Header().Set("Content-Type", contentType) + w.Header().Add("Etag", etag) _, _ = w.Write(studio.Image) } diff --git a/pkg/api/server.go b/pkg/api/server.go index 27141c5bf..9d3a038c3 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "net/http" + "net/url" "os" "path" "path/filepath" @@ -20,6 +21,7 @@ import ( "github.com/gobuffalo/packr/v2" "github.com/gorilla/websocket" "github.com/rs/cors" + "github.com/stashapp/stash/pkg/database" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/manager" "github.com/stashapp/stash/pkg/manager/config" @@ -28,46 +30,81 @@ import ( "github.com/stashapp/stash/pkg/utils" ) -var version string = "" -var buildstamp string = "" -var githash string = "" +var version string +var buildstamp string +var githash string var uiBox *packr.Box //var legacyUiBox *packr.Box var setupUIBox *packr.Box +var loginUIBox *packr.Box + +func allowUnauthenticated(r *http.Request) bool { + return strings.HasPrefix(r.URL.Path, "/login") || r.URL.Path == "/css" +} func authenticateHandler() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // only do this if credentials have been configured - if !config.HasCredentials() { - next.ServeHTTP(w, r) + ctx := r.Context() + + // translate api key into current user, if present + userID := "" + var err error + + // handle session + userID, err = getSessionUserID(w, r) + + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) return } - authUser, authPW, ok := r.BasicAuth() + // handle redirect if no user and user is required + if userID == "" && config.HasCredentials() && !allowUnauthenticated(r) { + // always allow - if !ok || !config.ValidateCredentials(authUser, authPW) { - unauthorized(w) + // if we don't have a userID, then redirect + // if graphql was requested, we just return a forbidden error + if r.URL.Path == "/graphql" { + w.Header().Add("WWW-Authenticate", `FormBased`) + w.WriteHeader(http.StatusUnauthorized) + return + } + + // otherwise redirect to the login page + u := url.URL{ + Path: "/login", + } + q := u.Query() + q.Set(returnURLParam, r.URL.Path) + u.RawQuery = q.Encode() + http.Redirect(w, r, u.String(), http.StatusFound) return } + ctx = context.WithValue(ctx, ContextUser, userID) + + r = r.WithContext(ctx) + next.ServeHTTP(w, r) }) } } -func unauthorized(w http.ResponseWriter) { - w.Header().Add("WWW-Authenticate", `Basic realm=\"Stash\"`) - w.WriteHeader(http.StatusUnauthorized) -} +const setupEndPoint = "/setup" +const migrateEndPoint = "/migrate" +const loginEndPoint = "/login" func Start() { - uiBox = packr.New("UI Box", "../../ui/v2/build") + uiBox = packr.New("UI Box", "../../ui/v2.5/build") //legacyUiBox = packr.New("UI Box", "../../ui/v1/dist/stash-frontend") setupUIBox = packr.New("Setup UI Box", "../../ui/setup") + loginUIBox = packr.New("Login UI Box", "../../ui/login") + initSessionStore() initialiseImages() r := chi.NewRouter() @@ -83,6 +120,7 @@ func Start() { r.Use(cors.AllowAll().Handler) r.Use(BaseURLMiddleware) r.Use(ConfigCheckMiddleware) + r.Use(DatabaseCheckMiddleware) recoverFunc := handler.RecoverFunc(func(ctx context.Context, err interface{}) error { logger.Error(err) @@ -105,12 +143,20 @@ func Start() { r.Handle("/graphql", gqlHandler) r.Handle("/playground", handler.Playground("GraphQL playground", "/graphql")) + // session handlers + r.Post(loginEndPoint, handleLogin) + r.Get("/logout", handleLogout) + + r.Get(loginEndPoint, getLoginHandler) + r.Mount("/gallery", galleryRoutes{}.Routes()) r.Mount("/performer", performerRoutes{}.Routes()) r.Mount("/scene", sceneRoutes{}.Routes()) r.Mount("/studio", studioRoutes{}.Routes()) + r.Mount("/movie", movieRoutes{}.Routes()) r.HandleFunc("/css", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/css") if !config.GetCSSEnabled() { return } @@ -125,6 +171,10 @@ func Start() { http.ServeFile(w, r, fn) }) + // Serve the migration UI + r.Get("/migrate", getMigrateHandler) + r.Post("/migrate", doMigrateHandler) + // Serve the setup UI r.HandleFunc("/setup*", func(w http.ResponseWriter, r *http.Request) { ext := path.Ext(r.URL.Path) @@ -136,6 +186,16 @@ func Start() { http.FileServer(setupUIBox).ServeHTTP(w, r) } }) + r.HandleFunc("/login*", func(w http.ResponseWriter, r *http.Request) { + ext := path.Ext(r.URL.Path) + if ext == ".html" || ext == "" { + data, _ := loginUIBox.Find("login.html") + _, _ = w.Write(data) + } else { + r.URL.Path = strings.Replace(r.URL.Path, loginEndPoint, "", 1) + http.FileServer(loginUIBox).ServeHTTP(w, r) + } + }) r.Post("/init", func(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { @@ -174,7 +234,8 @@ func Start() { _ = os.Mkdir(downloads, 0755) - config.Set(config.Stash, stash) + // #536 - set stash as slice of strings + config.Set(config.Stash, []string{stash}) config.Set(config.Generated, generated) config.Set(config.Metadata, metadata) config.Set(config.Cache, cache) @@ -189,6 +250,7 @@ func Start() { http.Redirect(w, r, "/", 301) }) + startThumbCache() // Serve the web app r.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) { ext := path.Ext(r.URL.Path) @@ -311,10 +373,27 @@ func BaseURLMiddleware(next http.Handler) http.Handler { func ConfigCheckMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ext := path.Ext(r.URL.Path) - shouldRedirect := ext == "" && r.Method == "GET" && r.URL.Path != "/init" + shouldRedirect := ext == "" && r.Method == "GET" if !config.IsValid() && shouldRedirect { - if !strings.HasPrefix(r.URL.Path, "/setup") { - http.Redirect(w, r, "/setup", 301) + // #539 - don't redirect if loading login page + if !strings.HasPrefix(r.URL.Path, setupEndPoint) && !strings.HasPrefix(r.URL.Path, loginEndPoint) { + http.Redirect(w, r, setupEndPoint, 301) + return + } + } + next.ServeHTTP(w, r) + }) +} + +func DatabaseCheckMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ext := path.Ext(r.URL.Path) + shouldRedirect := ext == "" && r.Method == "GET" + if shouldRedirect && database.NeedsMigration() { + // #451 - don't redirect if loading login page + // #539 - or setup page + if !strings.HasPrefix(r.URL.Path, migrateEndPoint) && !strings.HasPrefix(r.URL.Path, loginEndPoint) && !strings.HasPrefix(r.URL.Path, setupEndPoint) { + http.Redirect(w, r, migrateEndPoint, 301) return } } diff --git a/pkg/api/session.go b/pkg/api/session.go new file mode 100644 index 000000000..e619fd782 --- /dev/null +++ b/pkg/api/session.go @@ -0,0 +1,127 @@ +package api + +import ( + "fmt" + "html/template" + "net/http" + + "github.com/stashapp/stash/pkg/manager/config" + + "github.com/gorilla/sessions" +) + +const cookieName = "session" +const usernameFormKey = "username" +const passwordFormKey = "password" +const userIDKey = "userID" + +const returnURLParam = "returnURL" + +var sessionStore = sessions.NewCookieStore(config.GetSessionStoreKey()) + +type loginTemplateData struct { + URL string + Error string +} + +func initSessionStore() { + sessionStore.MaxAge(config.GetMaxSessionAge()) +} + +func redirectToLogin(w http.ResponseWriter, returnURL string, loginError string) { + data, _ := loginUIBox.Find("login.html") + templ, err := template.New("Login").Parse(string(data)) + if err != nil { + http.Error(w, fmt.Sprintf("error: %s", err), http.StatusInternalServerError) + return + } + + err = templ.Execute(w, loginTemplateData{URL: returnURL, Error: loginError}) + if err != nil { + http.Error(w, fmt.Sprintf("error: %s", err), http.StatusInternalServerError) + } +} + +func getLoginHandler(w http.ResponseWriter, r *http.Request) { + if !config.HasCredentials() { + http.Redirect(w, r, "/", http.StatusFound) + return + } + + redirectToLogin(w, r.URL.Query().Get(returnURLParam), "") +} + +func handleLogin(w http.ResponseWriter, r *http.Request) { + url := r.FormValue(returnURLParam) + if url == "" { + url = "/" + } + + // ignore error - we want a new session regardless + newSession, _ := sessionStore.Get(r, cookieName) + + username := r.FormValue("username") + password := r.FormValue("password") + + // authenticate the user + if !config.ValidateCredentials(username, password) { + // redirect back to the login page with an error + redirectToLogin(w, url, "Username or password is invalid") + return + } + + newSession.Values[userIDKey] = username + + err := newSession.Save(r, w) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + http.Redirect(w, r, url, http.StatusFound) +} + +func handleLogout(w http.ResponseWriter, r *http.Request) { + session, err := sessionStore.Get(r, cookieName) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + delete(session.Values, userIDKey) + session.Options.MaxAge = -1 + + err = session.Save(r, w) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // redirect to the login page if credentials are required + getLoginHandler(w, r) +} + +func getSessionUserID(w http.ResponseWriter, r *http.Request) (string, error) { + session, err := sessionStore.Get(r, cookieName) + // ignore errors and treat as an empty user id, so that we handle expired + // cookie + if err != nil { + return "", nil + } + + if !session.IsNew { + val := session.Values[userIDKey] + + // refresh the cookie + err = session.Save(r, w) + if err != nil { + return "", err + } + + ret, _ := val.(string) + + return ret, nil + } + + return "", nil +} diff --git a/pkg/api/urlbuilders/movie.go b/pkg/api/urlbuilders/movie.go new file mode 100644 index 000000000..7e454c070 --- /dev/null +++ b/pkg/api/urlbuilders/movie.go @@ -0,0 +1,24 @@ +package urlbuilders + +import "strconv" + +type MovieURLBuilder struct { + BaseURL string + MovieID string +} + +func NewMovieURLBuilder(baseURL string, movieID int) MovieURLBuilder { + return MovieURLBuilder{ + BaseURL: baseURL, + MovieID: strconv.Itoa(movieID), + } +} + +func (b MovieURLBuilder) GetMovieFrontImageURL() string { + return b.BaseURL + "/movie/" + b.MovieID + "/frontimage" +} + +func (b MovieURLBuilder) GetMovieBackImageURL() string { + return b.BaseURL + "/movie/" + b.MovieID + "/backimage" +} + diff --git a/pkg/database/database.go b/pkg/database/database.go index 66e0eba43..63f6d9cb1 100644 --- a/pkg/database/database.go +++ b/pkg/database/database.go @@ -5,10 +5,11 @@ import ( "errors" "fmt" "os" - "regexp" + "time" "github.com/gobuffalo/packr/v2" "github.com/golang-migrate/migrate/v4" + sqlite3mig "github.com/golang-migrate/migrate/v4/database/sqlite3" "github.com/golang-migrate/migrate/v4/source" "github.com/jmoiron/sqlx" sqlite3 "github.com/mattn/go-sqlite3" @@ -17,26 +18,62 @@ import ( ) var DB *sqlx.DB -var appSchemaVersion uint = 3 +var dbPath string +var appSchemaVersion uint = 8 +var databaseSchemaVersion uint -const sqlite3Driver = "sqlite3_regexp" +const sqlite3Driver = "sqlite3ex" func init() { // register custom driver with regexp function - registerRegexpFunc() + registerCustomDriver() } func Initialize(databasePath string) { - runMigrations(databasePath) + dbPath = databasePath + if err := getDatabaseSchemaVersion(); err != nil { + panic(err) + } + + if databaseSchemaVersion == 0 { + // new database, just run the migrations + if err := RunMigrations(); err != nil { + panic(err) + } + // RunMigrations calls Initialise. Just return + return + } else { + if databaseSchemaVersion > appSchemaVersion { + panic(fmt.Sprintf("Database schema version %d is incompatible with required schema version %d", databaseSchemaVersion, appSchemaVersion)) + } + + // if migration is needed, then don't open the connection + if NeedsMigration() { + logger.Warnf("Database schema version %d does not match required schema version %d.", databaseSchemaVersion, appSchemaVersion) + return + } + } + + const disableForeignKeys = false + DB = open(databasePath, disableForeignKeys) +} + +func open(databasePath string, disableForeignKeys bool) *sqlx.DB { // https://github.com/mattn/go-sqlite3 - conn, err := sqlx.Open(sqlite3Driver, "file:"+databasePath+"?_fk=true") + url := "file:" + databasePath + if !disableForeignKeys { + url += "?_fk=true" + } + + conn, err := sqlx.Open(sqlite3Driver, url) conn.SetMaxOpenConns(25) conn.SetMaxIdleConns(4) if err != nil { logger.Fatalf("db.Open(): %q\n", err) } - DB = conn + + return conn } func Reset(databasePath string) error { @@ -55,45 +92,123 @@ func Reset(databasePath string) error { return nil } +// Backup the database +func Backup(backupPath string) error { + db, err := sqlx.Connect(sqlite3Driver, "file:"+dbPath+"?_fk=true") + if err != nil { + return fmt.Errorf("Open database %s failed:%s", dbPath, err) + } + defer db.Close() + + _, err = db.Exec(`VACUUM INTO "` + backupPath + `"`) + if err != nil { + return fmt.Errorf("Vacuum failed: %s", err) + } + + return nil +} + +func RestoreFromBackup(backupPath string) error { + return os.Rename(backupPath, dbPath) +} + // Migrate the database -func runMigrations(databasePath string) { +func NeedsMigration() bool { + return databaseSchemaVersion != appSchemaVersion +} + +func AppSchemaVersion() uint { + return appSchemaVersion +} + +func DatabaseBackupPath() string { + return fmt.Sprintf("%s.%d.%s", dbPath, databaseSchemaVersion, time.Now().Format("20060102_150405")) +} + +func Version() uint { + return databaseSchemaVersion +} + +func getMigrate() (*migrate.Migrate, error) { migrationsBox := packr.New("Migrations Box", "./migrations") packrSource := &Packr2Source{ Box: migrationsBox, Migrations: source.NewMigrations(), } - databasePath = utils.FixWindowsPath(databasePath) + databasePath := utils.FixWindowsPath(dbPath) s, _ := WithInstance(packrSource) - m, err := migrate.NewWithSourceInstance( + + const disableForeignKeys = true + conn := open(databasePath, disableForeignKeys) + + driver, err := sqlite3mig.WithInstance(conn.DB, &sqlite3mig.Config{}) + if err != nil { + return nil, err + } + + // use sqlite3Driver so that migration has access to durationToTinyInt + return migrate.NewWithInstance( "packr2", s, - fmt.Sprintf("sqlite3://%s", "file:"+databasePath), + databasePath, + driver, ) +} + +func getDatabaseSchemaVersion() error { + m, err := getMigrate() + if err != nil { + return err + } + + databaseSchemaVersion, _, _ = m.Version() + m.Close() + return nil +} + +// Migrate the database +func RunMigrations() error { + m, err := getMigrate() if err != nil { panic(err.Error()) } - databaseSchemaVersion, _, _ := m.Version() + databaseSchemaVersion, _, _ = m.Version() stepNumber := appSchemaVersion - databaseSchemaVersion if stepNumber != 0 { err = m.Steps(int(stepNumber)) if err != nil { - panic(err.Error()) + // migration failed + m.Close() + return err } } m.Close() + + // re-initialise the database + Initialize(dbPath) + + return nil } -func registerRegexpFunc() { - regexFn := func(re, s string) (bool, error) { - return regexp.MatchString(re, s) - } - +func registerCustomDriver() { sql.Register(sqlite3Driver, &sqlite3.SQLiteDriver{ ConnectHook: func(conn *sqlite3.SQLiteConn) error { - return conn.RegisterFunc("regexp", regexFn, true) + funcs := map[string]interface{}{ + "regexp": regexFn, + "durationToTinyInt": durationToTinyIntFn, + } + + for name, fn := range funcs { + if err := conn.RegisterFunc(name, fn, true); err != nil { + return fmt.Errorf("Error registering function %s: %s", name, err.Error()) + } + } + + return nil }, - }) + }, + ) } diff --git a/pkg/database/functions.go b/pkg/database/functions.go new file mode 100644 index 000000000..69dc8c0fc --- /dev/null +++ b/pkg/database/functions.go @@ -0,0 +1,37 @@ +package database + +import ( + "regexp" + "strconv" + "strings" +) + +func regexFn(re, s string) (bool, error) { + return regexp.MatchString(re, s) +} + +func durationToTinyIntFn(str string) (int64, error) { + splits := strings.Split(str, ":") + + if len(splits) > 3 { + return 0, nil + } + + seconds := 0 + factor := 1 + for len(splits) > 0 { + // pop the last split + var thisSplit string + thisSplit, splits = splits[len(splits)-1], splits[:len(splits)-1] + + thisInt, err := strconv.Atoi(thisSplit) + if err != nil { + return 0, nil + } + + seconds += factor * thisInt + factor *= 60 + } + + return int64(seconds), nil +} diff --git a/pkg/database/migrations/4_movie.up.sql b/pkg/database/migrations/4_movie.up.sql new file mode 100644 index 000000000..8dd6d0e00 --- /dev/null +++ b/pkg/database/migrations/4_movie.up.sql @@ -0,0 +1,32 @@ +CREATE TABLE `movies` ( + `id` integer not null primary key autoincrement, + `name` varchar(255), + `aliases` varchar(255), + `duration` varchar(6), + `date` date, + `rating` varchar(1), + `director` varchar(255), + `synopsis` text, + `front_image` blob not null, + `back_image` blob, + `checksum` varchar(255) not null, + `url` varchar(255), + `created_at` datetime not null, + `updated_at` datetime not null +); +CREATE TABLE `movies_scenes` ( + `movie_id` integer, + `scene_id` integer, + `scene_index` varchar(2), + foreign key(`movie_id`) references `movies`(`id`), + foreign key(`scene_id`) references `scenes`(`id`) +); + + +ALTER TABLE `scraped_items` ADD COLUMN `movie_id` integer; +CREATE UNIQUE INDEX `movies_checksum_unique` on `movies` (`checksum`); +CREATE UNIQUE INDEX `index_movie_id_scene_index_unique` ON `movies_scenes` ( `movie_id`, `scene_index` ); +CREATE INDEX `index_movies_scenes_on_movie_id` on `movies_scenes` (`movie_id`); +CREATE INDEX `index_movies_scenes_on_scene_id` on `movies_scenes` (`scene_id`); + + diff --git a/pkg/database/migrations/5_performer_gender.down.sql b/pkg/database/migrations/5_performer_gender.down.sql new file mode 100644 index 000000000..abe9c746c --- /dev/null +++ b/pkg/database/migrations/5_performer_gender.down.sql @@ -0,0 +1,89 @@ + +PRAGMA foreign_keys=off; + +-- need to re-create the performers table without the added column. +-- also need re-create the performers_scenes table due to the foreign key + +-- rename existing performers table +ALTER TABLE `performers` RENAME TO `performers_old`; +ALTER TABLE `performers_scenes` RENAME TO `performers_scenes_old`; + +-- drop the indexes +DROP INDEX IF EXISTS `index_performers_on_name`; +DROP INDEX IF EXISTS `index_performers_on_checksum`; +DROP INDEX IF EXISTS `index_performers_scenes_on_scene_id`; +DROP INDEX IF EXISTS `index_performers_scenes_on_performer_id`; + +-- recreate the tables +CREATE TABLE `performers` ( + `id` integer not null primary key autoincrement, + `image` blob not null, + `checksum` varchar(255) not null, + `name` varchar(255), + `url` varchar(255), + `twitter` varchar(255), + `instagram` varchar(255), + `birthdate` date, + `ethnicity` varchar(255), + `country` varchar(255), + `eye_color` varchar(255), + `height` varchar(255), + `measurements` varchar(255), + `fake_tits` varchar(255), + `career_length` varchar(255), + `tattoos` varchar(255), + `piercings` varchar(255), + `aliases` varchar(255), + `favorite` boolean not null default '0', + `created_at` datetime not null, + `updated_at` datetime not null +); + +CREATE TABLE `performers_scenes` ( + `performer_id` integer, + `scene_id` integer, + foreign key(`performer_id`) references `performers`(`id`), + foreign key(`scene_id`) references `scenes`(`id`) +); + +INSERT INTO `performers` + SELECT + `id`, + `image`, + `checksum`, + `name`, + `url`, + `twitter`, + `instagram`, + `birthdate`, + `ethnicity`, + `country`, + `eye_color`, + `height`, + `measurements`, + `fake_tits`, + `career_length`, + `tattoos`, + `piercings`, + `aliases`, + `favorite`, + `created_at`, + `updated_at` + FROM `performers_old`; + +INSERT INTO `performers_scenes` + SELECT + `performer_id`, + `scene_id` + FROM `performers_scenes_old`; + +DROP TABLE `performers_scenes_old`; +DROP TABLE `performers_old`; + +-- re-create the indexes after removing the old tables +CREATE INDEX `index_performers_on_name` on `performers` (`name`); +CREATE INDEX `index_performers_on_checksum` on `performers` (`checksum`); +CREATE INDEX `index_performers_scenes_on_scene_id` on `performers_scenes` (`scene_id`); +CREATE INDEX `index_performers_scenes_on_performer_id` on `performers_scenes` (`performer_id`); + +PRAGMA foreign_keys=on; diff --git a/pkg/database/migrations/5_performer_gender.up.sql b/pkg/database/migrations/5_performer_gender.up.sql new file mode 100644 index 000000000..1f6e85485 --- /dev/null +++ b/pkg/database/migrations/5_performer_gender.up.sql @@ -0,0 +1 @@ +ALTER TABLE `performers` ADD COLUMN `gender` varchar(20); diff --git a/pkg/database/migrations/6_scenes_format.up.sql b/pkg/database/migrations/6_scenes_format.up.sql new file mode 100644 index 000000000..93f5c44a9 --- /dev/null +++ b/pkg/database/migrations/6_scenes_format.up.sql @@ -0,0 +1 @@ +ALTER TABLE `scenes` ADD COLUMN `format` varchar(255); diff --git a/pkg/database/migrations/7_performer_optimization.up.sql b/pkg/database/migrations/7_performer_optimization.up.sql new file mode 100644 index 000000000..c09d3c4b4 --- /dev/null +++ b/pkg/database/migrations/7_performer_optimization.up.sql @@ -0,0 +1,101 @@ +DROP INDEX `performers_checksum_unique`; +DROP INDEX `index_performers_on_name`; +DROP INDEX `index_performers_on_checksum`; +ALTER TABLE `performers` RENAME TO `temp_old_performers`; +CREATE TABLE `performers` ( + `id` integer not null primary key autoincrement, + `checksum` varchar(255) not null, + `name` varchar(255), + `gender` varchar(20), + `url` varchar(255), + `twitter` varchar(255), + `instagram` varchar(255), + `birthdate` date, + `ethnicity` varchar(255), + `country` varchar(255), + `eye_color` varchar(255), + `height` varchar(255), + `measurements` varchar(255), + `fake_tits` varchar(255), + `career_length` varchar(255), + `tattoos` varchar(255), + `piercings` varchar(255), + `aliases` varchar(255), + `favorite` boolean not null default '0', + `created_at` datetime not null, + `updated_at` datetime not null, + `image` blob not null +); +CREATE UNIQUE INDEX `performers_checksum_unique` on `performers` (`checksum`); +CREATE INDEX `index_performers_on_name` on `performers` (`name`); +INSERT INTO `performers` ( + `id`, + `checksum`, + `name`, + `gender`, + `url`, + `twitter`, + `instagram`, + `birthdate`, + `ethnicity`, + `country`, + `eye_color`, + `height`, + `measurements`, + `fake_tits`, + `career_length`, + `tattoos`, + `piercings`, + `aliases`, + `favorite`, + `created_at`, + `updated_at`, + `image` +) +SELECT + `id`, + `checksum`, + `name`, + `gender`, + `url`, + `twitter`, + `instagram`, + `birthdate`, + `ethnicity`, + `country`, + `eye_color`, + `height`, + `measurements`, + `fake_tits`, + `career_length`, + `tattoos`, + `piercings`, + `aliases`, + `favorite`, + `created_at`, + `updated_at`, + `image` +FROM `temp_old_performers`; + +DROP INDEX `index_performers_scenes_on_scene_id`; +DROP INDEX `index_performers_scenes_on_performer_id`; +ALTER TABLE performers_scenes RENAME TO temp_old_performers_scenes; +CREATE TABLE `performers_scenes` ( + `performer_id` integer, + `scene_id` integer, + foreign key(`performer_id`) references `performers`(`id`), + foreign key(`scene_id`) references `scenes`(`id`) +); +CREATE INDEX `index_performers_scenes_on_scene_id` on `performers_scenes` (`scene_id`); +CREATE INDEX `index_performers_scenes_on_performer_id` on `performers_scenes` (`performer_id`); +INSERT INTO `performers_scenes` ( + `performer_id`, + `scene_id` +) +SELECT + `performer_id`, + `scene_id` +FROM `temp_old_performers_scenes`; + +DROP TABLE `temp_old_performers`; +DROP TABLE `temp_old_performers_scenes`; diff --git a/pkg/database/migrations/8_movie_fix.up.sql b/pkg/database/migrations/8_movie_fix.up.sql new file mode 100644 index 000000000..33414bd99 --- /dev/null +++ b/pkg/database/migrations/8_movie_fix.up.sql @@ -0,0 +1,106 @@ +ALTER TABLE `movies` rename to `_movies_old`; +ALTER TABLE `movies_scenes` rename to `_movies_scenes_old`; + +DROP INDEX IF EXISTS `movies_checksum_unique`; +DROP INDEX IF EXISTS `index_movie_id_scene_index_unique`; +DROP INDEX IF EXISTS `index_movies_scenes_on_movie_id`; +DROP INDEX IF EXISTS `index_movies_scenes_on_scene_id`; + +-- recreate the movies table with fixed column types and constraints +CREATE TABLE `movies` ( + `id` integer not null primary key autoincrement, + -- add not null + `name` varchar(255) not null, + `aliases` varchar(255), + -- varchar(6) -> integer + `duration` integer, + `date` date, + -- varchar(1) -> tinyint + `rating` tinyint, + `studio_id` integer, + `director` varchar(255), + `synopsis` text, + `checksum` varchar(255) not null, + `url` varchar(255), + `created_at` datetime not null, + `updated_at` datetime not null, + `front_image` blob not null, + `back_image` blob, + foreign key(`studio_id`) references `studios`(`id`) on delete set null +); +CREATE TABLE `movies_scenes` ( + `movie_id` integer, + `scene_id` integer, + -- varchar(2) -> tinyint + `scene_index` tinyint, + foreign key(`movie_id`) references `movies`(`id`) on delete cascade, + foreign key(`scene_id`) references `scenes`(`id`) on delete cascade +); + +-- add unique index on movie name +CREATE UNIQUE INDEX `movies_name_unique` on `movies` (`name`); +CREATE UNIQUE INDEX `movies_checksum_unique` on `movies` (`checksum`); +-- remove unique index on movies_scenes +CREATE INDEX `index_movies_scenes_on_movie_id` on `movies_scenes` (`movie_id`); +CREATE INDEX `index_movies_scenes_on_scene_id` on `movies_scenes` (`scene_id`); +CREATE INDEX `index_movies_on_studio_id` on `movies` (`studio_id`); + +-- custom functions cannot accept NULL values, so massage the old data +UPDATE `_movies_old` set `duration` = 0 WHERE `duration` IS NULL; + +-- now populate from the old tables +INSERT INTO `movies` + ( + `id`, + `name`, + `aliases`, + `duration`, + `date`, + `rating`, + `director`, + `synopsis`, + `front_image`, + `back_image`, + `checksum`, + `url`, + `created_at`, + `updated_at` + ) + SELECT + `id`, + `name`, + `aliases`, + durationToTinyInt(`duration`), + `date`, + CAST(`rating` as tinyint), + `director`, + `synopsis`, + `front_image`, + `back_image`, + `checksum`, + `url`, + `created_at`, + `updated_at` + FROM `_movies_old` + -- ignore null named movies + WHERE `name` is not null; + +-- durationToTinyInt returns 0 if it cannot parse the string +-- set these values to null instead +UPDATE `movies` SET `duration` = NULL WHERE `duration` = 0; + +INSERT INTO `movies_scenes` + ( + `movie_id`, + `scene_id`, + `scene_index` + ) + SELECT + `movie_id`, + `scene_id`, + CAST(`scene_index` as tinyint) + FROM `_movies_scenes_old`; + +-- drop old tables +DROP TABLE `_movies_scenes_old`; +DROP TABLE `_movies_old`; diff --git a/pkg/ffmpeg/encoder.go b/pkg/ffmpeg/encoder.go index 7ceb4b594..46711d146 100644 --- a/pkg/ffmpeg/encoder.go +++ b/pkg/ffmpeg/encoder.go @@ -18,8 +18,8 @@ type Encoder struct { } var ( - runningEncoders map[string][]*os.Process = make(map[string][]*os.Process) - runningEncodersMutex = sync.RWMutex{} + runningEncoders = make(map[string][]*os.Process) + runningEncodersMutex = sync.RWMutex{} ) func NewEncoder(ffmpegPath string) Encoder { diff --git a/pkg/ffmpeg/encoder_scene_preview_chunk.go b/pkg/ffmpeg/encoder_scene_preview_chunk.go index 9ff655ead..4f6a8a6fd 100644 --- a/pkg/ffmpeg/encoder_scene_preview_chunk.go +++ b/pkg/ffmpeg/encoder_scene_preview_chunk.go @@ -13,9 +13,10 @@ type ScenePreviewChunkOptions struct { OutputPath string } -func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePreviewChunkOptions) { +func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePreviewChunkOptions, preset string) { args := []string{ "-v", "error", + "-xerror", "-ss", strconv.Itoa(options.Time), "-i", probeResult.Path, "-t", "0.75", @@ -25,7 +26,7 @@ func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePre "-pix_fmt", "yuv420p", "-profile:v", "high", "-level", "4.2", - "-preset", "veryslow", + "-preset", preset, "-crf", "21", "-threads", "4", "-vf", fmt.Sprintf("scale=%v:-2", options.Width), diff --git a/pkg/ffmpeg/encoder_screenshot.go b/pkg/ffmpeg/encoder_screenshot.go index f9923cf1e..bd1926ba3 100644 --- a/pkg/ffmpeg/encoder_screenshot.go +++ b/pkg/ffmpeg/encoder_screenshot.go @@ -10,7 +10,7 @@ type ScreenshotOptions struct { Verbosity string } -func (e *Encoder) Screenshot(probeResult VideoFile, options ScreenshotOptions) { +func (e *Encoder) Screenshot(probeResult VideoFile, options ScreenshotOptions) error { if options.Verbosity == "" { options.Verbosity = "error" } @@ -28,5 +28,7 @@ func (e *Encoder) Screenshot(probeResult VideoFile, options ScreenshotOptions) { "-f", "image2", options.OutputPath, } - _, _ = e.run(probeResult, args) + _, err := e.run(probeResult, args) + + return err } diff --git a/pkg/ffmpeg/encoder_transcode.go b/pkg/ffmpeg/encoder_transcode.go index a908f00ac..12b596396 100644 --- a/pkg/ffmpeg/encoder_transcode.go +++ b/pkg/ffmpeg/encoder_transcode.go @@ -69,6 +69,49 @@ func (e *Encoder) Transcode(probeResult VideoFile, options TranscodeOptions) { _, _ = e.run(probeResult, args) } +//transcode the video, remove the audio +//in some videos where the audio codec is not supported by ffmpeg +//ffmpeg fails if you try to transcode the audio +func (e *Encoder) TranscodeVideo(probeResult VideoFile, options TranscodeOptions) { + scale := calculateTranscodeScale(probeResult, options.MaxTranscodeSize) + args := []string{ + "-i", probeResult.Path, + "-an", + "-c:v", "libx264", + "-pix_fmt", "yuv420p", + "-profile:v", "high", + "-level", "4.2", + "-preset", "superfast", + "-crf", "23", + "-vf", "scale=" + scale, + options.OutputPath, + } + _, _ = e.run(probeResult, args) +} + +//copy the video stream as is, transcode audio +func (e *Encoder) TranscodeAudio(probeResult VideoFile, options TranscodeOptions) { + args := []string{ + "-i", probeResult.Path, + "-c:v", "copy", + "-c:a", "aac", + "-strict", "-2", + options.OutputPath, + } + _, _ = e.run(probeResult, args) +} + +//copy the video stream as is, drop audio +func (e *Encoder) CopyVideo(probeResult VideoFile, options TranscodeOptions) { + args := []string{ + "-i", probeResult.Path, + "-an", + "-c:v", "copy", + options.OutputPath, + } + _, _ = e.run(probeResult, args) +} + func (e *Encoder) StreamTranscode(probeResult VideoFile, startTime string, maxTranscodeSize models.StreamingResolutionEnum) (io.ReadCloser, *os.Process, error) { scale := calculateTranscodeScale(probeResult, maxTranscodeSize) args := []string{} @@ -92,3 +135,53 @@ func (e *Encoder) StreamTranscode(probeResult VideoFile, startTime string, maxTr return e.stream(probeResult, args) } + +//transcode the video, remove the audio +//in some videos where the audio codec is not supported by ffmpeg +//ffmpeg fails if you try to transcode the audio +func (e *Encoder) StreamTranscodeVideo(probeResult VideoFile, startTime string, maxTranscodeSize models.StreamingResolutionEnum) (io.ReadCloser, *os.Process, error) { + scale := calculateTranscodeScale(probeResult, maxTranscodeSize) + args := []string{} + + if startTime != "" { + args = append(args, "-ss", startTime) + } + + args = append(args, + "-i", probeResult.Path, + "-an", + "-c:v", "libvpx-vp9", + "-vf", "scale="+scale, + "-deadline", "realtime", + "-cpu-used", "5", + "-row-mt", "1", + "-crf", "30", + "-b:v", "0", + "-f", "webm", + "pipe:", + ) + + return e.stream(probeResult, args) +} + +//it is very common in MKVs to have just the audio codec unsupported +//copy the video stream, transcode the audio and serve as Matroska +func (e *Encoder) StreamMkvTranscodeAudio(probeResult VideoFile, startTime string, maxTranscodeSize models.StreamingResolutionEnum) (io.ReadCloser, *os.Process, error) { + args := []string{} + + if startTime != "" { + args = append(args, "-ss", startTime) + } + + args = append(args, + "-i", probeResult.Path, + "-c:v", "copy", + "-c:a", "libopus", + "-b:a", "96k", + "-vbr", "on", + "-f", "matroska", + "pipe:", + ) + + return e.stream(probeResult, args) +} diff --git a/pkg/ffmpeg/ffprobe.go b/pkg/ffmpeg/ffprobe.go index cbddb14d3..e309619e3 100644 --- a/pkg/ffmpeg/ffprobe.go +++ b/pkg/ffmpeg/ffprobe.go @@ -10,11 +10,106 @@ import ( "strconv" "strings" "time" + + "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/manager/config" ) -var ValidCodecs = []string{"h264", "h265", "vp8", "vp9"} +type Container string +type AudioCodec string + +const ( + Mp4 Container = "mp4" + M4v Container = "m4v" + Mov Container = "mov" + Wmv Container = "wmv" + Webm Container = "webm" + Matroska Container = "matroska" + Avi Container = "avi" + Flv Container = "flv" + Mpegts Container = "mpegts" + Aac AudioCodec = "aac" + Mp3 AudioCodec = "mp3" + Opus AudioCodec = "opus" + Vorbis AudioCodec = "vorbis" + MissingUnsupported AudioCodec = "" + Mp4Ffmpeg string = "mov,mp4,m4a,3gp,3g2,mj2" // browsers support all of them + M4vFfmpeg string = "mov,mp4,m4a,3gp,3g2,mj2" // so we don't care that ffmpeg + MovFfmpeg string = "mov,mp4,m4a,3gp,3g2,mj2" // can't differentiate between them + WmvFfmpeg string = "asf" + WebmFfmpeg string = "matroska,webm" + MatroskaFfmpeg string = "matroska,webm" + AviFfmpeg string = "avi" + FlvFfmpeg string = "flv" + MpegtsFfmpeg string = "mpegts" + H264 string = "h264" + H265 string = "h265" // found in rare cases from a faulty encoder + Hevc string = "hevc" + Vp8 string = "vp8" + Vp9 string = "vp9" + MimeWebm string = "video/webm" + MimeMkv string = "video/x-matroska" +) + +var ValidCodecs = []string{H264, H265, Vp8, Vp9} + +var validForH264Mkv = []Container{Mp4, Matroska} +var validForH264 = []Container{Mp4} +var validForH265Mkv = []Container{Mp4, Matroska} +var validForH265 = []Container{Mp4} +var validForVp8 = []Container{Webm} +var validForVp9Mkv = []Container{Webm, Matroska} +var validForVp9 = []Container{Webm} +var validForHevcMkv = []Container{Mp4, Matroska} +var validForHevc = []Container{Mp4} + +var validAudioForMkv = []AudioCodec{Aac, Mp3, Vorbis, Opus} +var validAudioForWebm = []AudioCodec{Vorbis, Opus} +var validAudioForMp4 = []AudioCodec{Aac, Mp3} + +//maps user readable container strings to ffprobe's format_name +//on some formats ffprobe can't differentiate +var ContainerToFfprobe = map[Container]string{ + Mp4: Mp4Ffmpeg, + M4v: M4vFfmpeg, + Mov: MovFfmpeg, + Wmv: WmvFfmpeg, + Webm: WebmFfmpeg, + Matroska: MatroskaFfmpeg, + Avi: AviFfmpeg, + Flv: FlvFfmpeg, + Mpegts: MpegtsFfmpeg, +} + +var FfprobeToContainer = map[string]Container{ + Mp4Ffmpeg: Mp4, + WmvFfmpeg: Wmv, + AviFfmpeg: Avi, + FlvFfmpeg: Flv, + MpegtsFfmpeg: Mpegts, + MatroskaFfmpeg: Matroska, +} + +func MatchContainer(format string, filePath string) Container { // match ffprobe string to our Container + + container := FfprobeToContainer[format] + if container == Matroska { + container = MagicContainer(filePath) // use magic number instead of ffprobe for matroska,webm + } + if container == "" { // if format is not in our Container list leave it as ffprobes reported format_name + container = Container(format) + } + return container +} func IsValidCodec(codecName string) bool { + forceHEVC := config.GetForceHEVC() + if forceHEVC { + if codecName == Hevc { + return true + } + } + for _, c := range ValidCodecs { if c == codecName { return true @@ -23,6 +118,78 @@ func IsValidCodec(codecName string) bool { return false } +func IsValidAudio(audio AudioCodec, ValidCodecs []AudioCodec) bool { + + // if audio codec is missing or unsupported by ffmpeg we can't do anything about it + // report it as valid so that the file can at least be streamed directly if the video codec is supported + if audio == MissingUnsupported { + return true + } + + for _, c := range ValidCodecs { + if c == audio { + return true + } + } + + return false +} + +func IsValidAudioForContainer(audio AudioCodec, format Container) bool { + switch format { + case Matroska: + return IsValidAudio(audio, validAudioForMkv) + case Webm: + return IsValidAudio(audio, validAudioForWebm) + case Mp4: + return IsValidAudio(audio, validAudioForMp4) + } + return false + +} + +func IsValidForContainer(format Container, validContainers []Container) bool { + for _, fmt := range validContainers { + if fmt == format { + return true + } + } + return false +} + +//extend stream validation check to take into account container +func IsValidCombo(codecName string, format Container) bool { + forceMKV := config.GetForceMKV() + forceHEVC := config.GetForceHEVC() + switch codecName { + case H264: + if forceMKV { + return IsValidForContainer(format, validForH264Mkv) + } + return IsValidForContainer(format, validForH264) + case H265: + if forceMKV { + return IsValidForContainer(format, validForH265Mkv) + } + return IsValidForContainer(format, validForH265) + case Vp8: + return IsValidForContainer(format, validForVp8) + case Vp9: + if forceMKV { + return IsValidForContainer(format, validForVp9Mkv) + } + return IsValidForContainer(format, validForVp9) + case Hevc: + if forceHEVC { + if forceMKV { + return IsValidForContainer(format, validForHevcMkv) + } + return IsValidForContainer(format, validForHevc) + } + } + return false +} + type VideoFile struct { JSON FFProbeJSON AudioStream *FFProbeStream @@ -98,7 +265,11 @@ func parse(filePath string, probeJSON *FFProbeJSON) (*VideoFile, error) { result.Container = probeJSON.Format.FormatName duration, _ := strconv.ParseFloat(probeJSON.Format.Duration, 64) result.Duration = math.Round(duration*100) / 100 - fileStat, _ := os.Stat(filePath) + fileStat, err := os.Stat(filePath) + if err != nil { + logger.Errorf("Error statting file: %v", err) + return nil, err + } result.Size = fileStat.Size() result.StartTime, _ = strconv.ParseFloat(probeJSON.Format.StartTime, 64) result.CreationTime = probeJSON.Format.Tags.CreationTime.Time diff --git a/pkg/ffmpeg/media_detection.go b/pkg/ffmpeg/media_detection.go new file mode 100644 index 000000000..4de7e4ba6 --- /dev/null +++ b/pkg/ffmpeg/media_detection.go @@ -0,0 +1,66 @@ +package ffmpeg + +import ( + "bytes" + "github.com/stashapp/stash/pkg/logger" + "os" +) + +// detect file format from magic file number +// https://github.com/lex-r/filetype/blob/73c10ad714e3b8ecf5cd1564c882ed6d440d5c2d/matchers/video.go + +func mkv(buf []byte) bool { + return len(buf) > 3 && + buf[0] == 0x1A && buf[1] == 0x45 && + buf[2] == 0xDF && buf[3] == 0xA3 && + containsMatroskaSignature(buf, []byte{'m', 'a', 't', 'r', 'o', 's', 'k', 'a'}) +} + +func webm(buf []byte) bool { + return len(buf) > 3 && + buf[0] == 0x1A && buf[1] == 0x45 && + buf[2] == 0xDF && buf[3] == 0xA3 && + containsMatroskaSignature(buf, []byte{'w', 'e', 'b', 'm'}) +} + +func containsMatroskaSignature(buf, subType []byte) bool { + limit := 4096 + if len(buf) < limit { + limit = len(buf) + } + + index := bytes.Index(buf[:limit], subType) + if index < 3 { + return false + } + + return buf[index-3] == 0x42 && buf[index-2] == 0x82 +} + +//returns container as string ("" on error or no match) +//implements only mkv or webm as ffprobe can't distinguish between them +//and not all browsers support mkv +func MagicContainer(file_path string) Container { + file, err := os.Open(file_path) + if err != nil { + logger.Errorf("[magicfile] %v", err) + return "" + } + + defer file.Close() + + buf := make([]byte, 4096) + _, err = file.Read(buf) + if err != nil { + logger.Errorf("[magicfile] %v", err) + return "" + } + + if webm(buf) { + return Webm + } + if mkv(buf) { + return Matroska + } + return "" +} diff --git a/pkg/manager/config/config.go b/pkg/manager/config/config.go index 490094966..f21493329 100644 --- a/pkg/manager/config/config.go +++ b/pkg/manager/config/config.go @@ -19,10 +19,12 @@ const Metadata = "metadata" const Downloads = "downloads" const Username = "username" const Password = "password" +const MaxSessionAge = "max_session_age" + +const DefaultMaxSessionAge = 60 * 60 * 1 // 1 hours const Database = "database" -const ScrapersPath = "scrapers_path" const Exclude = "exclude" const MaxTranscodeSize = "max_transcode_size" @@ -32,6 +34,19 @@ const Host = "host" const Port = "port" const ExternalHost = "external_host" +// key used to sign JWT tokens +const JWTSignKey = "jwt_secret_key" + +// key used for session store +const SessionStoreKey = "session_store_key" + +// scraping options +const ScrapersPath = "scrapers_path" +const ScraperUserAgent = "scraper_user_agent" + +// i18n +const Language = "language" + // Interface options const SoundOnPreview = "sound_on_preview" const WallShowTitle = "wall_show_title" @@ -39,6 +54,11 @@ const MaximumLoopDuration = "maximum_loop_duration" const AutostartVideo = "autostart_video" const ShowStudioAsText = "show_studio_as_text" const CSSEnabled = "cssEnabled" +const WallPlayback = "wall_playback" + +// Playback force codec,container +const ForceMKV = "forceMKV" +const ForceHEVC = "forceHEVC" // Logging options const LogFile = "logFile" @@ -83,6 +103,14 @@ func GetDatabasePath() string { return viper.GetString(Database) } +func GetJWTSignKey() []byte { + return []byte(viper.GetString(JWTSignKey)) +} + +func GetSessionStoreKey() []byte { + return []byte(viper.GetString(SessionStoreKey)) +} + func GetDefaultScrapersPath() string { // default to the same directory as the config file configFileUsed := viper.ConfigFileUsed() @@ -97,10 +125,25 @@ func GetExcludes() []string { return viper.GetStringSlice(Exclude) } +func GetLanguage() string { + ret := viper.GetString(Language) + + // default to English + if ret == "" { + return "en-US" + } + + return ret +} + func GetScrapersPath() string { return viper.GetString(ScrapersPath) } +func GetScraperUserAgent() string { + return viper.GetString(ScraperUserAgent) +} + func GetHost() string { return viper.GetString(Host) } @@ -181,6 +224,13 @@ func ValidateCredentials(username string, password string) bool { return username == authUser && err == nil } +// GetMaxSessionAge gets the maximum age for session cookies, in seconds. +// Session cookie expiry times are refreshed every request. +func GetMaxSessionAge() int { + viper.SetDefault(MaxSessionAge, DefaultMaxSessionAge) + return viper.GetInt(MaxSessionAge) +} + // Interface options func GetSoundOnPreview() bool { viper.SetDefault(SoundOnPreview, true) @@ -192,6 +242,11 @@ func GetWallShowTitle() bool { return viper.GetBool(WallShowTitle) } +func GetWallPlayback() string { + viper.SetDefault(WallPlayback, "video") + return viper.GetString(WallPlayback) +} + func GetMaximumLoopDuration() int { viper.SetDefault(MaximumLoopDuration, 0) return viper.GetInt(MaximumLoopDuration) @@ -246,6 +301,15 @@ func GetCSSEnabled() bool { return viper.GetBool(CSSEnabled) } +// force codec,container +func GetForceMKV() bool { + return viper.GetBool(ForceMKV) +} + +func GetForceHEVC() bool { + return viper.GetBool(ForceHEVC) +} + // GetLogFile returns the filename of the file to output logs to. // An empty string means that file logging will be disabled. func GetLogFile() string { @@ -294,3 +358,21 @@ func IsValid() bool { // TODO: check valid paths return setPaths } + +// SetInitialConfig fills in missing required config fields +func SetInitialConfig() error { + // generate some api keys + const apiKeyLength = 32 + + if string(GetJWTSignKey()) == "" { + signKey := utils.GenerateRandomKey(apiKeyLength) + Set(JWTSignKey, signKey) + } + + if string(GetSessionStoreKey()) == "" { + sessionStoreKey := utils.GenerateRandomKey(apiKeyLength) + Set(SessionStoreKey, sessionStoreKey) + } + + return Write() +} diff --git a/pkg/manager/exclude_files.go b/pkg/manager/exclude_files.go index 818cb25f1..6d5a28f9f 100644 --- a/pkg/manager/exclude_files.go +++ b/pkg/manager/exclude_files.go @@ -1,9 +1,10 @@ package manager import ( - "github.com/stashapp/stash/pkg/logger" "regexp" "strings" + + "github.com/stashapp/stash/pkg/logger" ) func excludeFiles(files []string, patterns []string) ([]string, int) { @@ -37,21 +38,13 @@ func excludeFiles(files []string, patterns []string) ([]string, int) { } func matchFile(file string, patterns []string) bool { - if patterns == nil { - logger.Infof("No exclude patterns in config.") - - } else { + if patterns != nil { fileRegexps := generateRegexps(patterns) - if len(fileRegexps) == 0 { - return false - } - for _, regPattern := range fileRegexps { if regPattern.MatchString(strings.ToLower(file)) { return true } - } } diff --git a/pkg/manager/filename_parser.go b/pkg/manager/filename_parser.go index 869948f46..eae6ba365 100644 --- a/pkg/manager/filename_parser.go +++ b/pkg/manager/filename_parser.go @@ -7,6 +7,7 @@ import ( "regexp" "strconv" "strings" + "time" "github.com/stashapp/stash/pkg/models" @@ -87,8 +88,10 @@ func initParserFields() { //I = new ParserField("i", undefined, "Matches any ignored word", false); ret["d"] = newParserField("d", `(?:\.|-|_)`, false) + ret["rating"] = newParserField("rating", `\d`, true) ret["performer"] = newParserField("performer", ".*", true) ret["studio"] = newParserField("studio", ".*", true) + ret["movie"] = newParserField("movie", ".*", true) ret["tag"] = newParserField("tag", ".*", true) // date fields @@ -96,6 +99,7 @@ func initParserFields() { ret["yyyy"] = newParserField("yyyy", `\d{4}`, true) ret["yy"] = newParserField("yy", `\d{2}`, true) ret["mm"] = newParserField("mm", `\d{2}`, true) + ret["mmm"] = newParserField("mmm", `\w{3}`, true) ret["dd"] = newParserField("dd", `\d{2}`, true) ret["yyyymmdd"] = newFullDateParserField("yyyymmdd", `\d{8}`) ret["yymmdd"] = newFullDateParserField("yymmdd", `\d{6}`) @@ -204,6 +208,7 @@ type sceneHolder struct { mm string dd string performers []string + movies []string studio string tags []string } @@ -222,6 +227,10 @@ func newSceneHolder(scene *models.Scene) *sceneHolder { return &ret } +func validateRating(rating int) bool { + return rating >= 1 && rating <= 5 +} + func validateDate(dateStr string) bool { splits := strings.Split(dateStr, "-") if len(splits) != 3 { @@ -283,6 +292,20 @@ func (h *sceneHolder) setDate(field *parserField, value string) { } } +func mmmToMonth(mmm string) string { + format := "02-Jan-2006" + dateStr := "01-" + mmm + "-2000" + t, err := time.Parse(format, dateStr) + + if err != nil { + return "" + } + + // expect month in two-digit format + format = "01-02-2006" + return t.Format(format)[0:2] +} + func (h *sceneHolder) setField(field parserField, value interface{}) { if field.isFullDateField { h.setDate(&field, value.(string)) @@ -302,27 +325,35 @@ func (h *sceneHolder) setField(field parserField, value interface{}) { Valid: true, } } + case "rating": + rating, _ := strconv.Atoi(value.(string)) + if validateRating(rating) { + h.result.Rating = sql.NullInt64{ + Int64: int64(rating), + Valid: true, + } + } case "performer": // add performer to list h.performers = append(h.performers, value.(string)) case "studio": h.studio = value.(string) + case "movie": + h.movies = append(h.movies, value.(string)) case "tag": h.tags = append(h.tags, value.(string)) case "yyyy": h.yyyy = value.(string) - break case "yy": v := value.(string) v = "20" + v h.yyyy = v - break + case "mmm": + h.mm = mmmToMonth(value.(string)) case "mm": h.mm = value.(string) - break case "dd": h.dd = value.(string) - break } } @@ -374,7 +405,7 @@ func (m parseMapper) parse(scene *models.Scene) *sceneHolder { } type performerQueryer interface { - FindByNames(names []string, tx *sqlx.Tx) ([]*models.Performer, error) + FindByNames(names []string, tx *sqlx.Tx, nocase bool) ([]*models.Performer, error) } type sceneQueryer interface { @@ -382,11 +413,15 @@ type sceneQueryer interface { } type tagQueryer interface { - FindByName(name string, tx *sqlx.Tx) (*models.Tag, error) + FindByName(name string, tx *sqlx.Tx, nocase bool) (*models.Tag, error) } type studioQueryer interface { - FindByName(name string, tx *sqlx.Tx) (*models.Studio, error) + FindByName(name string, tx *sqlx.Tx, nocase bool) (*models.Studio, error) +} + +type movieQueryer interface { + FindByName(name string, tx *sqlx.Tx, nocase bool) (*models.Movie, error) } type SceneFilenameParser struct { @@ -396,12 +431,14 @@ type SceneFilenameParser struct { whitespaceRE *regexp.Regexp performerCache map[string]*models.Performer studioCache map[string]*models.Studio + movieCache map[string]*models.Movie tagCache map[string]*models.Tag performerQuery performerQueryer sceneQuery sceneQueryer tagQuery tagQueryer studioQuery studioQueryer + movieQuery movieQueryer } func NewSceneFilenameParser(filter *models.FindFilterType, config models.SceneParserInput) *SceneFilenameParser { @@ -413,6 +450,7 @@ func NewSceneFilenameParser(filter *models.FindFilterType, config models.ScenePa p.performerCache = make(map[string]*models.Performer) p.studioCache = make(map[string]*models.Studio) + p.movieCache = make(map[string]*models.Movie) p.tagCache = make(map[string]*models.Tag) p.initWhiteSpaceRegex() @@ -429,6 +467,9 @@ func NewSceneFilenameParser(filter *models.FindFilterType, config models.ScenePa studioQuery := models.NewStudioQueryBuilder() p.studioQuery = &studioQuery + movieQuery := models.NewMovieQueryBuilder() + p.movieQuery = &movieQuery + return p } @@ -505,7 +546,7 @@ func (p *SceneFilenameParser) queryPerformer(performerName string) *models.Perfo } // perform an exact match and grab the first - performers, _ := p.performerQuery.FindByNames([]string{performerName}, nil) + performers, _ := p.performerQuery.FindByNames([]string{performerName}, nil, true) var ret *models.Performer if len(performers) > 0 { @@ -527,7 +568,7 @@ func (p *SceneFilenameParser) queryStudio(studioName string) *models.Studio { return ret } - ret, _ := p.studioQuery.FindByName(studioName, nil) + ret, _ := p.studioQuery.FindByName(studioName, nil, true) // add result to cache p.studioCache[studioName] = ret @@ -535,6 +576,23 @@ func (p *SceneFilenameParser) queryStudio(studioName string) *models.Studio { return ret } +func (p *SceneFilenameParser) queryMovie(movieName string) *models.Movie { + // massage the movie name + movieName = delimiterRE.ReplaceAllString(movieName, " ") + + // check cache first + if ret, found := p.movieCache[movieName]; found { + return ret + } + + ret, _ := p.movieQuery.FindByName(movieName, nil, true) + + // add result to cache + p.movieCache[movieName] = ret + + return ret +} + func (p *SceneFilenameParser) queryTag(tagName string) *models.Tag { // massage the performer name tagName = delimiterRE.ReplaceAllString(tagName, " ") @@ -545,7 +603,7 @@ func (p *SceneFilenameParser) queryTag(tagName string) *models.Tag { } // match tag name exactly - ret, _ := p.tagQuery.FindByName(tagName, nil) + ret, _ := p.tagQuery.FindByName(tagName, nil, true) // add result to cache p.tagCache[tagName] = ret @@ -596,6 +654,24 @@ func (p *SceneFilenameParser) setStudio(h sceneHolder, result *models.SceneParse } } +func (p *SceneFilenameParser) setMovies(h sceneHolder, result *models.SceneParserResult) { + // query for each movie + moviesSet := make(map[int]bool) + for _, movieName := range h.movies { + if movieName != "" { + movie := p.queryMovie(movieName) + if movie != nil { + if _, found := moviesSet[movie.ID]; !found { + result.Movies = append(result.Movies, &models.SceneMovieID{ + MovieID: strconv.Itoa(movie.ID), + }) + moviesSet[movie.ID] = true + } + } + } + } +} + func (p *SceneFilenameParser) setParserResult(h sceneHolder, result *models.SceneParserResult) { if h.result.Title.Valid { title := h.result.Title.String @@ -612,6 +688,11 @@ func (p *SceneFilenameParser) setParserResult(h sceneHolder, result *models.Scen result.Date = &h.result.Date.String } + if h.result.Rating.Valid { + rating := int(h.result.Rating.Int64) + result.Rating = &rating + } + if len(h.performers) > 0 { p.setPerformers(h, result) } @@ -619,4 +700,9 @@ func (p *SceneFilenameParser) setParserResult(h sceneHolder, result *models.Scen p.setTags(h, result) } p.setStudio(h, result) + + if len(h.movies) > 0 { + p.setMovies(h, result) + } + } diff --git a/pkg/manager/generator_preview.go b/pkg/manager/generator_preview.go index 5043ce349..f91fdf956 100644 --- a/pkg/manager/generator_preview.go +++ b/pkg/manager/generator_preview.go @@ -16,9 +16,14 @@ type PreviewGenerator struct { VideoFilename string ImageFilename string OutputDirectory string + + GenerateVideo bool + GenerateImage bool + + PreviewPreset string } -func NewPreviewGenerator(videoFile ffmpeg.VideoFile, videoFilename string, imageFilename string, outputDirectory string) (*PreviewGenerator, error) { +func NewPreviewGenerator(videoFile ffmpeg.VideoFile, videoFilename string, imageFilename string, outputDirectory string, generateVideo bool, generateImage bool, previewPreset string) (*PreviewGenerator, error) { exists, err := utils.FileExists(videoFile.Path) if !exists { return nil, err @@ -37,6 +42,9 @@ func NewPreviewGenerator(videoFile ffmpeg.VideoFile, videoFilename string, image VideoFilename: videoFilename, ImageFilename: imageFilename, OutputDirectory: outputDirectory, + GenerateVideo: generateVideo, + GenerateImage: generateImage, + PreviewPreset: previewPreset, }, nil } @@ -47,11 +55,16 @@ func (g *PreviewGenerator) Generate() error { if err := g.generateConcatFile(); err != nil { return err } - if err := g.generateVideo(&encoder); err != nil { - return err + + if g.GenerateVideo { + if err := g.generateVideo(&encoder); err != nil { + return err + } } - if err := g.generateImage(&encoder); err != nil { - return err + if g.GenerateImage { + if err := g.generateImage(&encoder); err != nil { + return err + } } return nil } @@ -91,7 +104,7 @@ func (g *PreviewGenerator) generateVideo(encoder *ffmpeg.Encoder) error { Width: 640, OutputPath: chunkOutputPath, } - encoder.ScenePreviewVideoChunk(g.Info.VideoFile, options) + encoder.ScenePreviewVideoChunk(g.Info.VideoFile, options, g.PreviewPreset) } videoOutputPath := filepath.Join(g.OutputDirectory, g.VideoFilename) diff --git a/pkg/manager/json_utils.go b/pkg/manager/json_utils.go index af7205f52..384f5937c 100644 --- a/pkg/manager/json_utils.go +++ b/pkg/manager/json_utils.go @@ -38,6 +38,14 @@ func (jp *jsonUtils) saveStudio(checksum string, studio *jsonschema.Studio) erro return jsonschema.SaveStudioFile(instance.Paths.JSON.StudioJSONPath(checksum), studio) } +func (jp *jsonUtils) getMovie(checksum string) (*jsonschema.Movie, error) { + return jsonschema.LoadMovieFile(instance.Paths.JSON.MovieJSONPath(checksum)) +} + +func (jp *jsonUtils) saveMovie(checksum string, movie *jsonschema.Movie) error { + return jsonschema.SaveMovieFile(instance.Paths.JSON.MovieJSONPath(checksum), movie) +} + func (jp *jsonUtils) getScene(checksum string) (*jsonschema.Scene, error) { return jsonschema.LoadSceneFile(instance.Paths.JSON.SceneJSONPath(checksum)) } diff --git a/pkg/manager/jsonschema/mappings.go b/pkg/manager/jsonschema/mappings.go index 7a41ebc92..621ffc024 100644 --- a/pkg/manager/jsonschema/mappings.go +++ b/pkg/manager/jsonschema/mappings.go @@ -1,8 +1,8 @@ package jsonschema import ( - "encoding/json" "fmt" + "github.com/json-iterator/go" "os" ) @@ -19,6 +19,7 @@ type PathMapping struct { type Mappings struct { Performers []NameMapping `json:"performers"` Studios []NameMapping `json:"studios"` + Movies []NameMapping `json:"movies"` Galleries []PathMapping `json:"galleries"` Scenes []PathMapping `json:"scenes"` } @@ -30,6 +31,7 @@ func LoadMappingsFile(filePath string) (*Mappings, error) { if err != nil { return nil, err } + var json = jsoniter.ConfigCompatibleWithStandardLibrary jsonParser := json.NewDecoder(file) err = jsonParser.Decode(&mappings) if err != nil { diff --git a/pkg/manager/jsonschema/movie.go b/pkg/manager/jsonschema/movie.go new file mode 100644 index 000000000..ae062acb6 --- /dev/null +++ b/pkg/manager/jsonschema/movie.go @@ -0,0 +1,47 @@ +package jsonschema + +import ( + "fmt" + "github.com/json-iterator/go" + "os" + + "github.com/stashapp/stash/pkg/models" +) + +type Movie struct { + Name string `json:"name,omitempty"` + Aliases string `json:"aliases,omitempty"` + Duration int `json:"duration,omitempty"` + Date string `json:"date,omitempty"` + Rating int `json:"rating,omitempty"` + Director string `json:"director,omitempty"` + Synopsis string `json:"sypnopsis,omitempty"` + FrontImage string `json:"front_image,omitempty"` + BackImage string `json:"back_image,omitempty"` + URL string `json:"url,omitempty"` + CreatedAt models.JSONTime `json:"created_at,omitempty"` + UpdatedAt models.JSONTime `json:"updated_at,omitempty"` +} + +func LoadMovieFile(filePath string) (*Movie, error) { + var movie Movie + file, err := os.Open(filePath) + defer file.Close() + if err != nil { + return nil, err + } + var json = jsoniter.ConfigCompatibleWithStandardLibrary + jsonParser := json.NewDecoder(file) + err = jsonParser.Decode(&movie) + if err != nil { + return nil, err + } + return &movie, nil +} + +func SaveMovieFile(filePath string, movie *Movie) error { + if movie == nil { + return fmt.Errorf("movie must not be nil") + } + return marshalToFile(filePath, movie) +} diff --git a/pkg/manager/jsonschema/performer.go b/pkg/manager/jsonschema/performer.go index 44aec069a..52122dd0a 100644 --- a/pkg/manager/jsonschema/performer.go +++ b/pkg/manager/jsonschema/performer.go @@ -1,14 +1,16 @@ package jsonschema import ( - "encoding/json" "fmt" - "github.com/stashapp/stash/pkg/models" + "github.com/json-iterator/go" "os" + + "github.com/stashapp/stash/pkg/models" ) type Performer struct { Name string `json:"name,omitempty"` + Gender string `json:"gender,omitempty"` URL string `json:"url,omitempty"` Twitter string `json:"twitter,omitempty"` Instagram string `json:"instagram,omitempty"` @@ -36,6 +38,7 @@ func LoadPerformerFile(filePath string) (*Performer, error) { if err != nil { return nil, err } + var json = jsoniter.ConfigCompatibleWithStandardLibrary jsonParser := json.NewDecoder(file) err = jsonParser.Decode(&performer) if err != nil { diff --git a/pkg/manager/jsonschema/scene.go b/pkg/manager/jsonschema/scene.go index 0f4098571..b08c8a844 100644 --- a/pkg/manager/jsonschema/scene.go +++ b/pkg/manager/jsonschema/scene.go @@ -1,10 +1,11 @@ package jsonschema import ( - "encoding/json" "fmt" - "github.com/stashapp/stash/pkg/models" + "github.com/json-iterator/go" "os" + + "github.com/stashapp/stash/pkg/models" ) type SceneMarker struct { @@ -21,21 +22,29 @@ type SceneFile struct { Duration string `json:"duration"` VideoCodec string `json:"video_codec"` AudioCodec string `json:"audio_codec"` + Format string `json:"format"` Width int `json:"width"` Height int `json:"height"` Framerate string `json:"framerate"` Bitrate int `json:"bitrate"` } +type SceneMovie struct { + MovieName string `json:"movieName,omitempty"` + SceneIndex int `json:"scene_index,omitempty"` +} + type Scene struct { Title string `json:"title,omitempty"` Studio string `json:"studio,omitempty"` URL string `json:"url,omitempty"` Date string `json:"date,omitempty"` Rating int `json:"rating,omitempty"` + OCounter int `json:"o_counter,omitempty"` Details string `json:"details,omitempty"` Gallery string `json:"gallery,omitempty"` Performers []string `json:"performers,omitempty"` + Movies []SceneMovie `json:"movies,omitempty"` Tags []string `json:"tags,omitempty"` Markers []SceneMarker `json:"markers,omitempty"` File *SceneFile `json:"file,omitempty"` @@ -51,6 +60,7 @@ func LoadSceneFile(filePath string) (*Scene, error) { if err != nil { return nil, err } + var json = jsoniter.ConfigCompatibleWithStandardLibrary jsonParser := json.NewDecoder(file) err = jsonParser.Decode(&scene) if err != nil { diff --git a/pkg/manager/jsonschema/scraped.go b/pkg/manager/jsonschema/scraped.go index 26684a85d..5ac26b676 100644 --- a/pkg/manager/jsonschema/scraped.go +++ b/pkg/manager/jsonschema/scraped.go @@ -1,8 +1,8 @@ package jsonschema import ( - "encoding/json" "fmt" + "github.com/json-iterator/go" "github.com/stashapp/stash/pkg/models" "os" ) @@ -31,6 +31,7 @@ func LoadScrapedFile(filePath string) ([]ScrapedItem, error) { if err != nil { return nil, err } + var json = jsoniter.ConfigCompatibleWithStandardLibrary jsonParser := json.NewDecoder(file) err = jsonParser.Decode(&scraped) if err != nil { diff --git a/pkg/manager/jsonschema/studio.go b/pkg/manager/jsonschema/studio.go index 75e50d302..246c36050 100644 --- a/pkg/manager/jsonschema/studio.go +++ b/pkg/manager/jsonschema/studio.go @@ -1,8 +1,8 @@ package jsonschema import ( - "encoding/json" "fmt" + "github.com/json-iterator/go" "github.com/stashapp/stash/pkg/models" "os" ) @@ -22,6 +22,7 @@ func LoadStudioFile(filePath string) (*Studio, error) { if err != nil { return nil, err } + var json = jsoniter.ConfigCompatibleWithStandardLibrary jsonParser := json.NewDecoder(file) err = jsonParser.Decode(&studio) if err != nil { diff --git a/pkg/manager/jsonschema/utils.go b/pkg/manager/jsonschema/utils.go index 18e180cf3..cbe3cd3ad 100644 --- a/pkg/manager/jsonschema/utils.go +++ b/pkg/manager/jsonschema/utils.go @@ -2,7 +2,8 @@ package jsonschema import ( "bytes" - "encoding/json" + "github.com/json-iterator/go" + "io/ioutil" "time" ) @@ -25,6 +26,7 @@ func marshalToFile(filePath string, j interface{}) error { func encode(j interface{}) ([]byte, error) { buffer := &bytes.Buffer{} + var json = jsoniter.ConfigCompatibleWithStandardLibrary encoder := json.NewEncoder(buffer) encoder.SetEscapeHTML(false) encoder.SetIndent("", " ") diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index b75ff4d51..f3bef5530 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -154,9 +154,6 @@ func (s *singleton) RefreshConfig() { _ = utils.EnsureDir(s.Paths.Generated.Markers) _ = utils.EnsureDir(s.Paths.Generated.Transcodes) - _ = utils.EnsureDir(s.Paths.JSON.Performers) - _ = utils.EnsureDir(s.Paths.JSON.Scenes) - _ = utils.EnsureDir(s.Paths.JSON.Galleries) - _ = utils.EnsureDir(s.Paths.JSON.Studios) + paths.EnsureJSONDirs() } } diff --git a/pkg/manager/manager_tasks.go b/pkg/manager/manager_tasks.go index db6da95c4..70d83c09a 100644 --- a/pkg/manager/manager_tasks.go +++ b/pkg/manager/manager_tasks.go @@ -1,17 +1,44 @@ package manager import ( + "path/filepath" + "strconv" + "sync" + "time" + "github.com/bmatcuk/doublestar" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/utils" - "path/filepath" - "strconv" - "sync" - "time" ) +var extensionsToScan = []string{"zip", "m4v", "mp4", "mov", "wmv", "avi", "mpg", "mpeg", "rmvb", "rm", "flv", "asf", "mkv", "webm"} +var extensionsGallery = []string{"zip"} + +func constructGlob() string { // create a sequence for glob doublestar from our extensions + extLen := len(extensionsToScan) + glb := "{" + for i := 0; i < extLen-1; i++ { // append extensions and commas + glb += extensionsToScan[i] + "," + } + if extLen >= 1 { // append last extension without comma + glb += extensionsToScan[extLen-1] + } + glb += "}" + return glb + +} + +func isGallery(pathname string) bool { + for _, ext := range extensionsGallery { + if filepath.Ext(pathname) == "."+ext { + return true + } + } + return false +} + type TaskStatus struct { Status JobStatus Progress float64 @@ -67,7 +94,7 @@ func (s *singleton) Scan(useFileMetadata bool) { var results []string for _, path := range config.GetStashPaths() { - globPath := filepath.Join(path, "**/*.{zip,m4v,mp4,mov,wmv,avi,mpg,mpeg,rmvb,rm,flv,asf,mkv,webm}") // TODO: Make this configurable + globPath := filepath.Join(path, "**/*."+constructGlob()) globResults, _ := doublestar.Glob(globPath) results = append(results, globResults...) } @@ -96,6 +123,15 @@ func (s *singleton) Scan(useFileMetadata bool) { } logger.Info("Finished scan") + for _, path := range results { + if isGallery(path) { + wg.Add(1) + task := ScanTask{FilePath: path, UseFileMetadata: false} + go task.associateGallery(&wg) + wg.Wait() + } + } + logger.Info("Finished gallery association") }() } @@ -135,7 +171,7 @@ func (s *singleton) Export() { }() } -func (s *singleton) Generate(sprites bool, previews bool, markers bool, transcodes bool) { +func (s *singleton) Generate(sprites bool, previews bool, previewPreset *models.PreviewPreset, imagePreviews bool, markers bool, transcodes bool, thumbnails bool) { if s.Status.Status != Idle { return } @@ -143,13 +179,21 @@ func (s *singleton) Generate(sprites bool, previews bool, markers bool, transcod s.Status.indefiniteProgress() qb := models.NewSceneQueryBuilder() + qg := models.NewGalleryQueryBuilder() //this.job.total = await ObjectionUtils.getCount(Scene); instance.Paths.Generated.EnsureTmpDir() + preset := string(models.PreviewPresetSlow) + if previewPreset != nil && previewPreset.IsValid() { + preset = string(*previewPreset) + } + go func() { defer s.returnToIdleState() scenes, err := qb.All() + var galleries []*models.Gallery + if err != nil { logger.Errorf("failed to get scenes for generate") return @@ -158,18 +202,27 @@ func (s *singleton) Generate(sprites bool, previews bool, markers bool, transcod delta := utils.Btoi(sprites) + utils.Btoi(previews) + utils.Btoi(markers) + utils.Btoi(transcodes) var wg sync.WaitGroup s.Status.Progress = 0 - total := len(scenes) + lenScenes := len(scenes) + total := lenScenes + if thumbnails { + galleries, err = qg.All() + if err != nil { + logger.Errorf("failed to get galleries for generate") + return + } + total += len(galleries) + } if s.Status.stopping { logger.Info("Stopping due to user request") return } - totalsNeeded := s.neededGenerate(scenes, sprites, previews, markers, transcodes) + totalsNeeded := s.neededGenerate(scenes, sprites, previews, imagePreviews, markers, transcodes) if totalsNeeded == nil { logger.Infof("Taking too long to count content. Skipping...") logger.Infof("Generating content") } else { - logger.Infof("Generating %d sprites %d previews %d markers %d transcodes", totalsNeeded.sprites, totalsNeeded.previews, totalsNeeded.markers, totalsNeeded.transcodes) + logger.Infof("Generating %d sprites %d previews %d image previews %d markers %d transcodes", totalsNeeded.sprites, totalsNeeded.previews, totalsNeeded.imagePreviews, totalsNeeded.markers, totalsNeeded.transcodes) } for i, scene := range scenes { s.Status.setProgress(i, total) @@ -196,7 +249,7 @@ func (s *singleton) Generate(sprites bool, previews bool, markers bool, transcod } if previews { - task := GeneratePreviewTask{Scene: *scene} + task := GeneratePreviewTask{Scene: *scene, ImagePreview: imagePreviews, PreviewPreset: preset} go task.Start(&wg) } @@ -212,6 +265,77 @@ func (s *singleton) Generate(sprites bool, previews bool, markers bool, transcod wg.Wait() } + + if thumbnails { + logger.Infof("Generating thumbnails for the galleries") + for i, gallery := range galleries { + s.Status.setProgress(lenScenes+i, total) + if s.Status.stopping { + logger.Info("Stopping due to user request") + return + } + + if gallery == nil { + logger.Errorf("nil gallery, skipping generate") + continue + } + + wg.Add(1) + task := GenerateGthumbsTask{Gallery: *gallery} + go task.Start(&wg) + wg.Wait() + } + } + + logger.Infof("Generate finished") + }() +} + +func (s *singleton) GenerateDefaultScreenshot(sceneId string) { + s.generateScreenshot(sceneId, nil) +} + +func (s *singleton) GenerateScreenshot(sceneId string, at float64) { + s.generateScreenshot(sceneId, &at) +} + +// generate default screenshot if at is nil +func (s *singleton) generateScreenshot(sceneId string, at *float64) { + if s.Status.Status != Idle { + return + } + s.Status.SetStatus(Generate) + s.Status.indefiniteProgress() + + qb := models.NewSceneQueryBuilder() + instance.Paths.Generated.EnsureTmpDir() + + go func() { + defer s.returnToIdleState() + + sceneIdInt, err := strconv.Atoi(sceneId) + if err != nil { + logger.Errorf("Error parsing scene id %s: %s", sceneId, err.Error()) + return + } + + scene, err := qb.Find(sceneIdInt) + if err != nil || scene == nil { + logger.Errorf("failed to get scene for generate") + return + } + + task := GenerateScreenshotTask{ + Scene: *scene, + ScreenshotAt: at, + } + + var wg sync.WaitGroup + wg.Add(1) + go task.Start(&wg) + + wg.Wait() + logger.Infof("Generate finished") }() } @@ -390,6 +514,7 @@ func (s *singleton) Clean() { s.Status.indefiniteProgress() qb := models.NewSceneQueryBuilder() + gqb := models.NewGalleryQueryBuilder() go func() { defer s.returnToIdleState() @@ -400,6 +525,12 @@ func (s *singleton) Clean() { return } + galleries, err := gqb.All() + if err != nil { + logger.Errorf("failed to fetch list of galleries for cleaning") + return + } + if s.Status.stopping { logger.Info("Stopping due to user request") return @@ -407,7 +538,7 @@ func (s *singleton) Clean() { var wg sync.WaitGroup s.Status.Progress = 0 - total := len(scenes) + total := len(scenes) + len(galleries) for i, scene := range scenes { s.Status.setProgress(i, total) if s.Status.stopping { @@ -422,7 +553,26 @@ func (s *singleton) Clean() { wg.Add(1) - task := CleanTask{Scene: *scene} + task := CleanTask{Scene: scene} + go task.Start(&wg) + wg.Wait() + } + + for i, gallery := range galleries { + s.Status.setProgress(len(scenes)+i, total) + if s.Status.stopping { + logger.Info("Stopping due to user request") + return + } + + if gallery == nil { + logger.Errorf("nil gallery, skipping Clean") + continue + } + + wg.Add(1) + + task := CleanTask{Gallery: gallery} go task.Start(&wg) wg.Wait() } @@ -445,7 +595,7 @@ func (s *singleton) returnToIdleState() { } func (s *singleton) neededScan(paths []string) int64 { - var neededScans int64 = 0 + var neededScans int64 for _, path := range paths { task := ScanTask{FilePath: path} @@ -457,23 +607,24 @@ func (s *singleton) neededScan(paths []string) int64 { } type totalsGenerate struct { - sprites int64 - previews int64 - markers int64 - transcodes int64 + sprites int64 + previews int64 + imagePreviews int64 + markers int64 + transcodes int64 } -func (s *singleton) neededGenerate(scenes []*models.Scene, sprites, previews, markers, transcodes bool) *totalsGenerate { +func (s *singleton) neededGenerate(scenes []*models.Scene, sprites, previews, imagePreviews, markers, transcodes bool) *totalsGenerate { var totals totalsGenerate - const timeoutSecs = 90 * time.Second + const timeout = 90 * time.Second // create a control channel through which to signal the counting loop when the timeout is reached chTimeout := make(chan struct{}) //run the timeout function in a separate thread go func() { - time.Sleep(timeoutSecs) + time.Sleep(timeout) chTimeout <- struct{}{} }() @@ -488,10 +639,13 @@ func (s *singleton) neededGenerate(scenes []*models.Scene, sprites, previews, ma } if previews { - task := GeneratePreviewTask{Scene: *scene} - if !task.doesPreviewExist(task.Scene.Checksum) { + task := GeneratePreviewTask{Scene: *scene, ImagePreview: imagePreviews} + if !task.doesVideoPreviewExist(task.Scene.Checksum) { totals.previews++ } + if imagePreviews && !task.doesImagePreviewExist(task.Scene.Checksum) { + totals.imagePreviews++ + } } if markers { diff --git a/pkg/manager/paths/paths_gallery.go b/pkg/manager/paths/paths_gallery.go index 4db60e311..9e4665c95 100644 --- a/pkg/manager/paths/paths_gallery.go +++ b/pkg/manager/paths/paths_gallery.go @@ -1,12 +1,18 @@ package paths import ( + "fmt" "github.com/stashapp/stash/pkg/manager/config" + "github.com/stashapp/stash/pkg/utils" "path/filepath" ) type galleryPaths struct{} +const thumbDir = "gthumbs" +const thumbDirDepth int = 2 +const thumbDirLength int = 2 // thumbDirDepth * thumbDirLength must be smaller than the length of checksum + func newGalleryPaths() *galleryPaths { return &galleryPaths{} } @@ -15,6 +21,19 @@ func (gp *galleryPaths) GetExtractedPath(checksum string) string { return filepath.Join(config.GetCachePath(), checksum) } +func GetGthumbCache() string { + return filepath.Join(config.GetCachePath(), thumbDir) +} + +func GetGthumbDir(checksum string) string { + return filepath.Join(config.GetCachePath(), thumbDir, utils.GetIntraDir(checksum, thumbDirDepth, thumbDirLength), checksum) +} + +func GetGthumbPath(checksum string, index int, width int) string { + fname := fmt.Sprintf("%s_%d_%d.jpg", checksum, index, width) + return filepath.Join(config.GetCachePath(), thumbDir, utils.GetIntraDir(checksum, thumbDirDepth, thumbDirLength), checksum, fname) +} + func (gp *galleryPaths) GetExtractedFilePath(checksum string, fileName string) string { return filepath.Join(config.GetCachePath(), checksum, fileName) } diff --git a/pkg/manager/paths/paths_json.go b/pkg/manager/paths/paths_json.go index 8344352a4..3f2ccbcb1 100644 --- a/pkg/manager/paths/paths_json.go +++ b/pkg/manager/paths/paths_json.go @@ -2,10 +2,13 @@ package paths import ( "github.com/stashapp/stash/pkg/manager/config" + "github.com/stashapp/stash/pkg/utils" "path/filepath" ) type jsonPaths struct { + Metadata string + MappingsFile string ScrapedFile string @@ -13,19 +16,37 @@ type jsonPaths struct { Scenes string Galleries string Studios string + Movies string } func newJSONPaths() *jsonPaths { jp := jsonPaths{} + jp.Metadata = config.GetMetadataPath() jp.MappingsFile = filepath.Join(config.GetMetadataPath(), "mappings.json") jp.ScrapedFile = filepath.Join(config.GetMetadataPath(), "scraped.json") jp.Performers = filepath.Join(config.GetMetadataPath(), "performers") jp.Scenes = filepath.Join(config.GetMetadataPath(), "scenes") jp.Galleries = filepath.Join(config.GetMetadataPath(), "galleries") jp.Studios = filepath.Join(config.GetMetadataPath(), "studios") + jp.Movies = filepath.Join(config.GetMetadataPath(), "movies") return &jp } +func GetJSONPaths() *jsonPaths { + jp := newJSONPaths() + return jp +} + +func EnsureJSONDirs() { + jsonPaths := GetJSONPaths() + utils.EnsureDir(jsonPaths.Metadata) + utils.EnsureDir(jsonPaths.Scenes) + utils.EnsureDir(jsonPaths.Galleries) + utils.EnsureDir(jsonPaths.Performers) + utils.EnsureDir(jsonPaths.Studios) + utils.EnsureDir(jsonPaths.Movies) +} + func (jp *jsonPaths) PerformerJSONPath(checksum string) string { return filepath.Join(jp.Performers, checksum+".json") } @@ -37,3 +58,7 @@ func (jp *jsonPaths) SceneJSONPath(checksum string) string { func (jp *jsonPaths) StudioJSONPath(checksum string) string { return filepath.Join(jp.Studios, checksum+".json") } + +func (jp *jsonPaths) MovieJSONPath(checksum string) string { + return filepath.Join(jp.Movies, checksum+".json") +} diff --git a/pkg/manager/scene.go b/pkg/manager/scene.go index 1bca4568f..9afb07221 100644 --- a/pkg/manager/scene.go +++ b/pkg/manager/scene.go @@ -122,6 +122,27 @@ func DeleteGeneratedSceneFiles(scene *models.Scene) { } } +func DeleteSceneMarkerFiles(scene *models.Scene, seconds int) { + videoPath := GetInstance().Paths.SceneMarkers.GetStreamPath(scene.Checksum, seconds) + imagePath := GetInstance().Paths.SceneMarkers.GetStreamPreviewImagePath(scene.Checksum, seconds) + + exists, _ := utils.FileExists(videoPath) + if exists { + err := os.Remove(videoPath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", videoPath, err.Error()) + } + } + + exists, _ = utils.FileExists(imagePath) + if exists { + err := os.Remove(imagePath) + if err != nil { + logger.Warnf("Could not delete file %s: %s", videoPath, err.Error()) + } + } +} + func DeleteSceneFile(scene *models.Scene) { // kill any running encoders KillRunningStreams(scene.Path) diff --git a/pkg/manager/screenshot.go b/pkg/manager/screenshot.go new file mode 100644 index 000000000..fc417ede7 --- /dev/null +++ b/pkg/manager/screenshot.go @@ -0,0 +1,16 @@ +package manager + +import ( + "github.com/stashapp/stash/pkg/ffmpeg" +) + +func makeScreenshot(probeResult ffmpeg.VideoFile, outputPath string, quality int, width int, time float64) { + encoder := ffmpeg.NewEncoder(instance.FFMPEGPath) + options := ffmpeg.ScreenshotOptions{ + OutputPath: outputPath, + Quality: quality, + Time: time, + Width: width, + } + encoder.Screenshot(probeResult, options) +} diff --git a/pkg/manager/task_autotag.go b/pkg/manager/task_autotag.go index 4e6e150cc..78f37ce69 100644 --- a/pkg/manager/task_autotag.go +++ b/pkg/manager/task_autotag.go @@ -24,12 +24,10 @@ func (t *AutoTagPerformerTask) Start(wg *sync.WaitGroup) { func getQueryRegex(name string) string { const separatorChars = `.\-_ ` // handle path separators - const endSeparatorChars = separatorChars + `\\/` const separator = `[` + separatorChars + `]` - const endSeparator = `[` + endSeparatorChars + `]` ret := strings.Replace(name, " ", separator+"*", -1) - ret = "(?:^|" + endSeparator + "+)" + ret + "(?:$|" + endSeparator + "+)" + ret = `(?:^|_|[^\w\d])` + ret + `(?:$|_|[^\w\d])` return ret } diff --git a/pkg/manager/task_autotag_test.go b/pkg/manager/task_autotag_test.go index 05221e399..1b302a94e 100644 --- a/pkg/manager/task_autotag_test.go +++ b/pkg/manager/task_autotag_test.go @@ -36,7 +36,15 @@ var testSeparators = []string{ " ", } -func generateNamePatterns(name string, separator string) []string { +var testEndSeparators = []string{ + "{", + "}", + "(", + ")", + ",", +} + +func generateNamePatterns(name, separator string) []string { var ret []string ret = append(ret, fmt.Sprintf("%s%saaa"+testExtension, name, separator)) ret = append(ret, fmt.Sprintf("aaa%s%s"+testExtension, separator, name)) @@ -152,13 +160,20 @@ func createScenes(tx *sqlx.Tx) error { // create the scenes var scenePatterns []string var falseScenePatterns []string - for _, separator := range testSeparators { + + separators := append(testSeparators, testEndSeparators...) + + for _, separator := range separators { scenePatterns = append(scenePatterns, generateNamePatterns(testName, separator)...) scenePatterns = append(scenePatterns, generateNamePatterns(strings.ToLower(testName), separator)...) + falseScenePatterns = append(falseScenePatterns, generateFalseNamePattern(testName, separator)) + } + + // add test cases for intra-name separators + for _, separator := range testSeparators { if separator != " " { scenePatterns = append(scenePatterns, generateNamePatterns(strings.Replace(testName, " ", separator, -1), separator)...) } - falseScenePatterns = append(falseScenePatterns, generateFalseNamePattern(testName, separator)) } for _, fn := range scenePatterns { diff --git a/pkg/manager/task_clean.go b/pkg/manager/task_clean.go index 580d3631a..8cca80bbd 100644 --- a/pkg/manager/task_clean.go +++ b/pkg/manager/task_clean.go @@ -2,33 +2,48 @@ package manager import ( "context" - "github.com/stashapp/stash/pkg/database" - "github.com/stashapp/stash/pkg/logger" - "github.com/stashapp/stash/pkg/manager/config" - "github.com/stashapp/stash/pkg/models" "os" "path/filepath" "strings" "sync" + + "github.com/stashapp/stash/pkg/database" + "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/manager/config" + "github.com/stashapp/stash/pkg/manager/paths" + "github.com/stashapp/stash/pkg/models" ) type CleanTask struct { - Scene models.Scene + Scene *models.Scene + Gallery *models.Gallery } func (t *CleanTask) Start(wg *sync.WaitGroup) { defer wg.Done() - if t.fileExists(t.Scene.Path) && t.pathInStash() { - logger.Debugf("File Found: %s", t.Scene.Path) - if matchFile(t.Scene.Path, config.GetExcludes()) { - logger.Infof("File matched regex. Cleaning: \"%s\"", t.Scene.Path) - t.deleteScene(t.Scene.ID) - } - } else { - logger.Infof("File not found. Cleaning: \"%s\"", t.Scene.Path) + if t.Scene != nil && t.shouldClean(t.Scene.Path) { t.deleteScene(t.Scene.ID) } + + if t.Gallery != nil && t.shouldClean(t.Gallery.Path) { + t.deleteGallery(t.Gallery.ID) + } +} + +func (t *CleanTask) shouldClean(path string) bool { + if t.fileExists(path) && t.pathInStash(path) { + logger.Debugf("File Found: %s", path) + if matchFile(path, config.GetExcludes()) { + logger.Infof("File matched regex. Cleaning: \"%s\"", path) + return true + } + } else { + logger.Infof("File not found. Cleaning: \"%s\"", path) + return true + } + + return false } func (t *CleanTask) deleteScene(sceneID int) { @@ -40,19 +55,43 @@ func (t *CleanTask) deleteScene(sceneID int) { err = DestroyScene(sceneID, tx) if err != nil { - logger.Infof("Error deleting scene from database: %s", err.Error()) + logger.Errorf("Error deleting scene from database: %s", err.Error()) tx.Rollback() return } if err := tx.Commit(); err != nil { - logger.Infof("Error deleting scene from database: %s", err.Error()) + logger.Errorf("Error deleting scene from database: %s", err.Error()) return } DeleteGeneratedSceneFiles(scene) } +func (t *CleanTask) deleteGallery(galleryID int) { + ctx := context.TODO() + qb := models.NewGalleryQueryBuilder() + tx := database.DB.MustBeginTx(ctx, nil) + + err := qb.Destroy(galleryID, tx) + + if err != nil { + logger.Errorf("Error deleting gallery from database: %s", err.Error()) + tx.Rollback() + return + } + + if err := tx.Commit(); err != nil { + logger.Errorf("Error deleting gallery from database: %s", err.Error()) + return + } + + pathErr := os.RemoveAll(paths.GetGthumbDir(t.Gallery.Checksum)) // remove cache dir of gallery + if pathErr != nil { + logger.Errorf("Error deleting gallery directory from cache: %s", pathErr) + } +} + func (t *CleanTask) fileExists(filename string) bool { info, err := os.Stat(filename) if os.IsNotExist(err) { @@ -61,19 +100,19 @@ func (t *CleanTask) fileExists(filename string) bool { return !info.IsDir() } -func (t *CleanTask) pathInStash() bool { +func (t *CleanTask) pathInStash(pathToCheck string) bool { for _, path := range config.GetStashPaths() { - rel, error := filepath.Rel(path, filepath.Dir(t.Scene.Path)) + rel, error := filepath.Rel(path, filepath.Dir(pathToCheck)) if error == nil { if !strings.HasPrefix(rel, ".."+string(filepath.Separator)) { - logger.Debugf("File %s belongs to stash path %s", t.Scene.Path, path) + logger.Debugf("File %s belongs to stash path %s", pathToCheck, path) return true } } } - logger.Debugf("File %s is out from stash path", t.Scene.Path) + logger.Debugf("File %s is out from stash path", pathToCheck) return false } diff --git a/pkg/manager/task_export.go b/pkg/manager/task_export.go index f9c883b26..27d8bb6cc 100644 --- a/pkg/manager/task_export.go +++ b/pkg/manager/task_export.go @@ -3,14 +3,18 @@ package manager import ( "context" "fmt" + "github.com/jmoiron/sqlx" "github.com/stashapp/stash/pkg/database" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/manager/jsonschema" + "github.com/stashapp/stash/pkg/manager/paths" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/utils" "math" + "runtime" "strconv" "sync" + "time" ) type ExportTask struct { @@ -20,46 +24,77 @@ type ExportTask struct { func (t *ExportTask) Start(wg *sync.WaitGroup) { defer wg.Done() - // @manager.total = Scene.count + Gallery.count + Performer.count + Studio.count + // @manager.total = Scene.count + Gallery.count + Performer.count + Studio.count + Movie.count + workerCount := runtime.GOMAXPROCS(0) // set worker count to number of cpus available t.Mappings = &jsonschema.Mappings{} t.Scraped = []jsonschema.ScrapedItem{} ctx := context.TODO() + startTime := time.Now() - t.ExportScenes(ctx) + paths.EnsureJSONDirs() + + t.ExportScenes(ctx, workerCount) t.ExportGalleries(ctx) - t.ExportPerformers(ctx) - t.ExportStudios(ctx) + t.ExportPerformers(ctx, workerCount) + t.ExportStudios(ctx, workerCount) + t.ExportMovies(ctx, workerCount) if err := instance.JSON.saveMappings(t.Mappings); err != nil { logger.Errorf("[mappings] failed to save json: %s", err.Error()) } t.ExportScrapedItems(ctx) + logger.Infof("Export complete in %s.", time.Since(startTime)) } -func (t *ExportTask) ExportScenes(ctx context.Context) { - tx := database.DB.MustBeginTx(ctx, nil) - defer tx.Commit() +func (t *ExportTask) ExportScenes(ctx context.Context, workers int) { + var scenesWg sync.WaitGroup + qb := models.NewSceneQueryBuilder() - studioQB := models.NewStudioQueryBuilder() - galleryQB := models.NewGalleryQueryBuilder() - performerQB := models.NewPerformerQueryBuilder() - tagQB := models.NewTagQueryBuilder() - sceneMarkerQB := models.NewSceneMarkerQueryBuilder() + scenes, err := qb.All() if err != nil { logger.Errorf("[scenes] failed to fetch all scenes: %s", err.Error()) } + jobCh := make(chan *models.Scene, workers*2) // make a buffered channel to feed workers + logger.Info("[scenes] exporting") + startTime := time.Now() + + for w := 0; w < workers; w++ { // create export Scene workers + scenesWg.Add(1) + go exportScene(&scenesWg, jobCh, t, nil) // no db data is changed so tx is set to nil + } for i, scene := range scenes { index := i + 1 - logger.Progressf("[scenes] %d of %d", index, len(scenes)) + if (i % 100) == 0 { // make progress easier to read + logger.Progressf("[scenes] %d of %d", index, len(scenes)) + } t.Mappings.Scenes = append(t.Mappings.Scenes, jsonschema.PathMapping{Path: scene.Path, Checksum: scene.Checksum}) + jobCh <- scene // feed workers + } + + close(jobCh) // close channel so that workers will know no more jobs are available + scenesWg.Wait() + + logger.Infof("[scenes] export complete in %s. %d workers used.", time.Since(startTime), workers) +} +func exportScene(wg *sync.WaitGroup, jobChan <-chan *models.Scene, t *ExportTask, tx *sqlx.Tx) { + defer wg.Done() + studioQB := models.NewStudioQueryBuilder() + movieQB := models.NewMovieQueryBuilder() + galleryQB := models.NewGalleryQueryBuilder() + performerQB := models.NewPerformerQueryBuilder() + tagQB := models.NewTagQueryBuilder() + sceneMarkerQB := models.NewSceneMarkerQueryBuilder() + joinQB := models.NewJoinsQueryBuilder() + + for scene := range jobChan { newSceneJSON := jsonschema.Scene{ CreatedAt: models.JSONTime{Time: scene.CreatedAt.Timestamp}, UpdatedAt: models.JSONTime{Time: scene.UpdatedAt.Timestamp}, @@ -79,7 +114,8 @@ func (t *ExportTask) ExportScenes(ctx context.Context) { galleryChecksum = gallery.Checksum } - performers, _ := performerQB.FindBySceneID(scene.ID, tx) + performers, _ := performerQB.FindNameBySceneID(scene.ID, tx) + sceneMovies, _ := joinQB.GetSceneMovies(scene.ID, tx) tags, _ := tagQB.FindBySceneID(scene.ID, tx) sceneMarkers, _ := sceneMarkerQB.FindBySceneID(scene.ID, tx) @@ -98,6 +134,9 @@ func (t *ExportTask) ExportScenes(ctx context.Context) { if scene.Rating.Valid { newSceneJSON.Rating = int(scene.Rating.Int64) } + + newSceneJSON.OCounter = scene.OCounter + if scene.Details.Valid { newSceneJSON.Details = scene.Details.String } @@ -135,6 +174,18 @@ func (t *ExportTask) ExportScenes(ctx context.Context) { newSceneJSON.Markers = append(newSceneJSON.Markers, sceneMarkerJSON) } + for _, sceneMovie := range sceneMovies { + movie, _ := movieQB.Find(sceneMovie.MovieID, tx) + + if movie.Name.Valid { + sceneMovieJSON := jsonschema.SceneMovie{ + MovieName: movie.Name.String, + SceneIndex: int(sceneMovie.SceneIndex.Int64), + } + newSceneJSON.Movies = append(newSceneJSON.Movies, sceneMovieJSON) + } + } + newSceneJSON.File = &jsonschema.SceneFile{} if scene.Size.Valid { newSceneJSON.File.Size = scene.Size.String @@ -148,6 +199,9 @@ func (t *ExportTask) ExportScenes(ctx context.Context) { if scene.AudioCodec.Valid { newSceneJSON.File.AudioCodec = scene.AudioCodec.String } + if scene.Format.Valid { + newSceneJSON.File.Format = scene.Format.String + } if scene.Width.Valid { newSceneJSON.File.Width = int(scene.Width.Int64) } @@ -177,7 +231,6 @@ func (t *ExportTask) ExportScenes(ctx context.Context) { } } - logger.Infof("[scenes] export complete") } func (t *ExportTask) ExportGalleries(ctx context.Context) { @@ -198,21 +251,42 @@ func (t *ExportTask) ExportGalleries(ctx context.Context) { logger.Infof("[galleries] export complete") } -func (t *ExportTask) ExportPerformers(ctx context.Context) { +func (t *ExportTask) ExportPerformers(ctx context.Context, workers int) { + var performersWg sync.WaitGroup + qb := models.NewPerformerQueryBuilder() performers, err := qb.All() if err != nil { logger.Errorf("[performers] failed to fetch all performers: %s", err.Error()) } + jobCh := make(chan *models.Performer, workers*2) // make a buffered channel to feed workers logger.Info("[performers] exporting") + startTime := time.Now() + + for w := 0; w < workers; w++ { // create export Performer workers + performersWg.Add(1) + go exportPerformer(&performersWg, jobCh) + } for i, performer := range performers { index := i + 1 logger.Progressf("[performers] %d of %d", index, len(performers)) t.Mappings.Performers = append(t.Mappings.Performers, jsonschema.NameMapping{Name: performer.Name.String, Checksum: performer.Checksum}) + jobCh <- performer // feed workers + } + close(jobCh) // close channel so workers will know that no more jobs are available + performersWg.Wait() + + logger.Infof("[performers] export complete in %s. %d workers used.", time.Since(startTime), workers) +} + +func exportPerformer(wg *sync.WaitGroup, jobChan <-chan *models.Performer) { + defer wg.Done() + + for performer := range jobChan { newPerformerJSON := jsonschema.Performer{ CreatedAt: models.JSONTime{Time: performer.CreatedAt.Timestamp}, UpdatedAt: models.JSONTime{Time: performer.UpdatedAt.Timestamp}, @@ -221,6 +295,9 @@ func (t *ExportTask) ExportPerformers(ctx context.Context) { if performer.Name.Valid { newPerformerJSON.Name = performer.Name.String } + if performer.Gender.Valid { + newPerformerJSON.Gender = performer.Gender.String + } if performer.URL.Valid { newPerformerJSON.URL = performer.URL.String } @@ -280,11 +357,11 @@ func (t *ExportTask) ExportPerformers(ctx context.Context) { logger.Errorf("[performers] <%s> failed to save json: %s", performer.Checksum, err.Error()) } } - - logger.Infof("[performers] export complete") } -func (t *ExportTask) ExportStudios(ctx context.Context) { +func (t *ExportTask) ExportStudios(ctx context.Context, workers int) { + var studiosWg sync.WaitGroup + qb := models.NewStudioQueryBuilder() studios, err := qb.All() if err != nil { @@ -292,12 +369,33 @@ func (t *ExportTask) ExportStudios(ctx context.Context) { } logger.Info("[studios] exporting") + startTime := time.Now() + + jobCh := make(chan *models.Studio, workers*2) // make a buffered channel to feed workers + + for w := 0; w < workers; w++ { // create export Studio workers + studiosWg.Add(1) + go exportStudio(&studiosWg, jobCh) + } for i, studio := range studios { index := i + 1 logger.Progressf("[studios] %d of %d", index, len(studios)) t.Mappings.Studios = append(t.Mappings.Studios, jsonschema.NameMapping{Name: studio.Name.String, Checksum: studio.Checksum}) + jobCh <- studio // feed workers + } + + close(jobCh) + studiosWg.Wait() + + logger.Infof("[studios] export complete in %s. %d workers used.", time.Since(startTime), workers) +} + +func exportStudio(wg *sync.WaitGroup, jobChan <-chan *models.Studio) { + defer wg.Done() + + for studio := range jobChan { newStudioJSON := jsonschema.Studio{ CreatedAt: models.JSONTime{Time: studio.CreatedAt.Timestamp}, @@ -324,8 +422,91 @@ func (t *ExportTask) ExportStudios(ctx context.Context) { logger.Errorf("[studios] <%s> failed to save json: %s", studio.Checksum, err.Error()) } } +} - logger.Infof("[studios] export complete") +func (t *ExportTask) ExportMovies(ctx context.Context, workers int) { + var moviesWg sync.WaitGroup + + qb := models.NewMovieQueryBuilder() + movies, err := qb.All() + if err != nil { + logger.Errorf("[movies] failed to fetch all movies: %s", err.Error()) + } + + logger.Info("[movies] exporting") + startTime := time.Now() + + jobCh := make(chan *models.Movie, workers*2) // make a buffered channel to feed workers + + for w := 0; w < workers; w++ { // create export Studio workers + moviesWg.Add(1) + go exportMovie(&moviesWg, jobCh) + } + + for i, movie := range movies { + index := i + 1 + logger.Progressf("[movies] %d of %d", index, len(movies)) + + t.Mappings.Movies = append(t.Mappings.Movies, jsonschema.NameMapping{Name: movie.Name.String, Checksum: movie.Checksum}) + jobCh <- movie // feed workers + } + + close(jobCh) + moviesWg.Wait() + + logger.Infof("[movies] export complete in %s. %d workers used.", time.Since(startTime), workers) + +} +func exportMovie(wg *sync.WaitGroup, jobChan <-chan *models.Movie) { + defer wg.Done() + + for movie := range jobChan { + newMovieJSON := jsonschema.Movie{ + CreatedAt: models.JSONTime{Time: movie.CreatedAt.Timestamp}, + UpdatedAt: models.JSONTime{Time: movie.UpdatedAt.Timestamp}, + } + + if movie.Name.Valid { + newMovieJSON.Name = movie.Name.String + } + if movie.Aliases.Valid { + newMovieJSON.Aliases = movie.Aliases.String + } + if movie.Date.Valid { + newMovieJSON.Date = utils.GetYMDFromDatabaseDate(movie.Date.String) + } + if movie.Rating.Valid { + newMovieJSON.Rating = int(movie.Rating.Int64) + } + if movie.Duration.Valid { + newMovieJSON.Duration = int(movie.Duration.Int64) + } + + if movie.Director.Valid { + newMovieJSON.Director = movie.Director.String + } + + if movie.Synopsis.Valid { + newMovieJSON.Synopsis = movie.Synopsis.String + } + + if movie.URL.Valid { + newMovieJSON.URL = movie.URL.String + } + + newMovieJSON.FrontImage = utils.GetBase64StringFromData(movie.FrontImage) + newMovieJSON.BackImage = utils.GetBase64StringFromData(movie.BackImage) + movieJSON, err := instance.JSON.getMovie(movie.Checksum) + if err != nil { + logger.Debugf("[movies] error reading movie json: %s", err.Error()) + } else if jsonschema.CompareJSON(*movieJSON, newMovieJSON) { + continue + } + + if err := instance.JSON.saveMovie(movie.Checksum, &newMovieJSON); err != nil { + logger.Errorf("[movies] <%s> failed to save json: %s", movie.Checksum, err.Error()) + } + } } func (t *ExportTask) ExportScrapedItems(ctx context.Context) { diff --git a/pkg/manager/task_generate_gallery_thumbs.go b/pkg/manager/task_generate_gallery_thumbs.go new file mode 100644 index 000000000..2079e980d --- /dev/null +++ b/pkg/manager/task_generate_gallery_thumbs.go @@ -0,0 +1,37 @@ +package manager + +import ( + "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/manager/paths" + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/utils" + "sync" +) + +type GenerateGthumbsTask struct { + Gallery models.Gallery +} + +func (t *GenerateGthumbsTask) Start(wg *sync.WaitGroup) { + defer wg.Done() + generated := 0 + count := t.Gallery.ImageCount() + for i := 0; i < count; i++ { + thumbPath := paths.GetGthumbPath(t.Gallery.Checksum, i, models.DefaultGthumbWidth) + exists, _ := utils.FileExists(thumbPath) + if exists { + continue + } + data := t.Gallery.GetThumbnail(i, models.DefaultGthumbWidth) + err := utils.WriteFile(thumbPath, data) + if err != nil { + logger.Errorf("error writing gallery thumbnail: %s", err) + } else { + generated++ + } + + } + if generated > 0 { + logger.Infof("Generated %d thumbnails for %s", generated, t.Gallery.Path) + } +} diff --git a/pkg/manager/task_generate_preview.go b/pkg/manager/task_generate_preview.go index 380560ba0..4aba82095 100644 --- a/pkg/manager/task_generate_preview.go +++ b/pkg/manager/task_generate_preview.go @@ -9,7 +9,9 @@ import ( ) type GeneratePreviewTask struct { - Scene models.Scene + Scene models.Scene + ImagePreview bool + PreviewPreset string } func (t *GeneratePreviewTask) Start(wg *sync.WaitGroup) { @@ -17,7 +19,8 @@ func (t *GeneratePreviewTask) Start(wg *sync.WaitGroup) { videoFilename := t.videoFilename() imageFilename := t.imageFilename() - if t.doesPreviewExist(t.Scene.Checksum) { + videoExists := t.doesVideoPreviewExist(t.Scene.Checksum) + if (!t.ImagePreview || t.doesImagePreviewExist(t.Scene.Checksum)) && videoExists { return } @@ -27,7 +30,7 @@ func (t *GeneratePreviewTask) Start(wg *sync.WaitGroup) { return } - generator, err := NewPreviewGenerator(*videoFile, videoFilename, imageFilename, instance.Paths.Generated.Screenshots) + generator, err := NewPreviewGenerator(*videoFile, videoFilename, imageFilename, instance.Paths.Generated.Screenshots, !videoExists, t.ImagePreview, t.PreviewPreset) if err != nil { logger.Errorf("error creating preview generator: %s", err.Error()) return @@ -39,10 +42,14 @@ func (t *GeneratePreviewTask) Start(wg *sync.WaitGroup) { } } -func (t *GeneratePreviewTask) doesPreviewExist(sceneChecksum string) bool { +func (t *GeneratePreviewTask) doesVideoPreviewExist(sceneChecksum string) bool { videoExists, _ := utils.FileExists(instance.Paths.Scene.GetStreamPreviewPath(sceneChecksum)) + return videoExists +} + +func (t *GeneratePreviewTask) doesImagePreviewExist(sceneChecksum string) bool { imageExists, _ := utils.FileExists(instance.Paths.Scene.GetStreamPreviewImagePath(sceneChecksum)) - return videoExists && imageExists + return imageExists } func (t *GeneratePreviewTask) videoFilename() string { diff --git a/pkg/manager/task_generate_screenshot.go b/pkg/manager/task_generate_screenshot.go new file mode 100644 index 000000000..c4360b482 --- /dev/null +++ b/pkg/manager/task_generate_screenshot.go @@ -0,0 +1,84 @@ +package manager + +import ( + "context" + "io/ioutil" + "os" + "sync" + "time" + + "github.com/stashapp/stash/pkg/database" + "github.com/stashapp/stash/pkg/ffmpeg" + "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/models" +) + +type GenerateScreenshotTask struct { + Scene models.Scene + ScreenshotAt *float64 +} + +func (t *GenerateScreenshotTask) Start(wg *sync.WaitGroup) { + defer wg.Done() + + scenePath := t.Scene.Path + probeResult, err := ffmpeg.NewVideoFile(instance.FFProbePath, scenePath) + + if err != nil { + logger.Error(err.Error()) + return + } + + var at float64 + if t.ScreenshotAt == nil { + at = float64(probeResult.Duration) * 0.2 + } else { + at = *t.ScreenshotAt + } + + checksum := t.Scene.Checksum + normalPath := instance.Paths.Scene.GetScreenshotPath(checksum) + + // we'll generate the screenshot, grab the generated data and set it + // in the database. We'll use SetSceneScreenshot to set the data + // which also generates the thumbnail + + logger.Debugf("Creating screenshot for %s", scenePath) + makeScreenshot(*probeResult, normalPath, 2, probeResult.Width, at) + + f, err := os.Open(normalPath) + if err != nil { + logger.Errorf("Error reading screenshot: %s", err.Error()) + return + } + defer f.Close() + + coverImageData, err := ioutil.ReadAll(f) + if err != nil { + logger.Errorf("Error reading screenshot: %s", err.Error()) + return + } + + ctx := context.TODO() + tx := database.DB.MustBeginTx(ctx, nil) + + qb := models.NewSceneQueryBuilder() + updatedTime := time.Now() + updatedScene := models.ScenePartial{ + ID: t.Scene.ID, + UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime}, + } + + updatedScene.Cover = &coverImageData + err = SetSceneScreenshot(t.Scene.Checksum, coverImageData) + _, err = qb.Update(updatedScene, tx) + if err != nil { + logger.Errorf("Error setting screenshot: %s", err.Error()) + return + } + + if err := tx.Commit(); err != nil { + logger.Errorf("Error setting screenshot: %s", err.Error()) + return + } +} diff --git a/pkg/manager/task_import.go b/pkg/manager/task_import.go index 634c164dc..efc2d62c2 100644 --- a/pkg/manager/task_import.go +++ b/pkg/manager/task_import.go @@ -46,6 +46,7 @@ func (t *ImportTask) Start(wg *sync.WaitGroup) { t.ImportPerformers(ctx) t.ImportStudios(ctx) + t.ImportMovies(ctx) t.ImportGalleries(ctx) t.ImportTags(ctx) @@ -93,6 +94,9 @@ func (t *ImportTask) ImportPerformers(ctx context.Context) { if performerJSON.Name != "" { newPerformer.Name = sql.NullString{String: performerJSON.Name, Valid: true} } + if performerJSON.Gender != "" { + newPerformer.Gender = sql.NullString{String: performerJSON.Gender, Valid: true} + } if performerJSON.URL != "" { newPerformer.URL = sql.NullString{String: performerJSON.URL, Valid: true} } @@ -204,6 +208,77 @@ func (t *ImportTask) ImportStudios(ctx context.Context) { logger.Info("[studios] import complete") } +func (t *ImportTask) ImportMovies(ctx context.Context) { + tx := database.DB.MustBeginTx(ctx, nil) + qb := models.NewMovieQueryBuilder() + + for i, mappingJSON := range t.Mappings.Movies { + index := i + 1 + movieJSON, err := instance.JSON.getMovie(mappingJSON.Checksum) + if err != nil { + logger.Errorf("[movies] failed to read json: %s", err.Error()) + continue + } + if mappingJSON.Checksum == "" || mappingJSON.Name == "" || movieJSON == nil { + return + } + + logger.Progressf("[movies] %d of %d", index, len(t.Mappings.Movies)) + + // generate checksum from movie name rather than image + checksum := utils.MD5FromString(movieJSON.Name) + + // Process the base 64 encoded image string + _, frontimageData, err := utils.ProcessBase64Image(movieJSON.FrontImage) + if err != nil { + _ = tx.Rollback() + logger.Errorf("[movies] <%s> invalid front_image: %s", mappingJSON.Checksum, err.Error()) + return + } + _, backimageData, err := utils.ProcessBase64Image(movieJSON.BackImage) + if err != nil { + _ = tx.Rollback() + logger.Errorf("[movies] <%s> invalid back_image: %s", mappingJSON.Checksum, err.Error()) + return + } + + // Populate a new movie from the input + newMovie := models.Movie{ + FrontImage: frontimageData, + BackImage: backimageData, + Checksum: checksum, + Name: sql.NullString{String: movieJSON.Name, Valid: true}, + Aliases: sql.NullString{String: movieJSON.Aliases, Valid: true}, + Date: models.SQLiteDate{String: movieJSON.Date, Valid: true}, + Director: sql.NullString{String: movieJSON.Director, Valid: true}, + Synopsis: sql.NullString{String: movieJSON.Synopsis, Valid: true}, + URL: sql.NullString{String: movieJSON.URL, Valid: true}, + CreatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(movieJSON.CreatedAt)}, + UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(movieJSON.UpdatedAt)}, + } + + if movieJSON.Rating != 0 { + newMovie.Rating = sql.NullInt64{Int64: int64(movieJSON.Rating), Valid: true} + } + if movieJSON.Duration != 0 { + newMovie.Duration = sql.NullInt64{Int64: int64(movieJSON.Duration), Valid: true} + } + + _, err = qb.Create(newMovie, tx) + if err != nil { + _ = tx.Rollback() + logger.Errorf("[movies] <%s> failed to create: %s", mappingJSON.Checksum, err.Error()) + return + } + } + + logger.Info("[movies] importing") + if err := tx.Commit(); err != nil { + logger.Errorf("[movies] import failed to commit: %s", err.Error()) + } + logger.Info("[movies] import complete") +} + func (t *ImportTask) ImportGalleries(ctx context.Context) { tx := database.DB.MustBeginTx(ctx, nil) qb := models.NewGalleryQueryBuilder() @@ -335,7 +410,7 @@ func (t *ImportTask) ImportScrapedItems(ctx context.Context) { UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(mappingJSON.UpdatedAt)}, } - studio, err := sqb.FindByName(mappingJSON.Studio, tx) + studio, err := sqb.FindByName(mappingJSON.Studio, tx, false) if err != nil { logger.Errorf("[scraped sites] failed to fetch studio: %s", err.Error()) } @@ -414,6 +489,8 @@ func (t *ImportTask) ImportScenes(ctx context.Context) { if sceneJSON.Rating != 0 { newScene.Rating = sql.NullInt64{Int64: int64(sceneJSON.Rating), Valid: true} } + + newScene.OCounter = sceneJSON.OCounter newScene.CreatedAt = models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(sceneJSON.CreatedAt)} newScene.UpdatedAt = models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(sceneJSON.UpdatedAt)} @@ -431,6 +508,9 @@ func (t *ImportTask) ImportScenes(ctx context.Context) { if sceneJSON.File.AudioCodec != "" { newScene.AudioCodec = sql.NullString{String: sceneJSON.File.AudioCodec, Valid: true} } + if sceneJSON.File.Format != "" { + newScene.Format = sql.NullString{String: sceneJSON.File.Format, Valid: true} + } if sceneJSON.File.Width != 0 { newScene.Width = sql.NullInt64{Int64: int64(sceneJSON.File.Width), Valid: true} } @@ -452,7 +532,7 @@ func (t *ImportTask) ImportScenes(ctx context.Context) { // Populate the studio ID if sceneJSON.Studio != "" { sqb := models.NewStudioQueryBuilder() - studio, err := sqb.FindByName(sceneJSON.Studio, tx) + studio, err := sqb.FindByName(sceneJSON.Studio, tx, false) if err != nil { logger.Warnf("[scenes] studio <%s> does not exist: %s", sceneJSON.Studio, err.Error()) } else { @@ -508,6 +588,18 @@ func (t *ImportTask) ImportScenes(ctx context.Context) { } } + // Relate the scene to the movies + if len(sceneJSON.Movies) > 0 { + moviesScenes, err := t.getMoviesScenes(sceneJSON.Movies, scene.ID, tx) + if err != nil { + logger.Warnf("[scenes] <%s> failed to fetch movies: %s", scene.Checksum, err.Error()) + } else { + if err := jqb.CreateMoviesScenes(moviesScenes, tx); err != nil { + logger.Errorf("[scenes] <%s> failed to associate movies: %s", scene.Checksum, err.Error()) + } + } + } + // Relate the scene to the tags if len(sceneJSON.Tags) > 0 { tags, err := t.getTags(scene.Checksum, sceneJSON.Tags, tx) @@ -542,7 +634,7 @@ func (t *ImportTask) ImportScenes(ctx context.Context) { UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(marker.UpdatedAt)}, } - primaryTag, err := tqb.FindByName(marker.PrimaryTag, tx) + primaryTag, err := tqb.FindByName(marker.PrimaryTag, tx, false) if err != nil { logger.Errorf("[scenes] <%s> failed to find primary tag for marker: %s", scene.Checksum, err.Error()) } else { @@ -590,7 +682,7 @@ func (t *ImportTask) ImportScenes(ctx context.Context) { func (t *ImportTask) getPerformers(names []string, tx *sqlx.Tx) ([]*models.Performer, error) { pqb := models.NewPerformerQueryBuilder() - performers, err := pqb.FindByNames(names, tx) + performers, err := pqb.FindByNames(names, tx, false) if err != nil { return nil, err } @@ -614,9 +706,41 @@ func (t *ImportTask) getPerformers(names []string, tx *sqlx.Tx) ([]*models.Perfo return performers, nil } +func (t *ImportTask) getMoviesScenes(input []jsonschema.SceneMovie, sceneID int, tx *sqlx.Tx) ([]models.MoviesScenes, error) { + mqb := models.NewMovieQueryBuilder() + + var movies []models.MoviesScenes + for _, inputMovie := range input { + movie, err := mqb.FindByName(inputMovie.MovieName, tx, false) + if err != nil { + return nil, err + } + + if movie == nil { + logger.Warnf("[scenes] movie %s does not exist", inputMovie.MovieName) + } else { + toAdd := models.MoviesScenes{ + MovieID: movie.ID, + SceneID: sceneID, + } + + if inputMovie.SceneIndex != 0 { + toAdd.SceneIndex = sql.NullInt64{ + Int64: int64(inputMovie.SceneIndex), + Valid: true, + } + } + + movies = append(movies, toAdd) + } + } + + return movies, nil +} + func (t *ImportTask) getTags(sceneChecksum string, names []string, tx *sqlx.Tx) ([]*models.Tag, error) { tqb := models.NewTagQueryBuilder() - tags, err := tqb.FindByNames(names, tx) + tags, err := tqb.FindByNames(names, tx, false) if err != nil { return nil, err } diff --git a/pkg/manager/task_scan.go b/pkg/manager/task_scan.go index 579a3fc00..3e784ae56 100644 --- a/pkg/manager/task_scan.go +++ b/pkg/manager/task_scan.go @@ -5,6 +5,7 @@ import ( "database/sql" "path/filepath" "strconv" + "strings" "sync" "time" @@ -21,7 +22,7 @@ type ScanTask struct { } func (t *ScanTask) Start(wg *sync.WaitGroup) { - if filepath.Ext(t.FilePath) == ".zip" { + if isGallery(t.FilePath) { t.scanGallery() } else { t.scanScene() @@ -33,11 +34,16 @@ func (t *ScanTask) Start(wg *sync.WaitGroup) { func (t *ScanTask) scanGallery() { qb := models.NewGalleryQueryBuilder() gallery, _ := qb.FindByPath(t.FilePath) + if gallery != nil { // We already have this item in the database, keep going return } + ok, err := utils.IsZipFileUncompressed(t.FilePath) + if err == nil && !ok { + logger.Warnf("%s is using above store (0) level compression.", t.FilePath) + } checksum, err := t.calculateChecksum() if err != nil { logger.Error(err.Error()) @@ -60,6 +66,7 @@ func (t *ScanTask) scanGallery() { } else { logger.Infof("%s doesn't exist. Creating new item...", t.FilePath) currentTime := time.Now() + newGallery := models.Gallery{ Checksum: checksum, Path: t.FilePath, @@ -77,12 +84,85 @@ func (t *ScanTask) scanGallery() { } } +// associates a gallery to a scene with the same basename +func (t *ScanTask) associateGallery(wg *sync.WaitGroup) { + qb := models.NewGalleryQueryBuilder() + gallery, _ := qb.FindByPath(t.FilePath) + if gallery == nil { + // shouldn't happen , associate is run after scan is finished + logger.Errorf("associate: gallery %s not found in DB", t.FilePath) + wg.Done() + return + } + + if !gallery.SceneID.Valid { // gallery has no SceneID + basename := strings.TrimSuffix(t.FilePath, filepath.Ext(t.FilePath)) + var relatedFiles []string + for _, ext := range extensionsToScan { // make a list of media files that can be related to the gallery + related := basename + "." + ext + if !isGallery(related) { //exclude gallery extensions from the related files + relatedFiles = append(relatedFiles, related) + } + } + for _, scenePath := range relatedFiles { + qbScene := models.NewSceneQueryBuilder() + scene, _ := qbScene.FindByPath(scenePath) + if scene != nil { // found related Scene + logger.Infof("associate: Gallery %s is related to scene: %d", t.FilePath, scene.ID) + + gallery.SceneID.Int64 = int64(scene.ID) + gallery.SceneID.Valid = true + + ctx := context.TODO() + tx := database.DB.MustBeginTx(ctx, nil) + + _, err := qb.Update(*gallery, tx) + if err != nil { + logger.Errorf("associate: Error updating gallery sceneId %s", err) + _ = tx.Rollback() + } else if err := tx.Commit(); err != nil { + logger.Error(err.Error()) + } + + break // since a gallery can have only one related scene + // only first found is associated + } + + } + + } + wg.Done() +} + func (t *ScanTask) scanScene() { qb := models.NewSceneQueryBuilder() scene, _ := qb.FindByPath(t.FilePath) if scene != nil { - // We already have this item in the database, check for thumbnails,screenshots + // We already have this item in the database + //check for thumbnails,screenshots t.makeScreenshots(nil, scene.Checksum) + + //check for container + if !scene.Format.Valid { + videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.FilePath) + if err != nil { + logger.Error(err.Error()) + return + } + container := ffmpeg.MatchContainer(videoFile.Container, t.FilePath) + logger.Infof("Adding container %s to file %s", container, t.FilePath) + + ctx := context.TODO() + tx := database.DB.MustBeginTx(ctx, nil) + err = qb.UpdateFormat(scene.ID, string(container), tx) + if err != nil { + logger.Error(err.Error()) + _ = tx.Rollback() + } else if err := tx.Commit(); err != nil { + logger.Error(err.Error()) + } + + } return } @@ -91,6 +171,7 @@ func (t *ScanTask) scanScene() { logger.Error(err.Error()) return } + container := ffmpeg.MatchContainer(videoFile.Container, t.FilePath) // Override title to be filename if UseFileMetadata is false if !t.UseFileMetadata { @@ -130,6 +211,7 @@ func (t *ScanTask) scanScene() { Duration: sql.NullFloat64{Float64: videoFile.Duration, Valid: true}, VideoCodec: sql.NullString{String: videoFile.VideoCodec, Valid: true}, AudioCodec: sql.NullString{String: videoFile.AudioCodec, Valid: true}, + Format: sql.NullString{String: string(container), Valid: true}, Width: sql.NullInt64{Int64: int64(videoFile.Width), Valid: true}, Height: sql.NullInt64{Int64: int64(videoFile.Height), Valid: true}, Framerate: sql.NullFloat64{Float64: videoFile.FrameRate, Valid: true}, @@ -177,28 +259,19 @@ func (t *ScanTask) makeScreenshots(probeResult *ffmpeg.VideoFile, checksum strin logger.Infof("Regenerating images for %s", t.FilePath) } + at := float64(probeResult.Duration) * 0.2 + if !thumbExists { logger.Debugf("Creating thumbnail for %s", t.FilePath) - t.makeScreenshot(*probeResult, thumbPath, 5, 320) + makeScreenshot(*probeResult, thumbPath, 5, 320, at) } if !normalExists { logger.Debugf("Creating screenshot for %s", t.FilePath) - t.makeScreenshot(*probeResult, normalPath, 2, probeResult.Width) + makeScreenshot(*probeResult, normalPath, 2, probeResult.Width, at) } } -func (t *ScanTask) makeScreenshot(probeResult ffmpeg.VideoFile, outputPath string, quality int, width int) { - encoder := ffmpeg.NewEncoder(instance.FFMPEGPath) - options := ffmpeg.ScreenshotOptions{ - OutputPath: outputPath, - Quality: quality, - Time: float64(probeResult.Duration) * 0.2, - Width: width, - } - encoder.Screenshot(probeResult, options) -} - func (t *ScanTask) calculateChecksum() (string, error) { logger.Infof("%s not found. Calculating checksum...", t.FilePath) checksum, err := utils.MD5FromFilePath(t.FilePath) diff --git a/pkg/manager/task_transcode.go b/pkg/manager/task_transcode.go index a43e50cd3..7db3be0e3 100644 --- a/pkg/manager/task_transcode.go +++ b/pkg/manager/task_transcode.go @@ -16,17 +16,37 @@ type GenerateTranscodeTask struct { func (t *GenerateTranscodeTask) Start(wg *sync.WaitGroup) { defer wg.Done() - videoCodec := t.Scene.VideoCodec.String - if ffmpeg.IsValidCodec(videoCodec) { - return - } hasTranscode, _ := HasTranscode(&t.Scene) if hasTranscode { return } - logger.Infof("[transcode] <%s> scene has codec %s", t.Scene.Checksum, t.Scene.VideoCodec.String) + var container ffmpeg.Container + + if t.Scene.Format.Valid { + container = ffmpeg.Container(t.Scene.Format.String) + + } else { // container isn't in the DB + // shouldn't happen unless user hasn't scanned after updating to PR#384+ version + tmpVideoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path) + if err != nil { + logger.Errorf("[transcode] error reading video file: %s", err.Error()) + return + } + + container = ffmpeg.MatchContainer(tmpVideoFile.Container, t.Scene.Path) + } + + videoCodec := t.Scene.VideoCodec.String + audioCodec := ffmpeg.MissingUnsupported + if t.Scene.AudioCodec.Valid { + audioCodec = ffmpeg.AudioCodec(t.Scene.AudioCodec.String) + } + + if ffmpeg.IsValidCodec(videoCodec) && ffmpeg.IsValidCombo(videoCodec, container) && ffmpeg.IsValidAudioForContainer(audioCodec, container) { + return + } videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path) if err != nil { @@ -41,24 +61,52 @@ func (t *GenerateTranscodeTask) Start(wg *sync.WaitGroup) { MaxTranscodeSize: transcodeSize, } encoder := ffmpeg.NewEncoder(instance.FFMPEGPath) - encoder.Transcode(*videoFile, options) + + if videoCodec == ffmpeg.H264 { // for non supported h264 files stream copy the video part + if audioCodec == ffmpeg.MissingUnsupported { + encoder.CopyVideo(*videoFile, options) + } else { + encoder.TranscodeAudio(*videoFile, options) + } + } else { + if audioCodec == ffmpeg.MissingUnsupported { + //ffmpeg fails if it trys to transcode an unsupported audio codec + encoder.TranscodeVideo(*videoFile, options) + } else { + encoder.Transcode(*videoFile, options) + } + } + if err := os.Rename(outputPath, instance.Paths.Scene.GetTranscodePath(t.Scene.Checksum)); err != nil { logger.Errorf("[transcode] error generating transcode: %s", err.Error()) return } + logger.Debugf("[transcode] <%s> created transcode: %s", t.Scene.Checksum, outputPath) return } +// return true if transcode is needed +// used only when counting files to generate, doesn't affect the actual transcode generation +// if container is missing from DB it is treated as non supported in order not to delay the user func (t *GenerateTranscodeTask) isTranscodeNeeded() bool { videoCodec := t.Scene.VideoCodec.String - hasTranscode, _ := HasTranscode(&t.Scene) + container := "" + audioCodec := ffmpeg.MissingUnsupported + if t.Scene.AudioCodec.Valid { + audioCodec = ffmpeg.AudioCodec(t.Scene.AudioCodec.String) + } - if ffmpeg.IsValidCodec(videoCodec) { + if t.Scene.Format.Valid { + container = t.Scene.Format.String + } + + if ffmpeg.IsValidCodec(videoCodec) && ffmpeg.IsValidCombo(videoCodec, ffmpeg.Container(container)) && ffmpeg.IsValidAudioForContainer(audioCodec, ffmpeg.Container(container)) { return false } + hasTranscode, _ := HasTranscode(&t.Scene) if hasTranscode { return false } diff --git a/pkg/manager/utils.go b/pkg/manager/utils.go index af767a291..38f747d95 100644 --- a/pkg/manager/utils.go +++ b/pkg/manager/utils.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/stashapp/stash/pkg/ffmpeg" + "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/utils" ) @@ -12,12 +13,30 @@ func IsStreamable(scene *models.Scene) (bool, error) { if scene == nil { return false, fmt.Errorf("nil scene") } + var container ffmpeg.Container + if scene.Format.Valid { + container = ffmpeg.Container(scene.Format.String) + } else { // container isn't in the DB + // shouldn't happen, fallback to ffprobe reading from file + tmpVideoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, scene.Path) + if err != nil { + return false, fmt.Errorf("error reading video file: %s", err.Error()) + } + container = ffmpeg.MatchContainer(tmpVideoFile.Container, scene.Path) + } videoCodec := scene.VideoCodec.String - if ffmpeg.IsValidCodec(videoCodec) { + audioCodec := ffmpeg.MissingUnsupported + if scene.AudioCodec.Valid { + audioCodec = ffmpeg.AudioCodec(scene.AudioCodec.String) + } + + if ffmpeg.IsValidCodec(videoCodec) && ffmpeg.IsValidCombo(videoCodec, container) && ffmpeg.IsValidAudioForContainer(audioCodec, container) { + logger.Debugf("File is streamable %s, %s, %s\n", videoCodec, audioCodec, container) return true, nil } else { hasTranscode, _ := HasTranscode(scene) + logger.Debugf("File is not streamable , transcode is needed %s, %s, %s\n", videoCodec, audioCodec, container) return hasTranscode, nil } } diff --git a/pkg/models/model_gallery.go b/pkg/models/model_gallery.go index 53ab2b406..9f8a83f5d 100644 --- a/pkg/models/model_gallery.go +++ b/pkg/models/model_gallery.go @@ -8,6 +8,7 @@ import ( "github.com/stashapp/stash/pkg/api/urlbuilders" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/utils" + _ "golang.org/x/image/webp" "image" "image/jpeg" "io/ioutil" @@ -25,6 +26,8 @@ type Gallery struct { UpdatedAt SQLiteTimestamp `db:"updated_at" json:"updated_at"` } +const DefaultGthumbWidth int = 200 + func (g *Gallery) GetFiles(baseURL string) []*GalleryFilesType { var galleryFiles []*GalleryFilesType filteredFiles, readCloser, err := g.listZipContents() @@ -88,7 +91,7 @@ func (g *Gallery) readZipFile(index int) ([]byte, error) { func (g *Gallery) listZipContents() ([]*zip.File, *zip.ReadCloser, error) { readCloser, err := zip.OpenReader(g.Path) if err != nil { - logger.Warn("failed to read zip file") + logger.Warnf("failed to read zip file %s", g.Path) return nil, nil, err } @@ -98,7 +101,8 @@ func (g *Gallery) listZipContents() ([]*zip.File, *zip.ReadCloser, error) { continue } ext := filepath.Ext(file.Name) - if ext != ".jpg" && ext != ".jpeg" && ext != ".png" && ext != ".gif" { + ext = strings.ToLower(ext) + if ext != ".jpg" && ext != ".jpeg" && ext != ".png" && ext != ".gif" && ext != ".webp" { continue } if strings.Contains(file.Name, "__MACOSX") { @@ -112,5 +116,49 @@ func (g *Gallery) listZipContents() ([]*zip.File, *zip.ReadCloser, error) { return utils.NaturalCompare(a.Name, b.Name) }) + cover := contains(filteredFiles, "cover.jpg") // first image with cover.jpg in the name + if cover >= 0 { // will be moved to the start + reorderedFiles := reorder(filteredFiles, cover) + if reorderedFiles != nil { + return reorderedFiles, readCloser, nil + } + } + return filteredFiles, readCloser, nil } + +// return index of first occurrenece of string x ( case insensitive ) in name of zip contents, -1 otherwise +func contains(a []*zip.File, x string) int { + for i, n := range a { + if strings.Contains(strings.ToLower(n.Name), strings.ToLower(x)) { + return i + } + } + return -1 +} + +// reorder slice so that element with position toFirst gets at the start +func reorder(a []*zip.File, toFirst int) []*zip.File { + var first *zip.File + switch { + case toFirst < 0 || toFirst >= len(a): + return nil + case toFirst == 0: + return a + default: + first = a[toFirst] + copy(a[toFirst:], a[toFirst+1:]) // Shift a[toFirst+1:] left one index removing a[toFirst] element + a[len(a)-1] = nil // Nil now unused element for garbage collection + a = a[:len(a)-1] // Truncate slice + a = append([]*zip.File{first}, a...) // Push first to the start of the slice + } + return a +} + +func (g *Gallery) ImageCount() int { + images, _, _ := g.listZipContents() + if images == nil { + return 0 + } + return len(images) +} diff --git a/pkg/models/model_joins.go b/pkg/models/model_joins.go index 2a1129bd1..f69be8946 100644 --- a/pkg/models/model_joins.go +++ b/pkg/models/model_joins.go @@ -1,10 +1,18 @@ package models +import "database/sql" + type PerformersScenes struct { PerformerID int `db:"performer_id" json:"performer_id"` SceneID int `db:"scene_id" json:"scene_id"` } +type MoviesScenes struct { + MovieID int `db:"movie_id" json:"movie_id"` + SceneID int `db:"scene_id" json:"scene_id"` + SceneIndex sql.NullInt64 `db:"scene_index" json:"scene_index"` +} + type ScenesTags struct { SceneID int `db:"scene_id" json:"scene_id"` TagID int `db:"tag_id" json:"tag_id"` diff --git a/pkg/models/model_movie.go b/pkg/models/model_movie.go new file mode 100644 index 000000000..865fcab0e --- /dev/null +++ b/pkg/models/model_movie.go @@ -0,0 +1,43 @@ +package models + +import ( + "database/sql" +) + +type Movie struct { + ID int `db:"id" json:"id"` + FrontImage []byte `db:"front_image" json:"front_image"` + BackImage []byte `db:"back_image" json:"back_image"` + Checksum string `db:"checksum" json:"checksum"` + Name sql.NullString `db:"name" json:"name"` + Aliases sql.NullString `db:"aliases" json:"aliases"` + Duration sql.NullInt64 `db:"duration" json:"duration"` + Date SQLiteDate `db:"date" json:"date"` + Rating sql.NullInt64 `db:"rating" json:"rating"` + StudioID sql.NullInt64 `db:"studio_id,omitempty" json:"studio_id"` + Director sql.NullString `db:"director" json:"director"` + Synopsis sql.NullString `db:"synopsis" json:"synopsis"` + URL sql.NullString `db:"url" json:"url"` + CreatedAt SQLiteTimestamp `db:"created_at" json:"created_at"` + UpdatedAt SQLiteTimestamp `db:"updated_at" json:"updated_at"` +} + +type MoviePartial struct { + ID int `db:"id" json:"id"` + FrontImage *[]byte `db:"front_image" json:"front_image"` + BackImage *[]byte `db:"back_image" json:"back_image"` + Checksum *string `db:"checksum" json:"checksum"` + Name *sql.NullString `db:"name" json:"name"` + Aliases *sql.NullString `db:"aliases" json:"aliases"` + Duration *sql.NullInt64 `db:"duration" json:"duration"` + Date *SQLiteDate `db:"date" json:"date"` + Rating *sql.NullInt64 `db:"rating" json:"rating"` + StudioID *sql.NullInt64 `db:"studio_id,omitempty" json:"studio_id"` + Director *sql.NullString `db:"director" json:"director"` + Synopsis *sql.NullString `db:"synopsis" json:"synopsis"` + URL *sql.NullString `db:"url" json:"url"` + CreatedAt *SQLiteTimestamp `db:"created_at" json:"created_at"` + UpdatedAt *SQLiteTimestamp `db:"updated_at" json:"updated_at"` +} + +var DefaultMovieImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4wgVBQsJl1CMZAAAASJJREFUeNrt3N0JwyAYhlEj3cj9R3Cm5rbkqtAP+qrnGaCYHPwJpLlaa++mmLpbAERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAHZuVflj40x4i94zhk9vqsVvEq6AsQqMP1EjORx20OACAgQRRx7T+zzcFBxcjNDfoB4ntQqTm5Awo7MlqywZxcgYQ+RlqywJ3ozJAQCSBiEJSsQA0gYBpDAgAARECACAkRAgAgIEAERECACAmSjUv6eAOSB8m8YIGGzBUjYbAESBgMkbBkDEjZbgITBAClcxiqQvEoatreYIWEBASIgJ4Gkf11ntXH3nS9uxfGWfJ5J9hAgAgJEQAQEiIAAERAgAgJEQAQEiIAAERAgAgJEQAQEiL7qBuc6RKLHxr0CAAAAAElFTkSuQmCC" diff --git a/pkg/models/model_performer.go b/pkg/models/model_performer.go index 8d3beb3db..71818a025 100644 --- a/pkg/models/model_performer.go +++ b/pkg/models/model_performer.go @@ -9,6 +9,7 @@ type Performer struct { Image []byte `db:"image" json:"image"` Checksum string `db:"checksum" json:"checksum"` Name sql.NullString `db:"name" json:"name"` + Gender sql.NullString `db:"gender" json:"gender"` URL sql.NullString `db:"url" json:"url"` Twitter sql.NullString `db:"twitter" json:"twitter"` Instagram sql.NullString `db:"instagram" json:"instagram"` diff --git a/pkg/models/model_scene.go b/pkg/models/model_scene.go index e55f42117..1623533be 100644 --- a/pkg/models/model_scene.go +++ b/pkg/models/model_scene.go @@ -19,6 +19,7 @@ type Scene struct { Size sql.NullString `db:"size" json:"size"` Duration sql.NullFloat64 `db:"duration" json:"duration"` VideoCodec sql.NullString `db:"video_codec" json:"video_codec"` + Format sql.NullString `db:"format" json:"format_name"` AudioCodec sql.NullString `db:"audio_codec" json:"audio_codec"` Width sql.NullInt64 `db:"width" json:"width"` Height sql.NullInt64 `db:"height" json:"height"` @@ -48,6 +49,7 @@ type ScenePartial struct { Framerate *sql.NullFloat64 `db:"framerate" json:"framerate"` Bitrate *sql.NullInt64 `db:"bitrate" json:"bitrate"` StudioID *sql.NullInt64 `db:"studio_id,omitempty" json:"studio_id"` + MovieID *sql.NullInt64 `db:"movie_id,omitempty" json:"movie_id"` CreatedAt *SQLiteTimestamp `db:"created_at" json:"created_at"` UpdatedAt *SQLiteTimestamp `db:"updated_at" json:"updated_at"` } diff --git a/pkg/models/model_scraped_item.go b/pkg/models/model_scraped_item.go index cdef49bc5..719274b5f 100644 --- a/pkg/models/model_scraped_item.go +++ b/pkg/models/model_scraped_item.go @@ -25,6 +25,28 @@ type ScrapedItem struct { type ScrapedPerformer struct { Name *string `graphql:"name" json:"name"` + Gender *string `graphql:"gender" json:"gender"` + URL *string `graphql:"url" json:"url"` + Twitter *string `graphql:"twitter" json:"twitter"` + Instagram *string `graphql:"instagram" json:"instagram"` + Birthdate *string `graphql:"birthdate" json:"birthdate"` + Ethnicity *string `graphql:"ethnicity" json:"ethnicity"` + Country *string `graphql:"country" json:"country"` + EyeColor *string `graphql:"eye_color" json:"eye_color"` + Height *string `graphql:"height" json:"height"` + Measurements *string `graphql:"measurements" json:"measurements"` + FakeTits *string `graphql:"fake_tits" json:"fake_tits"` + CareerLength *string `graphql:"career_length" json:"career_length"` + Tattoos *string `graphql:"tattoos" json:"tattoos"` + Piercings *string `graphql:"piercings" json:"piercings"` + Aliases *string `graphql:"aliases" json:"aliases"` + Image *string `graphql:"image" json:"image"` +} + +// this type has no Image field +type ScrapedPerformerStash struct { + Name *string `graphql:"name" json:"name"` + Gender *string `graphql:"gender" json:"gender"` URL *string `graphql:"url" json:"url"` Twitter *string `graphql:"twitter" json:"twitter"` Instagram *string `graphql:"instagram" json:"instagram"` @@ -42,6 +64,21 @@ type ScrapedPerformer struct { } type ScrapedScene struct { + Title *string `graphql:"title" json:"title"` + Details *string `graphql:"details" json:"details"` + URL *string `graphql:"url" json:"url"` + Date *string `graphql:"date" json:"date"` + Image *string `graphql:"image" json:"image"` + File *SceneFileType `graphql:"file" json:"file"` + Studio *ScrapedSceneStudio `graphql:"studio" json:"studio"` + Movies []*ScrapedSceneMovie `graphql:"movies" json:"movies"` + Tags []*ScrapedSceneTag `graphql:"tags" json:"tags"` + Performers []*ScrapedScenePerformer `graphql:"performers" json:"performers"` +} + +// stash doesn't return image, and we need id +type ScrapedSceneStash struct { + ID string `graphql:"id" json:"id"` Title *string `graphql:"title" json:"title"` Details *string `graphql:"details" json:"details"` URL *string `graphql:"url" json:"url"` @@ -56,6 +93,7 @@ type ScrapedScenePerformer struct { // Set if performer matched ID *string `graphql:"id" json:"id"` Name string `graphql:"name" json:"name"` + Gender *string `graphql:"gender" json:"gender"` URL *string `graphql:"url" json:"url"` Twitter *string `graphql:"twitter" json:"twitter"` Instagram *string `graphql:"instagram" json:"instagram"` @@ -79,6 +117,19 @@ type ScrapedSceneStudio struct { URL *string `graphql:"url" json:"url"` } +type ScrapedSceneMovie struct { + // Set if movie matched + ID *string `graphql:"id" json:"id"` + Name string `graphql:"name" json:"name"` + Aliases string `graphql:"aliases" json:"aliases"` + Duration string `graphql:"duration" json:"duration"` + Date string `graphql:"date" json:"date"` + Rating string `graphql:"rating" json:"rating"` + Director string `graphql:"director" json:"director"` + Synopsis string `graphql:"synopsis" json:"synopsis"` + URL *string `graphql:"url" json:"url"` +} + type ScrapedSceneTag struct { // Set if tag matched ID *string `graphql:"id" json:"id"` diff --git a/pkg/models/model_studio.go b/pkg/models/model_studio.go index 51ec69ba0..e978bb439 100644 --- a/pkg/models/model_studio.go +++ b/pkg/models/model_studio.go @@ -14,4 +14,4 @@ type Studio struct { UpdatedAt SQLiteTimestamp `db:"updated_at" json:"updated_at"` } -var DefaultStudioImage string = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4wgVBQsJl1CMZAAAASJJREFUeNrt3N0JwyAYhlEj3cj9R3Cm5rbkqtAP+qrnGaCYHPwJpLlaa++mmLpbAERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAHZuVflj40x4i94zhk9vqsVvEq6AsQqMP1EjORx20OACAgQRRx7T+zzcFBxcjNDfoB4ntQqTm5Awo7MlqywZxcgYQ+RlqywJ3ozJAQCSBiEJSsQA0gYBpDAgAARECACAkRAgAgIEAERECACAmSjUv6eAOSB8m8YIGGzBUjYbAESBgMkbBkDEjZbgITBAClcxiqQvEoatreYIWEBASIgJ4Gkf11ntXH3nS9uxfGWfJ5J9hAgAgJEQAQEiIAAERAgAgJEQAQEiIAAERAgAgJEQAQEiL7qBuc6RKLHxr0CAAAAAElFTkSuQmCC" +var DefaultStudioImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4wgVBQsJl1CMZAAAASJJREFUeNrt3N0JwyAYhlEj3cj9R3Cm5rbkqtAP+qrnGaCYHPwJpLlaa++mmLpbAERAgAgIEAEBIiBABERAgAgIEAEBIiBABERAgAgIEAHZuVflj40x4i94zhk9vqsVvEq6AsQqMP1EjORx20OACAgQRRx7T+zzcFBxcjNDfoB4ntQqTm5Awo7MlqywZxcgYQ+RlqywJ3ozJAQCSBiEJSsQA0gYBpDAgAARECACAkRAgAgIEAERECACAmSjUv6eAOSB8m8YIGGzBUjYbAESBgMkbBkDEjZbgITBAClcxiqQvEoatreYIWEBASIgJ4Gkf11ntXH3nS9uxfGWfJ5J9hAgAgJEQAQEiIAAERAgAgJEQAQEiIAAERAgAgJEQAQEiL7qBuc6RKLHxr0CAAAAAElFTkSuQmCC" diff --git a/pkg/models/querybuilder_gallery.go b/pkg/models/querybuilder_gallery.go index f77fe0de2..0f2b06e06 100644 --- a/pkg/models/querybuilder_gallery.go +++ b/pkg/models/querybuilder_gallery.go @@ -3,6 +3,7 @@ package models import ( "database/sql" "path/filepath" + "strconv" "github.com/jmoiron/sqlx" "github.com/stashapp/stash/pkg/database" @@ -51,6 +52,10 @@ func (qb *GalleryQueryBuilder) Update(updatedGallery Gallery, tx *sqlx.Tx) (*Gal return &updatedGallery, nil } +func (qb *GalleryQueryBuilder) Destroy(id int, tx *sqlx.Tx) error { + return executeDeleteQuery("galleries", strconv.Itoa(id), tx) +} + type GalleryNullSceneID struct { SceneID sql.NullInt64 } @@ -88,7 +93,7 @@ func (qb *GalleryQueryBuilder) FindByPath(path string) (*Gallery, error) { } func (qb *GalleryQueryBuilder) FindBySceneID(sceneID int, tx *sqlx.Tx) (*Gallery, error) { - query := "SELECT galleries.* FROM galleries JOIN scenes ON scenes.id = galleries.scene_id WHERE scenes.id = ? LIMIT 1" + query := "SELECT galleries.* FROM galleries WHERE galleries.scene_id = ? LIMIT 1" args := []interface{}{sceneID} return qb.queryGallery(query, args, tx) } @@ -119,7 +124,9 @@ func (qb *GalleryQueryBuilder) Query(findFilter *FindFilterType) ([]*Gallery, in if q := findFilter.Q; q != nil && *q != "" { searchColumns := []string{"galleries.path", "galleries.checksum"} - whereClauses = append(whereClauses, getSearch(searchColumns, *q)) + clause, thisArgs := getSearchBinding(searchColumns, *q, false) + whereClauses = append(whereClauses, clause) + args = append(args, thisArgs...) } sortAndPagination := qb.getGallerySort(findFilter) + getPagination(findFilter) @@ -137,13 +144,13 @@ func (qb *GalleryQueryBuilder) Query(findFilter *FindFilterType) ([]*Gallery, in func (qb *GalleryQueryBuilder) getGallerySort(findFilter *FindFilterType) string { var sort string var direction string - //if findFilter == nil { // TODO temp until title is removed from schema and UI - sort = "path" - direction = "ASC" - //} else { - // sort = findFilter.getSort("path") - // direction = findFilter.getDirection() - //} + if findFilter == nil { + sort = "path" + direction = "ASC" + } else { + sort = findFilter.GetSort("path") + direction = findFilter.GetDirection() + } return getSort(sort, direction, "galleries") } diff --git a/pkg/models/querybuilder_gallery_test.go b/pkg/models/querybuilder_gallery_test.go new file mode 100644 index 000000000..d3a409d08 --- /dev/null +++ b/pkg/models/querybuilder_gallery_test.go @@ -0,0 +1,107 @@ +// +build integration + +package models_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/stashapp/stash/pkg/models" +) + +func TestGalleryFind(t *testing.T) { + gqb := models.NewGalleryQueryBuilder() + + const galleryIdx = 0 + gallery, err := gqb.Find(galleryIDs[galleryIdx]) + + if err != nil { + t.Fatalf("Error finding gallery: %s", err.Error()) + } + + assert.Equal(t, getGalleryStringValue(galleryIdx, "Path"), gallery.Path) + + gallery, err = gqb.Find(0) + + if err != nil { + t.Fatalf("Error finding gallery: %s", err.Error()) + } + + assert.Nil(t, gallery) +} + +func TestGalleryFindByChecksum(t *testing.T) { + gqb := models.NewGalleryQueryBuilder() + + const galleryIdx = 0 + galleryChecksum := getGalleryStringValue(galleryIdx, "Checksum") + gallery, err := gqb.FindByChecksum(galleryChecksum, nil) + + if err != nil { + t.Fatalf("Error finding gallery: %s", err.Error()) + } + + assert.Equal(t, getGalleryStringValue(galleryIdx, "Path"), gallery.Path) + + galleryChecksum = "not exist" + gallery, err = gqb.FindByChecksum(galleryChecksum, nil) + + if err != nil { + t.Fatalf("Error finding gallery: %s", err.Error()) + } + + assert.Nil(t, gallery) +} + +func TestGalleryFindByPath(t *testing.T) { + gqb := models.NewGalleryQueryBuilder() + + const galleryIdx = 0 + galleryPath := getGalleryStringValue(galleryIdx, "Path") + gallery, err := gqb.FindByPath(galleryPath) + + if err != nil { + t.Fatalf("Error finding gallery: %s", err.Error()) + } + + assert.Equal(t, galleryPath, gallery.Path) + + galleryPath = "not exist" + gallery, err = gqb.FindByPath(galleryPath) + + if err != nil { + t.Fatalf("Error finding gallery: %s", err.Error()) + } + + assert.Nil(t, gallery) +} + +func TestGalleryFindBySceneID(t *testing.T) { + gqb := models.NewGalleryQueryBuilder() + + sceneID := sceneIDs[sceneIdxWithGallery] + gallery, err := gqb.FindBySceneID(sceneID, nil) + + if err != nil { + t.Fatalf("Error finding gallery: %s", err.Error()) + } + + assert.Equal(t, getGalleryStringValue(galleryIdxWithScene, "Path"), gallery.Path) + + gallery, err = gqb.FindBySceneID(0, nil) + + if err != nil { + t.Fatalf("Error finding gallery: %s", err.Error()) + } + + assert.Nil(t, gallery) +} + +// TODO ValidGalleriesForScenePath +// TODO Count +// TODO All +// TODO Query +// TODO Update +// TODO Destroy +// TODO ClearGalleryId diff --git a/pkg/models/querybuilder_joins.go b/pkg/models/querybuilder_joins.go index 310bc8dad..416b85a18 100644 --- a/pkg/models/querybuilder_joins.go +++ b/pkg/models/querybuilder_joins.go @@ -111,6 +111,109 @@ func (qb *JoinsQueryBuilder) DestroyPerformersScenes(sceneID int, tx *sqlx.Tx) e return err } +func (qb *JoinsQueryBuilder) GetSceneMovies(sceneID int, tx *sqlx.Tx) ([]MoviesScenes, error) { + query := `SELECT * from movies_scenes WHERE scene_id = ?` + + var rows *sqlx.Rows + var err error + if tx != nil { + rows, err = tx.Queryx(query, sceneID) + } else { + rows, err = database.DB.Queryx(query, sceneID) + } + + if err != nil && err != sql.ErrNoRows { + return nil, err + } + defer rows.Close() + + movieScenes := make([]MoviesScenes, 0) + for rows.Next() { + movieScene := MoviesScenes{} + if err := rows.StructScan(&movieScene); err != nil { + return nil, err + } + movieScenes = append(movieScenes, movieScene) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return movieScenes, nil +} + +func (qb *JoinsQueryBuilder) CreateMoviesScenes(newJoins []MoviesScenes, tx *sqlx.Tx) error { + ensureTx(tx) + for _, join := range newJoins { + _, err := tx.NamedExec( + `INSERT INTO movies_scenes (movie_id, scene_id, scene_index) VALUES (:movie_id, :scene_id, :scene_index)`, + join, + ) + if err != nil { + return err + } + } + return nil +} + +// AddMovieScene adds a movie to a scene. It does not make any change +// if the movie already exists on the scene. It returns true if scene +// movie was added. + +func (qb *JoinsQueryBuilder) AddMoviesScene(sceneID int, movieID int, sceneIdx *int, tx *sqlx.Tx) (bool, error) { + ensureTx(tx) + + existingMovies, err := qb.GetSceneMovies(sceneID, tx) + + if err != nil { + return false, err + } + + // ensure not already present + for _, p := range existingMovies { + if p.MovieID == movieID && p.SceneID == sceneID { + return false, nil + } + } + + movieJoin := MoviesScenes{ + MovieID: movieID, + SceneID: sceneID, + } + + if sceneIdx != nil { + movieJoin.SceneIndex = sql.NullInt64{ + Int64: int64(*sceneIdx), + Valid: true, + } + } + movieJoins := append(existingMovies, movieJoin) + + err = qb.UpdateMoviesScenes(sceneID, movieJoins, tx) + + return err == nil, err +} + +func (qb *JoinsQueryBuilder) UpdateMoviesScenes(sceneID int, updatedJoins []MoviesScenes, tx *sqlx.Tx) error { + ensureTx(tx) + + // Delete the existing joins and then create new ones + _, err := tx.Exec("DELETE FROM movies_scenes WHERE scene_id = ?", sceneID) + if err != nil { + return err + } + return qb.CreateMoviesScenes(updatedJoins, tx) +} + +func (qb *JoinsQueryBuilder) DestroyMoviesScenes(sceneID int, tx *sqlx.Tx) error { + ensureTx(tx) + + // Delete the existing joins + _, err := tx.Exec("DELETE FROM movies_scenes WHERE scene_id = ?", sceneID) + return err +} + func (qb *JoinsQueryBuilder) GetSceneTags(sceneID int, tx *sqlx.Tx) ([]ScenesTags, error) { ensureTx(tx) diff --git a/pkg/models/querybuilder_movies.go b/pkg/models/querybuilder_movies.go new file mode 100644 index 000000000..cccd4d180 --- /dev/null +++ b/pkg/models/querybuilder_movies.go @@ -0,0 +1,240 @@ +package models + +import ( + "database/sql" + "strconv" + + "github.com/jmoiron/sqlx" + "github.com/stashapp/stash/pkg/database" +) + +type MovieQueryBuilder struct{} + +func NewMovieQueryBuilder() MovieQueryBuilder { + return MovieQueryBuilder{} +} + +func (qb *MovieQueryBuilder) Create(newMovie Movie, tx *sqlx.Tx) (*Movie, error) { + ensureTx(tx) + result, err := tx.NamedExec( + `INSERT INTO movies (front_image, back_image, checksum, name, aliases, duration, date, rating, studio_id, director, synopsis, url, created_at, updated_at) + VALUES (:front_image, :back_image, :checksum, :name, :aliases, :duration, :date, :rating, :studio_id, :director, :synopsis, :url, :created_at, :updated_at) + `, + newMovie, + ) + if err != nil { + return nil, err + } + movieID, err := result.LastInsertId() + if err != nil { + return nil, err + } + + if err := tx.Get(&newMovie, `SELECT * FROM movies WHERE id = ? LIMIT 1`, movieID); err != nil { + return nil, err + } + return &newMovie, nil +} + +func (qb *MovieQueryBuilder) Update(updatedMovie MoviePartial, tx *sqlx.Tx) (*Movie, error) { + ensureTx(tx) + _, err := tx.NamedExec( + `UPDATE movies SET `+SQLGenKeysPartial(updatedMovie)+` WHERE movies.id = :id`, + updatedMovie, + ) + if err != nil { + return nil, err + } + + return qb.Find(updatedMovie.ID, tx) +} + +func (qb *MovieQueryBuilder) Destroy(id string, tx *sqlx.Tx) error { + // delete movie from movies_scenes + + _, err := tx.Exec("DELETE FROM movies_scenes WHERE movie_id = ?", id) + if err != nil { + return err + } + + // // remove movie from scraped items + // _, err = tx.Exec("UPDATE scraped_items SET movie_id = null WHERE movie_id = ?", id) + // if err != nil { + // return err + // } + + return executeDeleteQuery("movies", id, tx) +} + +func (qb *MovieQueryBuilder) Find(id int, tx *sqlx.Tx) (*Movie, error) { + query := "SELECT * FROM movies WHERE id = ? LIMIT 1" + args := []interface{}{id} + return qb.queryMovie(query, args, tx) +} + +func (qb *MovieQueryBuilder) FindBySceneID(sceneID int, tx *sqlx.Tx) ([]*Movie, error) { + query := ` + SELECT movies.* FROM movies + LEFT JOIN movies_scenes as scenes_join on scenes_join.movie_id = movies.id + WHERE scenes_join.scene_id = ? + GROUP BY movies.id + ` + args := []interface{}{sceneID} + return qb.queryMovies(query, args, tx) +} + +func (qb *MovieQueryBuilder) FindByName(name string, tx *sqlx.Tx, nocase bool) (*Movie, error) { + query := "SELECT * FROM movies WHERE name = ?" + if nocase { + query += " COLLATE NOCASE" + } + query += " LIMIT 1" + args := []interface{}{name} + return qb.queryMovie(query, args, tx) +} + +func (qb *MovieQueryBuilder) FindByNames(names []string, tx *sqlx.Tx, nocase bool) ([]*Movie, error) { + query := "SELECT * FROM movies WHERE name" + if nocase { + query += " COLLATE NOCASE" + } + query += " IN " + getInBinding(len(names)) + var args []interface{} + for _, name := range names { + args = append(args, name) + } + return qb.queryMovies(query, args, tx) +} + +func (qb *MovieQueryBuilder) Count() (int, error) { + return runCountQuery(buildCountQuery("SELECT movies.id FROM movies"), nil) +} + +func (qb *MovieQueryBuilder) All() ([]*Movie, error) { + return qb.queryMovies(selectAll("movies")+qb.getMovieSort(nil), nil, nil) +} + +func (qb *MovieQueryBuilder) AllSlim() ([]*Movie, error) { + return qb.queryMovies("SELECT movies.id, movies.name FROM movies "+qb.getMovieSort(nil), nil, nil) +} + +func (qb *MovieQueryBuilder) Query(movieFilter *MovieFilterType, findFilter *FindFilterType) ([]*Movie, int) { + if findFilter == nil { + findFilter = &FindFilterType{} + } + if movieFilter == nil { + movieFilter = &MovieFilterType{} + } + + var whereClauses []string + var havingClauses []string + var args []interface{} + body := selectDistinctIDs("movies") + body += ` + left join movies_scenes as scenes_join on scenes_join.movie_id = movies.id + left join scenes on scenes_join.scene_id = scenes.id + left join studios as studio on studio.id = movies.studio_id +` + + if q := findFilter.Q; q != nil && *q != "" { + searchColumns := []string{"movies.name"} + clause, thisArgs := getSearchBinding(searchColumns, *q, false) + whereClauses = append(whereClauses, clause) + args = append(args, thisArgs...) + } + + if studiosFilter := movieFilter.Studios; studiosFilter != nil && len(studiosFilter.Value) > 0 { + for _, studioID := range studiosFilter.Value { + args = append(args, studioID) + } + + whereClause, havingClause := qb.getMultiCriterionClause("studio", "", "studio_id", studiosFilter) + whereClauses = appendClause(whereClauses, whereClause) + havingClauses = appendClause(havingClauses, havingClause) + } + + sortAndPagination := qb.getMovieSort(findFilter) + getPagination(findFilter) + idsResult, countResult := executeFindQuery("movies", body, args, sortAndPagination, whereClauses, havingClauses) + + var movies []*Movie + for _, id := range idsResult { + movie, _ := qb.Find(id, nil) + movies = append(movies, movie) + } + + return movies, countResult +} + +// returns where clause and having clause +func (qb *MovieQueryBuilder) getMultiCriterionClause(table string, joinTable string, joinTableField string, criterion *MultiCriterionInput) (string, string) { + whereClause := "" + havingClause := "" + if criterion.Modifier == CriterionModifierIncludes { + // includes any of the provided ids + whereClause = table + ".id IN " + getInBinding(len(criterion.Value)) + } else if criterion.Modifier == CriterionModifierIncludesAll { + // includes all of the provided ids + whereClause = table + ".id IN " + getInBinding(len(criterion.Value)) + havingClause = "count(distinct " + table + ".id) IS " + strconv.Itoa(len(criterion.Value)) + } else if criterion.Modifier == CriterionModifierExcludes { + // excludes all of the provided ids + if joinTable != "" { + whereClause = "not exists (select " + joinTable + ".movie_id from " + joinTable + " where " + joinTable + ".movie_id = movies.id and " + joinTable + "." + joinTableField + " in " + getInBinding(len(criterion.Value)) + ")" + } else { + whereClause = "not exists (select m.id from movies as m where m.id = movies.id and m." + joinTableField + " in " + getInBinding(len(criterion.Value)) + ")" + } + } + + return whereClause, havingClause +} + +func (qb *MovieQueryBuilder) getMovieSort(findFilter *FindFilterType) string { + var sort string + var direction string + if findFilter == nil { + sort = "name" + direction = "ASC" + } else { + sort = findFilter.GetSort("name") + direction = findFilter.GetDirection() + } + return getSort(sort, direction, "movies") +} + +func (qb *MovieQueryBuilder) queryMovie(query string, args []interface{}, tx *sqlx.Tx) (*Movie, error) { + results, err := qb.queryMovies(query, args, tx) + if err != nil || len(results) < 1 { + return nil, err + } + return results[0], nil +} + +func (qb *MovieQueryBuilder) queryMovies(query string, args []interface{}, tx *sqlx.Tx) ([]*Movie, error) { + var rows *sqlx.Rows + var err error + if tx != nil { + rows, err = tx.Queryx(query, args...) + } else { + rows, err = database.DB.Queryx(query, args...) + } + + if err != nil && err != sql.ErrNoRows { + return nil, err + } + defer rows.Close() + + movies := make([]*Movie, 0) + for rows.Next() { + movie := Movie{} + if err := rows.StructScan(&movie); err != nil { + return nil, err + } + movies = append(movies, &movie) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return movies, nil +} diff --git a/pkg/models/querybuilder_movies_test.go b/pkg/models/querybuilder_movies_test.go new file mode 100644 index 000000000..a11f94f18 --- /dev/null +++ b/pkg/models/querybuilder_movies_test.go @@ -0,0 +1,94 @@ +// +build integration + +package models_test + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/stashapp/stash/pkg/models" +) + +func TestMovieFindBySceneID(t *testing.T) { + mqb := models.NewMovieQueryBuilder() + sceneID := sceneIDs[sceneIdxWithMovie] + + movies, err := mqb.FindBySceneID(sceneID, nil) + + if err != nil { + t.Fatalf("Error finding movie: %s", err.Error()) + } + + assert.Equal(t, 1, len(movies), "expect 1 movie") + + movie := movies[0] + assert.Equal(t, getMovieStringValue(movieIdxWithScene, "Name"), movie.Name.String) + + movies, err = mqb.FindBySceneID(0, nil) + + if err != nil { + t.Fatalf("Error finding movie: %s", err.Error()) + } + + assert.Equal(t, 0, len(movies)) +} + +func TestMovieFindByName(t *testing.T) { + + mqb := models.NewMovieQueryBuilder() + + name := movieNames[movieIdxWithScene] // find a movie by name + + movie, err := mqb.FindByName(name, nil, false) + + if err != nil { + t.Fatalf("Error finding movies: %s", err.Error()) + } + + assert.Equal(t, movieNames[movieIdxWithScene], movie.Name.String) + + name = movieNames[movieIdxWithDupName] // find a movie by name nocase + + movie, err = mqb.FindByName(name, nil, true) + + if err != nil { + t.Fatalf("Error finding movies: %s", err.Error()) + } + // movieIdxWithDupName and movieIdxWithScene should have similar names ( only diff should be Name vs NaMe) + //movie.Name should match with movieIdxWithScene since its ID is before moveIdxWithDupName + assert.Equal(t, movieNames[movieIdxWithScene], movie.Name.String) + //movie.Name should match with movieIdxWithDupName if the check is not case sensitive + assert.Equal(t, strings.ToLower(movieNames[movieIdxWithDupName]), strings.ToLower(movie.Name.String)) +} + +func TestMovieFindByNames(t *testing.T) { + var names []string + + mqb := models.NewMovieQueryBuilder() + + names = append(names, movieNames[movieIdxWithScene]) // find movies by names + + movies, err := mqb.FindByNames(names, nil, false) + if err != nil { + t.Fatalf("Error finding movies: %s", err.Error()) + } + assert.Len(t, movies, 1) + assert.Equal(t, movieNames[movieIdxWithScene], movies[0].Name.String) + + movies, err = mqb.FindByNames(names, nil, true) // find movies by names nocase + if err != nil { + t.Fatalf("Error finding movies: %s", err.Error()) + } + assert.Len(t, movies, 2) // movieIdxWithScene and movieIdxWithDupName + assert.Equal(t, strings.ToLower(movieNames[movieIdxWithScene]), strings.ToLower(movies[0].Name.String)) + assert.Equal(t, strings.ToLower(movieNames[movieIdxWithScene]), strings.ToLower(movies[1].Name.String)) +} + +// TODO Update +// TODO Destroy +// TODO Find +// TODO Count +// TODO All +// TODO Query diff --git a/pkg/models/querybuilder_performer.go b/pkg/models/querybuilder_performer.go index 7cdb10093..5b0dca723 100644 --- a/pkg/models/querybuilder_performer.go +++ b/pkg/models/querybuilder_performer.go @@ -18,10 +18,10 @@ func NewPerformerQueryBuilder() PerformerQueryBuilder { func (qb *PerformerQueryBuilder) Create(newPerformer Performer, tx *sqlx.Tx) (*Performer, error) { ensureTx(tx) result, err := tx.NamedExec( - `INSERT INTO performers (image, checksum, name, url, twitter, instagram, birthdate, ethnicity, country, + `INSERT INTO performers (image, checksum, name, url, gender, twitter, instagram, birthdate, ethnicity, country, eye_color, height, measurements, fake_tits, career_length, tattoos, piercings, aliases, favorite, created_at, updated_at) - VALUES (:image, :checksum, :name, :url, :twitter, :instagram, :birthdate, :ethnicity, :country, + VALUES (:image, :checksum, :name, :url, :gender, :twitter, :instagram, :birthdate, :ethnicity, :country, :eye_color, :height, :measurements, :fake_tits, :career_length, :tattoos, :piercings, :aliases, :favorite, :created_at, :updated_at) `, @@ -77,19 +77,31 @@ func (qb *PerformerQueryBuilder) Find(id int) (*Performer, error) { } func (qb *PerformerQueryBuilder) FindBySceneID(sceneID int, tx *sqlx.Tx) ([]*Performer, error) { - query := ` - SELECT performers.* FROM performers + query := selectAll("performers") + ` LEFT JOIN performers_scenes as scenes_join on scenes_join.performer_id = performers.id - LEFT JOIN scenes on scenes_join.scene_id = scenes.id - WHERE scenes.id = ? - GROUP BY performers.id + WHERE scenes_join.scene_id = ? ` args := []interface{}{sceneID} return qb.queryPerformers(query, args, tx) } -func (qb *PerformerQueryBuilder) FindByNames(names []string, tx *sqlx.Tx) ([]*Performer, error) { - query := "SELECT * FROM performers WHERE name IN " + getInBinding(len(names)) +func (qb *PerformerQueryBuilder) FindNameBySceneID(sceneID int, tx *sqlx.Tx) ([]*Performer, error) { + query := ` + SELECT performers.name FROM performers + LEFT JOIN performers_scenes as scenes_join on scenes_join.performer_id = performers.id + WHERE scenes_join.scene_id = ? + ` + args := []interface{}{sceneID} + return qb.queryPerformers(query, args, tx) +} + +func (qb *PerformerQueryBuilder) FindByNames(names []string, tx *sqlx.Tx, nocase bool) ([]*Performer, error) { + query := "SELECT * FROM performers WHERE name" + if nocase { + query += " COLLATE NOCASE" + } + query += " IN " + getInBinding(len(names)) + var args []interface{} for _, name := range names { args = append(args, name) @@ -105,6 +117,10 @@ func (qb *PerformerQueryBuilder) All() ([]*Performer, error) { return qb.queryPerformers(selectAll("performers")+qb.getPerformerSort(nil), nil, nil) } +func (qb *PerformerQueryBuilder) AllSlim() ([]*Performer, error) { + return qb.queryPerformers("SELECT performers.id, performers.name, performers.gender FROM performers "+qb.getPerformerSort(nil), nil, nil) +} + func (qb *PerformerQueryBuilder) Query(performerFilter *PerformerFilterType, findFilter *FindFilterType) ([]*Performer, int) { if performerFilter == nil { performerFilter = &PerformerFilterType{} @@ -113,11 +129,12 @@ func (qb *PerformerQueryBuilder) Query(performerFilter *PerformerFilterType, fin findFilter = &FindFilterType{} } + tableName := "performers" query := queryBuilder{ - tableName: "performers", + tableName: tableName, } - query.body = selectDistinctIDs("performers") + query.body = selectDistinctIDs(tableName) query.body += ` left join performers_scenes as scenes_join on scenes_join.performer_id = performers.id left join scenes on scenes_join.scene_id = scenes.id @@ -152,18 +169,32 @@ func (qb *PerformerQueryBuilder) Query(performerFilter *PerformerFilterType, fin query.addArg(thisArgs...) } - handleStringCriterion("ethnicity", performerFilter.Ethnicity, &query) - handleStringCriterion("country", performerFilter.Country, &query) - handleStringCriterion("eye_color", performerFilter.EyeColor, &query) - handleStringCriterion("height", performerFilter.Height, &query) - handleStringCriterion("measurements", performerFilter.Measurements, &query) - handleStringCriterion("fake_tits", performerFilter.FakeTits, &query) - handleStringCriterion("career_length", performerFilter.CareerLength, &query) - handleStringCriterion("tattoos", performerFilter.Tattoos, &query) - handleStringCriterion("piercings", performerFilter.Piercings, &query) + if gender := performerFilter.Gender; gender != nil { + query.addWhere("performers.gender = ?") + query.addArg(gender.Value.String()) + } + + if isMissingFilter := performerFilter.IsMissing; isMissingFilter != nil && *isMissingFilter != "" { + switch *isMissingFilter { + case "scenes": + query.addWhere("scenes_join.scene_id IS NULL") + default: + query.addWhere("performers." + *isMissingFilter + " IS NULL") + } + } + + handleStringCriterion(tableName+".ethnicity", performerFilter.Ethnicity, &query) + handleStringCriterion(tableName+".country", performerFilter.Country, &query) + handleStringCriterion(tableName+".eye_color", performerFilter.EyeColor, &query) + handleStringCriterion(tableName+".height", performerFilter.Height, &query) + handleStringCriterion(tableName+".measurements", performerFilter.Measurements, &query) + handleStringCriterion(tableName+".fake_tits", performerFilter.FakeTits, &query) + handleStringCriterion(tableName+".career_length", performerFilter.CareerLength, &query) + handleStringCriterion(tableName+".tattoos", performerFilter.Tattoos, &query) + handleStringCriterion(tableName+".piercings", performerFilter.Piercings, &query) // TODO - need better handling of aliases - handleStringCriterion("aliases", performerFilter.Aliases, &query) + handleStringCriterion(tableName+".aliases", performerFilter.Aliases, &query) query.sortAndPagination = qb.getPerformerSort(findFilter) + getPagination(findFilter) idsResult, countResult := query.executeFind() diff --git a/pkg/models/querybuilder_performer_test.go b/pkg/models/querybuilder_performer_test.go new file mode 100644 index 000000000..1c2b26979 --- /dev/null +++ b/pkg/models/querybuilder_performer_test.go @@ -0,0 +1,112 @@ +// +build integration + +package models_test + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/stashapp/stash/pkg/models" +) + +func TestPerformerFindBySceneID(t *testing.T) { + pqb := models.NewPerformerQueryBuilder() + sceneID := sceneIDs[sceneIdxWithPerformer] + + performers, err := pqb.FindBySceneID(sceneID, nil) + + if err != nil { + t.Fatalf("Error finding performer: %s", err.Error()) + } + + assert.Equal(t, 1, len(performers)) + performer := performers[0] + + assert.Equal(t, getPerformerStringValue(performerIdxWithScene, "Name"), performer.Name.String) + + performers, err = pqb.FindBySceneID(0, nil) + + if err != nil { + t.Fatalf("Error finding performer: %s", err.Error()) + } + + assert.Equal(t, 0, len(performers)) +} + +func TestPerformerFindNameBySceneID(t *testing.T) { + pqb := models.NewPerformerQueryBuilder() + sceneID := sceneIDs[sceneIdxWithPerformer] + + performers, err := pqb.FindNameBySceneID(sceneID, nil) + + if err != nil { + t.Fatalf("Error finding performer: %s", err.Error()) + } + + assert.Equal(t, 1, len(performers)) + performer := performers[0] + + assert.Equal(t, getPerformerStringValue(performerIdxWithScene, "Name"), performer.Name.String) + + performers, err = pqb.FindBySceneID(0, nil) + + if err != nil { + t.Fatalf("Error finding performer: %s", err.Error()) + } + + assert.Equal(t, 0, len(performers)) +} + +func TestPerformerFindByNames(t *testing.T) { + var names []string + + pqb := models.NewPerformerQueryBuilder() + + names = append(names, performerNames[performerIdxWithScene]) // find performers by names + + performers, err := pqb.FindByNames(names, nil, false) + if err != nil { + t.Fatalf("Error finding performers: %s", err.Error()) + } + assert.Len(t, performers, 1) + assert.Equal(t, performerNames[performerIdxWithScene], performers[0].Name.String) + + performers, err = pqb.FindByNames(names, nil, true) // find performers by names nocase + if err != nil { + t.Fatalf("Error finding performers: %s", err.Error()) + } + assert.Len(t, performers, 2) // performerIdxWithScene and performerIdxWithDupName + assert.Equal(t, strings.ToLower(performerNames[performerIdxWithScene]), strings.ToLower(performers[0].Name.String)) + assert.Equal(t, strings.ToLower(performerNames[performerIdxWithScene]), strings.ToLower(performers[1].Name.String)) + + names = append(names, performerNames[performerIdx1WithScene]) // find performers by names ( 2 names ) + + performers, err = pqb.FindByNames(names, nil, false) + if err != nil { + t.Fatalf("Error finding performers: %s", err.Error()) + } + assert.Len(t, performers, 2) // performerIdxWithScene and performerIdx1WithScene + assert.Equal(t, performerNames[performerIdxWithScene], performers[0].Name.String) + assert.Equal(t, performerNames[performerIdx1WithScene], performers[1].Name.String) + + performers, err = pqb.FindByNames(names, nil, true) // find performers by names ( 2 names nocase) + if err != nil { + t.Fatalf("Error finding performers: %s", err.Error()) + } + assert.Len(t, performers, 4) // performerIdxWithScene and performerIdxWithDupName , performerIdx1WithScene and performerIdx1WithDupName + assert.Equal(t, performerNames[performerIdxWithScene], performers[0].Name.String) + assert.Equal(t, performerNames[performerIdx1WithScene], performers[1].Name.String) + assert.Equal(t, performerNames[performerIdx1WithDupName], performers[2].Name.String) + assert.Equal(t, performerNames[performerIdxWithDupName], performers[3].Name.String) + +} + +// TODO Update +// TODO Destroy +// TODO Find +// TODO Count +// TODO All +// TODO AllSlim +// TODO Query diff --git a/pkg/models/querybuilder_scene.go b/pkg/models/querybuilder_scene.go index 502af4bb5..2a8d162c4 100644 --- a/pkg/models/querybuilder_scene.go +++ b/pkg/models/querybuilder_scene.go @@ -7,31 +7,40 @@ import ( "github.com/jmoiron/sqlx" "github.com/stashapp/stash/pkg/database" + "github.com/stashapp/stash/pkg/utils" ) -const scenesForPerformerQuery = ` -SELECT scenes.* FROM scenes +const sceneTable = "scenes" + +var scenesForPerformerQuery = selectAll(sceneTable) + ` LEFT JOIN performers_scenes as performers_join on performers_join.scene_id = scenes.id -LEFT JOIN performers on performers_join.performer_id = performers.id -WHERE performers.id = ? +WHERE performers_join.performer_id = ? GROUP BY scenes.id ` -const scenesForStudioQuery = ` -SELECT scenes.* FROM scenes +var countScenesForPerformerQuery = ` +SELECT performer_id FROM performers_scenes as performers_join +WHERE performer_id = ? +GROUP BY scene_id +` + +var scenesForStudioQuery = selectAll(sceneTable) + ` JOIN studios ON studios.id = scenes.studio_id WHERE studios.id = ? GROUP BY scenes.id ` - -const scenesForTagQuery = ` -SELECT scenes.* FROM scenes -LEFT JOIN scenes_tags as tags_join on tags_join.scene_id = scenes.id -LEFT JOIN tags on tags_join.tag_id = tags.id -WHERE tags.id = ? +var scenesForMovieQuery = selectAll(sceneTable) + ` +LEFT JOIN movies_scenes as movies_join on movies_join.scene_id = scenes.id +WHERE movies_join.movie_id = ? GROUP BY scenes.id ` +var countScenesForTagQuery = ` +SELECT tag_id AS id FROM scenes_tags +WHERE scenes_tags.tag_id = ? +GROUP BY scenes_tags.scene_id +` + type SceneQueryBuilder struct{} func NewSceneQueryBuilder() SceneQueryBuilder { @@ -41,11 +50,11 @@ func NewSceneQueryBuilder() SceneQueryBuilder { func (qb *SceneQueryBuilder) Create(newScene Scene, tx *sqlx.Tx) (*Scene, error) { ensureTx(tx) result, err := tx.NamedExec( - `INSERT INTO scenes (checksum, path, title, details, url, date, rating, size, duration, video_codec, - audio_codec, width, height, framerate, bitrate, studio_id, cover, + `INSERT INTO scenes (checksum, path, title, details, url, date, rating, o_counter, size, duration, video_codec, + audio_codec, format, width, height, framerate, bitrate, studio_id, cover, created_at, updated_at) - VALUES (:checksum, :path, :title, :details, :url, :date, :rating, :size, :duration, :video_codec, - :audio_codec, :width, :height, :framerate, :bitrate, :studio_id, :cover, + VALUES (:checksum, :path, :title, :details, :url, :date, :rating, :o_counter, :size, :duration, :video_codec, + :audio_codec, :format, :width, :height, :framerate, :bitrate, :studio_id, :cover, :created_at, :updated_at) `, newScene, @@ -131,6 +140,10 @@ func (qb *SceneQueryBuilder) ResetOCounter(id int, tx *sqlx.Tx) (int, error) { } func (qb *SceneQueryBuilder) Destroy(id string, tx *sqlx.Tx) error { + _, err := tx.Exec("DELETE FROM movies_scenes WHERE scene_id = ?", id) + if err != nil { + return err + } return executeDeleteQuery("scenes", id, tx) } func (qb *SceneQueryBuilder) Find(id int) (*Scene, error) { @@ -138,7 +151,7 @@ func (qb *SceneQueryBuilder) Find(id int) (*Scene, error) { } func (qb *SceneQueryBuilder) find(id int, tx *sqlx.Tx) (*Scene, error) { - query := "SELECT * FROM scenes WHERE id = ? LIMIT 1" + query := selectAll(sceneTable) + "WHERE id = ? LIMIT 1" args := []interface{}{id} return qb.queryScene(query, args, tx) } @@ -150,7 +163,7 @@ func (qb *SceneQueryBuilder) FindByChecksum(checksum string) (*Scene, error) { } func (qb *SceneQueryBuilder) FindByPath(path string) (*Scene, error) { - query := "SELECT * FROM scenes WHERE path = ? LIMIT 1" + query := selectAll(sceneTable) + "WHERE path = ? LIMIT 1" args := []interface{}{path} return qb.queryScene(query, args, nil) } @@ -162,7 +175,7 @@ func (qb *SceneQueryBuilder) FindByPerformerID(performerID int) ([]*Scene, error func (qb *SceneQueryBuilder) CountByPerformerID(performerID int) (int, error) { args := []interface{}{performerID} - return runCountQuery(buildCountQuery(scenesForPerformerQuery), args) + return runCountQuery(buildCountQuery(countScenesForPerformerQuery), args) } func (qb *SceneQueryBuilder) FindByStudioID(studioID int) ([]*Scene, error) { @@ -170,10 +183,28 @@ func (qb *SceneQueryBuilder) FindByStudioID(studioID int) ([]*Scene, error) { return qb.queryScenes(scenesForStudioQuery, args, nil) } +func (qb *SceneQueryBuilder) FindByMovieID(movieID int) ([]*Scene, error) { + args := []interface{}{movieID} + return qb.queryScenes(scenesForMovieQuery, args, nil) +} + +func (qb *SceneQueryBuilder) CountByMovieID(movieID int) (int, error) { + args := []interface{}{movieID} + return runCountQuery(buildCountQuery(scenesForMovieQuery), args) +} + func (qb *SceneQueryBuilder) Count() (int, error) { return runCountQuery(buildCountQuery("SELECT scenes.id FROM scenes"), nil) } +func (qb *SceneQueryBuilder) SizeCount() (string, error) { + sum, err := runSumQuery("SELECT SUM(size) as sum FROM scenes", nil) + if err != nil { + return "0 B", err + } + return utils.HumanizeBytes(sum), err +} + func (qb *SceneQueryBuilder) CountByStudioID(studioID int) (int, error) { args := []interface{}{studioID} return runCountQuery(buildCountQuery(scenesForStudioQuery), args) @@ -181,7 +212,7 @@ func (qb *SceneQueryBuilder) CountByStudioID(studioID int) (int, error) { func (qb *SceneQueryBuilder) CountByTagID(tagID int) (int, error) { args := []interface{}{tagID} - return runCountQuery(buildCountQuery(scenesForTagQuery), args) + return runCountQuery(buildCountQuery(countScenesForTagQuery), args) } func (qb *SceneQueryBuilder) Wall(q *string) ([]*Scene, error) { @@ -189,12 +220,12 @@ func (qb *SceneQueryBuilder) Wall(q *string) ([]*Scene, error) { if q != nil { s = *q } - query := "SELECT scenes.* FROM scenes WHERE scenes.details LIKE '%" + s + "%' ORDER BY RANDOM() LIMIT 80" + query := selectAll(sceneTable) + "WHERE scenes.details LIKE '%" + s + "%' ORDER BY RANDOM() LIMIT 80" return qb.queryScenes(query, nil, nil) } func (qb *SceneQueryBuilder) All() ([]*Scene, error) { - return qb.queryScenes(selectAll("scenes")+qb.getSceneSort(nil), nil, nil) + return qb.queryScenes(selectAll(sceneTable)+qb.getSceneSort(nil), nil, nil) } func (qb *SceneQueryBuilder) Query(sceneFilter *SceneFilterType, findFilter *FindFilterType) ([]*Scene, int) { @@ -205,121 +236,138 @@ func (qb *SceneQueryBuilder) Query(sceneFilter *SceneFilterType, findFilter *Fin findFilter = &FindFilterType{} } - var whereClauses []string - var havingClauses []string - var args []interface{} - body := selectDistinctIDs("scenes") - body = body + ` + query := queryBuilder{ + tableName: sceneTable, + } + + query.body = selectDistinctIDs(sceneTable) + query.body += ` left join scene_markers on scene_markers.scene_id = scenes.id left join performers_scenes as performers_join on performers_join.scene_id = scenes.id - left join performers on performers_join.performer_id = performers.id + left join movies_scenes as movies_join on movies_join.scene_id = scenes.id left join studios as studio on studio.id = scenes.studio_id left join galleries as gallery on gallery.scene_id = scenes.id left join scenes_tags as tags_join on tags_join.scene_id = scenes.id - left join tags on tags_join.tag_id = tags.id ` if q := findFilter.Q; q != nil && *q != "" { searchColumns := []string{"scenes.title", "scenes.details", "scenes.path", "scenes.checksum", "scene_markers.title"} - whereClauses = append(whereClauses, getSearch(searchColumns, *q)) + clause, thisArgs := getSearchBinding(searchColumns, *q, false) + query.addWhere(clause) + query.addArg(thisArgs...) } if rating := sceneFilter.Rating; rating != nil { clause, count := getIntCriterionWhereClause("scenes.rating", *sceneFilter.Rating) - whereClauses = append(whereClauses, clause) + query.addWhere(clause) if count == 1 { - args = append(args, sceneFilter.Rating.Value) + query.addArg(sceneFilter.Rating.Value) } } if oCounter := sceneFilter.OCounter; oCounter != nil { clause, count := getIntCriterionWhereClause("scenes.o_counter", *sceneFilter.OCounter) - whereClauses = append(whereClauses, clause) + query.addWhere(clause) if count == 1 { - args = append(args, sceneFilter.OCounter.Value) + query.addArg(sceneFilter.OCounter.Value) } } if durationFilter := sceneFilter.Duration; durationFilter != nil { clause, thisArgs := getDurationWhereClause(*durationFilter) - whereClauses = append(whereClauses, clause) - args = append(args, thisArgs...) + query.addWhere(clause) + query.addArg(thisArgs...) } if resolutionFilter := sceneFilter.Resolution; resolutionFilter != nil { if resolution := resolutionFilter.String(); resolutionFilter.IsValid() { switch resolution { case "LOW": - whereClauses = append(whereClauses, "(scenes.height >= 240 AND scenes.height < 480)") + query.addWhere("scenes.height < 480") case "STANDARD": - whereClauses = append(whereClauses, "(scenes.height >= 480 AND scenes.height < 720)") + query.addWhere("(scenes.height >= 480 AND scenes.height < 720)") case "STANDARD_HD": - whereClauses = append(whereClauses, "(scenes.height >= 720 AND scenes.height < 1080)") + query.addWhere("(scenes.height >= 720 AND scenes.height < 1080)") case "FULL_HD": - whereClauses = append(whereClauses, "(scenes.height >= 1080 AND scenes.height < 2160)") + query.addWhere("(scenes.height >= 1080 AND scenes.height < 2160)") case "FOUR_K": - whereClauses = append(whereClauses, "scenes.height >= 2160") - default: - whereClauses = append(whereClauses, "scenes.height < 240") + query.addWhere("scenes.height >= 2160") } } } if hasMarkersFilter := sceneFilter.HasMarkers; hasMarkersFilter != nil { if strings.Compare(*hasMarkersFilter, "true") == 0 { - havingClauses = append(havingClauses, "count(scene_markers.scene_id) > 0") + query.addHaving("count(scene_markers.scene_id) > 0") } else { - whereClauses = append(whereClauses, "scene_markers.id IS NULL") + query.addWhere("scene_markers.id IS NULL") } } if isMissingFilter := sceneFilter.IsMissing; isMissingFilter != nil && *isMissingFilter != "" { switch *isMissingFilter { case "gallery": - whereClauses = append(whereClauses, "gallery.scene_id IS NULL") + query.addWhere("gallery.scene_id IS NULL") case "studio": - whereClauses = append(whereClauses, "scenes.studio_id IS NULL") + query.addWhere("scenes.studio_id IS NULL") + case "movie": + query.addWhere("movies_join.scene_id IS NULL") case "performers": - whereClauses = append(whereClauses, "performers_join.scene_id IS NULL") + query.addWhere("performers_join.scene_id IS NULL") case "date": - whereClauses = append(whereClauses, "scenes.date IS \"\" OR scenes.date IS \"0001-01-01\"") + query.addWhere("scenes.date IS \"\" OR scenes.date IS \"0001-01-01\"") + case "tags": + query.addWhere("tags_join.scene_id IS NULL") default: - whereClauses = append(whereClauses, "scenes."+*isMissingFilter+" IS NULL") + query.addWhere("scenes." + *isMissingFilter + " IS NULL") } } if tagsFilter := sceneFilter.Tags; tagsFilter != nil && len(tagsFilter.Value) > 0 { for _, tagID := range tagsFilter.Value { - args = append(args, tagID) + query.addArg(tagID) } + query.body += " LEFT JOIN tags on tags_join.tag_id = tags.id" whereClause, havingClause := getMultiCriterionClause("tags", "scenes_tags", "tag_id", tagsFilter) - whereClauses = appendClause(whereClauses, whereClause) - havingClauses = appendClause(havingClauses, havingClause) + query.addWhere(whereClause) + query.addHaving(havingClause) } if performersFilter := sceneFilter.Performers; performersFilter != nil && len(performersFilter.Value) > 0 { for _, performerID := range performersFilter.Value { - args = append(args, performerID) + query.addArg(performerID) } + query.body += " LEFT JOIN performers ON performers_join.performer_id = performers.id" whereClause, havingClause := getMultiCriterionClause("performers", "performers_scenes", "performer_id", performersFilter) - whereClauses = appendClause(whereClauses, whereClause) - havingClauses = appendClause(havingClauses, havingClause) + query.addWhere(whereClause) + query.addHaving(havingClause) } if studiosFilter := sceneFilter.Studios; studiosFilter != nil && len(studiosFilter.Value) > 0 { for _, studioID := range studiosFilter.Value { - args = append(args, studioID) + query.addArg(studioID) } whereClause, havingClause := getMultiCriterionClause("studio", "", "studio_id", studiosFilter) - whereClauses = appendClause(whereClauses, whereClause) - havingClauses = appendClause(havingClauses, havingClause) + query.addWhere(whereClause) + query.addHaving(havingClause) } - sortAndPagination := qb.getSceneSort(findFilter) + getPagination(findFilter) - idsResult, countResult := executeFindQuery("scenes", body, args, sortAndPagination, whereClauses, havingClauses) + if moviesFilter := sceneFilter.Movies; moviesFilter != nil && len(moviesFilter.Value) > 0 { + for _, movieID := range moviesFilter.Value { + query.addArg(movieID) + } + + query.body += " LEFT JOIN movies ON movies_join.movie_id = movies.id" + whereClause, havingClause := getMultiCriterionClause("movies", "movies_scenes", "movie_id", moviesFilter) + query.addWhere(whereClause) + query.addHaving(havingClause) + } + + query.sortAndPagination = qb.getSceneSort(findFilter) + getPagination(findFilter) + idsResult, countResult := query.executeFind() var scenes []*Scene for _, id := range idsResult { @@ -488,3 +536,16 @@ func (qb *SceneQueryBuilder) queryScenes(query string, args []interface{}, tx *s return scenes, nil } + +func (qb *SceneQueryBuilder) UpdateFormat(id int, format string, tx *sqlx.Tx) error { + ensureTx(tx) + _, err := tx.Exec( + `UPDATE scenes SET format = ? WHERE scenes.id = ? `, + format, id, + ) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/models/querybuilder_scene_marker.go b/pkg/models/querybuilder_scene_marker.go index 5e0b683db..8cd9f0d69 100644 --- a/pkg/models/querybuilder_scene_marker.go +++ b/pkg/models/querybuilder_scene_marker.go @@ -7,12 +7,10 @@ import ( "strconv" ) -const sceneMarkersForTagQuery = ` -SELECT scene_markers.* FROM scene_markers +const countSceneMarkersForTagQuery = ` +SELECT scene_markers.id FROM scene_markers LEFT JOIN scene_markers_tags as tags_join on tags_join.scene_marker_id = scene_markers.id -LEFT JOIN tags on tags_join.tag_id = tags.id -LEFT JOIN tags AS ptj ON ptj.id = scene_markers.primary_tag_id -WHERE tags.id = ? OR ptj.id = ? +WHERE tags_join.tag_id = ? OR scene_markers.primary_tag_id = ? GROUP BY scene_markers.id ` @@ -77,8 +75,7 @@ func (qb *SceneMarkerQueryBuilder) Find(id int) (*SceneMarker, error) { func (qb *SceneMarkerQueryBuilder) FindBySceneID(sceneID int, tx *sqlx.Tx) ([]*SceneMarker, error) { query := ` SELECT scene_markers.* FROM scene_markers - JOIN scenes ON scenes.id = scene_markers.scene_id - WHERE scenes.id = ? + WHERE scene_markers.scene_id = ? GROUP BY scene_markers.id ORDER BY scene_markers.seconds ASC ` @@ -88,7 +85,7 @@ func (qb *SceneMarkerQueryBuilder) FindBySceneID(sceneID int, tx *sqlx.Tx) ([]*S func (qb *SceneMarkerQueryBuilder) CountByTagID(tagID int) (int, error) { args := []interface{}{tagID, tagID} - return runCountQuery(buildCountQuery(sceneMarkersForTagQuery), args) + return runCountQuery(buildCountQuery(countSceneMarkersForTagQuery), args) } func (qb *SceneMarkerQueryBuilder) GetMarkerStrings(q *string, sort *string) ([]*MarkerStringsResultType, error) { @@ -227,7 +224,9 @@ func (qb *SceneMarkerQueryBuilder) Query(sceneMarkerFilter *SceneMarkerFilterTyp if q := findFilter.Q; q != nil && *q != "" { searchColumns := []string{"scene_markers.title", "scene.title"} - whereClauses = append(whereClauses, getSearch(searchColumns, *q)) + clause, thisArgs := getSearchBinding(searchColumns, *q, false) + whereClauses = append(whereClauses, clause) + args = append(args, thisArgs...) } if tagID := sceneMarkerFilter.TagID; tagID != nil { diff --git a/pkg/models/querybuilder_scene_marker_test.go b/pkg/models/querybuilder_scene_marker_test.go new file mode 100644 index 000000000..ee8be5406 --- /dev/null +++ b/pkg/models/querybuilder_scene_marker_test.go @@ -0,0 +1,68 @@ +// +build integration + +package models_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/stashapp/stash/pkg/models" +) + +func TestMarkerFindBySceneID(t *testing.T) { + mqb := models.NewSceneMarkerQueryBuilder() + + sceneID := sceneIDs[sceneIdxWithMarker] + markers, err := mqb.FindBySceneID(sceneID, nil) + + if err != nil { + t.Fatalf("Error finding markers: %s", err.Error()) + } + + assert.Len(t, markers, 1) + assert.Equal(t, markerIDs[markerIdxWithScene], markers[0].ID) + + markers, err = mqb.FindBySceneID(0, nil) + + if err != nil { + t.Fatalf("Error finding marker: %s", err.Error()) + } + + assert.Len(t, markers, 0) +} + +func TestMarkerCountByTagID(t *testing.T) { + mqb := models.NewSceneMarkerQueryBuilder() + + markerCount, err := mqb.CountByTagID(tagIDs[tagIdxWithPrimaryMarker]) + + if err != nil { + t.Fatalf("error calling CountByTagID: %s", err.Error()) + } + + assert.Equal(t, 1, markerCount) + + markerCount, err = mqb.CountByTagID(tagIDs[tagIdxWithMarker]) + + if err != nil { + t.Fatalf("error calling CountByTagID: %s", err.Error()) + } + + assert.Equal(t, 1, markerCount) + + markerCount, err = mqb.CountByTagID(0) + + if err != nil { + t.Fatalf("error calling CountByTagID: %s", err.Error()) + } + + assert.Equal(t, 0, markerCount) +} + +// TODO Update +// TODO Destroy +// TODO Find +// TODO GetMarkerStrings +// TODO Wall +// TODO Query diff --git a/pkg/models/querybuilder_scene_test.go b/pkg/models/querybuilder_scene_test.go new file mode 100644 index 000000000..df6b0e817 --- /dev/null +++ b/pkg/models/querybuilder_scene_test.go @@ -0,0 +1,869 @@ +// +build integration + +package models_test + +import ( + "database/sql" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/stashapp/stash/pkg/models" +) + +func TestSceneFind(t *testing.T) { + // assume that the first scene is sceneWithGalleryPath + sqb := models.NewSceneQueryBuilder() + + const sceneIdx = 0 + sceneID := sceneIDs[sceneIdx] + scene, err := sqb.Find(sceneID) + + if err != nil { + t.Fatalf("Error finding scene: %s", err.Error()) + } + + assert.Equal(t, getSceneStringValue(sceneIdx, "Path"), scene.Path) + + sceneID = 0 + scene, err = sqb.Find(sceneID) + + if err != nil { + t.Fatalf("Error finding scene: %s", err.Error()) + } + + assert.Nil(t, scene) +} + +func TestSceneFindByPath(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + + const sceneIdx = 1 + scenePath := getSceneStringValue(sceneIdx, "Path") + scene, err := sqb.FindByPath(scenePath) + + if err != nil { + t.Fatalf("Error finding scene: %s", err.Error()) + } + + assert.Equal(t, sceneIDs[sceneIdx], scene.ID) + assert.Equal(t, scenePath, scene.Path) + + scenePath = "not exist" + scene, err = sqb.FindByPath(scenePath) + + if err != nil { + t.Fatalf("Error finding scene: %s", err.Error()) + } + + assert.Nil(t, scene) +} + +func TestSceneCountByPerformerID(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + count, err := sqb.CountByPerformerID(performerIDs[performerIdxWithScene]) + + if err != nil { + t.Fatalf("Error counting scenes: %s", err.Error()) + } + + assert.Equal(t, 1, count) + + count, err = sqb.CountByPerformerID(0) + + if err != nil { + t.Fatalf("Error counting scenes: %s", err.Error()) + } + + assert.Equal(t, 0, count) +} + +func TestSceneWall(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + + const sceneIdx = 2 + wallQuery := getSceneStringValue(sceneIdx, "Details") + scenes, err := sqb.Wall(&wallQuery) + + if err != nil { + t.Fatalf("Error finding scenes: %s", err.Error()) + } + + assert.Len(t, scenes, 1) + scene := scenes[0] + assert.Equal(t, sceneIDs[sceneIdx], scene.ID) + assert.Equal(t, getSceneStringValue(sceneIdx, "Path"), scene.Path) + + wallQuery = "not exist" + scenes, err = sqb.Wall(&wallQuery) + + if err != nil { + t.Fatalf("Error finding scene: %s", err.Error()) + } + + assert.Len(t, scenes, 0) +} + +func TestSceneQueryQ(t *testing.T) { + const sceneIdx = 2 + + q := getSceneStringValue(sceneIdx, titleField) + + sqb := models.NewSceneQueryBuilder() + + sceneQueryQ(t, sqb, q, sceneIdx) +} + +func sceneQueryQ(t *testing.T, sqb models.SceneQueryBuilder, q string, expectedSceneIdx int) { + filter := models.FindFilterType{ + Q: &q, + } + scenes, _ := sqb.Query(nil, &filter) + + assert.Len(t, scenes, 1) + scene := scenes[0] + assert.Equal(t, sceneIDs[expectedSceneIdx], scene.ID) + + // no Q should return all results + filter.Q = nil + scenes, _ = sqb.Query(nil, &filter) + + assert.Len(t, scenes, totalScenes) +} + +func TestSceneQueryRating(t *testing.T) { + const rating = 3 + ratingCriterion := models.IntCriterionInput{ + Value: rating, + Modifier: models.CriterionModifierEquals, + } + + verifyScenesRating(t, ratingCriterion) + + ratingCriterion.Modifier = models.CriterionModifierNotEquals + verifyScenesRating(t, ratingCriterion) + + ratingCriterion.Modifier = models.CriterionModifierGreaterThan + verifyScenesRating(t, ratingCriterion) + + ratingCriterion.Modifier = models.CriterionModifierLessThan + verifyScenesRating(t, ratingCriterion) + + ratingCriterion.Modifier = models.CriterionModifierIsNull + verifyScenesRating(t, ratingCriterion) + + ratingCriterion.Modifier = models.CriterionModifierNotNull + verifyScenesRating(t, ratingCriterion) +} + +func verifyScenesRating(t *testing.T, ratingCriterion models.IntCriterionInput) { + sqb := models.NewSceneQueryBuilder() + sceneFilter := models.SceneFilterType{ + Rating: &ratingCriterion, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + for _, scene := range scenes { + verifyInt64(t, scene.Rating, ratingCriterion) + } +} + +func verifyInt64(t *testing.T, value sql.NullInt64, criterion models.IntCriterionInput) { + assert := assert.New(t) + if criterion.Modifier == models.CriterionModifierIsNull { + assert.False(value.Valid, "expect is null values to be null") + } + if criterion.Modifier == models.CriterionModifierNotNull { + assert.True(value.Valid, "expect is null values to be null") + } + if criterion.Modifier == models.CriterionModifierEquals { + assert.Equal(int64(criterion.Value), value.Int64) + } + if criterion.Modifier == models.CriterionModifierNotEquals { + assert.NotEqual(int64(criterion.Value), value.Int64) + } + if criterion.Modifier == models.CriterionModifierGreaterThan { + assert.True(value.Int64 > int64(criterion.Value)) + } + if criterion.Modifier == models.CriterionModifierLessThan { + assert.True(value.Int64 < int64(criterion.Value)) + } +} + +func TestSceneQueryOCounter(t *testing.T) { + const oCounter = 1 + oCounterCriterion := models.IntCriterionInput{ + Value: oCounter, + Modifier: models.CriterionModifierEquals, + } + + verifyScenesOCounter(t, oCounterCriterion) + + oCounterCriterion.Modifier = models.CriterionModifierNotEquals + verifyScenesOCounter(t, oCounterCriterion) + + oCounterCriterion.Modifier = models.CriterionModifierGreaterThan + verifyScenesOCounter(t, oCounterCriterion) + + oCounterCriterion.Modifier = models.CriterionModifierLessThan + verifyScenesOCounter(t, oCounterCriterion) +} + +func verifyScenesOCounter(t *testing.T, oCounterCriterion models.IntCriterionInput) { + sqb := models.NewSceneQueryBuilder() + sceneFilter := models.SceneFilterType{ + OCounter: &oCounterCriterion, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + for _, scene := range scenes { + verifyInt(t, scene.OCounter, oCounterCriterion) + } +} + +func verifyInt(t *testing.T, value int, criterion models.IntCriterionInput) { + assert := assert.New(t) + if criterion.Modifier == models.CriterionModifierEquals { + assert.Equal(criterion.Value, value) + } + if criterion.Modifier == models.CriterionModifierNotEquals { + assert.NotEqual(criterion.Value, value) + } + if criterion.Modifier == models.CriterionModifierGreaterThan { + assert.True(value > criterion.Value) + } + if criterion.Modifier == models.CriterionModifierLessThan { + assert.True(value < criterion.Value) + } +} + +func TestSceneQueryDuration(t *testing.T) { + duration := 200.432 + + durationCriterion := models.IntCriterionInput{ + Value: int(duration), + Modifier: models.CriterionModifierEquals, + } + verifyScenesDuration(t, durationCriterion) + + durationCriterion.Modifier = models.CriterionModifierNotEquals + verifyScenesDuration(t, durationCriterion) + + durationCriterion.Modifier = models.CriterionModifierGreaterThan + verifyScenesDuration(t, durationCriterion) + + durationCriterion.Modifier = models.CriterionModifierLessThan + verifyScenesDuration(t, durationCriterion) + + durationCriterion.Modifier = models.CriterionModifierIsNull + verifyScenesDuration(t, durationCriterion) + + durationCriterion.Modifier = models.CriterionModifierNotNull + verifyScenesDuration(t, durationCriterion) +} + +func verifyScenesDuration(t *testing.T, durationCriterion models.IntCriterionInput) { + sqb := models.NewSceneQueryBuilder() + sceneFilter := models.SceneFilterType{ + Duration: &durationCriterion, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + for _, scene := range scenes { + if durationCriterion.Modifier == models.CriterionModifierEquals { + assert.True(t, scene.Duration.Float64 >= float64(durationCriterion.Value) && scene.Duration.Float64 < float64(durationCriterion.Value+1)) + } else if durationCriterion.Modifier == models.CriterionModifierNotEquals { + assert.True(t, scene.Duration.Float64 < float64(durationCriterion.Value) || scene.Duration.Float64 >= float64(durationCriterion.Value+1)) + } else { + verifyFloat64(t, scene.Duration, durationCriterion) + } + } +} + +func verifyFloat64(t *testing.T, value sql.NullFloat64, criterion models.IntCriterionInput) { + assert := assert.New(t) + if criterion.Modifier == models.CriterionModifierIsNull { + assert.False(value.Valid, "expect is null values to be null") + } + if criterion.Modifier == models.CriterionModifierNotNull { + assert.True(value.Valid, "expect is null values to be null") + } + if criterion.Modifier == models.CriterionModifierEquals { + assert.Equal(float64(criterion.Value), value.Float64) + } + if criterion.Modifier == models.CriterionModifierNotEquals { + assert.NotEqual(float64(criterion.Value), value.Float64) + } + if criterion.Modifier == models.CriterionModifierGreaterThan { + assert.True(value.Float64 > float64(criterion.Value)) + } + if criterion.Modifier == models.CriterionModifierLessThan { + assert.True(value.Float64 < float64(criterion.Value)) + } +} + +func TestSceneQueryResolution(t *testing.T) { + verifyScenesResolution(t, models.ResolutionEnumLow) + verifyScenesResolution(t, models.ResolutionEnumStandard) + verifyScenesResolution(t, models.ResolutionEnumStandardHd) + verifyScenesResolution(t, models.ResolutionEnumFullHd) + verifyScenesResolution(t, models.ResolutionEnumFourK) + verifyScenesResolution(t, models.ResolutionEnum("unknown")) +} + +func verifyScenesResolution(t *testing.T, resolution models.ResolutionEnum) { + sqb := models.NewSceneQueryBuilder() + sceneFilter := models.SceneFilterType{ + Resolution: &resolution, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + for _, scene := range scenes { + verifySceneResolution(t, scene.Height, resolution) + } +} + +func verifySceneResolution(t *testing.T, height sql.NullInt64, resolution models.ResolutionEnum) { + assert := assert.New(t) + h := height.Int64 + + switch resolution { + case models.ResolutionEnumLow: + assert.True(h < 480) + case models.ResolutionEnumStandard: + assert.True(h >= 480 && h < 720) + case models.ResolutionEnumStandardHd: + assert.True(h >= 720 && h < 1080) + case models.ResolutionEnumFullHd: + assert.True(h >= 1080 && h < 2160) + case models.ResolutionEnumFourK: + assert.True(h >= 2160) + } +} + +func TestSceneQueryHasMarkers(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + hasMarkers := "true" + sceneFilter := models.SceneFilterType{ + HasMarkers: &hasMarkers, + } + + q := getSceneStringValue(sceneIdxWithMarker, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ := sqb.Query(&sceneFilter, &findFilter) + + assert.Len(t, scenes, 1) + assert.Equal(t, sceneIDs[sceneIdxWithMarker], scenes[0].ID) + + hasMarkers = "false" + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + assert.Len(t, scenes, 0) + + findFilter.Q = nil + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + + assert.NotEqual(t, 0, len(scenes)) + + // ensure non of the ids equal the one with gallery + for _, scene := range scenes { + assert.NotEqual(t, sceneIDs[sceneIdxWithMarker], scene.ID) + } +} + +func TestSceneQueryIsMissingGallery(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + isMissing := "gallery" + sceneFilter := models.SceneFilterType{ + IsMissing: &isMissing, + } + + q := getSceneStringValue(sceneIdxWithGallery, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ := sqb.Query(&sceneFilter, &findFilter) + + assert.Len(t, scenes, 0) + + findFilter.Q = nil + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + + // ensure non of the ids equal the one with gallery + for _, scene := range scenes { + assert.NotEqual(t, sceneIDs[sceneIdxWithGallery], scene.ID) + } +} + +func TestSceneQueryIsMissingStudio(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + isMissing := "studio" + sceneFilter := models.SceneFilterType{ + IsMissing: &isMissing, + } + + q := getSceneStringValue(sceneIdxWithStudio, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ := sqb.Query(&sceneFilter, &findFilter) + + assert.Len(t, scenes, 0) + + findFilter.Q = nil + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + + // ensure non of the ids equal the one with studio + for _, scene := range scenes { + assert.NotEqual(t, sceneIDs[sceneIdxWithStudio], scene.ID) + } +} + +func TestSceneQueryIsMissingMovies(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + isMissing := "movie" + sceneFilter := models.SceneFilterType{ + IsMissing: &isMissing, + } + + q := getSceneStringValue(sceneIdxWithMovie, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ := sqb.Query(&sceneFilter, &findFilter) + + assert.Len(t, scenes, 0) + + findFilter.Q = nil + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + + // ensure non of the ids equal the one with movies + for _, scene := range scenes { + assert.NotEqual(t, sceneIDs[sceneIdxWithMovie], scene.ID) + } +} + +func TestSceneQueryIsMissingPerformers(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + isMissing := "performers" + sceneFilter := models.SceneFilterType{ + IsMissing: &isMissing, + } + + q := getSceneStringValue(sceneIdxWithPerformer, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ := sqb.Query(&sceneFilter, &findFilter) + + assert.Len(t, scenes, 0) + + findFilter.Q = nil + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + + assert.True(t, len(scenes) > 0) + + // ensure non of the ids equal the one with movies + for _, scene := range scenes { + assert.NotEqual(t, sceneIDs[sceneIdxWithPerformer], scene.ID) + } +} + +func TestSceneQueryIsMissingDate(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + isMissing := "date" + sceneFilter := models.SceneFilterType{ + IsMissing: &isMissing, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + assert.True(t, len(scenes) > 0) + + // ensure date is null, empty or "0001-01-01" + for _, scene := range scenes { + assert.True(t, !scene.Date.Valid || scene.Date.String == "" || scene.Date.String == "0001-01-01") + } +} + +func TestSceneQueryIsMissingTags(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + isMissing := "tags" + sceneFilter := models.SceneFilterType{ + IsMissing: &isMissing, + } + + q := getSceneStringValue(sceneIdxWithTwoTags, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ := sqb.Query(&sceneFilter, &findFilter) + + assert.Len(t, scenes, 0) + + findFilter.Q = nil + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + + assert.True(t, len(scenes) > 0) +} + +func TestSceneQueryIsMissingRating(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + isMissing := "rating" + sceneFilter := models.SceneFilterType{ + IsMissing: &isMissing, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + assert.True(t, len(scenes) > 0) + + // ensure date is null, empty or "0001-01-01" + for _, scene := range scenes { + assert.True(t, !scene.Rating.Valid) + } +} + +func TestSceneQueryPerformers(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + performerCriterion := models.MultiCriterionInput{ + Value: []string{ + strconv.Itoa(performerIDs[performerIdxWithScene]), + strconv.Itoa(performerIDs[performerIdx1WithScene]), + }, + Modifier: models.CriterionModifierIncludes, + } + + sceneFilter := models.SceneFilterType{ + Performers: &performerCriterion, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + assert.Len(t, scenes, 2) + + // ensure ids are correct + for _, scene := range scenes { + assert.True(t, scene.ID == sceneIDs[sceneIdxWithPerformer] || scene.ID == sceneIDs[sceneIdxWithTwoPerformers]) + } + + performerCriterion = models.MultiCriterionInput{ + Value: []string{ + strconv.Itoa(performerIDs[performerIdx1WithScene]), + strconv.Itoa(performerIDs[performerIdx2WithScene]), + }, + Modifier: models.CriterionModifierIncludesAll, + } + + scenes, _ = sqb.Query(&sceneFilter, nil) + + assert.Len(t, scenes, 1) + assert.Equal(t, sceneIDs[sceneIdxWithTwoPerformers], scenes[0].ID) + + performerCriterion = models.MultiCriterionInput{ + Value: []string{ + strconv.Itoa(performerIDs[performerIdx1WithScene]), + }, + Modifier: models.CriterionModifierExcludes, + } + + q := getSceneStringValue(sceneIdxWithTwoPerformers, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + assert.Len(t, scenes, 0) +} + +func TestSceneQueryTags(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + tagCriterion := models.MultiCriterionInput{ + Value: []string{ + strconv.Itoa(tagIDs[tagIdxWithScene]), + strconv.Itoa(tagIDs[tagIdx1WithScene]), + }, + Modifier: models.CriterionModifierIncludes, + } + + sceneFilter := models.SceneFilterType{ + Tags: &tagCriterion, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + assert.Len(t, scenes, 2) + + // ensure ids are correct + for _, scene := range scenes { + assert.True(t, scene.ID == sceneIDs[sceneIdxWithTag] || scene.ID == sceneIDs[sceneIdxWithTwoTags]) + } + + tagCriterion = models.MultiCriterionInput{ + Value: []string{ + strconv.Itoa(tagIDs[tagIdx1WithScene]), + strconv.Itoa(tagIDs[tagIdx2WithScene]), + }, + Modifier: models.CriterionModifierIncludesAll, + } + + scenes, _ = sqb.Query(&sceneFilter, nil) + + assert.Len(t, scenes, 1) + assert.Equal(t, sceneIDs[sceneIdxWithTwoTags], scenes[0].ID) + + tagCriterion = models.MultiCriterionInput{ + Value: []string{ + strconv.Itoa(tagIDs[tagIdx1WithScene]), + }, + Modifier: models.CriterionModifierExcludes, + } + + q := getSceneStringValue(sceneIdxWithTwoTags, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + assert.Len(t, scenes, 0) +} + +func TestSceneQueryStudio(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + studioCriterion := models.MultiCriterionInput{ + Value: []string{ + strconv.Itoa(studioIDs[studioIdxWithScene]), + }, + Modifier: models.CriterionModifierIncludes, + } + + sceneFilter := models.SceneFilterType{ + Studios: &studioCriterion, + } + + scenes, _ := sqb.Query(&sceneFilter, nil) + + assert.Len(t, scenes, 1) + + // ensure id is correct + assert.Equal(t, sceneIDs[sceneIdxWithStudio], scenes[0].ID) + + studioCriterion = models.MultiCriterionInput{ + Value: []string{ + strconv.Itoa(studioIDs[studioIdxWithScene]), + }, + Modifier: models.CriterionModifierExcludes, + } + + q := getSceneStringValue(sceneIdxWithStudio, titleField) + findFilter := models.FindFilterType{ + Q: &q, + } + + scenes, _ = sqb.Query(&sceneFilter, &findFilter) + assert.Len(t, scenes, 0) +} + +func TestSceneQuerySorting(t *testing.T) { + sort := titleField + direction := models.SortDirectionEnumAsc + findFilter := models.FindFilterType{ + Sort: &sort, + Direction: &direction, + } + + sqb := models.NewSceneQueryBuilder() + scenes, _ := sqb.Query(nil, &findFilter) + + // scenes should be in same order as indexes + firstScene := scenes[0] + lastScene := scenes[len(scenes)-1] + + assert.Equal(t, sceneIDs[0], firstScene.ID) + assert.Equal(t, sceneIDs[len(sceneIDs)-1], lastScene.ID) + + // sort in descending order + direction = models.SortDirectionEnumDesc + + scenes, _ = sqb.Query(nil, &findFilter) + firstScene = scenes[0] + lastScene = scenes[len(scenes)-1] + + assert.Equal(t, sceneIDs[len(sceneIDs)-1], firstScene.ID) + assert.Equal(t, sceneIDs[0], lastScene.ID) +} + +func TestSceneQueryPagination(t *testing.T) { + perPage := 1 + findFilter := models.FindFilterType{ + PerPage: &perPage, + } + + sqb := models.NewSceneQueryBuilder() + scenes, _ := sqb.Query(nil, &findFilter) + + assert.Len(t, scenes, 1) + + firstID := scenes[0].ID + + page := 2 + findFilter.Page = &page + scenes, _ = sqb.Query(nil, &findFilter) + + assert.Len(t, scenes, 1) + secondID := scenes[0].ID + assert.NotEqual(t, firstID, secondID) + + perPage = 2 + page = 1 + + scenes, _ = sqb.Query(nil, &findFilter) + assert.Len(t, scenes, 2) + assert.Equal(t, firstID, scenes[0].ID) + assert.Equal(t, secondID, scenes[1].ID) +} + +func TestSceneCountByTagID(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + + sceneCount, err := sqb.CountByTagID(tagIDs[tagIdxWithScene]) + + if err != nil { + t.Fatalf("error calling CountByTagID: %s", err.Error()) + } + + assert.Equal(t, 1, sceneCount) + + sceneCount, err = sqb.CountByTagID(0) + + if err != nil { + t.Fatalf("error calling CountByTagID: %s", err.Error()) + } + + assert.Equal(t, 0, sceneCount) +} + +func TestSceneCountByMovieID(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + + sceneCount, err := sqb.CountByMovieID(movieIDs[movieIdxWithScene]) + + if err != nil { + t.Fatalf("error calling CountByMovieID: %s", err.Error()) + } + + assert.Equal(t, 1, sceneCount) + + sceneCount, err = sqb.CountByMovieID(0) + + if err != nil { + t.Fatalf("error calling CountByMovieID: %s", err.Error()) + } + + assert.Equal(t, 0, sceneCount) +} + +func TestSceneCountByStudioID(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + + sceneCount, err := sqb.CountByStudioID(studioIDs[studioIdxWithScene]) + + if err != nil { + t.Fatalf("error calling CountByStudioID: %s", err.Error()) + } + + assert.Equal(t, 1, sceneCount) + + sceneCount, err = sqb.CountByStudioID(0) + + if err != nil { + t.Fatalf("error calling CountByStudioID: %s", err.Error()) + } + + assert.Equal(t, 0, sceneCount) +} + +func TestFindByMovieID(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + + scenes, err := sqb.FindByMovieID(movieIDs[movieIdxWithScene]) + + if err != nil { + t.Fatalf("error calling FindByMovieID: %s", err.Error()) + } + + assert.Len(t, scenes, 1) + assert.Equal(t, sceneIDs[sceneIdxWithMovie], scenes[0].ID) + + scenes, err = sqb.FindByMovieID(0) + + if err != nil { + t.Fatalf("error calling FindByMovieID: %s", err.Error()) + } + + assert.Len(t, scenes, 0) +} + +func TestFindByPerformerID(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + + scenes, err := sqb.FindByPerformerID(performerIDs[performerIdxWithScene]) + + if err != nil { + t.Fatalf("error calling FindByPerformerID: %s", err.Error()) + } + + assert.Len(t, scenes, 1) + assert.Equal(t, sceneIDs[sceneIdxWithPerformer], scenes[0].ID) + + scenes, err = sqb.FindByPerformerID(0) + + if err != nil { + t.Fatalf("error calling FindByPerformerID: %s", err.Error()) + } + + assert.Len(t, scenes, 0) +} + +func TestFindByStudioID(t *testing.T) { + sqb := models.NewSceneQueryBuilder() + + scenes, err := sqb.FindByStudioID(performerIDs[studioIdxWithScene]) + + if err != nil { + t.Fatalf("error calling FindByStudioID: %s", err.Error()) + } + + assert.Len(t, scenes, 1) + assert.Equal(t, sceneIDs[sceneIdxWithStudio], scenes[0].ID) + + scenes, err = sqb.FindByStudioID(0) + + if err != nil { + t.Fatalf("error calling FindByStudioID: %s", err.Error()) + } + + assert.Len(t, scenes, 0) +} + +// TODO Update +// TODO IncrementOCounter +// TODO DecrementOCounter +// TODO ResetOCounter +// TODO Destroy +// TODO FindByChecksum +// TODO Count +// TODO SizeCount +// TODO All diff --git a/pkg/models/querybuilder_sql.go b/pkg/models/querybuilder_sql.go index e20645b7c..2944462c2 100644 --- a/pkg/models/querybuilder_sql.go +++ b/pkg/models/querybuilder_sql.go @@ -29,11 +29,19 @@ func (qb queryBuilder) executeFind() ([]int, int) { } func (qb *queryBuilder) addWhere(clauses ...string) { - qb.whereClauses = append(qb.whereClauses, clauses...) + for _, clause := range clauses { + if len(clause) > 0 { + qb.whereClauses = append(qb.whereClauses, clauses...) + } + } } func (qb *queryBuilder) addHaving(clauses ...string) { - qb.havingClauses = append(qb.havingClauses, clauses...) + for _, clause := range clauses { + if len(clause) > 0 { + qb.havingClauses = append(qb.havingClauses, clause) + } + } } func (qb *queryBuilder) addArg(args ...interface{}) { @@ -118,7 +126,7 @@ func getSort(sort string, direction string, tableName string) string { colName := getColumn(tableName, sort) var additional string if tableName == "scenes" { - additional = ", bitrate DESC, framerate DESC, rating DESC, duration DESC" + additional = ", bitrate DESC, framerate DESC, scenes.rating DESC, scenes.duration DESC" } else if tableName == "scene_markers" { additional = ", scene_markers.scene_id ASC, scene_markers.seconds ASC" } @@ -137,29 +145,6 @@ func getRandomSort(tableName string, direction string, seed float64) string { return " ORDER BY " + "(substr(" + colName + " * " + randomSortString + ", length(" + colName + ") + 2))" + " " + direction } -func getSearch(columns []string, q string) string { - // TODO - susceptible to SQL injection - var likeClauses []string - queryWords := strings.Split(q, " ") - trimmedQuery := strings.Trim(q, "\"") - if trimmedQuery == q { - // Search for any word - for _, word := range queryWords { - for _, column := range columns { - likeClauses = append(likeClauses, column+" LIKE '%"+word+"%'") - } - } - } else { - // Search the exact query - for _, column := range columns { - likeClauses = append(likeClauses, column+" LIKE '%"+trimmedQuery+"%'") - } - } - likes := strings.Join(likeClauses, " OR ") - - return "(" + likes + ")" -} - func getSearchBinding(columns []string, q string, not bool) (string, []interface{}) { var likeClauses []string var args []interface{} @@ -281,6 +266,18 @@ func runCountQuery(query string, args []interface{}) (int, error) { return result.Int, nil } +func runSumQuery(query string, args []interface{}) (uint64, error) { + // Perform query and fetch result + result := struct { + Uint uint64 `db:"sum"` + }{0} + if err := database.DB.Get(&result, query, args...); err != nil && err != sql.ErrNoRows { + return 0, err + } + + return result.Uint, nil +} + func executeFindQuery(tableName string, body string, args []interface{}, sortAndPagination string, whereClauses []string, havingClauses []string) ([]int, int) { if len(whereClauses) > 0 { body = body + " WHERE " + strings.Join(whereClauses, " AND ") // TODO handle AND or OR diff --git a/pkg/models/querybuilder_studio.go b/pkg/models/querybuilder_studio.go index 1bf501a43..2b65bba2a 100644 --- a/pkg/models/querybuilder_studio.go +++ b/pkg/models/querybuilder_studio.go @@ -79,8 +79,12 @@ func (qb *StudioQueryBuilder) FindBySceneID(sceneID int) (*Studio, error) { return qb.queryStudio(query, args, nil) } -func (qb *StudioQueryBuilder) FindByName(name string, tx *sqlx.Tx) (*Studio, error) { - query := "SELECT * FROM studios WHERE name = ? LIMIT 1" +func (qb *StudioQueryBuilder) FindByName(name string, tx *sqlx.Tx, nocase bool) (*Studio, error) { + query := "SELECT * FROM studios WHERE name = ?" + if nocase { + query += " COLLATE NOCASE" + } + query += " LIMIT 1" args := []interface{}{name} return qb.queryStudio(query, args, tx) } @@ -93,6 +97,10 @@ func (qb *StudioQueryBuilder) All() ([]*Studio, error) { return qb.queryStudios(selectAll("studios")+qb.getStudioSort(nil), nil, nil) } +func (qb *StudioQueryBuilder) AllSlim() ([]*Studio, error) { + return qb.queryStudios("SELECT studios.id, studios.name FROM studios "+qb.getStudioSort(nil), nil, nil) +} + func (qb *StudioQueryBuilder) Query(findFilter *FindFilterType) ([]*Studio, int) { if findFilter == nil { findFilter = &FindFilterType{} @@ -108,7 +116,9 @@ func (qb *StudioQueryBuilder) Query(findFilter *FindFilterType) ([]*Studio, int) if q := findFilter.Q; q != nil && *q != "" { searchColumns := []string{"studios.name"} - whereClauses = append(whereClauses, getSearch(searchColumns, *q)) + clause, thisArgs := getSearchBinding(searchColumns, *q, false) + whereClauses = append(whereClauses, clause) + args = append(args, thisArgs...) } sortAndPagination := qb.getStudioSort(findFilter) + getPagination(findFilter) diff --git a/pkg/models/querybuilder_studio_test.go b/pkg/models/querybuilder_studio_test.go new file mode 100644 index 000000000..5f7460844 --- /dev/null +++ b/pkg/models/querybuilder_studio_test.go @@ -0,0 +1,50 @@ +// +build integration + +package models_test + +import ( + "strings" + "testing" + + "github.com/stashapp/stash/pkg/models" + "github.com/stretchr/testify/assert" +) + +func TestStudioFindByName(t *testing.T) { + + sqb := models.NewStudioQueryBuilder() + + name := studioNames[studioIdxWithScene] // find a studio by name + + studio, err := sqb.FindByName(name, nil, false) + + if err != nil { + t.Fatalf("Error finding studios: %s", err.Error()) + } + + assert.Equal(t, studioNames[studioIdxWithScene], studio.Name.String) + + name = studioNames[studioIdxWithDupName] // find a studio by name nocase + + studio, err = sqb.FindByName(name, nil, true) + + if err != nil { + t.Fatalf("Error finding studios: %s", err.Error()) + } + // studioIdxWithDupName and studioIdxWithScene should have similar names ( only diff should be Name vs NaMe) + //studio.Name should match with studioIdxWithScene since its ID is before studioIdxWithDupName + assert.Equal(t, studioNames[studioIdxWithScene], studio.Name.String) + //studio.Name should match with studioIdxWithDupName if the check is not case sensitive + assert.Equal(t, strings.ToLower(studioNames[studioIdxWithDupName]), strings.ToLower(studio.Name.String)) + +} + +// TODO Create +// TODO Update +// TODO Destroy +// TODO Find +// TODO FindBySceneID +// TODO Count +// TODO All +// TODO AllSlim +// TODO Query diff --git a/pkg/models/querybuilder_tag.go b/pkg/models/querybuilder_tag.go index 91c376d33..35c64c323 100644 --- a/pkg/models/querybuilder_tag.go +++ b/pkg/models/querybuilder_tag.go @@ -33,6 +33,7 @@ func (qb *TagQueryBuilder) Create(newTag Tag, tx *sqlx.Tx) (*Tag, error) { if err := tx.Get(&newTag, `SELECT * FROM tags WHERE id = ? LIMIT 1`, studioID); err != nil { return nil, err } + return &newTag, nil } @@ -90,8 +91,7 @@ func (qb *TagQueryBuilder) FindBySceneID(sceneID int, tx *sqlx.Tx) ([]*Tag, erro query := ` SELECT tags.* FROM tags LEFT JOIN scenes_tags as scenes_join on scenes_join.tag_id = tags.id - LEFT JOIN scenes on scenes_join.scene_id = scenes.id - WHERE scenes.id = ? + WHERE scenes_join.scene_id = ? GROUP BY tags.id ` query += qb.getTagSort(nil) @@ -103,8 +103,7 @@ func (qb *TagQueryBuilder) FindBySceneMarkerID(sceneMarkerID int, tx *sqlx.Tx) ( query := ` SELECT tags.* FROM tags LEFT JOIN scene_markers_tags as scene_markers_join on scene_markers_join.tag_id = tags.id - LEFT JOIN scene_markers on scene_markers_join.scene_marker_id = scene_markers.id - WHERE scene_markers.id = ? + WHERE scene_markers_join.scene_marker_id = ? GROUP BY tags.id ` query += qb.getTagSort(nil) @@ -112,14 +111,22 @@ func (qb *TagQueryBuilder) FindBySceneMarkerID(sceneMarkerID int, tx *sqlx.Tx) ( return qb.queryTags(query, args, tx) } -func (qb *TagQueryBuilder) FindByName(name string, tx *sqlx.Tx) (*Tag, error) { - query := "SELECT * FROM tags WHERE name = ? LIMIT 1" +func (qb *TagQueryBuilder) FindByName(name string, tx *sqlx.Tx, nocase bool) (*Tag, error) { + query := "SELECT * FROM tags WHERE name = ?" + if nocase { + query += " COLLATE NOCASE" + } + query += " LIMIT 1" args := []interface{}{name} return qb.queryTag(query, args, tx) } -func (qb *TagQueryBuilder) FindByNames(names []string, tx *sqlx.Tx) ([]*Tag, error) { - query := "SELECT * FROM tags WHERE name IN " + getInBinding(len(names)) +func (qb *TagQueryBuilder) FindByNames(names []string, tx *sqlx.Tx, nocase bool) ([]*Tag, error) { + query := "SELECT * FROM tags WHERE name" + if nocase { + query += " COLLATE NOCASE" + } + query += " IN " + getInBinding(len(names)) var args []interface{} for _, name := range names { args = append(args, name) @@ -135,6 +142,10 @@ func (qb *TagQueryBuilder) All() ([]*Tag, error) { return qb.queryTags(selectAll("tags")+qb.getTagSort(nil), nil, nil) } +func (qb *TagQueryBuilder) AllSlim() ([]*Tag, error) { + return qb.queryTags("SELECT tags.id, tags.name FROM tags "+qb.getTagSort(nil), nil, nil) +} + func (qb *TagQueryBuilder) Query(findFilter *FindFilterType) ([]*Tag, int) { if findFilter == nil { findFilter = &FindFilterType{} @@ -147,7 +158,9 @@ func (qb *TagQueryBuilder) Query(findFilter *FindFilterType) ([]*Tag, int) { if q := findFilter.Q; q != nil && *q != "" { searchColumns := []string{"tags.name"} - whereClauses = append(whereClauses, getSearch(searchColumns, *q)) + clause, thisArgs := getSearchBinding(searchColumns, *q, false) + whereClauses = append(whereClauses, clause) + args = append(args, thisArgs...) } sortAndPagination := qb.getTagSort(findFilter) + getPagination(findFilter) diff --git a/pkg/models/querybuilder_tag_test.go b/pkg/models/querybuilder_tag_test.go new file mode 100644 index 000000000..052c89fc3 --- /dev/null +++ b/pkg/models/querybuilder_tag_test.go @@ -0,0 +1,118 @@ +// +build integration + +package models_test + +import ( + "strings" + "testing" + + "github.com/stashapp/stash/pkg/models" + "github.com/stretchr/testify/assert" +) + +func TestMarkerFindBySceneMarkerID(t *testing.T) { + tqb := models.NewTagQueryBuilder() + + markerID := markerIDs[markerIdxWithScene] + + tags, err := tqb.FindBySceneMarkerID(markerID, nil) + + if err != nil { + t.Fatalf("Error finding tags: %s", err.Error()) + } + + assert.Len(t, tags, 1) + assert.Equal(t, tagIDs[tagIdxWithMarker], tags[0].ID) + + tags, err = tqb.FindBySceneMarkerID(0, nil) + + if err != nil { + t.Fatalf("Error finding tags: %s", err.Error()) + } + + assert.Len(t, tags, 0) +} + +func TestTagFindByName(t *testing.T) { + + tqb := models.NewTagQueryBuilder() + + name := tagNames[tagIdxWithScene] // find a tag by name + + tag, err := tqb.FindByName(name, nil, false) + + if err != nil { + t.Fatalf("Error finding tags: %s", err.Error()) + } + + assert.Equal(t, tagNames[tagIdxWithScene], tag.Name) + + name = tagNames[tagIdxWithDupName] // find a tag by name nocase + + tag, err = tqb.FindByName(name, nil, true) + + if err != nil { + t.Fatalf("Error finding tags: %s", err.Error()) + } + // tagIdxWithDupName and tagIdxWithScene should have similar names ( only diff should be Name vs NaMe) + //tag.Name should match with tagIdxWithScene since its ID is before tagIdxWithDupName + assert.Equal(t, tagNames[tagIdxWithScene], tag.Name) + //tag.Name should match with tagIdxWithDupName if the check is not case sensitive + assert.Equal(t, strings.ToLower(tagNames[tagIdxWithDupName]), strings.ToLower(tag.Name)) + +} + +func TestTagFindByNames(t *testing.T) { + var names []string + + tqb := models.NewTagQueryBuilder() + + names = append(names, tagNames[tagIdxWithScene]) // find tags by names + + tags, err := tqb.FindByNames(names, nil, false) + if err != nil { + t.Fatalf("Error finding tags: %s", err.Error()) + } + assert.Len(t, tags, 1) + assert.Equal(t, tagNames[tagIdxWithScene], tags[0].Name) + + tags, err = tqb.FindByNames(names, nil, true) // find tags by names nocase + if err != nil { + t.Fatalf("Error finding tags: %s", err.Error()) + } + assert.Len(t, tags, 2) // tagIdxWithScene and tagIdxWithDupName + assert.Equal(t, strings.ToLower(tagNames[tagIdxWithScene]), strings.ToLower(tags[0].Name)) + assert.Equal(t, strings.ToLower(tagNames[tagIdxWithScene]), strings.ToLower(tags[1].Name)) + + names = append(names, tagNames[tagIdx1WithScene]) // find tags by names ( 2 names ) + + tags, err = tqb.FindByNames(names, nil, false) + if err != nil { + t.Fatalf("Error finding tags: %s", err.Error()) + } + assert.Len(t, tags, 2) // tagIdxWithScene and tagIdx1WithScene + assert.Equal(t, tagNames[tagIdxWithScene], tags[0].Name) + assert.Equal(t, tagNames[tagIdx1WithScene], tags[1].Name) + + tags, err = tqb.FindByNames(names, nil, true) // find tags by names ( 2 names nocase) + if err != nil { + t.Fatalf("Error finding tags: %s", err.Error()) + } + assert.Len(t, tags, 4) // tagIdxWithScene and tagIdxWithDupName , tagIdx1WithScene and tagIdx1WithDupName + assert.Equal(t, tagNames[tagIdxWithScene], tags[0].Name) + assert.Equal(t, tagNames[tagIdx1WithScene], tags[1].Name) + assert.Equal(t, tagNames[tagIdx1WithDupName], tags[2].Name) + assert.Equal(t, tagNames[tagIdxWithDupName], tags[3].Name) + +} + +// TODO Create +// TODO Update +// TODO Destroy +// TODO Find +// TODO FindBySceneID +// TODO FindBySceneMarkerID +// TODO Count +// TODO All +// TODO AllSlim +// TODO Query diff --git a/pkg/models/setup_test.go b/pkg/models/setup_test.go new file mode 100644 index 000000000..0cfb25328 --- /dev/null +++ b/pkg/models/setup_test.go @@ -0,0 +1,584 @@ +// +build integration + +package models_test + +import ( + "context" + "database/sql" + "errors" + "fmt" + "io/ioutil" + "os" + "strconv" + "testing" + + "github.com/jmoiron/sqlx" + + "github.com/stashapp/stash/pkg/database" + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/utils" +) + +const totalScenes = 12 +const performersNameCase = 3 +const performersNameNoCase = 2 +const moviesNameCase = 1 +const moviesNameNoCase = 1 +const totalGalleries = 1 +const tagsNameNoCase = 2 +const tagsNameCase = 5 +const studiosNameCase = 1 +const studiosNameNoCase = 1 + +var sceneIDs []int +var performerIDs []int +var movieIDs []int +var galleryIDs []int +var tagIDs []int +var studioIDs []int +var markerIDs []int + +var tagNames []string +var studioNames []string +var movieNames []string +var performerNames []string + +const sceneIdxWithMovie = 0 +const sceneIdxWithGallery = 1 +const sceneIdxWithPerformer = 2 +const sceneIdxWithTwoPerformers = 3 +const sceneIdxWithTag = 4 +const sceneIdxWithTwoTags = 5 +const sceneIdxWithStudio = 6 +const sceneIdxWithMarker = 7 + +const performerIdxWithScene = 0 +const performerIdx1WithScene = 1 +const performerIdx2WithScene = 2 + +// performers with dup names start from the end +const performerIdx1WithDupName = 3 +const performerIdxWithDupName = 4 + +const movieIdxWithScene = 0 + +// movies with dup names start from the end +const movieIdxWithDupName = 1 + +const galleryIdxWithScene = 0 + +const tagIdxWithScene = 0 +const tagIdx1WithScene = 1 +const tagIdx2WithScene = 2 +const tagIdxWithPrimaryMarker = 3 +const tagIdxWithMarker = 4 + +// tags with dup names start from the end +const tagIdx1WithDupName = 5 +const tagIdxWithDupName = 6 + +const studioIdxWithScene = 0 + +// studios with dup names start from the end +const studioIdxWithDupName = 1 + +const markerIdxWithScene = 0 + +const pathField = "Path" +const checksumField = "Checksum" +const titleField = "Title" + +func TestMain(m *testing.M) { + ret := runTests(m) + os.Exit(ret) +} + +func testTeardown(databaseFile string) { + err := database.DB.Close() + + if err != nil { + panic(err) + } + + err = os.Remove(databaseFile) + if err != nil { + panic(err) + } +} + +func runTests(m *testing.M) int { + // create the database file + f, err := ioutil.TempFile("", "*.sqlite") + if err != nil { + panic(fmt.Sprintf("Could not create temporary file: %s", err.Error())) + } + + f.Close() + databaseFile := f.Name() + database.Initialize(databaseFile) + + // defer close and delete the database + defer testTeardown(databaseFile) + + err = populateDB() + if err != nil { + panic(fmt.Sprintf("Could not populate database: %s", err.Error())) + } else { + // run the tests + return m.Run() + } +} + +func populateDB() error { + ctx := context.TODO() + tx := database.DB.MustBeginTx(ctx, nil) + + if err := createScenes(tx, totalScenes); err != nil { + tx.Rollback() + return err + } + + if err := createGalleries(tx, totalGalleries); err != nil { + tx.Rollback() + return err + } + + if err := createMovies(tx, moviesNameCase, moviesNameNoCase); err != nil { + tx.Rollback() + return err + } + + if err := createPerformers(tx, performersNameCase, performersNameNoCase); err != nil { + tx.Rollback() + return err + } + + if err := createTags(tx, tagsNameCase, tagsNameNoCase); err != nil { + tx.Rollback() + return err + } + + if err := createStudios(tx, studiosNameCase, studiosNameNoCase); err != nil { + tx.Rollback() + return err + } + + // TODO - the link methods use Find which don't accept a transaction, so + // to commit the transaction and start a new one + if err := tx.Commit(); err != nil { + return fmt.Errorf("Error committing: %s", err.Error()) + } + + tx = database.DB.MustBeginTx(ctx, nil) + + if err := linkSceneGallery(tx, sceneIdxWithGallery, galleryIdxWithScene); err != nil { + tx.Rollback() + return err + } + + if err := linkSceneMovie(tx, sceneIdxWithMovie, movieIdxWithScene); err != nil { + tx.Rollback() + return err + } + + if err := linkScenePerformers(tx); err != nil { + tx.Rollback() + return err + } + + if err := linkSceneTags(tx); err != nil { + tx.Rollback() + return err + } + + if err := linkSceneStudio(tx, sceneIdxWithStudio, studioIdxWithScene); err != nil { + tx.Rollback() + return err + } + + if err := createMarker(tx, sceneIdxWithMarker, tagIdxWithPrimaryMarker, []int{tagIdxWithMarker}); err != nil { + tx.Rollback() + return err + } + + if err := tx.Commit(); err != nil { + return fmt.Errorf("Error committing: %s", err.Error()) + } + + return nil +} + +func getSceneStringValue(index int, field string) string { + return fmt.Sprintf("scene_%04d_%s", index, field) +} + +func getSceneRating(index int) sql.NullInt64 { + rating := index % 6 + return sql.NullInt64{Int64: int64(rating), Valid: rating > 0} +} + +func getSceneOCounter(index int) int { + return index % 3 +} + +func getSceneDuration(index int) sql.NullFloat64 { + duration := index % 4 + duration = duration * 100 + + return sql.NullFloat64{ + Float64: float64(duration) + 0.432, + Valid: duration != 0, + } +} + +func getSceneHeight(index int) sql.NullInt64 { + heights := []int64{0, 200, 240, 300, 480, 700, 720, 800, 1080, 1500, 2160, 3000} + height := heights[index%len(heights)] + return sql.NullInt64{ + Int64: height, + Valid: height != 0, + } +} + +func getSceneDate(index int) models.SQLiteDate { + dates := []string{"null", "", "0001-01-01", "2001-02-03"} + date := dates[index%len(dates)] + return models.SQLiteDate{ + String: date, + Valid: date != "null", + } +} + +func createScenes(tx *sqlx.Tx, n int) error { + sqb := models.NewSceneQueryBuilder() + + for i := 0; i < n; i++ { + scene := models.Scene{ + Path: getSceneStringValue(i, pathField), + Title: sql.NullString{String: getSceneStringValue(i, titleField), Valid: true}, + Checksum: getSceneStringValue(i, checksumField), + Details: sql.NullString{String: getSceneStringValue(i, "Details"), Valid: true}, + Rating: getSceneRating(i), + OCounter: getSceneOCounter(i), + Duration: getSceneDuration(i), + Height: getSceneHeight(i), + Date: getSceneDate(i), + } + + created, err := sqb.Create(scene, tx) + + if err != nil { + return fmt.Errorf("Error creating scene %v+: %s", scene, err.Error()) + } + + sceneIDs = append(sceneIDs, created.ID) + } + + return nil +} + +func getGalleryStringValue(index int, field string) string { + return "gallery_" + strconv.FormatInt(int64(index), 10) + "_" + field +} + +func createGalleries(tx *sqlx.Tx, n int) error { + gqb := models.NewGalleryQueryBuilder() + + for i := 0; i < n; i++ { + gallery := models.Gallery{ + Path: getGalleryStringValue(i, pathField), + Checksum: getGalleryStringValue(i, checksumField), + } + + created, err := gqb.Create(gallery, tx) + + if err != nil { + return fmt.Errorf("Error creating gallery %v+: %s", gallery, err.Error()) + } + + galleryIDs = append(galleryIDs, created.ID) + } + + return nil +} + +func getMovieStringValue(index int, field string) string { + return "movie_" + strconv.FormatInt(int64(index), 10) + "_" + field +} + +//createMoviees creates n movies with plain Name and o movies with camel cased NaMe included +func createMovies(tx *sqlx.Tx, n int, o int) error { + mqb := models.NewMovieQueryBuilder() + const namePlain = "Name" + const nameNoCase = "NaMe" + + name := namePlain + + for i := 0; i < n+o; i++ { + index := i + + if i >= n { // i=n movies get dup names if case is not checked + index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also + } // so count backwards to 0 as needed + // movies [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different + + movie := models.Movie{ + Name: sql.NullString{String: getMovieStringValue(index, name), Valid: true}, + FrontImage: []byte(models.DefaultMovieImage), + Checksum: utils.MD5FromString(name), + } + + created, err := mqb.Create(movie, tx) + + if err != nil { + return fmt.Errorf("Error creating movie %v+: %s", movie, err.Error()) + } + + movieIDs = append(movieIDs, created.ID) + movieNames = append(movieNames, created.Name.String) + } + + return nil +} + +func getPerformerStringValue(index int, field string) string { + return "performer_" + strconv.FormatInt(int64(index), 10) + "_" + field +} + +func getPerformerBoolValue(index int) bool { + index = index % 2 + return index == 1 +} + +//createPerformers creates n performers with plain Name and o performers with camel cased NaMe included +func createPerformers(tx *sqlx.Tx, n int, o int) error { + pqb := models.NewPerformerQueryBuilder() + const namePlain = "Name" + const nameNoCase = "NaMe" + + name := namePlain + + for i := 0; i < n+o; i++ { + index := i + + if i >= n { // i=n performers get dup names if case is not checked + index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also + } // so count backwards to 0 as needed + // performers [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different + + performer := models.Performer{ + Name: sql.NullString{String: getPerformerStringValue(index, name), Valid: true}, + Checksum: getPerformerStringValue(i, checksumField), + // just use movie image + Image: []byte(models.DefaultMovieImage), + Favorite: sql.NullBool{Bool: getPerformerBoolValue(i), Valid: true}, + } + + created, err := pqb.Create(performer, tx) + + if err != nil { + return fmt.Errorf("Error creating performer %v+: %s", performer, err.Error()) + } + + performerIDs = append(performerIDs, created.ID) + performerNames = append(performerNames, created.Name.String) + } + + return nil +} + +func getTagStringValue(index int, field string) string { + return "tag_" + strconv.FormatInt(int64(index), 10) + "_" + field +} + +//createTags creates n tags with plain Name and o tags with camel cased NaMe included +func createTags(tx *sqlx.Tx, n int, o int) error { + tqb := models.NewTagQueryBuilder() + const namePlain = "Name" + const nameNoCase = "NaMe" + + name := namePlain + + for i := 0; i < n+o; i++ { + index := i + + if i >= n { // i=n tags get dup names if case is not checked + index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also + } // so count backwards to 0 as needed + // tags [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different + + tag := models.Tag{ + Name: getTagStringValue(index, name), + } + + created, err := tqb.Create(tag, tx) + + if err != nil { + return fmt.Errorf("Error creating tag %v+: %s", tag, err.Error()) + } + + tagIDs = append(tagIDs, created.ID) + tagNames = append(tagNames, created.Name) + + } + + return nil +} + +func getStudioStringValue(index int, field string) string { + return "studio_" + strconv.FormatInt(int64(index), 10) + "_" + field +} + +//createStudios creates n studios with plain Name and o studios with camel cased NaMe included +func createStudios(tx *sqlx.Tx, n int, o int) error { + sqb := models.NewStudioQueryBuilder() + const namePlain = "Name" + const nameNoCase = "NaMe" + + name := namePlain + + for i := 0; i < n+o; i++ { + index := i + + if i >= n { // i=n studios get dup names if case is not checked + index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also + } // so count backwards to 0 as needed + // studios [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different + + tag := models.Studio{ + Name: sql.NullString{String: getStudioStringValue(index, name), Valid: true}, + Image: []byte(models.DefaultStudioImage), + Checksum: utils.MD5FromString(name), + } + + created, err := sqb.Create(tag, tx) + + if err != nil { + return fmt.Errorf("Error creating studio %v+: %s", tag, err.Error()) + } + + studioIDs = append(studioIDs, created.ID) + studioNames = append(studioNames, created.Name.String) + } + + return nil +} + +func createMarker(tx *sqlx.Tx, sceneIdx, primaryTagIdx int, tagIdxs []int) error { + mqb := models.NewSceneMarkerQueryBuilder() + + marker := models.SceneMarker{ + SceneID: sql.NullInt64{Int64: int64(sceneIDs[sceneIdx]), Valid: true}, + PrimaryTagID: tagIDs[primaryTagIdx], + } + + created, err := mqb.Create(marker, tx) + + if err != nil { + return fmt.Errorf("Error creating marker %v+: %s", marker, err.Error()) + } + + markerIDs = append(markerIDs, created.ID) + + jqb := models.NewJoinsQueryBuilder() + + joins := []models.SceneMarkersTags{} + + for _, tagIdx := range tagIdxs { + join := models.SceneMarkersTags{ + SceneMarkerID: created.ID, + TagID: tagIDs[tagIdx], + } + joins = append(joins, join) + } + + if err := jqb.CreateSceneMarkersTags(joins, tx); err != nil { + return fmt.Errorf("Error creating marker/tag join: %s", err.Error()) + } + + return nil +} + +func linkSceneMovie(tx *sqlx.Tx, sceneIndex, movieIndex int) error { + jqb := models.NewJoinsQueryBuilder() + + _, err := jqb.AddMoviesScene(sceneIDs[sceneIndex], movieIDs[movieIndex], nil, tx) + return err +} + +func linkScenePerformers(tx *sqlx.Tx) error { + if err := linkScenePerformer(tx, sceneIdxWithPerformer, performerIdxWithScene); err != nil { + return err + } + if err := linkScenePerformer(tx, sceneIdxWithTwoPerformers, performerIdx1WithScene); err != nil { + return err + } + if err := linkScenePerformer(tx, sceneIdxWithTwoPerformers, performerIdx2WithScene); err != nil { + return err + } + + return nil +} + +func linkScenePerformer(tx *sqlx.Tx, sceneIndex, performerIndex int) error { + jqb := models.NewJoinsQueryBuilder() + + _, err := jqb.AddPerformerScene(sceneIDs[sceneIndex], performerIDs[performerIndex], tx) + return err +} + +func linkSceneGallery(tx *sqlx.Tx, sceneIndex, galleryIndex int) error { + gqb := models.NewGalleryQueryBuilder() + + gallery, err := gqb.Find(galleryIDs[galleryIndex]) + + if err != nil { + return fmt.Errorf("error finding gallery: %s", err.Error()) + } + + if gallery == nil { + return errors.New("gallery is nil") + } + + gallery.SceneID = sql.NullInt64{Int64: int64(sceneIDs[sceneIndex]), Valid: true} + _, err = gqb.Update(*gallery, tx) + + return err +} + +func linkSceneTags(tx *sqlx.Tx) error { + if err := linkSceneTag(tx, sceneIdxWithTag, tagIdxWithScene); err != nil { + return err + } + if err := linkSceneTag(tx, sceneIdxWithTwoTags, tagIdx1WithScene); err != nil { + return err + } + if err := linkSceneTag(tx, sceneIdxWithTwoTags, tagIdx2WithScene); err != nil { + return err + } + + return nil +} + +func linkSceneTag(tx *sqlx.Tx, sceneIndex, tagIndex int) error { + jqb := models.NewJoinsQueryBuilder() + + _, err := jqb.AddSceneTag(sceneIDs[sceneIndex], tagIDs[tagIndex], tx) + return err +} + +func linkSceneStudio(tx *sqlx.Tx, sceneIndex, studioIndex int) error { + sqb := models.NewSceneQueryBuilder() + + scene := models.ScenePartial{ + ID: sceneIDs[sceneIndex], + StudioID: &sql.NullInt64{Int64: int64(studioIDs[studioIndex]), Valid: true}, + } + _, err := sqb.Update(scene, tx) + + return err +} diff --git a/pkg/scraper/config.go b/pkg/scraper/config.go index bfeb1e1bc..07e916d16 100644 --- a/pkg/scraper/config.go +++ b/pkg/scraper/config.go @@ -1,6 +1,7 @@ package scraper import ( + "io" "os" "path/filepath" "strings" @@ -139,6 +140,10 @@ func (c *scrapeSceneByURLConfig) resolveFn() { } } +type scraperDebugOptions struct { + PrintHTML bool `yaml:"printHTML"` +} + type scraperConfig struct { ID string Name string `yaml:"name"` @@ -148,21 +153,32 @@ type scraperConfig struct { SceneByFragment *sceneByFragmentConfig `yaml:"sceneByFragment"` SceneByURL []*scrapeSceneByURLConfig `yaml:"sceneByURL"` - StashServer *stashServer `yaml:"stashServer"` - XPathScrapers xpathScrapers `yaml:"xPathScrapers"` + DebugOptions *scraperDebugOptions `yaml:"debug"` + StashServer *stashServer `yaml:"stashServer"` + XPathScrapers xpathScrapers `yaml:"xPathScrapers"` } -func loadScraperFromYAML(path string) (*scraperConfig, error) { +func loadScraperFromYAML(id string, reader io.Reader) (*scraperConfig, error) { ret := &scraperConfig{} - file, err := os.Open(path) - defer file.Close() + parser := yaml.NewDecoder(reader) + parser.SetStrict(true) + err := parser.Decode(&ret) if err != nil { return nil, err } - parser := yaml.NewDecoder(file) - parser.SetStrict(true) - err = parser.Decode(&ret) + + ret.ID = id + + // set the scraper interface + ret.initialiseConfigs() + + return ret, nil +} + +func loadScraperFromYAMLFile(path string) (*scraperConfig, error) { + file, err := os.Open(path) + defer file.Close() if err != nil { return nil, err } @@ -170,12 +186,8 @@ func loadScraperFromYAML(path string) (*scraperConfig, error) { // set id to the filename id := filepath.Base(path) id = id[:strings.LastIndex(id, ".")] - ret.ID = id - // set the scraper interface - ret.initialiseConfigs() - - return ret, nil + return loadScraperFromYAML(id, file) } func (c *scraperConfig) initialiseConfigs() { diff --git a/pkg/scraper/freeones.go b/pkg/scraper/freeones.go index 94bde0e19..3bfc8bcc6 100644 --- a/pkg/scraper/freeones.go +++ b/pkg/scraper/freeones.go @@ -1,306 +1,108 @@ package scraper import ( - "fmt" - "net/http" - "net/url" - "regexp" "strings" - "time" - "github.com/PuerkitoBio/goquery" "github.com/stashapp/stash/pkg/logger" - "github.com/stashapp/stash/pkg/models" ) const freeonesScraperID = "builtin_freeones" -const freeonesName = "Freeones" -var freeonesURLs = []string{ - "freeones.com", -} +// 537: stolen from: https://github.com/stashapp/CommunityScrapers/blob/master/scrapers/NewFreeones.yml +const freeonesScraperConfig = ` +name: Freeones +performerByName: + action: scrapeXPath + queryURL: https://www.freeones.xxx/babes?q={}&v=teasers&s=relevance&l=96&m%5BcanPreviewFeatures%5D=0 + scraper: performerSearch +performerByURL: + - action: scrapeXPath + url: + - https://www.freeones.xxx + scraper: performerScraper + +xPathScrapers: + performerSearch: + performer: + Name: //div[@id="search-result"]//p[@data-test="subject-name"]/text() + URL: + selector: //div[@id="search-result"]//div[@data-test="teaser-subject"]/a/@href + replace: + - regex: ^ + with: https://www.freeones.xxx + - regex: $ + with: /profile + + performerScraper: + performer: + Name: //h1 + URL: + selector: //a[span[text()="Profile"]]/@href + replace: + - regex: ^ + with: https://www.freeones.xxx + Twitter: //div[p[text()='Follow On']]//div//a[@class='d-flex align-items-center justify-content-center mr-2 social-icons color-twitter']/@href + Instagram: //div[p[text()='Follow On']]//div//a[@class='d-flex align-items-center justify-content-center mr-2 social-icons color-telegram']/@href + Birthdate: + selector: //div[p[text()='Personal Information']]//div//p/a/span[contains(text(),'Born On')] + replace: + - regex: Born On + with: + - regex: "," + with: + parseDate: January 2 2006 + Ethnicity: + selector: //div[p[text()='Ethnicity']]//div//p[@class='mb-0 text-center'] + replace: + - regex: Asian + with: "asian" + - regex: Caucasian + with: "white" + - regex: Black + with: "black" + - regex: Latin + with: "hispanic" + Country: //div[p[text()='Personal Information']]//div//p//a[@data-test="link-country"] + EyeColor: //div[p[text()='Eye Color']]//div//p//a//span + Height: + selector: //div[p[text()='Height']]//div//p//a//span + replace: + - regex: \D+[\s\S]+ + with: "" + Measurements: + selector: //div[p[text()='Measurements']]//div[@class='p-3']//p + replace: + - regex: Unknown + with: + FakeTits: + selector: //span[@data-test='link_span_boobs'] + replace: + - regex: Unknown + with: + - regex: Fake + with: "Yes" + - regex: Natural + with: "No" + CareerLength: + selector: //div[p[text()='career']]//div//div[@class='timeline-horizontal mb-3']//div//p[@class='m-0'] + concat: "-" + replace: + - regex: -\w+-\w+-\w+-\w+-\w+$ + with: "" + Aliases: //div[p[text()='Aliases']]//div//p[@class='mb-0 text-center'] + Tattoos: //div[p[text()='Tattoos']]//div//p[@class='mb-0 text-center'] + Piercings: //div[p[text()='Piercings']]//div//p[@class='mb-0 text-center'] + Image: + selector: //div[@class='profile-image-large']//a/img/@src +` func GetFreeonesScraper() scraperConfig { - return scraperConfig{ - ID: freeonesScraperID, - Name: "Freeones", - PerformerByName: &performerByNameConfig{ - performScrape: GetPerformerNames, - }, - PerformerByFragment: &performerByFragmentConfig{ - performScrape: GetPerformer, - }, - PerformerByURL: []*scrapePerformerByURLConfig{ - &scrapePerformerByURLConfig{ - scrapeByURLConfig: scrapeByURLConfig{ - URL: freeonesURLs, - }, - performScrape: GetPerformerURL, - }, - }, - } -} + yml := freeonesScraperConfig -func GetPerformerNames(c scraperTypeConfig, q string) ([]*models.ScrapedPerformer, error) { - // Request the HTML page. - queryURL := "https://www.freeones.com/suggestions.php?q=" + url.PathEscape(q) + "&t=1" - res, err := http.Get(queryURL) + scraper, err := loadScraperFromYAML(freeonesScraperID, strings.NewReader(yml)) if err != nil { - logger.Fatal(err) - } - defer res.Body.Close() - if res.StatusCode != 200 { - return nil, fmt.Errorf("status code error: %d %s", res.StatusCode, res.Status) + logger.Fatalf("Error loading builtin freeones scraper: %s", err.Error()) } - // Load the HTML document - doc, err := goquery.NewDocumentFromReader(res.Body) - if err != nil { - return nil, err - } - - // Find the performers - var performers []*models.ScrapedPerformer - doc.Find(".suggestion").Each(func(i int, s *goquery.Selection) { - name := strings.Trim(s.Text(), " ") - p := models.ScrapedPerformer{ - Name: &name, - } - performers = append(performers, &p) - }) - - return performers, nil -} - -func GetPerformerURL(c scraperTypeConfig, href string) (*models.ScrapedPerformer, error) { - // if we're already in the bio page, just scrape it - if regexp.MustCompile(`\/bio_.*\.php$`).MatchString(href) { - return getPerformerBio(c, href) - } - - // otherwise try to get the bio page from the url - profileRE := regexp.MustCompile(`_links\/(.*?)\/$`) - if profileRE.MatchString(href) { - href = profileRE.ReplaceAllString(href, "_links/bio_$1.php") - return getPerformerBio(c, href) - } - - return nil, nil -} - -func getPerformerBio(c scraperTypeConfig, href string) (*models.ScrapedPerformer, error) { - bioRes, err := http.Get(href) - if err != nil { - return nil, err - } - defer bioRes.Body.Close() - if bioRes.StatusCode != 200 { - return nil, fmt.Errorf("status code error: %d %s", bioRes.StatusCode, bioRes.Status) - } - - // Load the HTML document - bioDoc, err := goquery.NewDocumentFromReader(bioRes.Body) - if err != nil { - return nil, err - } - - params := bioDoc.Find(".paramvalue") - paramIndexes := getIndexes(bioDoc) - - result := models.ScrapedPerformer{} - - performerURL := bioRes.Request.URL.String() - result.URL = &performerURL - - name := paramValue(params, paramIndexes["name"]) - result.Name = &name - - ethnicity := getEthnicity(paramValue(params, paramIndexes["ethnicity"])) - result.Ethnicity = ðnicity - - country := paramValue(params, paramIndexes["country"]) - result.Country = &country - - eyeColor := paramValue(params, paramIndexes["eye_color"]) - result.EyeColor = &eyeColor - - measurements := paramValue(params, paramIndexes["measurements"]) - result.Measurements = &measurements - - fakeTits := paramValue(params, paramIndexes["fake_tits"]) - result.FakeTits = &fakeTits - - careerLength := paramValue(params, paramIndexes["career_length"]) - careerRegex := regexp.MustCompile(`\([\s\S]*`) - careerLength = careerRegex.ReplaceAllString(careerLength, "") - careerLength = trim(careerLength) - result.CareerLength = &careerLength - - tattoos := paramValue(params, paramIndexes["tattoos"]) - result.Tattoos = &tattoos - - piercings := paramValue(params, paramIndexes["piercings"]) - result.Piercings = &piercings - - aliases := paramValue(params, paramIndexes["aliases"]) - result.Aliases = &aliases - - birthdate := paramValue(params, paramIndexes["birthdate"]) - birthdateRegex := regexp.MustCompile(` \(\d* years old\)`) - birthdate = birthdateRegex.ReplaceAllString(birthdate, "") - birthdate = trim(birthdate) - if birthdate != "Unknown" && len(birthdate) > 0 { - t, _ := time.Parse("January _2, 2006", birthdate) // TODO - formattedBirthdate := t.Format("2006-01-02") - result.Birthdate = &formattedBirthdate - } - - height := paramValue(params, paramIndexes["height"]) - heightRegex := regexp.MustCompile(`heightcm = "(.*)"\;`) - heightMatches := heightRegex.FindStringSubmatch(height) - if len(heightMatches) > 1 { - result.Height = &heightMatches[1] - } - - twitterElement := bioDoc.Find(".twitter a") - twitterHref, _ := twitterElement.Attr("href") - if twitterHref != "" { - twitterURL, _ := url.Parse(twitterHref) - twitterHandle := strings.Replace(twitterURL.Path, "/", "", -1) - result.Twitter = &twitterHandle - } - - instaElement := bioDoc.Find(".instagram a") - instaHref, _ := instaElement.Attr("href") - if instaHref != "" { - instaURL, _ := url.Parse(instaHref) - instaHandle := strings.Replace(instaURL.Path, "/", "", -1) - result.Instagram = &instaHandle - } - - return &result, nil -} - -func GetPerformer(c scraperTypeConfig, scrapedPerformer models.ScrapedPerformerInput) (*models.ScrapedPerformer, error) { - if scrapedPerformer.Name == nil { - return nil, nil - } - - performerName := *scrapedPerformer.Name - queryURL := "https://www.freeones.com/search/?t=1&q=" + url.PathEscape(performerName) + "&view=thumbs" - res, err := http.Get(queryURL) - if err != nil { - return nil, err - } - defer res.Body.Close() - if res.StatusCode != 200 { - return nil, fmt.Errorf("status code error: %d %s", res.StatusCode, res.Status) - } - - // Load the HTML document - doc, err := goquery.NewDocumentFromReader(res.Body) - if err != nil { - return nil, err - } - - performerLink := doc.Find("div.Block3 a").FilterFunction(func(i int, s *goquery.Selection) bool { - href, _ := s.Attr("href") - if href == "/html/j_links/Jenna_Leigh_c/" || href == "/html/a_links/Alexa_Grace_c/" { - return false - } - if strings.ToLower(s.Text()) == strings.ToLower(performerName) { - return true - } - alias := s.ParentsFiltered(".babeNameBlock").Find(".babeAlias").First() - if strings.Contains(strings.ToLower(alias.Text()), strings.ToLower(performerName)) { - return true - } - return false - }) - - href, _ := performerLink.Attr("href") - href = strings.TrimSuffix(href, "/") - regex := regexp.MustCompile(`.+_links\/(.+)`) - matches := regex.FindStringSubmatch(href) - if len(matches) < 2 { - return nil, fmt.Errorf("No matches found in %s", href) - } - - href = strings.Replace(href, matches[1], "bio_"+matches[1]+".php", -1) - href = "https://www.freeones.com" + href - - return getPerformerBio(c, href) -} - -func getIndexes(doc *goquery.Document) map[string]int { - var indexes = make(map[string]int) - doc.Find(".paramname").Each(func(i int, s *goquery.Selection) { - index := i + 1 - paramName := trim(s.Text()) - switch paramName { - case "Babe Name:": - indexes["name"] = index - case "Ethnicity:": - indexes["ethnicity"] = index - case "Country of Origin:": - indexes["country"] = index - case "Date of Birth:": - indexes["birthdate"] = index - case "Eye Color:": - indexes["eye_color"] = index - case "Height:": - indexes["height"] = index - case "Measurements:": - indexes["measurements"] = index - case "Fake boobs:": - indexes["fake_tits"] = index - case "Career Start And End": - indexes["career_length"] = index - case "Tattoos:": - indexes["tattoos"] = index - case "Piercings:": - indexes["piercings"] = index - case "Aliases:": - indexes["aliases"] = index - } - }) - return indexes -} - -func getEthnicity(ethnicity string) string { - switch ethnicity { - case "Caucasian": - return "white" - case "Black": - return "black" - case "Latin": - return "hispanic" - case "Asian": - return "asian" - default: - panic("unknown ethnicity") - } -} - -func paramValue(params *goquery.Selection, paramIndex int) string { - i := paramIndex - 1 - if paramIndex <= 0 { - return "" - } - node := params.Get(i).FirstChild - content := trim(node.Data) - if content != "" { - return content - } - node = node.NextSibling - if node == nil { - return "" - } - return trim(node.FirstChild.Data) -} - -// https://stackoverflow.com/questions/20305966/why-does-strip-not-remove-the-leading-whitespace -func trim(text string) string { - // return text.replace(/\A\p{Space}*|\p{Space}*\z/, ""); - return strings.TrimSpace(text) + return *scraper } diff --git a/pkg/scraper/image.go b/pkg/scraper/image.go new file mode 100644 index 000000000..4cdd691c1 --- /dev/null +++ b/pkg/scraper/image.go @@ -0,0 +1,95 @@ +package scraper + +import ( + "io/ioutil" + "net/http" + "strings" + "time" + + "github.com/stashapp/stash/pkg/manager/config" + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/utils" +) + +// Timeout to get the image. Includes transfer time. May want to make this +// configurable at some point. +const imageGetTimeout = time.Second * 30 + +func setPerformerImage(p *models.ScrapedPerformer) error { + if p == nil || p.Image == nil || !strings.HasPrefix(*p.Image, "http") { + // nothing to do + return nil + } + + img, err := getImage(*p.Image) + if err != nil { + return err + } + + p.Image = img + + return nil +} + +func setSceneImage(s *models.ScrapedScene) error { + // don't try to get the image if it doesn't appear to be a URL + if s == nil || s.Image == nil || !strings.HasPrefix(*s.Image, "http") { + // nothing to do + return nil + } + + img, err := getImage(*s.Image) + if err != nil { + return err + } + + s.Image = img + + return nil +} + +func getImage(url string) (*string, error) { + client := &http.Client{ + Timeout: imageGetTimeout, + } + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + userAgent := config.GetScraperUserAgent() + if userAgent != "" { + req.Header.Set("User-Agent", userAgent) + } + + // assume is a URL for now + resp, err := client.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + // determine the image type and set the base64 type + contentType := resp.Header.Get("Content-Type") + if contentType == "" { + contentType = http.DetectContentType(body) + } + + img := "data:" + contentType + ";base64," + utils.GetBase64StringFromData(body) + return &img, nil +} + +func getStashPerformerImage(stashURL string, performerID string) (*string, error) { + return getImage(stashURL + "/performer/" + performerID + "/image") +} + +func getStashSceneImage(stashURL string, sceneID string) (*string, error) { + return getImage(stashURL + "/scene/" + sceneID + "/screenshot") +} diff --git a/pkg/scraper/scrapers.go b/pkg/scraper/scrapers.go index 7c7fcb105..c352dfd20 100644 --- a/pkg/scraper/scrapers.go +++ b/pkg/scraper/scrapers.go @@ -2,6 +2,7 @@ package scraper import ( "errors" + "os" "path/filepath" "strconv" @@ -21,7 +22,13 @@ func loadScrapers() ([]scraperConfig, error) { scrapers = make([]scraperConfig, 0) logger.Debugf("Reading scraper configs from %s", path) - scraperFiles, err := filepath.Glob(filepath.Join(path, "*.yml")) + scraperFiles := []string{} + err := filepath.Walk(path, func(fp string, f os.FileInfo, err error) error { + if filepath.Ext(fp) == ".yml" { + scraperFiles = append(scraperFiles, fp) + } + return nil + }) if err != nil { logger.Errorf("Error reading scraper configs: %s", err.Error()) @@ -32,7 +39,7 @@ func loadScrapers() ([]scraperConfig, error) { scrapers = append(scrapers, GetFreeonesScraper()) for _, file := range scraperFiles { - scraper, err := loadScraperFromYAML(file) + scraper, err := loadScraperFromYAMLFile(file) if err != nil { logger.Errorf("Error loading scraper %s: %s", file, err.Error()) } else { @@ -108,7 +115,17 @@ func ScrapePerformer(scraperID string, scrapedPerformer models.ScrapedPerformerI // find scraper with the provided id s := findScraper(scraperID) if s != nil { - return s.ScrapePerformer(scrapedPerformer) + ret, err := s.ScrapePerformer(scrapedPerformer) + if err != nil { + return nil, err + } + + // post-process - set the image if applicable + if err := setPerformerImage(ret); err != nil { + logger.Warnf("Could not set image using URL %s: %s", *ret.Image, err.Error()) + } + + return ret, nil } return nil, errors.New("Scraper with ID " + scraperID + " not found") @@ -117,7 +134,17 @@ func ScrapePerformer(scraperID string, scrapedPerformer models.ScrapedPerformerI func ScrapePerformerURL(url string) (*models.ScrapedPerformer, error) { for _, s := range scrapers { if s.matchesPerformerURL(url) { - return s.ScrapePerformerURL(url) + ret, err := s.ScrapePerformerURL(url) + if err != nil { + return nil, err + } + + // post-process - set the image if applicable + if err := setPerformerImage(ret); err != nil { + logger.Warnf("Could not set image using URL %s: %s", *ret.Image, err.Error()) + } + + return ret, nil } } @@ -127,7 +154,7 @@ func ScrapePerformerURL(url string) (*models.ScrapedPerformer, error) { func matchPerformer(p *models.ScrapedScenePerformer) error { qb := models.NewPerformerQueryBuilder() - performers, err := qb.FindByNames([]string{p.Name}, nil) + performers, err := qb.FindByNames([]string{p.Name}, nil, true) if err != nil { return err @@ -146,7 +173,7 @@ func matchPerformer(p *models.ScrapedScenePerformer) error { func matchStudio(s *models.ScrapedSceneStudio) error { qb := models.NewStudioQueryBuilder() - studio, err := qb.FindByName(s.Name, nil) + studio, err := qb.FindByName(s.Name, nil, true) if err != nil { return err @@ -161,11 +188,29 @@ func matchStudio(s *models.ScrapedSceneStudio) error { s.ID = &id return nil } +func matchMovie(m *models.ScrapedSceneMovie) error { + qb := models.NewMovieQueryBuilder() + + movies, err := qb.FindByNames([]string{m.Name}, nil, true) + + if err != nil { + return err + } + + if len(movies) != 1 { + // ignore - cannot match + return nil + } + + id := strconv.Itoa(movies[0].ID) + m.ID = &id + return nil +} func matchTag(s *models.ScrapedSceneTag) error { qb := models.NewTagQueryBuilder() - tag, err := qb.FindByName(s.Name, nil) + tag, err := qb.FindByName(s.Name, nil, true) if err != nil { return err @@ -189,6 +234,13 @@ func postScrapeScene(ret *models.ScrapedScene) error { } } + for _, p := range ret.Movies { + err := matchMovie(p) + if err != nil { + return err + } + } + for _, t := range ret.Tags { err := matchTag(t) if err != nil { @@ -203,6 +255,11 @@ func postScrapeScene(ret *models.ScrapedScene) error { } } + // post-process - set the image if applicable + if err := setSceneImage(ret); err != nil { + logger.Warnf("Could not set image using URL %s: %s", *ret.Image, err.Error()) + } + return nil } diff --git a/pkg/scraper/stash.go b/pkg/scraper/stash.go index 3de82efae..92aed73d1 100644 --- a/pkg/scraper/stash.go +++ b/pkg/scraper/stash.go @@ -4,6 +4,7 @@ import ( "context" "strconv" + "github.com/jinzhu/copier" "github.com/shurcooL/graphql" "github.com/stashapp/stash/pkg/models" @@ -16,7 +17,7 @@ func getStashClient(c scraperTypeConfig) *graphql.Client { type stashFindPerformerNamePerformer struct { ID string `json:"id" graphql:"id"` - Name string `json:"id" graphql:"name"` + Name string `json:"name" graphql:"name"` } func (p stashFindPerformerNamePerformer) toPerformer() *models.ScrapedPerformer { @@ -67,12 +68,14 @@ func scrapePerformerFragmentStash(c scraperTypeConfig, scrapedPerformer models.S client := getStashClient(c) var q struct { - FindPerformer *models.ScrapedPerformer `graphql:"findPerformer(id: $f)"` + FindPerformer *models.ScrapedPerformerStash `graphql:"findPerformer(id: $f)"` } + performerID := *scrapedPerformer.URL + // get the id from the URL field vars := map[string]interface{}{ - "f": *scrapedPerformer.URL, + "f": performerID, } err := client.Query(context.Background(), &q, vars) @@ -80,7 +83,20 @@ func scrapePerformerFragmentStash(c scraperTypeConfig, scrapedPerformer models.S return nil, err } - return q.FindPerformer, nil + // need to copy back to a scraped performer + ret := models.ScrapedPerformer{} + err = copier.Copy(&ret, q.FindPerformer) + if err != nil { + return nil, err + } + + // get the performer image directly + ret.Image, err = getStashPerformerImage(c.scraperConfig.StashServer.URL, performerID) + if err != nil { + return nil, err + } + + return &ret, nil } func scrapeSceneFragmentStash(c scraperTypeConfig, scene models.SceneUpdateInput) (*models.ScrapedScene, error) { @@ -99,7 +115,7 @@ func scrapeSceneFragmentStash(c scraperTypeConfig, scene models.SceneUpdateInput } var q struct { - FindScene *models.ScrapedScene `graphql:"findScene(checksum: $c)"` + FindScene *models.ScrapedSceneStash `graphql:"findScene(checksum: $c)"` } checksum := graphql.String(storedScene.Checksum) @@ -128,5 +144,18 @@ func scrapeSceneFragmentStash(c scraperTypeConfig, scene models.SceneUpdateInput } } - return q.FindScene, nil + // need to copy back to a scraped scene + ret := models.ScrapedScene{} + err = copier.Copy(&ret, q.FindScene) + if err != nil { + return nil, err + } + + // get the performer image directly + ret.Image, err = getStashSceneImage(c.scraperConfig.StashServer.URL, q.FindScene.ID) + if err != nil { + return nil, err + } + + return &ret, nil } diff --git a/pkg/scraper/xpath.go b/pkg/scraper/xpath.go index 745e71437..8c2670870 100644 --- a/pkg/scraper/xpath.go +++ b/pkg/scraper/xpath.go @@ -1,7 +1,9 @@ package scraper import ( + "bytes" "errors" + "net/http" "net/url" "reflect" "regexp" @@ -10,11 +12,17 @@ import ( "github.com/antchfx/htmlquery" "golang.org/x/net/html" + "golang.org/x/net/html/charset" "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/models" ) +// Timeout for the scrape http request. Includes transfer time. May want to make this +// configurable at some point. +const scrapeGetTimeout = time.Second * 30 + type commonXPathConfig map[string]string func (c commonXPathConfig) applyCommon(src string) string { @@ -66,7 +74,12 @@ func (c xpathRegexConfig) apply(value string) string { return value } - return re.ReplaceAllString(value, with) + ret := re.ReplaceAllString(value, with) + + logger.Debugf(`Replace: '%s' with '%s'`, regex, with) + logger.Debugf("Before: %s", value) + logger.Debugf("After: %s", ret) + return ret } return value @@ -135,12 +148,28 @@ func (c xpathScraperAttrConfig) getReplace() xpathRegexConfigs { return ret } +func (c xpathScraperAttrConfig) getSubScraper() xpathScraperAttrConfig { + const subScraperKey = "subScraper" + val, _ := c[subScraperKey] + + if val == nil { + return nil + } + + asMap, _ := val.(map[interface{}]interface{}) + if asMap != nil { + return xpathScraperAttrConfig(asMap) + } + + return nil +} + func (c xpathScraperAttrConfig) concatenateResults(nodes []*html.Node) string { separator := c.getConcat() result := []string{} for _, elem := range nodes { - text := htmlquery.InnerText(elem) + text := NodeText(elem) text = commonPostProcess(text) result = append(result, text) @@ -174,10 +203,45 @@ func (c xpathScraperAttrConfig) replaceRegex(value string) string { return replace.apply(value) } +func (c xpathScraperAttrConfig) applySubScraper(value string) string { + subScraper := c.getSubScraper() + + if subScraper == nil { + return value + } + + logger.Debugf("Sub-scraping for: %s", value) + doc, err := loadURL(value, nil) + + if err != nil { + logger.Warnf("Error getting URL '%s' for sub-scraper: %s", value, err.Error()) + return "" + } + + found := runXPathQuery(doc, subScraper.getSelector(), nil) + + if len(found) > 0 { + // check if we're concatenating the results into a single result + var result string + if subScraper.hasConcat() { + result = subScraper.concatenateResults(found) + } else { + result = NodeText(found[0]) + result = commonPostProcess(result) + } + + result = subScraper.postProcess(result) + return result + } + + return "" +} + func (c xpathScraperAttrConfig) postProcess(value string) string { // perform regex replacements first value = c.replaceRegex(value) value = c.parseDate(value) + value = c.applySubScraper(value) return value } @@ -219,7 +283,7 @@ func (s xpathScraperConfig) process(doc *html.Node, common commonXPathConfig) xP if len(found) > 0 { for i, elem := range found { - text := htmlquery.InnerText(elem) + text := NodeText(elem) text = commonPostProcess(text) ret = ret.setKey(i, k, text) @@ -239,7 +303,7 @@ func (s xpathScraperConfig) process(doc *html.Node, common commonXPathConfig) xP ret = ret.setKey(i, k, result) } else { for i, elem := range found { - text := htmlquery.InnerText(elem) + text := NodeText(elem) text = commonPostProcess(text) text = attrConfig.postProcess(text) @@ -265,6 +329,7 @@ const ( XPathScraperConfigSceneTags = "Tags" XPathScraperConfigScenePerformers = "Performers" XPathScraperConfigSceneStudio = "Studio" + XPathScraperConfigSceneMovies = "Movies" ) func (s xpathScraper) GetSceneSimple() xpathScraperConfig { @@ -274,7 +339,7 @@ func (s xpathScraper) GetSceneSimple() xpathScraperConfig { if mapped != nil { for k, v := range mapped { - if k != XPathScraperConfigSceneTags && k != XPathScraperConfigScenePerformers && k != XPathScraperConfigSceneStudio { + if k != XPathScraperConfigSceneTags && k != XPathScraperConfigScenePerformers && k != XPathScraperConfigSceneStudio && k != XPathScraperConfigSceneMovies { ret[k] = v } } @@ -313,6 +378,10 @@ func (s xpathScraper) GetSceneStudio() xpathScraperConfig { return s.getSceneSubMap(XPathScraperConfigSceneStudio) } +func (s xpathScraper) GetSceneMovies() xpathScraperConfig { + return s.getSceneSubMap(XPathScraperConfigSceneMovies) +} + func (s xpathScraper) scrapePerformer(doc *html.Node) (*models.ScrapedPerformer, error) { var ret models.ScrapedPerformer @@ -358,13 +427,16 @@ func (s xpathScraper) scrapeScene(doc *html.Node) (*models.ScrapedScene, error) scenePerformersMap := s.GetScenePerformers() sceneTagsMap := s.GetSceneTags() sceneStudioMap := s.GetSceneStudio() + sceneMoviesMap := s.GetSceneMovies() + logger.Debug(`Processing scene:`) results := sceneMap.process(doc, s.Common) if len(results) > 0 { results[0].apply(&ret) // now apply the performers and tags if scenePerformersMap != nil { + logger.Debug(`Processing scene performers:`) performerResults := scenePerformersMap.process(doc, s.Common) for _, p := range performerResults { @@ -375,6 +447,7 @@ func (s xpathScraper) scrapeScene(doc *html.Node) (*models.ScrapedScene, error) } if sceneTagsMap != nil { + logger.Debug(`Processing scene tags:`) tagResults := sceneTagsMap.process(doc, s.Common) for _, p := range tagResults { @@ -385,6 +458,7 @@ func (s xpathScraper) scrapeScene(doc *html.Node) (*models.ScrapedScene, error) } if sceneStudioMap != nil { + logger.Debug(`Processing scene studio:`) studioResults := sceneStudioMap.process(doc, s.Common) if len(studioResults) > 0 { @@ -393,6 +467,18 @@ func (s xpathScraper) scrapeScene(doc *html.Node) (*models.ScrapedScene, error) ret.Studio = studio } } + + if sceneMoviesMap != nil { + logger.Debug(`Processing scene movies:`) + movieResults := sceneMoviesMap.process(doc, s.Common) + + for _, p := range movieResults { + movie := &models.ScrapedSceneMovie{} + p.apply(movie) + ret.Movies = append(ret.Movies, movie) + } + + } } return &ret, nil @@ -433,10 +519,47 @@ func (r xPathResults) setKey(index int, key string, value string) xPathResults { r = append(r, make(xPathResult)) } + logger.Debugf(`[%d][%s] = %s`, index, key, value) r[index][key] = value return r } +func loadURL(url string, c *scraperConfig) (*html.Node, error) { + client := &http.Client{ + Timeout: scrapeGetTimeout, + } + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + userAgent := config.GetScraperUserAgent() + 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")) + if err != nil { + return nil, err + } + + ret, err := html.Parse(r) + + if err == nil && c != nil && c.DebugOptions != nil && c.DebugOptions.PrintHTML { + var b bytes.Buffer + html.Render(&b, ret) + logger.Infof("loadURL (%s) response: \n%s", url, b.String()) + } + + return ret, err +} + func scrapePerformerURLXpath(c scraperTypeConfig, url string) (*models.ScrapedPerformer, error) { scraper := c.scraperConfig.XPathScrapers[c.Scraper] @@ -444,7 +567,7 @@ func scrapePerformerURLXpath(c scraperTypeConfig, url string) (*models.ScrapedPe return nil, errors.New("xpath scraper with name " + c.Scraper + " not found in config") } - doc, err := htmlquery.LoadURL(url) + doc, err := loadURL(url, c.scraperConfig) if err != nil { return nil, err @@ -460,7 +583,7 @@ func scrapeSceneURLXPath(c scraperTypeConfig, url string) (*models.ScrapedScene, return nil, errors.New("xpath scraper with name " + c.Scraper + " not found in config") } - doc, err := htmlquery.LoadURL(url) + doc, err := loadURL(url, c.scraperConfig) if err != nil { return nil, err @@ -484,7 +607,7 @@ func scrapePerformerNamesXPath(c scraperTypeConfig, name string) ([]*models.Scra u := c.QueryURL u = strings.Replace(u, placeholder, escapedName, -1) - doc, err := htmlquery.LoadURL(u) + doc, err := loadURL(u, c.scraperConfig) if err != nil { return nil, err @@ -492,3 +615,10 @@ func scrapePerformerNamesXPath(c scraperTypeConfig, name string) ([]*models.Scra return scraper.scrapePerformers(doc) } + +func NodeText(n *html.Node) string { + if n != nil && n.Type == html.CommentNode { + return htmlquery.OutputHTML(n, true) + } + return htmlquery.InnerText(n) +} diff --git a/pkg/utils/crypto.go b/pkg/utils/crypto.go index 4fd911ccb..ab765b6a0 100644 --- a/pkg/utils/crypto.go +++ b/pkg/utils/crypto.go @@ -2,6 +2,7 @@ package utils import ( "crypto/md5" + "crypto/rand" "fmt" "io" "os" @@ -31,3 +32,9 @@ func MD5FromFilePath(filePath string) (string, error) { checksum := h.Sum(nil) return fmt.Sprintf("%x", checksum), nil } + +func GenerateRandomKey(l int) string { + b := make([]byte, l) + rand.Read(b) + return fmt.Sprintf("%x", b) +} diff --git a/pkg/utils/file.go b/pkg/utils/file.go index e029c3073..b80e888c9 100644 --- a/pkg/utils/file.go +++ b/pkg/utils/file.go @@ -1,10 +1,12 @@ package utils import ( + "archive/zip" "fmt" "github.com/h2non/filetype" "github.com/h2non/filetype/types" "io/ioutil" + "math" "os" "os/user" "path/filepath" @@ -26,11 +28,8 @@ func FileExists(path string) (bool, error) { _, err := os.Stat(path) if err == nil { return true, nil - } else if os.IsNotExist(err) { - return false, err - } else { - panic(err) } + return false, err } // DirExists returns true if the given path exists and is a directory @@ -66,7 +65,12 @@ func EnsureDir(path string) error { return err } -// RemoveDir removes the given file path along with all of its contents +// EnsureDirAll will create a directory at the given path along with any necessary parents if they don't already exist +func EnsureDirAll(path string) error { + return os.MkdirAll(path, 0755) +} + +// RemoveDir removes the given dir (if it exists) along with all of its contents func RemoveDir(path string) error { return os.RemoveAll(path) } @@ -96,15 +100,6 @@ func EmptyDir(path string) error { // ListDir will return the contents of a given directory path as a string slice func ListDir(path string) []string { - if path == "" { - path = GetHomeDirectory() - } - - absolutePath, err := filepath.Abs(path) - if err == nil { - path = absolutePath - } - files, err := ioutil.ReadDir(path) if err != nil { path = filepath.Dir(path) @@ -133,3 +128,94 @@ func GetHomeDirectory() string { } return currentUser.HomeDir } + +// IsZipFileUnmcompressed returns true if zip file in path is using 0 compression level +func IsZipFileUncompressed(path string) (bool, error) { + r, err := zip.OpenReader(path) + if err != nil { + fmt.Printf("Error reading zip file %s: %s\n", path, err) + return false, err + } else { + defer r.Close() + for _, f := range r.File { + if f.FileInfo().IsDir() { // skip dirs, they always get store level compression + continue + } + return f.Method == 0, nil // check compression level of first actual file + } + } + return false, nil +} + +// humanize code taken from https://github.com/dustin/go-humanize and adjusted + +func logn(n, b float64) float64 { + return math.Log(n) / math.Log(b) +} + +// HumanizeBytes returns a human readable bytes string of a uint +func HumanizeBytes(s uint64) string { + sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"} + if s < 10 { + return fmt.Sprintf("%d B", s) + } + e := math.Floor(logn(float64(s), 1024)) + suffix := sizes[int(e)] + val := math.Floor(float64(s)/math.Pow(1024, e)*10+0.5) / 10 + f := "%.0f %s" + if val < 10 { + f = "%.1f %s" + } + + return fmt.Sprintf(f, val, suffix) +} + +// WriteFile writes file to path creating parent directories if needed +func WriteFile(path string, file []byte) error { + pathErr := EnsureDirAll(filepath.Dir(path)) + if pathErr != nil { + return fmt.Errorf("Cannot ensure path %s", pathErr) + } + + err := ioutil.WriteFile(path, file, 0755) + if err != nil { + return fmt.Errorf("Write error for thumbnail %s: %s ", path, err) + } + return nil +} + +// GetIntraDir returns a string that can be added to filepath.Join to implement directory depth, "" on error +//eg given a pattern of 0af63ce3c99162e9df23a997f62621c5 and a depth of 2 length of 3 +//returns 0af/63c or 0af\63c ( dependin on os) that can be later used like this filepath.Join(directory, intradir, basename) +func GetIntraDir(pattern string, depth, length int) string { + if depth < 1 || length < 1 || (depth*length > len(pattern)) { + return "" + } + intraDir := pattern[0:length] // depth 1 , get length number of characters from pattern + for i := 1; i < depth; i++ { // for every extra depth: move to the right of the pattern length positions, get length number of chars + intraDir = filepath.Join(intraDir, pattern[length*i:length*(i+1)]) // adding each time to intradir the extra characters with a filepath join + } + return intraDir +} + +func GetDir(path string) string { + if path == "" { + path = GetHomeDirectory() + } + + absolutePath, err := filepath.Abs(path) + if err == nil { + path = absolutePath + } + return absolutePath +} + +func GetParent(path string) *string { + isRoot := path[len(path)-1:] == "/" + if isRoot { + return nil + } else { + parentPath := filepath.Clean(path + "/..") + return &parentPath + } +} diff --git a/scripts/check-gofmt.sh b/scripts/check-gofmt.sh new file mode 100644 index 000000000..7ea5015c8 --- /dev/null +++ b/scripts/check-gofmt.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +# Copyright (c) 2012 The Go Authors. All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: + +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +gofiles=$(git diff --name-only --diff-filter=ACM develop -- '*.go' ':!vendor') +[ -z "$gofiles" ] && exit 0 + +unformatted=$(gofmt -l $gofiles) +[ -z "$unformatted" ] && exit 0 + +# Some files are not gofmt'd. Print message and fail. + +echo >&2 "Go files must be formatted with gofmt. Please run:" +for fn in $unformatted; do + echo >&2 " gofmt -w $PWD/$fn" +done + +exit 1 diff --git a/scripts/cross-compile.sh b/scripts/cross-compile.sh index daf9930ef..4601b8c85 100755 --- a/scripts/cross-compile.sh +++ b/scripts/cross-compile.sh @@ -4,11 +4,11 @@ DATE=`go run -mod=vendor scripts/getDate.go` GITHASH=`git rev-parse --short HEAD` STASH_VERSION=`git describe --tags --exclude latest_develop` VERSION_FLAGS="-X 'github.com/stashapp/stash/pkg/api.version=$STASH_VERSION' -X 'github.com/stashapp/stash/pkg/api.buildstamp=$DATE' -X 'github.com/stashapp/stash/pkg/api.githash=$GITHASH'" -SETUP="export GO111MODULE=on; export CGO_ENABLED=1;" -WINDOWS="GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ packr2 build -o dist/stash-win.exe -ldflags \"-extldflags '-static' $VERSION_FLAGS\" -tags extended -v -mod=vendor;" -DARWIN="GOOS=darwin GOARCH=amd64 CC=o64-clang CXX=o64-clang++ packr2 build -o dist/stash-osx -ldflags \"$VERSION_FLAGS\" -tags extended -v -mod=vendor;" -LINUX="packr2 build -o dist/stash-linux -ldflags \"$VERSION_FLAGS\" -v -mod=vendor;" -RASPPI="GOOS=linux GOARCH=arm GOARM=5 CC=arm-linux-gnueabi-gcc packr2 build -o dist/stash-pi -ldflags \"$VERSION_FLAGS\" -v -mod=vendor;" +SETUP="export GO111MODULE=on; export CGO_ENABLED=1; packr2;" +WINDOWS="echo '=== Building Windows binary ==='; GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build -o dist/stash-win.exe -ldflags \"-extldflags '-static' $VERSION_FLAGS\" -tags extended -v -mod=vendor;" +DARWIN="echo '=== Building OSX binary ==='; GOOS=darwin GOARCH=amd64 CC=o64-clang CXX=o64-clang++ go build -o dist/stash-osx -ldflags \"$VERSION_FLAGS\" -tags extended -v -mod=vendor;" +LINUX="echo '=== Building Linux binary ==='; go build -o dist/stash-linux -ldflags \"$VERSION_FLAGS\" -v -mod=vendor;" +RASPPI="echo '=== Building Raspberry Pi binary ==='; GOOS=linux GOARCH=arm GOARM=5 CC=arm-linux-gnueabi-gcc go build -o dist/stash-pi -ldflags \"$VERSION_FLAGS\" -v -mod=vendor;" COMMAND="$SETUP $WINDOWS $DARWIN $LINUX $RASPPI" diff --git a/static/performer_male/noname_male_01.jpg b/static/performer_male/noname_male_01.jpg new file mode 100644 index 000000000..f2c6fe51d Binary files /dev/null and b/static/performer_male/noname_male_01.jpg differ diff --git a/static/performer_male/noname_male_02.jpg b/static/performer_male/noname_male_02.jpg new file mode 100644 index 000000000..93ad7ec9d Binary files /dev/null and b/static/performer_male/noname_male_02.jpg differ diff --git a/ui/login/login.css b/ui/login/login.css new file mode 100644 index 000000000..e0ed5f797 --- /dev/null +++ b/ui/login/login.css @@ -0,0 +1,117 @@ +/* try to reflect the default css as much as possible */ +* { + box-sizing: border-box; +} +html { + font-size: 14px; +} + +body { + background-color: #202b33; + color: #f5f8fa; + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + margin: 0; + padding: 0; + overflow-y: hidden; +} + +h6 { + font-size: 1rem; + margin-top: 0; + margin-bottom: .5rem; + font-weight: 500; + line-height: 1.2; +} + +button, input { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +.card { + background-color: #30404d; + border-radius: 3px; + box-shadow: 0 0 0 1px rgba(16,22,26,.4), 0 0 0 rgba(16,22,26,0), 0 0 0 rgba(16,22,26,0); + padding: 20px; +} + +.dialog { + display: flex; + align-items: center; + justify-content: center; + + width: 100%; + height: 100vh; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +.form-group { + margin-bottom: 1rem; +} + +.form-control { + display: block; + width: 100%; + height: calc(1.5em + .75rem + 2px); + padding: .375rem .75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-clip: padding-box; + border: 1px solid #ced4da; + border-radius: .25rem; + -webkit-transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; + transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; +} + +.text-input { + border: 0; + box-shadow: 0 0 0 0 rgba(19,124,189,0), 0 0 0 0 rgba(19,124,189,0), 0 0 0 0 rgba(19,124,189,0), inset 0 0 0 1px rgba(16,22,26,.3), inset 0 1px 1px rgba(16,22,26,.4); + color: #f5f8fa; +} + +.text-input, .text-input:focus, .text-input[readonly] { + background-color: rgba(16,22,26,.3); +} + +.btn { + display: inline-block; + font-weight: 400; + color: #212529; + text-align: center; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: initial; + border: 1px solid transparent; + padding: .375rem .75rem; + font-size: 1rem; + line-height: 1.5; + border-radius: .25rem; + -webkit-transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; + transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out; +} + +.btn-primary { + color: #fff; + background-color: #137cbd; + border-color: #137cbd; +} + +.login-error { + color: #db3737; + font-size: 80%; + font-weight: 500; + padding-bottom: 1rem; +} diff --git a/ui/login/login.html b/ui/login/login.html new file mode 100644 index 000000000..c8ad61256 --- /dev/null +++ b/ui/login/login.html @@ -0,0 +1,40 @@ + + + + + + Login + + + + + + + +
+
+
+
+ + +
+
+
+ + +
+ + + + +
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/ui/setup/migrate.html b/ui/setup/migrate.html new file mode 100644 index 000000000..632f30144 --- /dev/null +++ b/ui/setup/migrate.html @@ -0,0 +1,37 @@ + + + + + Stash + + + + + + + +
+

+ Your current stash database is schema version {{.ExistingVersion}} and needs to be migrated to version {{.MigrateVersion}}. + This version of Stash will not function without migrating the database. The schema migration process is not reversible. Once the migration is + performed, your database will be incompatible with previous versions of stash. +

+ +

+ It is recommended that you backup your existing database before you migrate. We can do this for you, writing a backup to {{.BackupPath}} if required. +

+ +
+
+ + + +
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/ui/v2.5/.babelrc b/ui/v2.5/.babelrc new file mode 100644 index 000000000..c14b2828d --- /dev/null +++ b/ui/v2.5/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["react-app"] +} diff --git a/ui/v2.5/.editorconfig b/ui/v2.5/.editorconfig new file mode 100644 index 000000000..86a63dc0f --- /dev/null +++ b/ui/v2.5/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/ui/v2.5/.env b/ui/v2.5/.env new file mode 100644 index 000000000..e56c6e3aa --- /dev/null +++ b/ui/v2.5/.env @@ -0,0 +1,2 @@ +BROWSER=none +PORT=3000 diff --git a/ui/v2.5/.eslintrc.json b/ui/v2.5/.eslintrc.json new file mode 100644 index 000000000..f26d60fca --- /dev/null +++ b/ui/v2.5/.eslintrc.json @@ -0,0 +1,66 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json" + }, + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "airbnb-typescript", + "airbnb/hooks", + "prettier", + "prettier/react", + "prettier/@typescript-eslint" + ], + "rules": { + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-explicit-any": 2, + "lines-between-class-members": "off", + "@typescript-eslint/interface-name-prefix": [ + "warn", + { "prefixWithI": "always" } + ], + "import/extensions": [ + "error", + "ignorePackages", + { + "js": "never", + "jsx": "never", + "ts": "never", + "tsx": "never" + } + ], + "import/named": "off", + "import/namespace": "off", + "import/default": "off", + "import/no-named-as-default-member": "off", + "import/no-named-as-default": "off", + "import/no-cycle": "off", + "import/no-unused-modules": "off", + "import/no-deprecated": "off", + "import/no-unresolved": "off", + "import/prefer-default-export": "off", + "import/no-extraneous-dependencies": "off", + "indent": "off", + "@typescript-eslint/indent": "off", + "react/prop-types": "off", + "react/destructuring-assignment": "off", + "react/jsx-props-no-spreading": "off", + "react/style-prop-object": ["error", { + "allow": ["FormattedNumber"] + }], + "spaced-comment": ["error", "always", { + "markers": ["/"] + }], + "max-classes-per-file": "off", + "no-plusplus": "off", + "prefer-destructuring": ["error", {"object": true, "array": false}], + "default-case": "off", + "consistent-return": "off", + "@typescript-eslint/no-use-before-define": ["error", { "functions": false, "classes": true }], + "no-underscore-dangle": "off", + "no-nested-ternary": "off", + "jsx-a11y/media-has-caption": "off" + } +} diff --git a/ui/v2.5/.gitignore b/ui/v2.5/.gitignore new file mode 100755 index 000000000..d7b8f1bd7 --- /dev/null +++ b/ui/v2.5/.gitignore @@ -0,0 +1,25 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +.eslintcache diff --git a/ui/v2.5/.stylelintrc b/ui/v2.5/.stylelintrc new file mode 100644 index 000000000..a87318b34 --- /dev/null +++ b/ui/v2.5/.stylelintrc @@ -0,0 +1,93 @@ +{ + "plugins": [ + "stylelint-order" + ], + "extends": "stylelint-config-prettier", + "rules": { + "indentation": 2, + "at-rule-empty-line-before": [ "always", { + except: ["after-same-name", "first-nested" ], + ignore: ["after-comment"], + } ], + "at-rule-no-vendor-prefix": true, + "selector-no-vendor-prefix": true, + "block-closing-brace-newline-after": "always", + "block-closing-brace-newline-before": "always-multi-line", + "block-closing-brace-space-before": "always-single-line", + "block-no-empty": true, + "block-opening-brace-newline-after": "always-multi-line", + "block-opening-brace-space-after": "always-single-line", + "block-opening-brace-space-before": "always", + "color-hex-case": "lower", + "color-hex-length": "short", + "color-no-invalid-hex": true, + "comment-empty-line-before": [ "always", { + except: ["first-nested"], + ignore: ["stylelint-commands"], + } ], + "comment-whitespace-inside": "always", + "declaration-bang-space-after": "never", + "declaration-bang-space-before": "always", + "declaration-block-no-shorthand-property-overrides": true, + "declaration-block-semicolon-newline-after": "always-multi-line", + "declaration-block-semicolon-space-after": "always-single-line", + "declaration-block-semicolon-space-before": "never", + "declaration-block-single-line-max-declarations": 1, + "declaration-block-trailing-semicolon": "always", + "declaration-colon-space-after": "always-single-line", + "declaration-colon-space-before": "never", + "declaration-no-important": true, + "font-family-name-quotes": "always-where-recommended", + "function-calc-no-unspaced-operator": true, + "function-comma-newline-after": "always-multi-line", + "function-comma-space-after": "always-single-line", + "function-comma-space-before": "never", + "function-linear-gradient-no-nonstandard-direction": true, + "function-parentheses-newline-inside": "always-multi-line", + "function-parentheses-space-inside": "never-single-line", + "function-url-quotes": "always", + "function-whitespace-after": "always", + "length-zero-no-unit": true, + "max-empty-lines": 1, + "max-nesting-depth": 4, + "media-feature-colon-space-after": "always", + "media-feature-colon-space-before": "never", + "media-feature-range-operator-space-after": "always", + "media-feature-range-operator-space-before": "always", + "media-query-list-comma-newline-after": "always-multi-line", + "media-query-list-comma-space-after": "always-single-line", + "media-query-list-comma-space-before": "never", + "media-feature-parentheses-space-inside": "never", + "no-descending-specificity": null, + "no-invalid-double-slash-comments": true, + "no-missing-end-of-source-newline": true, + "number-max-precision": 2, + "number-no-trailing-zeros": true, + "order/order": [ + "custom-properties", + "declarations" + ], + "order/properties-alphabetical-order": true, + "rule-empty-line-before": ["always-multi-line", { + except: ["after-single-line-comment", "first-nested" ], + ignore: ["after-comment"], + }], + "selector-max-id": 1, + "selector-max-type": 2, + "selector-class-pattern": "^(\\.*[A-Z]*[a-z]+)+(-[a-z0-9]+)*$", + "selector-combinator-space-after": "always", + "selector-combinator-space-before": "always", + "selector-list-comma-newline-after": "always", + "selector-list-comma-space-before": "never", + "selector-max-universal": 0, + "selector-type-case": "lower", + "selector-pseudo-element-colon-notation": "double", + "string-no-newline": true, + "string-quotes": "double", + "time-min-milliseconds": 100, + "unit-blacklist": ["em"], + "value-list-comma-space-after": "always-single-line", + "value-list-comma-space-before": "never", + "value-no-vendor-prefix": true + }, +} diff --git a/ui/v2.5/.vscode/launch.json b/ui/v2.5/.vscode/launch.json new file mode 100644 index 000000000..a0b21cbef --- /dev/null +++ b/ui/v2.5/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Chrome", + "url": "http://localhost:3000", + "webRoot": "${workspaceFolder}/src", + "sourceMapPathOverrides": { + "webpack:///src/*": "${webRoot}/*" + } + } + ] +} \ No newline at end of file diff --git a/ui/v2.5/.vscode/settings.json b/ui/v2.5/.vscode/settings.json new file mode 100644 index 000000000..ba34e28f0 --- /dev/null +++ b/ui/v2.5/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib", + "editor.tabSize": 2, + "editor.renderWhitespace": "boundary", + "editor.wordWrap": "bounded", + "javascript.preferences.importModuleSpecifier": "relative", + "typescript.preferences.importModuleSpecifier": "relative", + "editor.wordWrapColumn": 120, + "editor.rulers": [120] +} \ No newline at end of file diff --git a/ui/v2.5/README.md b/ui/v2.5/README.md new file mode 100755 index 000000000..bb215a23c --- /dev/null +++ b/ui/v2.5/README.md @@ -0,0 +1,74 @@ +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `yarn start` + +Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.
+You will also see any lint errors in the console. + +### `yarn test` + +Launches the test runner in the interactive watch mode.
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `yarn build` + +Builds the app for production to the `build` folder.
+It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.
+Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `yarn format` + +Formats the whitespace of all typescript and scss code with prettier, to ease editing and ensure a common code style. + +Should ideally be run before all frontend PRs. + +### `yarn eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). + +### Code Splitting + +This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting + +### Analyzing the Bundle Size + +This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size + +### Making a Progressive Web App + +This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app + +### Advanced Configuration + +This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration + +### Deployment + +This section has moved here: https://facebook.github.io/create-react-app/docs/deployment + +### `yarn build` fails to minify + +This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify diff --git a/ui/v2.5/codegen.yml b/ui/v2.5/codegen.yml new file mode 100644 index 000000000..dbab06402 --- /dev/null +++ b/ui/v2.5/codegen.yml @@ -0,0 +1,15 @@ +overwrite: true +schema: "../../graphql/schema/**/*.graphql" +documents: "../../graphql/documents/**/*.graphql" +generates: + src/core/generated-graphql.tsx: + config: + withHooks: true + withHOC: false + withComponents: false + plugins: + - add: "/* eslint-disable */" + - time + - typescript + - typescript-operations + - typescript-react-apollo diff --git a/ui/v2.5/package.json b/ui/v2.5/package.json new file mode 100644 index 000000000..29f895d36 --- /dev/null +++ b/ui/v2.5/package.json @@ -0,0 +1,104 @@ +{ + "name": "stash", + "version": "0.1.0", + "private": true, + "sideEffects": false, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject", + "build-ci": "yarn validate && yarn build", + "validate": "yarn lint && yarn format-check", + "lint": "yarn lint:css && yarn lint:js", + "lint:js": "eslint --cache src/**/*.{ts,tsx}", + "lint:css": "stylelint \"src/**/*.scss\"", + "format": "prettier --write \"src/**/!(generated-graphql).{js,jsx,ts,tsx,scss}\"", + "format-check": "prettier --check \"src/**/!(generated-graphql).{js,jsx,ts,tsx,scss}\"", + "gqlgen": "gql-gen --config codegen.yml", + "extract": "NODE_ENV=development extract-messages -l=en,de -o src/locale -d en --flat false 'src/**/!(*.test).tsx'" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ], + "dependencies": { + "@apollo/react-hooks": "^3.1.5", + "@formatjs/intl-numberformat": "^4.2.1", + "@fortawesome/fontawesome-svg-core": "^1.2.28", + "@fortawesome/free-solid-svg-icons": "^5.13.0", + "@fortawesome/react-fontawesome": "^0.1.9", + "apollo-cache": "^1.3.4", + "apollo-cache-inmemory": "^1.6.5", + "apollo-client": "^2.6.8", + "apollo-link": "^1.2.14", + "apollo-link-error": "^1.1.13", + "apollo-link-http": "^1.5.17", + "apollo-link-ws": "^1.0.20", + "apollo-utilities": "^1.3.3", + "axios": "0.19.2", + "bootstrap": "^4.4.1", + "classnames": "^2.2.6", + "flag-icon-css": "^3.4.6", + "formik": "^2.1.4", + "graphql": "^14.5.8", + "graphql-tag": "^2.10.3", + "i18n-iso-countries": "^5.2.0", + "jimp": "^0.12.1", + "localforage": "1.7.3", + "lodash": "^4.17.15", + "query-string": "6.12.1", + "react": "16.13.1", + "react-apollo": "^3.1.5", + "react-bootstrap": "1.0.1", + "react-dom": "16.13.1", + "react-images": "0.5.19", + "react-intl": "^4.5.1", + "react-jw-player": "1.19.1", + "react-markdown": "^4.3.1", + "react-photo-gallery": "^8.0.0", + "react-router-bootstrap": "^0.25.0", + "react-router-dom": "^5.1.2", + "react-select": "^3.1.0", + "subscriptions-transport-ws": "^0.9.16", + "universal-cookie": "^4.0.3" + }, + "devDependencies": { + "@graphql-codegen/add": "^1.13.5", + "@graphql-codegen/cli": "^1.13.5", + "@graphql-codegen/time": "^1.13.5", + "@graphql-codegen/typescript": "^1.13.5", + "@graphql-codegen/typescript-compatibility": "^1.13.5", + "@graphql-codegen/typescript-operations": "^1.13.5", + "@graphql-codegen/typescript-react-apollo": "^1.13.5", + "@types/classnames": "^2.2.10", + "@types/lodash": "^4.14.150", + "@types/node": "13.13.4", + "@types/react": "16.9.34", + "@types/react-dom": "^16.9.7", + "@types/react-images": "^0.5.1", + "@types/react-router-bootstrap": "^0.24.5", + "@types/react-router-dom": "5.1.5", + "@types/react-select": "^3.0.12", + "@typescript-eslint/eslint-plugin": "^2.30.0", + "@typescript-eslint/parser": "^2.30.0", + "eslint": "^6.8.0", + "eslint-config-airbnb-typescript": "^7.2.1", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.20.2", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-hooks": "^4.0.0", + "extract-react-intl-messages": "^4.1.1", + "node-sass": "4.14.0", + "postcss-safe-parser": "^4.0.2", + "prettier": "2.0.5", + "react-scripts": "^3.4.1", + "stylelint": "^13.3.3", + "stylelint-config-prettier": "^8.0.1", + "stylelint-order": "^4.0.0", + "typescript": "^3.8.3" + } +} diff --git a/ui/v2.5/public/favicon.ico b/ui/v2.5/public/favicon.ico new file mode 100644 index 000000000..6ff0465ca Binary files /dev/null and b/ui/v2.5/public/favicon.ico differ diff --git a/ui/v2.5/public/index.html b/ui/v2.5/public/index.html new file mode 100755 index 000000000..322bc1d11 --- /dev/null +++ b/ui/v2.5/public/index.html @@ -0,0 +1,41 @@ + + + + + + + + + + + Stash + + + +
+ + + diff --git a/ui/v2.5/public/jwplayer/jwplayer.controls.js b/ui/v2.5/public/jwplayer/jwplayer.controls.js new file mode 100644 index 000000000..eb88b0783 --- /dev/null +++ b/ui/v2.5/public/jwplayer/jwplayer.controls.js @@ -0,0 +1,95 @@ +/*! +JW Player version 8.11.5 +Copyright (c) 2019, JW Player, All Rights Reserved +https://github.com/jwplayer/jwplayer/blob/v8.11.5/README.md + +This source code and its use and distribution is subject to the terms and conditions of the applicable license agreement. +https://www.jwplayer.com/tos/ + +This product includes portions of other software. For the full text of licenses, see below: + +JW Player Third Party Software Notices and/or Additional Terms and Conditions + +************************************************************************************************** +The following software is used under Apache License 2.0 +************************************************************************************************** + +vtt.js v0.13.0 +Copyright (c) 2019 Mozilla (http://mozilla.org) +https://github.com/mozilla/vtt.js/blob/v0.13.0/LICENSE + +* * * + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. + +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. + +************************************************************************************************** +The following software is used under MIT license +************************************************************************************************** + +Underscore.js v1.6.0 +Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative +https://github.com/jashkenas/underscore/blob/1.6.0/LICENSE + +Backbone backbone.events.js v1.1.2 +Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud +https://github.com/jashkenas/backbone/blob/1.1.2/LICENSE + +Promise Polyfill v7.1.1 +Copyright (c) 2014 Taylor Hakes and Forbes Lindesay +https://github.com/taylorhakes/promise-polyfill/blob/v7.1.1/LICENSE + +can-autoplay.js v3.0.0 +Copyright (c) 2017 video-dev +https://github.com/video-dev/can-autoplay/blob/v3.0.0/LICENSE + +* * * + +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. + +************************************************************************************************** +The following software is used under W3C license +************************************************************************************************** + +Intersection Observer v0.5.0 +Copyright (c) 2016 Google Inc. (http://google.com) +https://github.com/w3c/IntersectionObserver/blob/v0.5.0/LICENSE.md + +* * * + +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. + +This work is being provided by the copyright holders under the following license. + +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. + +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. + +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. +*/ +(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[1],[,,,,,,,,,,,,,,,,,function(t,e,n){"use strict";n.r(e);var i,o=n(8),a=n(3),r=n(7),l=n(43),s=n(5),c=n(15),u=n(40);function w(t){return i||(i=new DOMParser),Object(s.r)(Object(s.s)(i.parseFromString(t,"image/svg+xml").documentElement))}var p=function(t,e,n,i){var o=document.createElement("div");o.className="jw-icon jw-icon-inline jw-button-color jw-reset "+t,o.setAttribute("role","button"),o.setAttribute("tabindex","0"),n&&o.setAttribute("aria-label",n),o.style.display="none";var a=new u.a(o).on("click tap enter",e||function(){});return i&&Array.prototype.forEach.call(i,(function(t){"string"==typeof t?o.appendChild(w(t)):o.appendChild(t)})),{ui:a,element:function(){return o},toggle:function(t){t?this.show():this.hide()},show:function(){o.style.display=""},hide:function(){o.style.display="none"}}},d=n(0),j=n(71),h=n.n(j),f=n(72),g=n.n(f),b=n(73),y=n.n(b),v=n(74),m=n.n(v),x=n(75),k=n.n(x),O=n(76),C=n.n(O),S=n(77),T=n.n(S),M=n(78),z=n.n(M),E=n(79),L=n.n(E),B=n(80),_=n.n(B),V=n(81),A=n.n(V),N=n(82),H=n.n(N),P=n(83),I=n.n(P),R=n(84),q=n.n(R),D=n(85),U=n.n(D),F=n(86),W=n.n(F),Z=n(62),K=n.n(Z),X=n(87),Y=n.n(X),G=n(88),J=n.n(G),Q=n(89),$=n.n(Q),tt=n(90),et=n.n(tt),nt=n(91),it=n.n(nt),ot=n(92),at=n.n(ot),rt=n(93),lt=n.n(rt),st=n(94),ct=n.n(st),ut=null;function wt(t){var e=ht().querySelector(dt(t));if(e)return jt(e);throw new Error("Icon not found "+t)}function pt(t){var e=ht().querySelectorAll(t.split(",").map(dt).join(","));if(!e.length)throw new Error("Icons not found "+t);return Array.prototype.map.call(e,(function(t){return jt(t)}))}function dt(t){return".jw-svg-icon-".concat(t)}function jt(t){return t.cloneNode(!0)}function ht(){return ut||(ut=w(""+h.a+g.a+y.a+m.a+k.a+C.a+T.a+z.a+L.a+_.a+A.a+H.a+I.a+q.a+U.a+W.a+K.a+Y.a+J.a+$.a+et.a+it.a+at.a+lt.a+ct.a+"")),ut}var ft=n(10);function gt(t,e){for(var n=0;n10&&delete bt[e[0]];var n=w(t);bt[t]=n}return bt[t].cloneNode(!0)}(e):((r=document.createElement("div")).className="jw-icon jw-button-image jw-button-color jw-reset",e&&Object(ft.d)(r,{backgroundImage:"url(".concat(e,")")})),l.appendChild(r),new u.a(l).on("click tap enter",i,this),l.addEventListener("mousedown",(function(t){t.preventDefault()})),this.id=o,this.buttonElement=l}var e,n,i;return e=t,(n=[{key:"element",value:function(){return this.buttonElement}},{key:"toggle",value:function(t){t?this.show():this.hide()}},{key:"show",value:function(){this.buttonElement.style.display=""}},{key:"hide",value:function(){this.buttonElement.style.display="none"}}])&>(e.prototype,n),i&>(e,i),t}(),vt=n(11);function mt(t,e){for(var n=0;n=0&&(e.left-=n,e.right-=n),e},kt=function(){function t(e,n){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),Object(d.g)(this,r.a),this.className=e+" jw-background-color jw-reset",this.orientation=n}var e,n,i;return e=t,(n=[{key:"setup",value:function(){this.el=Object(s.e)(function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return''}(this.className,"jw-slider-"+this.orientation)),this.elementRail=this.el.getElementsByClassName("jw-slider-container")[0],this.elementBuffer=this.el.getElementsByClassName("jw-buffer")[0],this.elementProgress=this.el.getElementsByClassName("jw-progress")[0],this.elementThumb=this.el.getElementsByClassName("jw-knob")[0],this.ui=new u.a(this.element(),{preventScrolling:!0}).on("dragStart",this.dragStart,this).on("drag",this.dragMove,this).on("dragEnd",this.dragEnd,this).on("click tap",this.tap,this)}},{key:"dragStart",value:function(){this.trigger("dragStart"),this.railBounds=xt(this.elementRail)}},{key:"dragEnd",value:function(t){this.dragMove(t),this.trigger("dragEnd")}},{key:"dragMove",value:function(t){var e,n,i=this.railBounds=this.railBounds?this.railBounds:xt(this.elementRail);return n="horizontal"===this.orientation?(e=t.pageX)i.right?100:100*Object(l.a)((e-i.left)/i.width,0,1):(e=t.pageY)>=i.bottom?0:e<=i.top?100:100*Object(l.a)((i.height-(e-i.top))/i.height,0,1),this.render(n),this.update(n),!1}},{key:"tap",value:function(t){this.railBounds=xt(this.elementRail),this.dragMove(t)}},{key:"limit",value:function(t){return t}},{key:"update",value:function(t){this.trigger("update",{percentage:t})}},{key:"render",value:function(t){t=Math.max(0,Math.min(t,100)),"horizontal"===this.orientation?(this.elementThumb.style.left=t+"%",this.elementProgress.style.width=t+"%"):(this.elementThumb.style.bottom=t+"%",this.elementProgress.style.height=t+"%")}},{key:"updateBuffer",value:function(t){this.elementBuffer.style.width=t+"%"}},{key:"element",value:function(){return this.el}}])&&mt(e.prototype,n),i&&mt(e,i),t}(),Ot=function(t,e){t&&e&&(t.setAttribute("aria-label",e),t.setAttribute("role","button"),t.setAttribute("tabindex","0"))};function Ct(t,e){for(var n=0;n0&&Array.prototype.forEach.call(o,(function(t){"string"==typeof t?a.el.appendChild(w(t)):a.el.appendChild(t)}))}var e,n,i;return e=t,(n=[{key:"addContent",value:function(t){this.content&&this.removeContent(),this.content=t,this.tooltip.appendChild(t)}},{key:"removeContent",value:function(){this.content&&(this.tooltip.removeChild(this.content),this.content=null)}},{key:"hasContent",value:function(){return!!this.content}},{key:"element",value:function(){return this.el}},{key:"openTooltip",value:function(t){this.isOpen||(this.trigger("open-"+this.componentType,t,{isOpen:!0}),this.isOpen=!0,Object(s.v)(this.el,this.openClass,this.isOpen))}},{key:"closeTooltip",value:function(t){this.isOpen&&(this.trigger("close-"+this.componentType,t,{isOpen:!1}),this.isOpen=!1,Object(s.v)(this.el,this.openClass,this.isOpen))}},{key:"toggleOpenState",value:function(t){this.isOpen?this.closeTooltip(t):this.openTooltip(t)}}])&&Ct(e.prototype,n),i&&Ct(e,i),t}(),Tt=n(22),Mt=n(57);function zt(t,e){for(var n=0;n=this.thumbnails.length&&(e=this.thumbnails.length-1);var n=this.thumbnails[e].img;return n.indexOf("://")<0&&(n=this.vttPath?this.vttPath+"/"+n:n),n},loadThumbnail:function(t){var e=this.chooseThumbnail(t),n={margin:"0 auto",backgroundPosition:"0 0"};if(e.indexOf("#xywh")>0)try{var i=/(.+)#xywh=(\d+),(\d+),(\d+),(\d+)/.exec(e);e=i[1],n.backgroundPosition=-1*i[2]+"px "+-1*i[3]+"px",n.width=i[4],this.timeTip.setWidth(+n.width),n.height=i[5]}catch(t){return}else this.individualImage||(this.individualImage=new Image,this.individualImage.onload=Object(d.a)((function(){this.individualImage.onload=null,this.timeTip.image({width:this.individualImage.width,height:this.individualImage.height}),this.timeTip.setWidth(this.individualImage.width)}),this),this.individualImage.src=e);return n.backgroundImage='url("'+e+'")',n},showThumbnail:function(t){this._model.get("containerWidth")<=420||this.thumbnails.length<1||this.timeTip.image(this.loadThumbnail(t))},resetThumbnails:function(){this.timeTip.image({backgroundImage:"",width:0,height:0}),this.thumbnails=[]}};function Vt(t,e,n){return(Vt="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,n){var i=function(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=Rt(t)););return t}(t,e);if(i){var o=Object.getOwnPropertyDescriptor(i,e);return o.get?o.get.call(n):o.value}})(t,e,n||t)}function At(t){return(At="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function Nt(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Ht(t,e){for(var n=0;n-1&&(i="Live")}var w=this.timeTip;w.update(i),this.textLength!==i.length&&(this.textLength=i.length,w.resetWidth()),this.showThumbnail(u),Object(s.a)(w.el,"jw-open");var p=w.getWidth(),d=a.width/100,j=o-a.width,h=0;p>j&&(h=(p-j)/(200*d));var f=100*Math.min(1-h,Math.max(h,c)).toFixed(3);Object(ft.d)(w.el,{left:f+"%"})}}},{key:"hideTimeTooltip",value:function(){Object(s.o)(this.timeTip.el,"jw-open")}},{key:"updateCues",value:function(t,e){var n=this;this.resetCues(),e&&e.length&&(e.forEach((function(t){n.addCue(t)})),this.drawCues())}},{key:"updateAriaText",value:function(){var t=this._model;if(!t.get("seeking")){var e=t.get("position"),n=t.get("duration"),i=Object(vt.timeFormat)(e);"DVR"!==this.streamType&&(i+=" of ".concat(Object(vt.timeFormat)(n)));var o=this.el;document.activeElement!==o&&(this.timeUpdateKeeper.textContent=i),Object(s.t)(o,"aria-valuenow",e),Object(s.t)(o,"aria-valuetext",i)}}},{key:"reset",value:function(){this.resetThumbnails(),this.timeTip.resetWidth(),this.textLength=0}}]),e}(kt);Object(d.g)(Ft.prototype,Lt,_t);var Wt=Ft;function Zt(t,e){for(var n=0;n=75&&!t),Object(s.t)(r,"aria-valuenow",o),Object(s.t)(l,"aria-valuenow",o);var c="Volume ".concat(o,"%");Object(s.t)(r,"aria-valuetext",c),Object(s.t)(l,"aria-valuetext",c),document.activeElement!==r&&document.activeElement!==l&&(this._volumeAnnouncer.textContent=c)}}},{key:"onCastAvailable",value:function(t,e){this.elements.cast.toggle(e)}},{key:"onCastActive",value:function(t,e){this.elements.fullscreen.toggle(!e),this.elements.cast.button&&Object(s.v)(this.elements.cast.button,"jw-off",!e)}},{key:"onElapsed",value:function(t,e){var n,i,o=t.get("duration");if("DVR"===t.get("streamType")){var a=Math.ceil(e),r=this._model.get("dvrSeekLimit");n=i=a>=-r?"":"-"+Object(vt.timeFormat)(-(e+r)),t.set("dvrLive",a>=-r)}else n=Object(vt.timeFormat)(e),i=Object(vt.timeFormat)(o-e);this.elements.elapsed.textContent=n,this.elements.countdown.textContent=i}},{key:"onDuration",value:function(t,e){this.elements.duration.textContent=Object(vt.timeFormat)(Math.abs(e))}},{key:"onAudioMode",value:function(t,e){var n=this.elements.time.element();e?this.elements.buttonContainer.insertBefore(n,this.elements.elapsed):Object(s.m)(this.el,n)}},{key:"element",value:function(){return this.el}},{key:"setAltText",value:function(t,e){this.elements.alt.textContent=e}},{key:"closeMenus",value:function(t){this.menus.forEach((function(e){t&&t.target===e.el||e.closeTooltip(t)}))}},{key:"rewind",value:function(){var t,e=0,n=this._model.get("currentTime");n?t=n-10:(t=this._model.get("position")-10,"DVR"===this._model.get("streamType")&&(e=this._model.get("duration"))),this._api.seek(Math.max(t,e),{reason:"interaction"})}},{key:"onState",value:function(t,e){var n=t.get("localization"),i=n.play;this.setPlayText(i),e===a.pb&&("LIVE"!==t.get("streamType")?(i=n.pause,this.setPlayText(i)):(i=n.stop,this.setPlayText(i))),Object(s.t)(this.elements.play.element(),"aria-label",i)}},{key:"onStreamTypeChange",value:function(t,e){var n="LIVE"===e,i="DVR"===e;this.elements.rewind.toggle(!n),this.elements.live.toggle(n||i),Object(s.t)(this.elements.live.element(),"tabindex",n?"-1":"0"),this.elements.duration.style.display=i?"none":"",this.onDuration(t,t.get("duration")),this.onState(t,t.get("state"))}},{key:"addLogo",value:function(t){var e=this.elements.buttonContainer,n=new yt(t.file,this._model.get("localization").logo,(function(){t.link&&Object(s.l)(t.link,"_blank",{rel:"noreferrer"})}),"logo","jw-logo-button");t.link||Object(s.t)(n.element(),"tabindex","-1"),e.insertBefore(n.element(),e.querySelector(".jw-spacer").nextSibling)}},{key:"goToLiveEdge",value:function(){if("DVR"===this._model.get("streamType")){var t=Math.min(this._model.get("position"),-1),e=this._model.get("dvrSeekLimit");this._api.seek(Math.max(-e,t),{reason:"interaction"}),this._api.play({reason:"interaction"})}}},{key:"updateButtons",value:function(t,e,n){if(e){var i,o,a=this.elements.buttonContainer;e!==n&&n?(i=ce(e,n),o=ce(n,e),this.removeButtons(a,o)):i=e;for(var r=i.length-1;r>=0;r--){var l=i[r],s=new yt(l.img,l.tooltip,l.callback,l.id,l.btnClass);l.tooltip&&ie(s.element(),l.id,l.tooltip);var c=void 0;"related"===s.id?c=this.elements.settingsButton.element():"share"===s.id?c=a.querySelector('[button="related"]')||this.elements.settingsButton.element():(c=this.elements.spacer.nextSibling)&&"logo"===c.getAttribute("button")&&(c=c.nextSibling),a.insertBefore(s.element(),c)}}}},{key:"removeButtons",value:function(t,e){for(var n=e.length;n--;){var i=t.querySelector('[button="'.concat(e[n].id,'"]'));i&&t.removeChild(i)}}},{key:"toggleCaptionsButtonState",value:function(t){var e=this.elements.captionsButton;e&&Object(s.v)(e.element(),"jw-off",!t)}},{key:"destroy",value:function(){var t=this;this._model.off(null,null,this),Object.keys(this.elements).forEach((function(e){var n=t.elements[e];n&&"function"==typeof n.destroy&&t.elements[e].destroy()})),this.ui.forEach((function(t){t.destroy()})),this.ui=[]}}])&&ae(e.prototype,n),i&&ae(e,i),t}(),pe=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return'
')+'
')+"
"},de=function(t){return'
'+pe("rewind",t.rewind)+pe("display",t.playback)+pe("next",t.next)+"
"};function je(t,e){for(var n=0;n'.concat(a.playback,"
")),Object(s.a)(o.icon,"jw-idle-label"),o.icon.appendChild(l))}return o}var n,i,o;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&ve(t,e)}(e,t),n=e,(i=[{key:"element",value:function(){return this.el}}])&&ge(n.prototype,i),o&&ge(n,o),e}(r.a);function xe(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";return'
'+'
'.concat(t,"
")+'
'.concat(e,"
")+'
'.concat(n,"
")+"
"+'')+"
"}());e.querySelector(".jw-nextup-close").appendChild(wt("close")),this.addContent(e),this.closeButton=this.content.querySelector(".jw-nextup-close"),this.closeButton.setAttribute("aria-label",this.localization.close),this.tooltip=this.content.querySelector(".jw-nextup-tooltip");var n=this._model,i=n.player;this.enabled=!1,n.on("change:nextUp",this.onNextUp,this),i.change("duration",this.onDuration,this),i.change("position",this.onElapsed,this),i.change("streamType",this.onStreamType,this),i.change("state",(function(t,e){"complete"===e&&this.toggle(!1)}),this),this.closeUi=new u.a(this.closeButton,{directSelect:!0}).on("click tap enter",(function(){this.nextUpSticky=!1,this.toggle(!1)}),this),this.tooltipUi=new u.a(this.tooltip).on("click tap",this.click,this)}},{key:"loadThumbnail",value:function(t){return this.nextUpImage=new Image,this.nextUpImage.onload=function(){this.nextUpImage.onload=null}.bind(this),this.nextUpImage.src=t,{backgroundImage:'url("'+t+'")'}}},{key:"click",value:function(){var t=this.feedShownId;this.reset(),this._api.next({feedShownId:t,reason:"interaction"})}},{key:"toggle",value:function(t,e){if(this.enabled&&(Object(s.v)(this.container,"jw-nextup-sticky",!!this.nextUpSticky),this.shown!==t)){this.shown=t,Object(s.v)(this.container,"jw-nextup-container-visible",t),Object(s.v)(this._playerElement,"jw-flag-nextup",t);var n=this._model.get("nextUp");t&&n?(this.feedShownId=Object(oe.b)(oe.a),this.trigger("nextShown",{mode:n.mode,ui:"nextup",itemsShown:[n],feedData:n.feedData,reason:e,feedShownId:this.feedShownId})):this.feedShownId=""}}},{key:"setNextUpItem",value:function(t){var e=this;setTimeout((function(){if(e.thumbnail=e.content.querySelector(".jw-nextup-thumbnail"),Object(s.v)(e.content,"jw-nextup-thumbnail-visible",!!t.image),t.image){var n=e.loadThumbnail(t.image);Object(ft.d)(e.thumbnail,n)}e.header=e.content.querySelector(".jw-nextup-header"),e.header.textContent=Object(s.e)(e.localization.nextUp).textContent,e.title=e.content.querySelector(".jw-nextup-title");var i=t.title;e.title.textContent=i?Object(s.e)(i).textContent:"";var o=t.duration;o&&(e.duration=e.content.querySelector(".jw-nextup-duration"),e.duration.textContent="number"==typeof o?Object(vt.timeFormat)(o):o)}),500)}},{key:"onNextUp",value:function(t,e){this.reset(),e||(e={showNextUp:!1}),this.enabled=!(!e.title&&!e.image),this.enabled&&(e.showNextUp||(this.nextUpSticky=!1,this.toggle(!1)),this.setNextUpItem(e))}},{key:"onDuration",value:function(t,e){if(e){var n=t.get("nextupoffset"),i=-10;n&&(i=Object(Te.d)(n,e)),i<0&&(i+=e),Object(Te.c)(n)&&e-5=this.offset;i&&void 0===n?(this.nextUpSticky=i,this.toggle(i,"time")):!i&&n&&this.reset()}}},{key:"onStreamType",value:function(t,e){"VOD"!==e&&(this.nextUpSticky=!1,this.toggle(!1))}},{key:"element",value:function(){return this.container}},{key:"addContent",value:function(t){this.content&&this.removeContent(),this.content=t,this.container.appendChild(t)}},{key:"removeContent",value:function(){this.content&&(this.container.removeChild(this.content),this.content=null)}},{key:"reset",value:function(){this.nextUpSticky=void 0,this.toggle(!1)}},{key:"destroy",value:function(){this.off(),this._model.off(null,null,this),this.closeUi&&this.closeUi.destroy(),this.tooltipUi&&this.tooltipUi.destroy()}}])&&Me(e.prototype,n),i&&Me(e,i),t}(),Ee=function(t,e){var n=t.featured,i=t.showLogo,o=t.type;return t.logo=i?'':"",'
  • ').concat(Le[o](t,e),"
  • ")},Le={link:function(t){var e=t.link,n=t.title,i=t.logo;return'').concat(i).concat(n||"","")},info:function(t,e){return'")},share:function(t,e){return'")},keyboardShortcuts:function(t,e){return'")}},Be=n(23),_e=n(6),Ve=n(13);function Ae(t,e){for(var n=0;nJW Player '.concat(t,""),a={items:[{type:"info"},{title:Object(Ve.e)(i)?"".concat(o," ").concat(i):"".concat(i," ").concat(o),type:"link",featured:!0,showLogo:!0,link:"https://jwplayer.com/learn-more?e=".concat(Ne[n])}]},r=e.get("provider"),l=a.items;if(r&&r.name.indexOf("flash")>=0){var s="Flash Version "+Object(_e.a)();l.push({title:s,type:"link",link:"http://www.adobe.com/software/flash/about/"})}return this.shortcutsTooltip&&l.splice(l.length-1,0,{type:"keyboardShortcuts"}),a}},{key:"rightClick",value:function(t){if(this.lazySetup(),this.mouseOverContext)return!1;this.hideMenu(),this.showMenu(t),this.addHideMenuHandlers()}},{key:"getOffset",value:function(t){var e=Object(s.c)(this.wrapperElement),n=t.pageX-e.left,i=t.pageY-e.top;return this.model.get("touchMode")&&(i-=100),{x:n,y:i}}},{key:"showMenu",value:function(t){var e=this,n=this.getOffset(t);return this.el.style.left=n.x+"px",this.el.style.top=n.y+"px",this.outCount=0,Object(s.a)(this.playerContainer,"jw-flag-rightclick-open"),Object(s.a)(this.el,"jw-open"),clearTimeout(this._menuTimeout),this._menuTimeout=setTimeout((function(){return e.hideMenu()}),3e3),!1}},{key:"hideMenu",value:function(t){t&&this.el&&this.el.contains(t.target)||(Object(s.o)(this.playerContainer,"jw-flag-rightclick-open"),Object(s.o)(this.el,"jw-open"))}},{key:"lazySetup",value:function(){var t,e,n,i,o=this,a=(t=this.buildArray(),e=this.model.get("localization"),n=t.items,i=(void 0===n?[]:n).map((function(t){return Ee(t,e)})),'
    '+'
      '.concat(i.join(""),"
    ")+"
    ");if(this.el){if(this.html!==a){this.html=a;var r=He(a);Object(s.h)(this.el);for(var l=r.childNodes.length;l--;)this.el.appendChild(r.firstChild)}}else this.html=a,this.el=He(this.html),this.wrapperElement.appendChild(this.el),this.hideMenuHandler=function(t){return o.hideMenu(t)},this.overHandler=function(){o.mouseOverContext=!0},this.outHandler=function(t){o.mouseOverContext=!1,t.relatedTarget&&!o.el.contains(t.relatedTarget)&&++o.outCount>1&&o.hideMenu()},this.infoOverlayHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.infoOverlay.open()},this.shortcutsTooltipHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.shortcutsTooltip.open()}}},{key:"setup",value:function(t,e,n){this.wrapperElement=n,this.model=t,this.mouseOverContext=!1,this.playerContainer=e,this.ui=new u.a(n).on("longPress",this.rightClick,this)}},{key:"addHideMenuHandlers",value:function(){this.removeHideMenuHandlers(),this.wrapperElement.addEventListener("touchstart",this.hideMenuHandler),document.addEventListener("touchstart",this.hideMenuHandler),o.OS.mobile||(this.wrapperElement.addEventListener("click",this.hideMenuHandler),document.addEventListener("click",this.hideMenuHandler),this.el.addEventListener("mouseover",this.overHandler),this.el.addEventListener("mouseout",this.outHandler)),this.el.querySelector(".jw-info-overlay-item").addEventListener("click",this.infoOverlayHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").addEventListener("click",this.shortcutsTooltipHandler)}},{key:"removeHideMenuHandlers",value:function(){this.wrapperElement&&(this.wrapperElement.removeEventListener("click",this.hideMenuHandler),this.wrapperElement.removeEventListener("touchstart",this.hideMenuHandler)),this.el&&(this.el.querySelector(".jw-info-overlay-item").removeEventListener("click",this.infoOverlayHandler),this.el.removeEventListener("mouseover",this.overHandler),this.el.removeEventListener("mouseout",this.outHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").removeEventListener("click",this.shortcutsTooltipHandler)),document.removeEventListener("click",this.hideMenuHandler),document.removeEventListener("touchstart",this.hideMenuHandler)}},{key:"destroy",value:function(){clearTimeout(this._menuTimeout),this.removeHideMenuHandlers(),this.el&&(this.hideMenu(),this.hideMenuHandler=null,this.el=null),this.wrapperElement&&(this.wrapperElement.oncontextmenu=null,this.wrapperElement=null),this.model&&(this.model=null),this.ui&&(this.ui.destroy(),this.ui=null)}}])&&Ae(e.prototype,n),i&&Ae(e,i),t}(),Ie=function(t){return'")},Re=function(t){return'"},qe=function(t){return'"};function De(t){return(De="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function Ue(t,e){return!e||"object"!==De(e)&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function Fe(t){return(Fe=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function We(t,e){return(We=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function Ze(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Ke(t,e){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:Ie;Ze(this,t),this.el=Object(s.e)(i(e)),this.ui=new u.a(this.el).on("click tap enter",n,this)}return Xe(t,[{key:"destroy",value:function(){this.ui.destroy()}}]),t}(),Je=function(t){function e(t,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:qe;return Ze(this,e),Ue(this,Fe(e).call(this,t,n,i))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&We(t,e)}(e,t),Xe(e,[{key:"activate",value:function(){Object(s.v)(this.el,"jw-settings-item-active",!0),this.el.setAttribute("aria-checked","true"),this.active=!0}},{key:"deactivate",value:function(){Object(s.v)(this.el,"jw-settings-item-active",!1),this.el.setAttribute("aria-checked","false"),this.active=!1}}]),e}(Ge),Qe=function(t,e){return t?'':''},$e=function(t,e){var n=t.name,i={captions:"cc-off",audioTracks:"audio-tracks",quality:"quality-100",playbackRates:"playback-rate"}[n];if(i||t.icon){var o=p("jw-settings-".concat(n," jw-submenu-").concat(n),(function(e){t.open(e)}),n,[t.icon&&Object(s.e)(t.icon)||wt(i)]),a=o.element();return a.setAttribute("role","menuitemradio"),a.setAttribute("aria-checked","false"),a.setAttribute("aria-label",e),"ontouchstart"in window||(o.tooltip=ie(a,n,e)),o}};function tn(t){return(tn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function en(t,e){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:Qe;return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),a=this,(o=!(r=nn(e).call(this))||"object"!==tn(r)&&"function"!=typeof r?an(a):r).open=o.open.bind(an(an(o))),o.close=o.close.bind(an(an(o))),o.toggle=o.toggle.bind(an(an(o))),o.onDocumentClick=o.onDocumentClick.bind(an(an(o))),o.name=t,o.isSubmenu=!!n,o.el=Object(s.e)(l(o.isSubmenu,t)),o.topbar=o.el.querySelector(".jw-".concat(o.name,"-topbar")),o.buttonContainer=o.el.querySelector(".jw-".concat(o.name,"-topbar-buttons")),o.children={},o.openMenus=[],o.items=[],o.visible=!1,o.parentMenu=n,o.mainMenu=o.parentMenu?o.parentMenu.mainMenu:an(an(o)),o.categoryButton=null,o.closeButton=o.parentMenu&&o.parentMenu.closeButton||o.createCloseButton(i),o.isSubmenu?(o.categoryButton=o.parentMenu.categoryButton||o.createCategoryButton(i),o.parentMenu.parentMenu&&!o.mainMenu.backButton&&(o.mainMenu.backButton=o.createBackButton(i)),o.itemsContainer=o.createItemsContainer(),o.parentMenu.appendMenu(an(an(o)))):o.ui=ln(an(an(o))),o}var n,i,o;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&on(t,e)}(e,t),n=e,(i=[{key:"createItemsContainer",value:function(){var t,e,n=this,i=this.el.querySelector(".jw-settings-submenu-items"),o=new u.a(i),a=this.categoryButton&&this.categoryButton.element()||this.parentMenu.categoryButton&&this.parentMenu.categoryButton.element()||this.mainMenu.buttonContainer.firstChild;return this.parentMenu.isSubmenu&&(t=this.mainMenu.closeButton.element(),e=this.mainMenu.backButton.element()),o.on("keydown",(function(o){if(o.target.parentNode===i){var r=function(t,e){t?t.focus():void 0!==e&&i.childNodes[e].focus()},l=o.sourceEvent,c=l.target,u=i.firstChild===c,w=i.lastChild===c,p=n.topbar,d=t||Object(s.k)(a),j=e||Object(s.n)(a),h=Object(s.k)(l.target),f=Object(s.n)(l.target),g=l.key.replace(/(Arrow|ape)/,"");switch(g){case"Tab":r(l.shiftKey?j:d);break;case"Left":r(j||Object(s.n)(document.getElementsByClassName("jw-icon-settings")[0]));break;case"Up":p&&u?r(p.firstChild):r(f,i.childNodes.length-1);break;case"Right":r(d);break;case"Down":p&&w?r(p.firstChild):r(h,0)}l.preventDefault(),"Esc"!==g&&l.stopPropagation()}})),o}},{key:"createCloseButton",value:function(t){var e=p("jw-settings-close",this.close,t.close,[wt("close")]);return this.topbar.appendChild(e.element()),e.show(),e.ui.on("keydown",(function(t){var e=t.sourceEvent,n=e.key.replace(/(Arrow|ape)/,"");("Enter"===n||"Right"===n||"Tab"===n&&!e.shiftKey)&&this.close(t)}),this),this.buttonContainer.appendChild(e.element()),e}},{key:"createCategoryButton",value:function(t){var e=t[{captions:"cc",audioTracks:"audioTracks",quality:"hd",playbackRates:"playbackRates"}[this.name]];"sharing"===this.name&&(e=t.sharing.heading);var n=$e(this,e);return n.element().setAttribute("name",this.name),n}},{key:"createBackButton",value:function(t){var e=p("jw-settings-back",(function(t){Ye&&Ye.open(t)}),t.close,[wt("arrow-left")]);return Object(s.m)(this.mainMenu.topbar,e.element()),e}},{key:"createTopbar",value:function(){var t=Object(s.e)('
    ');return Object(s.m)(this.el,t),t}},{key:"createItems",value:function(t,e){var n=this,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Je,a=this.name,r=t.map((function(t,r){var l,s;switch(a){case"quality":l="Auto"===t.label&&0===r?"".concat(i.defaultText,' '):t.label;break;case"captions":l="Off"!==t.label&&"off"!==t.id||0!==r?t.label:i.defaultText;break;case"playbackRates":s=t,l=Object(Ve.e)(i.tooltipText)?"x"+t:t+"x";break;case"audioTracks":l=t.name}l||(l=t,"object"===tn(t)&&(l.options=i));var c=new o(l,function(t){c.active||(e(s||r),c.deactivate&&(n.items.filter((function(t){return!0===t.active})).forEach((function(t){t.deactivate()})),Ye?Ye.open(t):n.mainMenu.close(t)),c.activate&&c.activate())}.bind(n));return c}));return r}},{key:"setMenuItems",value:function(t,e){var n=this;t?(this.items=[],Object(s.h)(this.itemsContainer.el),t.forEach((function(t){n.items.push(t),n.itemsContainer.el.appendChild(t.el)})),e>-1&&t[e].activate(),this.categoryButton.show()):this.removeMenu()}},{key:"appendMenu",value:function(t){if(t){var e=t.el,n=t.name,i=t.categoryButton;if(this.children[n]=t,i){var o=this.mainMenu.buttonContainer,a=o.querySelector(".jw-settings-sharing"),r="quality"===n?o.firstChild:a||this.closeButton.element();o.insertBefore(i.element(),r)}this.mainMenu.el.appendChild(e)}}},{key:"removeMenu",value:function(t){if(!t)return this.parentMenu.removeMenu(this.name);var e=this.children[t];e&&(delete this.children[t],e.destroy())}},{key:"open",value:function(t){if(!this.visible||this.openMenus){var e;if(Ye=null,this.isSubmenu){var n=this.mainMenu,i=this.parentMenu,o=this.categoryButton;if(i.openMenus.length&&i.closeChildren(),o&&o.element().setAttribute("aria-checked","true"),i.isSubmenu){i.el.classList.remove("jw-settings-submenu-active"),n.topbar.classList.add("jw-nested-menu-open");var a=n.topbar.querySelector(".jw-settings-topbar-text");a.setAttribute("name",this.name),a.innerText=this.title||this.name,n.backButton.show(),Ye=this.parentMenu,e=this.topbar?this.topbar.firstChild:t&&"enter"===t.type?this.items[0].el:a}else n.topbar.classList.remove("jw-nested-menu-open"),n.backButton&&n.backButton.hide();this.el.classList.add("jw-settings-submenu-active"),i.openMenus.push(this.name),n.visible||(n.open(t),this.items&&t&&"enter"===t.type?e=this.topbar?this.topbar.firstChild.focus():this.items[0].el:o.tooltip&&(o.tooltip.suppress=!0,e=o.element())),this.openMenus.length&&this.closeChildren(),e&&e.focus(),this.el.scrollTop=0}else this.el.parentNode.classList.add("jw-settings-open"),this.trigger("menuVisibility",{visible:!0,evt:t}),document.addEventListener("click",this.onDocumentClick);this.visible=!0,this.el.setAttribute("aria-expanded","true")}}},{key:"close",value:function(t){var e=this;this.visible&&(this.visible=!1,this.el.setAttribute("aria-expanded","false"),this.isSubmenu?(this.el.classList.remove("jw-settings-submenu-active"),this.categoryButton.element().setAttribute("aria-checked","false"),this.parentMenu.openMenus=this.parentMenu.openMenus.filter((function(t){return t!==e.name})),!this.mainMenu.openMenus.length&&this.mainMenu.visible&&this.mainMenu.close(t)):(this.el.parentNode.classList.remove("jw-settings-open"),this.trigger("menuVisibility",{visible:!1,evt:t}),document.removeEventListener("click",this.onDocumentClick)),this.openMenus.length&&this.closeChildren())}},{key:"closeChildren",value:function(){var t=this;this.openMenus.forEach((function(e){var n=t.children[e];n&&n.close()}))}},{key:"toggle",value:function(t){this.visible?this.close(t):this.open(t)}},{key:"onDocumentClick",value:function(t){/jw-(settings|video|nextup-close|sharing-link|share-item)/.test(t.target.className)||this.close()}},{key:"destroy",value:function(){var t=this;if(document.removeEventListener("click",this.onDocumentClick),Object.keys(this.children).map((function(e){t.children[e].destroy()})),this.isSubmenu){this.parentMenu.name===this.mainMenu.name&&this.categoryButton&&(this.parentMenu.buttonContainer.removeChild(this.categoryButton.element()),this.categoryButton.ui.destroy()),this.itemsContainer&&this.itemsContainer.destroy();var e=this.parentMenu.openMenus,n=e.indexOf(this.name);e.length&&n>-1&&this.openMenus.splice(n,1),delete this.parentMenu}else this.ui.destroy();this.visible=!1,this.el.parentNode&&this.el.parentNode.removeChild(this.el)}},{key:"defaultChild",get:function(){var t=this.children,e=t.quality,n=t.captions,i=t.audioTracks,o=t.sharing,a=t.playbackRates;return e||n||i||o||a}}])&&en(n.prototype,i),o&&en(n,o),e}(r.a),ln=function(t){var e=t.closeButton,n=t.el;return new u.a(n).on("keydown",(function(n){var i=n.sourceEvent,o=n.target,a=Object(s.k)(o),r=Object(s.n)(o),l=i.key.replace(/(Arrow|ape)/,""),c=function(e){r?e||r.focus():t.close(n)};switch(l){case"Esc":t.close(n);break;case"Left":c();break;case"Right":a&&e.element()&&o!==e.element()&&a.focus();break;case"Tab":i.shiftKey&&c(!0);break;case"Up":case"Down":!function(){var e=t.children[o.getAttribute("name")];if(!e&&Ye&&(e=Ye.children[Ye.openMenus]),e)return e.open(n),void(e.topbar?e.topbar.firstChild.focus():e.items&&e.items.length&&e.items[0].el.focus());if(n.target.parentNode.classList.contains("jw-submenu-topbar")){var i=n.target.parentNode.parentNode.querySelector(".jw-settings-submenu-items");("Down"===l?i.childNodes[0]:i.childNodes[i.childNodes.length-1]).focus()}}()}if(i.stopPropagation(),/13|32|37|38|39|40/.test(i.keyCode))return i.preventDefault(),!1}))},sn=n(59),cn=function(t){return jn[t]},un=function(t){for(var e,n=Object.keys(jn),i=0;i1;n.elements.settingsButton.toggle(c)};e.change("levels",(function(t,e){r(e)}),o);var l=function(t,n,i){var o=e.get("levels");if(o&&"Auto"===o[0].label&&n&&n.items.length){var a=n.items[0].el.querySelector(".jw-auto-label"),r=o[t.index]||{label:""};a.textContent=i?"":r.label}};e.on("change:visualQuality",(function(t,n){var i=o.children.quality;n&&i&&l(n.level,i,e.get("currentLevel"))})),e.on("change:currentLevel",(function(t,n){var i=o.children.quality,a=e.get("visualQuality");a&&i&&l(a.level,i,n)}),o),e.change("captionsList",(function(n,r){var l={defaultText:i.off},s=e.get("captionsIndex");a("captions",r,(function(e){return t.setCurrentCaptions(e)}),s,l);var c=o.children.captions;if(c&&!c.children.captionsSettings){c.topbar=c.topbar||c.createTopbar();var u=new rn("captionsSettings",c,i);u.title="Subtitle Settings";var w=new Ge("Settings",u.open);c.topbar.appendChild(w.el);var p=new Je("Reset",(function(){e.set("captions",sn.a),h()}));p.el.classList.add("jw-settings-reset");var j=e.get("captions"),h=function(){var t=[];dn.forEach((function(n){j&&j[n.propertyName]&&(n.defaultVal=n.getOption(j[n.propertyName]));var o=new rn(n.name,u,i),a=new Ge({label:n.name,value:n.defaultVal},o.open,Re),r=o.createItems(n.options,(function(t){var i=a.el.querySelector(".jw-settings-content-item-value");!function(t,n){var i=e.get("captions"),o=t.propertyName,a=t.options&&t.options[n],r=t.getTypedValue(a),l=Object(d.g)({},i);l[o]=r,e.set("captions",l)}(n,t),i.innerText=n.options[t]}),null);o.setMenuItems(r,n.options.indexOf(n.defaultVal)||0),t.push(a)})),t.push(p),u.setMenuItems(t)};h()}}));var s=function(t,e){t&&e>-1&&t.items[e].activate()};e.change("captionsIndex",(function(t,e){var i=o.children.captions;i&&s(i,e),n.toggleCaptionsButtonState(!!e)}),o);var c=function(n){if(e.get("supportsPlaybackRate")&&"LIVE"!==e.get("streamType")&&e.get("playbackRateControls")){var r=n.indexOf(e.get("playbackRate")),l={tooltipText:i.playbackRates};a("playbackRates",n,(function(e){return t.setPlaybackRate(e)}),r,l)}else o.children.playbackRates&&o.removeMenu("playbackRates")};e.on("change:playbackRates",(function(t,e){c(e)}),o);var u=function(n){a("audioTracks",n,(function(e){return t.setCurrentAudioTrack(e)}),e.get("currentAudioTrack"))};return e.on("change:audioTracks",(function(t,e){u(e)}),o),e.on("change:playbackRate",(function(t,n){var i=e.get("playbackRates"),a=-1;i&&(a=i.indexOf(n)),s(o.children.playbackRates,a)}),o),e.on("change:currentAudioTrack",(function(t,e){o.children.audioTracks.items[e].activate()}),o),e.on("change:playlistItem",(function(){o.removeMenu("captions"),n.elements.captionsButton.hide(),o.visible&&o.close()}),o),e.on("change:playbackRateControls",(function(){c(e.get("playbackRates"))})),e.on("change:castActive",(function(t,n,i){n!==i&&(n?(o.removeMenu("audioTracks"),o.removeMenu("quality"),o.removeMenu("playbackRates")):(u(e.get("audioTracks")),r(e.get("levels")),c(e.get("playbackRates"))))}),o),e.on("change:streamType",(function(){c(e.get("playbackRates"))}),o),o},fn=n(58),gn=n(35),bn=n(12),yn=function(t,e,n,i){var o=Object(s.e)('
    '),r=!1,l=null,c=!1,u=function(t){/jw-info/.test(t.target.className)||d.close()},w=function(){var i,a,l,c,u,w=p("jw-info-close",(function(){d.close()}),e.get("localization").close,[wt("close")]);w.show(),Object(s.m)(o,w.element()),a=o.querySelector(".jw-info-title"),l=o.querySelector(".jw-info-duration"),c=o.querySelector(".jw-info-description"),u=o.querySelector(".jw-info-clientid"),e.change("playlistItem",(function(t,e){var n=e.description,i=e.title;Object(s.q)(c,n||""),Object(s.q)(a,i||"Unknown Title")})),e.change("duration",(function(t,n){var i="";switch(e.get("streamType")){case"LIVE":i="Live";break;case"DVR":i="DVR";break;default:n&&(i=Object(vt.timeFormat)(n))}l.textContent=i}),d),u.textContent=(i=n.getPlugin("jwpsrv"))&&"function"==typeof i.doNotTrackUser&&i.doNotTrackUser()?"":"Client ID: ".concat(function(){try{return window.localStorage.jwplayerLocalId}catch(t){return"none"}}()),t.appendChild(o),r=!0};var d={open:function(){r||w(),document.addEventListener("click",u),c=!0;var t=e.get("state");t===a.pb&&n.pause("infoOverlayInteraction"),l=t,i(!0)},close:function(){document.removeEventListener("click",u),c=!1,e.get("state")===a.ob&&l===a.pb&&n.play("infoOverlayInteraction"),l=null,i(!1)},destroy:function(){this.close(),e.off(null,null,this)}};return Object.defineProperties(d,{visible:{enumerable:!0,get:function(){return c}}}),d};var vn=function(t,e,n){var i,o=!1,r=null,l=n.get("localization").shortcuts,c=Object(s.e)(function(t,e){var n=t.map((function(t){return'
    '+''.concat(t.description,"")+''.concat(t.key,"")+"
    "})).join("");return'
    ')+'Press shift question mark to access a list of keyboard shortcuts
    '+''.concat(e,"")+'
    '+"".concat(n)+"
    "}(function(t){var e=t.playPause,n=t.volumeToggle,i=t.fullscreenToggle,o=t.seekPercent,a=t.increaseVolume,r=t.decreaseVolume,l=t.seekForward,s=t.seekBackward;return[{key:t.spacebar,description:e},{key:"↑",description:a},{key:"↓",description:r},{key:"→",description:l},{key:"←",description:s},{key:"c",description:t.captionsToggle},{key:"f",description:i},{key:"m",description:n},{key:"0-9",description:o}]}(l),l.keyboardShortcuts)),w={reason:"settingsInteraction"},d=new u.a(c.querySelector(".jw-switch")),j=function(){d.el.setAttribute("aria-checked",n.get("enableShortcuts")),Object(s.a)(c,"jw-open"),r=n.get("state"),c.querySelector(".jw-shortcuts-close").focus(),document.addEventListener("click",f),o=!0,e.pause(w)},h=function(){Object(s.o)(c,"jw-open"),document.removeEventListener("click",f),t.focus(),o=!1,r===a.pb&&e.play(w)},f=function(t){/jw-shortcuts|jw-switch/.test(t.target.className)||h()},g=function(t){var e=t.currentTarget,i="true"!==e.getAttribute("aria-checked");e.setAttribute("aria-checked",i),n.set("enableShortcuts",i)};return i=p("jw-shortcuts-close",h,n.get("localization").close,[wt("close")]),Object(s.m)(c,i.element()),i.show(),t.appendChild(c),d.on("click tap enter",g),{el:c,open:j,close:h,destroy:function(){h(),d.destroy()},toggleVisibility:function(){o?h():j()}}},mn=function(t){return'
    ')+"
    "};function xn(t){return(xn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function kn(t,e){for(var n=0;n16?i.activeTimeout=setTimeout(i.userInactiveTimeout,t):i.playerContainer.querySelector(".jw-tab-focus")?i.resetActiveTimeout():i.userInactive()},i}var n,i,r;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&Bn(t,e)}(e,t),n=e,(i=[{key:"resetActiveTimeout",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.inactiveTime=0}},{key:"enable",value:function(t,e){var n=this,i=this.context.createElement("div");i.className="jw-controls jw-reset",this.div=i;var r=this.context.createElement("div");r.className="jw-controls-backdrop jw-reset",this.backdrop=r,this.logo=this.playerContainer.querySelector(".jw-logo");var c=e.get("touchMode"),u=function(){(e.get("isFloating")?n.wrapperElement:n.playerContainer).focus()};if(!this.displayContainer){var w=new Ce(e,t);w.buttons.display.on("click tap enter",(function(){n.trigger(a.p),n.userActive(1e3),t.playToggle(An()),u()})),this.div.appendChild(w.element()),this.displayContainer=w}this.infoOverlay=new yn(i,e,t,(function(t){Object(s.v)(n.div,"jw-info-open",t),t&&n.div.querySelector(".jw-info-close").focus()})),o.OS.mobile||(this.shortcutsTooltip=new vn(this.wrapperElement,t,e)),this.rightClickMenu=new Pe(this.infoOverlay,this.shortcutsTooltip),c?(Object(s.a)(this.playerContainer,"jw-flag-touch"),this.rightClickMenu.setup(e,this.playerContainer,this.wrapperElement)):e.change("flashBlocked",(function(t,e){e?n.rightClickMenu.destroy():n.rightClickMenu.setup(t,n.playerContainer,n.wrapperElement)}),this);var d=e.get("floating");if(d){var j=new Tn(i,e.get("localization").close);j.on(a.sb,(function(){return n.trigger("dismissFloating",{doNotForward:!0})})),!1!==d.dismissible&&Object(s.a)(this.playerContainer,"jw-floating-dismissible")}var h=this.controlbar=new we(t,e,this.playerContainer.querySelector(".jw-hidden-accessibility"));if(h.on(a.sb,(function(){return n.userActive()})),h.on("nextShown",(function(t){this.trigger("nextShown",t)}),this),h.on("adjustVolume",x,this),e.get("nextUpDisplay")&&!h.nextUpToolTip){var f=new ze(e,t,this.playerContainer);f.on("all",this.trigger,this),f.setup(this.context),h.nextUpToolTip=f,this.div.appendChild(f.element())}this.div.appendChild(h.element());var g=e.get("localization"),b=this.settingsMenu=hn(t,e.player,this.controlbar,g),y=null;this.controlbar.on("menuVisibility",(function(i){var o=i.visible,r=i.evt,l=e.get("state"),s={reason:"settingsInteraction"},c=n.controlbar.elements.settingsButton,w="keydown"===(r&&r.sourceEvent||r||{}).type,p=o||w?0:_n;n.userActive(p),y=l,Object(fn.a)(e.get("containerWidth"))<2&&(o&&l===a.pb?t.pause(s):o||l!==a.ob||y!==a.pb||t.play(s)),!o&&w&&c?c.element().focus():r&&u()})),b.on("menuVisibility",(function(t){return n.controlbar.trigger("menuVisibility",t)})),this.controlbar.on("settingsInteraction",(function(t,e,n){if(e)return b.defaultChild.toggle(n);b.children[t].toggle(n)})),o.OS.mobile?this.div.appendChild(b.el):(this.playerContainer.setAttribute("aria-describedby","jw-shortcuts-tooltip-explanation"),this.div.insertBefore(b.el,h.element()));var v=function(e){if(e.get("autostartMuted")){var i=function(){return n.unmuteAutoplay(t,e)},a=function(t,e){e||i()};o.OS.mobile&&(n.mute=p("jw-autostart-mute jw-off",i,e.get("localization").unmute,[wt("volume-0")]),n.mute.show(),n.div.appendChild(n.mute.element())),h.renderVolume(!0,e.get("volume")),Object(s.a)(n.playerContainer,"jw-flag-autostart"),e.on("change:autostartFailed",i,n),e.on("change:autostartMuted change:mute",a,n),n.muteChangeCallback=a,n.unmuteCallback=i}};function m(n){var i=0,o=e.get("duration"),a=e.get("position");if("DVR"===e.get("streamType")){var r=e.get("dvrSeekLimit");i=o,o=Math.max(a,-r)}var s=Object(l.a)(a+n,i,o);t.seek(s,An())}function x(n){var i=Object(l.a)(e.get("volume")+n,0,100);t.setVolume(i)}e.once("change:autostartMuted",v),v(e);var k=function(i){if(i.ctrlKey||i.metaKey)return!0;var o=!n.settingsMenu.visible,a=!0===e.get("enableShortcuts"),r=n.instreamState;if(a||-1!==Vn.indexOf(i.keyCode)){switch(i.keyCode){case 27:if(e.get("fullscreen"))t.setFullscreen(!1),n.playerContainer.blur(),n.userInactive();else{var l=t.getPlugin("related");l&&l.close({type:"escape"})}n.rightClickMenu.el&&n.rightClickMenu.hideMenuHandler(),n.infoOverlay.visible&&n.infoOverlay.close(),n.shortcutsTooltip&&n.shortcutsTooltip.close();break;case 13:case 32:if(document.activeElement.classList.contains("jw-switch")&&13===i.keyCode)return!0;t.playToggle(An());break;case 37:!r&&o&&m(-5);break;case 39:!r&&o&&m(5);break;case 38:o&&x(10);break;case 40:o&&x(-10);break;case 67:var s=t.getCaptionsList().length;if(s){var c=(t.getCurrentCaptions()+1)%s;t.setCurrentCaptions(c)}break;case 77:t.setMute();break;case 70:t.setFullscreen();break;case 191:n.shortcutsTooltip&&n.shortcutsTooltip.toggleVisibility();break;default:if(i.keyCode>=48&&i.keyCode<=59){var u=(i.keyCode-48)/10*e.get("duration");t.seek(u,An())}}return/13|32|37|38|39|40/.test(i.keyCode)?(i.preventDefault(),!1):void 0}};this.playerContainer.addEventListener("keydown",k),this.keydownCallback=k;var O=function(t){switch(t.keyCode){case 9:var e=n.playerContainer.contains(t.target)?0:_n;n.userActive(e);break;case 32:t.preventDefault()}};this.playerContainer.addEventListener("keyup",O),this.keyupCallback=O;var C=function(t){var e=t.relatedTarget||document.querySelector(":focus");e&&(n.playerContainer.contains(e)||n.userInactive())};this.playerContainer.addEventListener("blur",C,!0),this.blurCallback=C;var S=function t(){"jw-shortcuts-tooltip-explanation"===n.playerContainer.getAttribute("aria-describedby")&&n.playerContainer.removeAttribute("aria-describedby"),n.playerContainer.removeEventListener("blur",t,!0)};this.shortcutsTooltip&&(this.playerContainer.addEventListener("blur",S,!0),this.onRemoveShortcutsDescription=S),this.userActive(),this.addControls(),this.addBackdrop(),e.set("controlsEnabled",!0)}},{key:"addControls",value:function(){this.wrapperElement.appendChild(this.div)}},{key:"disable",value:function(t){var e=this.nextUpToolTip,n=this.settingsMenu,i=this.infoOverlay,o=this.controlbar,a=this.rightClickMenu,r=this.shortcutsTooltip,l=this.playerContainer,c=this.div;clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.off(),t.off(null,null,this),t.set("controlsEnabled",!1),c.parentNode&&(Object(s.o)(l,"jw-flag-touch"),c.parentNode.removeChild(c)),o&&o.destroy(),a&&a.destroy(),this.keydownCallback&&l.removeEventListener("keydown",this.keydownCallback),this.keyupCallback&&l.removeEventListener("keyup",this.keyupCallback),this.blurCallback&&l.removeEventListener("blur",this.blurCallback),this.onRemoveShortcutsDescription&&l.removeEventListener("blur",this.onRemoveShortcutsDescription),this.displayContainer&&this.displayContainer.destroy(),e&&e.destroy(),n&&n.destroy(),i&&i.destroy(),r&&r.destroy(),this.removeBackdrop()}},{key:"controlbarHeight",value:function(){return this.dimensions.cbHeight||(this.dimensions.cbHeight=this.controlbar.element().clientHeight),this.dimensions.cbHeight}},{key:"element",value:function(){return this.div}},{key:"resize",value:function(){this.dimensions={}}},{key:"unmuteAutoplay",value:function(t,e){var n=!e.get("autostartFailed"),i=e.get("mute");n?i=!1:e.set("playOnViewable",!1),this.muteChangeCallback&&(e.off("change:autostartMuted change:mute",this.muteChangeCallback),this.muteChangeCallback=null),this.unmuteCallback&&(e.off("change:autostartFailed",this.unmuteCallback),this.unmuteCallback=null),e.set("autostartFailed",void 0),e.set("autostartMuted",void 0),t.setMute(i),this.controlbar.renderVolume(i,e.get("volume")),this.mute&&this.mute.hide(),Object(s.o)(this.playerContainer,"jw-flag-autostart"),this.userActive()}},{key:"mouseMove",value:function(t){var e=this.controlbar.element().contains(t.target),n=this.controlbar.nextUpToolTip&&this.controlbar.nextUpToolTip.element().contains(t.target),i=this.logo&&this.logo.contains(t.target),o=e||n||i?0:_n;this.userActive(o)}},{key:"userActive",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:_n;t>0?(this.inactiveTime=Object(c.a)()+t,-1===this.activeTimeout&&(this.activeTimeout=setTimeout(this.userInactiveTimeout,t))):this.resetActiveTimeout(),this.showing||(Object(s.o)(this.playerContainer,"jw-flag-user-inactive"),this.showing=!0,this.trigger("userActive"))}},{key:"userInactive",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.settingsMenu.visible||(this.inactiveTime=0,this.showing=!1,Object(s.a)(this.playerContainer,"jw-flag-user-inactive"),this.trigger("userInactive"))}},{key:"addBackdrop",value:function(){var t=this.instreamState?this.div:this.wrapperElement.querySelector(".jw-captions");this.wrapperElement.insertBefore(this.backdrop,t)}},{key:"removeBackdrop",value:function(){var t=this.backdrop.parentNode;t&&t.removeChild(this.backdrop)}},{key:"setupInstream",value:function(){this.instreamState=!0,this.userActive(),this.addBackdrop(),this.settingsMenu&&this.settingsMenu.close(),Object(s.o)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","-1")}},{key:"destroyInstream",value:function(t){this.instreamState=null,this.addBackdrop(),t.get("autostartMuted")&&Object(s.a)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","0")}}])&&zn(n.prototype,i),r&&zn(n,r),e}(r.a)},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,function(t,e,n){"use strict";n.d(e,"a",(function(){return o}));var i=n(2);function o(t){var e=[],n=(t=Object(i.i)(t)).split("\r\n\r\n");1===n.length&&(n=t.split("\n\n"));for(var o=0;o0&&(o=0),n.length>o+1&&n[o+1]){var a=n[o],r=a.indexOf(" --\x3e ");r>0&&(e.begin=Object(i.g)(a.substr(0,r)),e.end=Object(i.g)(a.substr(r+5)),e.text=n.slice(o+1).join("\r\n"))}return e}},function(t,e,n){"use strict";n.d(e,"a",(function(){return o})),n.d(e,"b",(function(){return a}));var i=n(5);function o(t){var e=-1;return t>=1280?e=7:t>=960?e=6:t>=800?e=5:t>=640?e=4:t>=540?e=3:t>=420?e=2:t>=320?e=1:t>=250&&(e=0),e}function a(t,e){var n="jw-breakpoint-"+e;Object(i.p)(t,/jw-breakpoint--?\d+/,n)}},function(t,e,n){"use strict";n.d(e,"a",(function(){return w}));var i,o=n(0),a=n(8),r=n(16),l=n(7),s=n(3),c=n(10),u=n(5),w={back:!0,backgroundOpacity:50,edgeStyle:null,fontSize:14,fontOpacity:100,fontScale:.05,preprocessor:o.k,windowOpacity:0},p=function(t){var e,l,p,d,j,h,f,g,b,y=this,v=t.player;function m(){Object(o.o)(e.fontSize)&&(v.get("containerHeight")?g=w.fontScale*(e.userFontScale||1)*e.fontSize/w.fontSize:v.once("change:containerHeight",m,this))}function x(){var t=v.get("containerHeight");if(t){var e;if(v.get("fullscreen")&&a.OS.iOS)e=null;else{var n=t*g;e=Math.round(10*function(t){var e=v.get("mediaElement");if(e&&e.videoHeight){var n=e.videoWidth,i=e.videoHeight,o=n/i,r=v.get("containerHeight"),l=v.get("containerWidth");if(v.get("fullscreen")&&a.OS.mobile){var s=window.screen;s.orientation&&(r=s.availHeight,l=s.availWidth)}if(l&&r&&n&&i)return(l/r>o?r:i*l/n)*g}return t}(n))/10}v.get("renderCaptionsNatively")?function(t,e){var n="#".concat(t," .jw-video::-webkit-media-text-track-display");e&&(e+="px",a.OS.iOS&&Object(c.b)(n,{fontSize:"inherit"},t,!0));b.fontSize=e,Object(c.b)(n,b,t,!0)}(v.get("id"),e):Object(c.d)(j,{fontSize:e})}}function k(t,e,n){var i=Object(c.c)("#000000",n);"dropshadow"===t?e.textShadow="0 2px 1px "+i:"raised"===t?e.textShadow="0 0 5px "+i+", 0 1px 5px "+i+", 0 2px 5px "+i:"depressed"===t?e.textShadow="0 -2px 1px "+i:"uniform"===t&&(e.textShadow="-2px 0 1px "+i+",2px 0 1px "+i+",0 -2px 1px "+i+",0 2px 1px "+i+",-1px 1px 1px "+i+",1px 1px 1px "+i+",1px -1px 1px "+i+",1px 1px 1px "+i)}(j=document.createElement("div")).className="jw-captions jw-reset",this.show=function(){Object(u.a)(j,"jw-captions-enabled")},this.hide=function(){Object(u.o)(j,"jw-captions-enabled")},this.populate=function(t){v.get("renderCaptionsNatively")||(p=[],l=t,t?this.selectCues(t,d):this.renderCues())},this.resize=function(){x(),this.renderCues(!0)},this.renderCues=function(t){t=!!t,i&&i.processCues(window,p,j,t)},this.selectCues=function(t,e){if(t&&t.data&&e&&!v.get("renderCaptionsNatively")){var n=this.getAlignmentPosition(t,e);!1!==n&&(p=this.getCurrentCues(t.data,n),this.renderCues(!0))}},this.getCurrentCues=function(t,e){return Object(o.h)(t,(function(t){return e>=t.startTime&&(!t.endTime||e<=t.endTime)}))},this.getAlignmentPosition=function(t,e){var n=t.source,i=e.metadata,a=e.currentTime;return n&&i&&Object(o.r)(i[n])&&(a=i[n]),a},this.clear=function(){Object(u.g)(j)},this.setup=function(t,n){h=document.createElement("div"),f=document.createElement("span"),h.className="jw-captions-window jw-reset",f.className="jw-captions-text jw-reset",e=Object(o.g)({},w,n),g=w.fontScale;var i=function(){if(!v.get("renderCaptionsNatively")){m(e.fontSize);var n=e.windowColor,i=e.windowOpacity,o=e.edgeStyle;b={};var r={};!function(t,e){var n=e.color,i=e.fontOpacity;(n||i!==w.fontOpacity)&&(t.color=Object(c.c)(n||"#ffffff",i));if(e.back){var o=e.backgroundColor,a=e.backgroundOpacity;o===w.backgroundColor&&a===w.backgroundOpacity||(t.backgroundColor=Object(c.c)(o,a))}else t.background="transparent";e.fontFamily&&(t.fontFamily=e.fontFamily);e.fontStyle&&(t.fontStyle=e.fontStyle);e.fontWeight&&(t.fontWeight=e.fontWeight);e.textDecoration&&(t.textDecoration=e.textDecoration)}(r,e),(n||i!==w.windowOpacity)&&(b.backgroundColor=Object(c.c)(n||"#000000",i)),k(o,r,e.fontOpacity),e.back||null!==o||k("uniform",r),Object(c.d)(h,b),Object(c.d)(f,r),function(t,e){x(),function(t,e){a.Browser.safari&&Object(c.b)("#"+t+" .jw-video::-webkit-media-text-track-display-backdrop",{backgroundColor:e.backgroundColor},t,!0);Object(c.b)("#"+t+" .jw-video::-webkit-media-text-track-display",b,t,!0),Object(c.b)("#"+t+" .jw-video::cue",e,t,!0)}(t,e),function(t,e){Object(c.b)("#"+t+" .jw-text-track-display",b,t),Object(c.b)("#"+t+" .jw-text-track-cue",e,t)}(t,e)}(t,r)}};i(),h.appendChild(f),j.appendChild(h),v.change("captionsTrack",(function(t,e){this.populate(e)}),this),v.set("captions",e),v.on("change:captions",(function(t,n){e=n,i()}))},this.element=function(){return j},this.destroy=function(){v.off(null,null,this),this.off()};var O=function(t){d=t,y.selectCues(l,d)};v.on("change:playlistItem",(function(){d=null,p=[]}),this),v.on(s.Q,(function(t){p=[],O(t)}),this),v.on(s.S,O,this),v.on("subtitlesTrackData",(function(){this.selectCues(l,d)}),this),v.on("change:captionsList",(function t(e,o){var a=this;1!==o.length&&(e.get("renderCaptionsNatively")||i||(n.e(8).then(function(t){i=n(68).default}.bind(null,n)).catch(Object(r.c)(301121)).catch((function(t){a.trigger(s.tb,t)})),e.off("change:captionsList",t,this)))}),this)};Object(o.g)(p.prototype,l.a),e.b=p},function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var n=function(t,e){var n=t[1]||"",i=t[3];if(!i)return n;if(e&&"function"==typeof btoa){var o=(r=i,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */"),a=i.sources.map((function(t){return"/*# sourceURL="+i.sourceRoot+t+" */"}));return[n].concat(a).concat([o]).join("\n")}var r;return[n].join("\n")}(e,t);return e[2]?"@media "+e[2]+"{"+n+"}":n})).join("")},e.i=function(t,n){"string"==typeof t&&(t=[[null,t,""]]);for(var i={},o=0;o'},,,,,,,,,function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e,n){var i=n(96);"string"==typeof i&&(i=[["all-players",i,""]]),n(61).style(i,"all-players"),i.locals&&(t.exports=i.locals)},function(t,e,n){(t.exports=n(60)(!1)).push([t.i,'.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-flag-small-player .jw-settings-menu,.jw-settings-submenu{height:100%;width:100%}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;right:0}.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-settings-item-active::before{top:0;position:absolute;left:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;bottom:0;left:0}.jw-nextup-close{position:absolute;top:0;right:0}.jw-overlays,.jw-controls,.jw-flag-small-player .jw-settings-menu{position:absolute;bottom:0;right:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-time-tip::after,.jw-settings-menu .jw-icon.jw-button-color::after,.jw-text-live::before,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{content:"";display:block}.jw-svg-icon{height:24px;width:24px;fill:currentColor;pointer-events:none}.jw-icon{height:44px;width:44px;background-color:transparent;outline:none}.jw-icon.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-icon-airplay .jw-svg-icon-airplay-off{display:none}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-off{display:block}.jw-icon-airplay .jw-svg-icon-airplay-on{display:block}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-on{display:none}.jw-icon-cc .jw-svg-icon-cc-off{display:none}.jw-off.jw-icon-cc .jw-svg-icon-cc-off{display:block}.jw-icon-cc .jw-svg-icon-cc-on{display:block}.jw-off.jw-icon-cc .jw-svg-icon-cc-on{display:none}.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:none}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:block}.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:block}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:none}.jw-icon-volume .jw-svg-icon-volume-0{display:none}.jw-off.jw-icon-volume .jw-svg-icon-volume-0{display:block}.jw-icon-volume .jw-svg-icon-volume-100{display:none}.jw-full.jw-icon-volume .jw-svg-icon-volume-100{display:block}.jw-icon-volume .jw-svg-icon-volume-50{display:block}.jw-off.jw-icon-volume .jw-svg-icon-volume-50,.jw-full.jw-icon-volume .jw-svg-icon-volume-50{display:none}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon[aria-checked="true"]::after,.jw-settings-open .jw-icon-settings::after,.jw-icon-volume.jw-open::after{opacity:1}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-cc,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-settings,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-audio-tracks,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-hd,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-settings-sharing,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-fullscreen,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-airplay,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-cast{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-text-live{bottom:6px}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume::after{display:none}.jw-overlays,.jw-controls{pointer-events:none}.jw-controls-backdrop{display:block;background:linear-gradient(to bottom, transparent, rgba(0,0,0,0.4) 77%, rgba(0,0,0,0.4) 100%) 100% 100% / 100% 240px no-repeat transparent;transition:opacity 250ms cubic-bezier(0, .25, .25, 1),background-size 250ms cubic-bezier(0, .25, .25, 1);pointer-events:none}.jw-overlays{cursor:auto}.jw-controls{overflow:hidden}.jw-flag-small-player .jw-controls{text-align:center}.jw-text{height:1em;font-family:Arial,Helvetica,sans-serif;font-size:.75em;font-style:normal;font-weight:normal;color:#fff;text-align:center;font-variant:normal;font-stretch:normal}.jw-controlbar,.jw-skip,.jw-display-icon-container .jw-icon,.jw-nextup-container,.jw-autostart-mute,.jw-overlays .jw-plugin{pointer-events:all}.jwplayer .jw-display-icon-container,.jw-error .jw-display-icon-container{width:auto;height:auto;box-sizing:content-box}.jw-display{display:table;height:100%;padding:57px 0;position:relative;width:100%}.jw-flag-dragging .jw-display{display:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-display-container{display:table-cell;height:100%;text-align:center;vertical-align:middle}.jw-display-controls{display:inline-block}.jwplayer .jw-display-icon-container{float:left}.jw-display-icon-container{display:inline-block;padding:5.5px;margin:0 22px}.jw-display-icon-container .jw-icon{height:75px;width:75px;cursor:pointer;display:flex;justify-content:center;align-items:center}.jw-display-icon-container .jw-icon .jw-svg-icon{height:33px;width:33px;padding:0;position:relative}.jw-display-icon-container .jw-icon .jw-svg-icon-rewind{padding:.2em .05em}.jw-breakpoint--1 .jw-nextup-container{display:none}.jw-breakpoint-0 .jw-display-icon-next,.jw-breakpoint--1 .jw-display-icon-next,.jw-breakpoint-0 .jw-display-icon-rewind,.jw-breakpoint--1 .jw-display-icon-rewind{display:none}.jw-breakpoint-0 .jw-display .jw-icon,.jw-breakpoint--1 .jw-display .jw-icon,.jw-breakpoint-0 .jw-display .jw-svg-icon,.jw-breakpoint--1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-0 .jw-display .jw-icon:before,.jw-breakpoint--1 .jw-display .jw-icon:before,.jw-breakpoint-0 .jw-display .jw-svg-icon:before,.jw-breakpoint--1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon,.jw-breakpoint-1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-1 .jw-display .jw-icon:before,.jw-breakpoint-1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon.jw-icon-rewind:before{width:33px;height:33px}.jw-breakpoint-2 .jw-display .jw-icon,.jw-breakpoint-3 .jw-display .jw-icon,.jw-breakpoint-2 .jw-display .jw-svg-icon,.jw-breakpoint-3 .jw-display .jw-svg-icon{width:77px;height:77px;line-height:77px}.jw-breakpoint-2 .jw-display .jw-icon:before,.jw-breakpoint-3 .jw-display .jw-icon:before,.jw-breakpoint-2 .jw-display .jw-svg-icon:before,.jw-breakpoint-3 .jw-display .jw-svg-icon:before{width:38.5px;height:38.5px}.jw-breakpoint-4 .jw-display .jw-icon,.jw-breakpoint-5 .jw-display .jw-icon,.jw-breakpoint-6 .jw-display .jw-icon,.jw-breakpoint-7 .jw-display .jw-icon,.jw-breakpoint-4 .jw-display .jw-svg-icon,.jw-breakpoint-5 .jw-display .jw-svg-icon,.jw-breakpoint-6 .jw-display .jw-svg-icon,.jw-breakpoint-7 .jw-display .jw-svg-icon{width:88px;height:88px;line-height:88px}.jw-breakpoint-4 .jw-display .jw-icon:before,.jw-breakpoint-5 .jw-display .jw-icon:before,.jw-breakpoint-6 .jw-display .jw-icon:before,.jw-breakpoint-7 .jw-display .jw-icon:before,.jw-breakpoint-4 .jw-display .jw-svg-icon:before,.jw-breakpoint-5 .jw-display .jw-svg-icon:before,.jw-breakpoint-6 .jw-display .jw-svg-icon:before,.jw-breakpoint-7 .jw-display .jw-svg-icon:before{width:44px;height:44px}.jw-controlbar{display:flex;flex-flow:row wrap;align-items:center;justify-content:center;position:absolute;left:0;bottom:0;width:100%;border:none;border-radius:0;background-size:auto;box-shadow:none;max-height:72px;transition:250ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s}.jw-breakpoint-7 .jw-controlbar{max-height:140px}.jw-breakpoint-7 .jw-controlbar .jw-button-container{padding:0 48px 20px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-tooltip{margin-bottom:-7px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-overlay{padding-bottom:40%}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text{font-size:1em}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text.jw-text-elapsed{justify-content:flex-end}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume{height:60px;width:60px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline .jw-svg-icon,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time{padding:0 60px;height:34px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time .jw-slider-container{height:10px}.jw-controlbar .jw-button-image{background:no-repeat 50% 50%;background-size:contain;max-height:24px}.jw-controlbar .jw-spacer{flex:1 1 auto;align-self:stretch}.jw-controlbar .jw-icon.jw-button-color:hover{color:#fff}.jw-button-container{display:flex;flex-flow:row nowrap;flex:1 1 auto;align-items:center;justify-content:center;width:100%;padding:0 12px}.jw-slider-horizontal{background-color:transparent}.jw-icon-inline{position:relative}.jw-icon-inline,.jw-icon-tooltip{height:44px;width:44px;align-items:center;display:flex;justify-content:center}.jw-icon-inline:not(.jw-text),.jw-icon-tooltip,.jw-slider-horizontal{cursor:pointer}.jw-text-elapsed,.jw-text-duration{justify-content:flex-start;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.jw-icon-tooltip{position:relative}.jw-knob:hover,.jw-icon-inline:hover,.jw-icon-tooltip:hover,.jw-icon-display:hover,.jw-option:before:hover{color:#fff}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{pointer-events:none}.jw-icon-cast{display:none;margin:0;padding:0}.jw-icon-cast google-cast-launcher{background-color:transparent;border:none;padding:0;width:24px;height:24px;cursor:pointer}.jw-icon-inline.jw-icon-volume{display:none}.jwplayer .jw-text-countdown{display:none}.jw-flag-small-player .jw-display{padding-top:0;padding-bottom:0}.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-rewind,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-next,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-playback{display:none}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop{opacity:0}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-countdown{display:flex}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-duration,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-duration{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-text-countdown,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-related-btn,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-slider-volume{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-controlbar{flex-direction:column-reverse}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-button-container{height:30px}.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-volume,.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-fullscreen{display:none}.jwplayer:not(.jw-breakpoint-0) .jw-text-duration:before,.jwplayer:not(.jw-breakpoint--1) .jw-text-duration:before{content:"/";padding-right:1ch;padding-left:1ch}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar{will-change:transform}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar .jw-text{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.jw-slider-container{display:flex;align-items:center;position:relative;touch-action:none}.jw-rail,.jw-buffer,.jw-progress{position:absolute;cursor:pointer}.jw-progress{background-color:#f2f2f2}.jw-rail{background-color:rgba(255,255,255,0.3)}.jw-buffer{background-color:rgba(255,255,255,0.3)}.jw-knob{height:13px;width:13px;background-color:#fff;border-radius:50%;box-shadow:0 0 10px rgba(0,0,0,0.4);opacity:1;pointer-events:none;position:absolute;-webkit-transform:translate(-50%, -50%) scale(0);transform:translate(-50%, -50%) scale(0);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform}.jw-flag-dragging .jw-slider-time .jw-knob,.jw-icon-volume:active .jw-slider-volume .jw-knob{box-shadow:0 0 26px rgba(0,0,0,0.2),0 0 10px rgba(0,0,0,0.4),0 0 0 6px rgba(255,255,255,0.2)}.jw-slider-horizontal,.jw-slider-vertical{display:flex}.jw-slider-horizontal .jw-slider-container{height:5px;width:100%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue,.jw-slider-horizontal .jw-knob{top:50%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue{-webkit-transform:translate(0, -50%);transform:translate(0, -50%)}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress{height:5px}.jw-slider-horizontal .jw-rail{width:100%}.jw-slider-vertical{align-items:center;flex-direction:column}.jw-slider-vertical .jw-slider-container{height:88px;width:5px}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress,.jw-slider-vertical .jw-knob{left:50%}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress{height:100%;width:5px;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out;bottom:0}.jw-slider-vertical .jw-knob{-webkit-transform:translate(-50%, 50%);transform:translate(-50%, 50%)}.jw-slider-time.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-slider-time,.jw-flag-audio-player .jw-slider-volume{height:17px;width:100%;align-items:center;background:transparent none;padding:0 12px}.jw-slider-time .jw-cue{background-color:rgba(33,33,33,0.8);cursor:pointer;position:absolute;width:6px}.jw-slider-time,.jw-horizontal-volume-container{z-index:1;outline:none}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail,.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer,.jw-slider-time .jw-progress,.jw-horizontal-volume-container .jw-progress,.jw-slider-time .jw-cue,.jw-horizontal-volume-container .jw-cue{-webkit-backface-visibility:hidden;backface-visibility:hidden;height:100%;-webkit-transform:translate(0, -50%) scale(1, .6);transform:translate(0, -50%) scale(1, .6);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out}.jw-slider-time:hover .jw-rail,.jw-horizontal-volume-container:hover .jw-rail,.jw-slider-time:focus .jw-rail,.jw-horizontal-volume-container:focus .jw-rail,.jw-flag-dragging .jw-slider-time .jw-rail,.jw-flag-dragging .jw-horizontal-volume-container .jw-rail,.jw-flag-touch .jw-slider-time .jw-rail,.jw-flag-touch .jw-horizontal-volume-container .jw-rail,.jw-slider-time:hover .jw-buffer,.jw-horizontal-volume-container:hover .jw-buffer,.jw-slider-time:focus .jw-buffer,.jw-horizontal-volume-container:focus .jw-buffer,.jw-flag-dragging .jw-slider-time .jw-buffer,.jw-flag-dragging .jw-horizontal-volume-container .jw-buffer,.jw-flag-touch .jw-slider-time .jw-buffer,.jw-flag-touch .jw-horizontal-volume-container .jw-buffer,.jw-slider-time:hover .jw-progress,.jw-horizontal-volume-container:hover .jw-progress,.jw-slider-time:focus .jw-progress,.jw-horizontal-volume-container:focus .jw-progress,.jw-flag-dragging .jw-slider-time .jw-progress,.jw-flag-dragging .jw-horizontal-volume-container .jw-progress,.jw-flag-touch .jw-slider-time .jw-progress,.jw-flag-touch .jw-horizontal-volume-container .jw-progress,.jw-slider-time:hover .jw-cue,.jw-horizontal-volume-container:hover .jw-cue,.jw-slider-time:focus .jw-cue,.jw-horizontal-volume-container:focus .jw-cue,.jw-flag-dragging .jw-slider-time .jw-cue,.jw-flag-dragging .jw-horizontal-volume-container .jw-cue,.jw-flag-touch .jw-slider-time .jw-cue,.jw-flag-touch .jw-horizontal-volume-container .jw-cue{-webkit-transform:translate(0, -50%) scale(1, 1);transform:translate(0, -50%) scale(1, 1)}.jw-slider-time:hover .jw-knob,.jw-horizontal-volume-container:hover .jw-knob,.jw-slider-time:focus .jw-knob,.jw-horizontal-volume-container:focus .jw-knob{-webkit-transform:translate(-50%, -50%) scale(1);transform:translate(-50%, -50%) scale(1)}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail{background-color:rgba(255,255,255,0.2)}.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer{background-color:rgba(255,255,255,0.4)}.jw-flag-touch .jw-slider-time::before,.jw-flag-touch .jw-horizontal-volume-container::before{height:44px;width:100%;content:"";position:absolute;display:block;bottom:calc(100% - 17px);left:0}.jw-slider-time.jw-tab-focus:focus .jw-rail,.jw-horizontal-volume-container.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time{height:17px;padding:0}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-slider-container{height:10px}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-knob{border-radius:0;border:1px solid rgba(0,0,0,0.75);height:12px;width:10px}.jw-modal{width:284px}.jw-breakpoint-7 .jw-modal,.jw-breakpoint-6 .jw-modal,.jw-breakpoint-5 .jw-modal{height:232px}.jw-breakpoint-4 .jw-modal,.jw-breakpoint-3 .jw-modal{height:192px}.jw-breakpoint-2 .jw-modal,.jw-flag-small-player .jw-modal{bottom:0;right:0;height:100%;width:100%;max-height:none;max-width:none;z-index:2}.jwplayer .jw-rightclick{display:none;position:absolute;white-space:nowrap}.jwplayer .jw-rightclick.jw-open{display:block}.jwplayer .jw-rightclick .jw-rightclick-list{border-radius:1px;list-style:none;margin:0;padding:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item{background-color:rgba(0,0,0,0.8);border-bottom:1px solid #444;margin:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo{color:#fff;display:inline-flex;padding:0 10px 0 0;vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo .jw-svg-icon{height:20px;width:20px}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-link{border:none;color:#fff;display:block;font-size:11px;line-height:1em;padding:15px 23px;text-align:start;text-decoration:none;width:100%}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:last-child{border-bottom:none}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:hover{cursor:pointer}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured{vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link{color:#fff}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link span{color:#fff}.jwplayer .jw-rightclick .jw-info-overlay-item,.jwplayer .jw-rightclick .jw-share-item,.jwplayer .jw-rightclick .jw-shortcuts-item{border:none;background-color:transparent;outline:none;cursor:pointer}.jw-icon-tooltip.jw-open .jw-overlay{opacity:1;pointer-events:auto;transition-delay:0s}.jw-icon-tooltip.jw-open .jw-overlay:focus{outline:none}.jw-icon-tooltip.jw-open .jw-overlay:focus.jw-tab-focus{outline:solid 2px #4d90fe}.jw-slider-time .jw-overlay:before{height:1em;top:auto}.jw-slider-time .jw-icon-tooltip.jw-open .jw-overlay{pointer-events:none}.jw-volume-tip{padding:13px 0 26px}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{height:auto;width:100%;box-shadow:0 0 10px rgba(0,0,0,0.4);color:#fff;display:block;margin:0 0 14px;pointer-events:none;position:relative;z-index:0}.jw-time-tip::after,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{top:100%;position:absolute;left:50%;height:14px;width:14px;border-radius:1px;background-color:currentColor;-webkit-transform-origin:75% 50%;transform-origin:75% 50%;-webkit-transform:translate(-50%, -50%) rotate(45deg);transform:translate(-50%, -50%) rotate(45deg);z-index:-1}.jw-time-tip .jw-text,.jw-controlbar .jw-tooltip .jw-text,.jw-settings-menu .jw-tooltip .jw-text{background-color:#fff;border-radius:1px;color:#000;font-size:10px;height:auto;line-height:1;padding:7px 10px;display:inline-block;min-width:100%;vertical-align:middle}.jw-controlbar .jw-overlay{position:absolute;bottom:100%;left:50%;margin:0;min-height:44px;min-width:44px;opacity:0;pointer-events:none;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s, 150ms;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);width:100%;z-index:1}.jw-controlbar .jw-overlay .jw-contents{position:relative}.jw-controlbar .jw-option{position:relative;white-space:nowrap;cursor:pointer;list-style:none;height:1.5em;font-family:inherit;line-height:1.5em;padding:0 .5em;font-size:.8em;margin:0}.jw-controlbar .jw-option::before{padding-right:.125em}.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{position:absolute;bottom:100%;left:50%;opacity:0;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:100ms 0s cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility, -webkit-transform;transition-property:opacity, transform, visibility;transition-property:opacity, transform, visibility, -webkit-transform;visibility:hidden;white-space:nowrap;width:auto;z-index:1}.jw-controlbar .jw-tooltip.jw-open,.jw-settings-menu .jw-tooltip.jw-open{opacity:1;-webkit-transform:translate(-50%, -10px);transform:translate(-50%, -10px);transition-duration:150ms;transition-delay:500ms,0s,500ms;visibility:visible}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen{left:auto;right:0;-webkit-transform:translate(0, 0);transform:translate(0, 0)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen.jw-open,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen.jw-open{-webkit-transform:translate(0, -10px);transform:translate(0, -10px)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen::after,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen::after{left:auto;right:9px}.jw-tooltip-time{height:auto;width:0;bottom:100%;line-height:normal;padding:0;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.jw-tooltip-time .jw-overlay{bottom:0;min-height:0;width:auto}.jw-tooltip{bottom:57px;display:none;position:absolute}.jw-tooltip .jw-text{height:100%;white-space:nowrap;text-overflow:ellipsis;direction:unset;max-width:246px;overflow:hidden}.jw-flag-audio-player .jw-tooltip{display:none}.jw-flag-small-player .jw-time-thumb{display:none}.jwplayer .jw-shortcuts-tooltip{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column;z-index:1}.jwplayer .jw-shortcuts-tooltip.jw-open{display:flex}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-close{flex:0 0 auto;margin:5px 5px 5px auto}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container{display:flex;flex:1 1 auto;flex-flow:column;font-size:12px;margin:0 20px 20px;overflow-y:auto;padding:5px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar{background-color:transparent;width:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-title{font-weight:bold}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list{display:flex;max-width:340px;margin:0 10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-tooltip-descriptions{width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row{display:flex;align-items:center;justify-content:space-between;margin:10px 0;width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-description{margin-right:10px;max-width:70%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-key{background:#fefefe;color:#333;overflow:hidden;padding:7px 10px;text-overflow:ellipsis;white-space:nowrap}.jw-skip{color:rgba(255,255,255,0.8);cursor:default;position:absolute;display:flex;right:.75em;bottom:56px;padding:.5em;border:1px solid #333;background-color:#000;align-items:center;height:2em}.jw-skip.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-skip.jw-skippable{cursor:pointer;padding:.25em .75em}.jw-skip.jw-skippable:hover{cursor:pointer;color:#fff}.jw-skip.jw-skippable .jw-skip-icon{display:inline;height:24px;width:24px;margin:0}.jw-breakpoint-7 .jw-skip{padding:1.35em 1em;bottom:130px}.jw-breakpoint-7 .jw-skip .jw-text{font-size:1em;font-weight:normal}.jw-breakpoint-7 .jw-skip .jw-icon-inline{height:30px;width:30px}.jw-breakpoint-7 .jw-skip .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-skip .jw-skip-icon{display:none;margin-left:-0.75em;padding:0 .5em;pointer-events:none}.jw-skip .jw-skip-icon .jw-svg-icon-next{display:block;padding:0}.jw-skip .jw-text,.jw-skip .jw-skip-icon{vertical-align:middle;font-size:.7em}.jw-skip .jw-text{font-weight:bold}.jw-cast{background-size:cover;display:none;height:100%;position:relative;width:100%}.jw-cast-container{background:linear-gradient(180deg, rgba(25,25,25,0.75), rgba(25,25,25,0.25), rgba(25,25,25,0));left:0;padding:20px 20px 80px;position:absolute;top:0;width:100%}.jw-cast-text{color:#fff;font-size:1.6em}.jw-breakpoint--1 .jw-cast-text,.jw-breakpoint-0 .jw-cast-text{font-size:1.15em}.jw-breakpoint-1 .jw-cast-text,.jw-breakpoint-2 .jw-cast-text,.jw-breakpoint-3 .jw-cast-text{font-size:1.3em}.jw-nextup-container{position:absolute;bottom:66px;left:0;background-color:transparent;cursor:pointer;margin:0 auto;padding:12px;pointer-events:none;right:0;text-align:right;visibility:hidden;width:100%}.jw-settings-open .jw-nextup-container,.jw-info-open .jw-nextup-container{display:none}.jw-breakpoint-7 .jw-nextup-container{padding:60px}.jw-flag-small-player .jw-nextup-container{padding:0 12px 0 0}.jw-flag-small-player .jw-nextup-container .jw-nextup-title,.jw-flag-small-player .jw-nextup-container .jw-nextup-duration,.jw-flag-small-player .jw-nextup-container .jw-nextup-close{display:none}.jw-flag-small-player .jw-nextup-container .jw-nextup-tooltip{height:30px}.jw-flag-small-player .jw-nextup-container .jw-nextup-header{font-size:12px}.jw-flag-small-player .jw-nextup-container .jw-nextup-body{justify-content:center;align-items:center;padding:.75em .3em}.jw-flag-small-player .jw-nextup-container .jw-nextup-thumbnail{width:50%}.jw-flag-small-player .jw-nextup-container .jw-nextup{max-width:65px}.jw-flag-small-player .jw-nextup-container .jw-nextup.jw-nextup-thumbnail-visible{max-width:120px}.jw-nextup{background:#333;border-radius:0;box-shadow:0 0 10px rgba(0,0,0,0.5);color:rgba(255,255,255,0.8);display:inline-block;max-width:280px;overflow:hidden;opacity:0;position:relative;width:64%;pointer-events:all;-webkit-transform:translate(0, -5px);transform:translate(0, -5px);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform;transition-delay:0s}.jw-nextup:hover .jw-nextup-tooltip{color:#fff}.jw-nextup.jw-nextup-thumbnail-visible{max-width:400px}.jw-nextup.jw-nextup-thumbnail-visible .jw-nextup-thumbnail{display:block}.jw-nextup-container-visible{visibility:visible}.jw-nextup-container-visible .jw-nextup{opacity:1;-webkit-transform:translate(0, 0);transform:translate(0, 0);transition-delay:0s, 0s, 150ms}.jw-nextup-tooltip{display:flex;height:80px}.jw-nextup-thumbnail{width:120px;background-position:center;background-size:cover;flex:0 0 auto;display:none}.jw-nextup-body{flex:1 1 auto;overflow:hidden;padding:.75em .875em;display:flex;flex-flow:column wrap;justify-content:space-between}.jw-nextup-header,.jw-nextup-title{font-size:14px;line-height:1.35}.jw-nextup-header{font-weight:bold}.jw-nextup-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.jw-nextup-duration{align-self:flex-end;text-align:right;font-size:12px}.jw-nextup-close{height:24px;width:24px;border:none;color:rgba(255,255,255,0.8);cursor:pointer;margin:6px;visibility:hidden}.jw-nextup-close:hover{color:#fff}.jw-nextup-sticky .jw-nextup-close{visibility:visible}.jw-autostart-mute{position:absolute;bottom:0;right:12px;height:44px;width:44px;background-color:rgba(33,33,33,0.4);padding:5px 4px 5px 6px;display:none}.jwplayer.jw-flag-autostart:not(.jw-flag-media-audio) .jw-nextup{display:none}.jw-settings-menu{position:absolute;bottom:57px;right:12px;align-items:flex-start;background-color:#333;display:none;flex-flow:column nowrap;max-width:284px;pointer-events:auto}.jw-settings-open .jw-settings-menu{display:flex}.jw-breakpoint-7 .jw-settings-menu{bottom:130px;right:60px;max-height:none;max-width:none;height:35%;width:25%}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline{height:60px;width:60px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-tooltip .jw-text{font-size:1em}.jw-breakpoint-7 .jw-settings-menu .jw-settings-back{min-width:60px}.jw-breakpoint-6 .jw-settings-menu,.jw-breakpoint-5 .jw-settings-menu{height:232px;width:284px;max-height:232px}.jw-breakpoint-4 .jw-settings-menu,.jw-breakpoint-3 .jw-settings-menu{height:192px;width:284px;max-height:192px}.jw-breakpoint-2 .jw-settings-menu{height:179px;width:284px;max-height:179px}.jw-flag-small-player .jw-settings-menu{max-width:none}.jw-settings-menu .jw-icon.jw-button-color::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon.jw-button-color[aria-checked="true"]::after{opacity:1}.jw-settings-menu .jw-settings-reset{text-decoration:underline}.jw-settings-topbar{align-items:center;background-color:rgba(0,0,0,0.4);display:flex;flex:0 0 auto;padding:3px 5px 0;width:100%}.jw-settings-topbar.jw-nested-menu-open{padding:0}.jw-settings-topbar.jw-nested-menu-open .jw-icon:not(.jw-settings-close):not(.jw-settings-back){display:none}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-close{width:20px}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-arrow-left{height:12px}.jw-settings-topbar.jw-nested-menu-open .jw-settings-topbar-text{display:block;outline:none}.jw-settings-topbar .jw-settings-back{min-width:44px}.jw-settings-topbar .jw-settings-topbar-buttons{display:inherit;width:100%;height:100%}.jw-settings-topbar .jw-settings-topbar-text{display:none;color:#fff;font-size:13px;width:100%}.jw-settings-topbar .jw-settings-close{margin-left:auto}.jw-settings-submenu{display:none;flex:1 1 auto;overflow-y:auto;padding:8px 20px 0 5px}.jw-settings-submenu::-webkit-scrollbar{background-color:transparent;width:6px}.jw-settings-submenu::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-settings-submenu.jw-settings-submenu-active{display:block}.jw-settings-submenu .jw-submenu-topbar{box-shadow:0 2px 9px 0 #1d1d1d;background-color:#2f2d2d;margin:-8px -20px 0 -5px}.jw-settings-submenu .jw-submenu-topbar .jw-settings-content-item{cursor:pointer;text-align:right;padding-right:15px;text-decoration:underline}.jw-settings-submenu .jw-settings-value-wrapper{float:right;display:flex;align-items:center}.jw-settings-submenu .jw-settings-value-wrapper .jw-settings-content-item-arrow{display:flex}.jw-settings-submenu .jw-settings-value-wrapper .jw-svg-icon-arrow-right{width:8px;margin-left:5px;height:12px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item{font-size:1em;padding:11px 15px 11px 30px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-settings-item-active::before{justify-content:flex-end}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-auto-label{font-size:.85em;padding-left:10px}.jw-flag-touch .jw-settings-submenu{overflow-y:scroll;-webkit-overflow-scrolling:touch}.jw-auto-label{font-size:10px;font-weight:initial;opacity:.75;padding-left:5px}.jw-settings-content-item{position:relative;color:rgba(255,255,255,0.8);cursor:pointer;font-size:12px;line-height:1;padding:7px 0 7px 15px;width:100%;text-align:left;outline:none}.jw-settings-content-item:hover{color:#fff}.jw-settings-content-item:focus{font-weight:bold}.jw-flag-small-player .jw-settings-content-item{line-height:1.75}.jw-settings-content-item.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-settings-item-active{font-weight:bold;position:relative}.jw-settings-item-active::before{height:100%;width:1em;align-items:center;content:"\\2022";display:inline-flex;justify-content:center}.jw-breakpoint-2 .jw-settings-open .jw-display-container,.jw-flag-small-player .jw-settings-open .jw-display-container,.jw-flag-touch .jw-settings-open .jw-display-container{display:none}.jw-breakpoint-2 .jw-settings-open.jw-controls,.jw-flag-small-player .jw-settings-open.jw-controls,.jw-flag-touch .jw-settings-open.jw-controls{z-index:1}.jw-flag-small-player .jw-settings-open .jw-controlbar{display:none}.jw-settings-open .jw-icon-settings::after{opacity:1}.jw-settings-open .jw-tooltip-settings{display:none}.jw-sharing-link{cursor:pointer}.jw-shortcuts-container .jw-switch{position:relative;display:inline-block;transition:ease-out .15s;transition-property:opacity, background;border-radius:18px;width:80px;height:20px;padding:10px;background:rgba(80,80,80,0.8);cursor:pointer;font-size:inherit;vertical-align:middle}.jw-shortcuts-container .jw-switch.jw-tab-focus{outline:solid 2px #4d90fe}.jw-shortcuts-container .jw-switch .jw-switch-knob{position:absolute;top:2px;left:1px;transition:ease-out .15s;box-shadow:0 0 10px rgba(0,0,0,0.4);border-radius:13px;width:15px;height:15px;background:#fefefe}.jw-shortcuts-container .jw-switch:before,.jw-shortcuts-container .jw-switch:after{position:absolute;top:3px;transition:inherit;color:#fefefe}.jw-shortcuts-container .jw-switch:before{content:attr(data-jw-switch-disabled);right:8px}.jw-shortcuts-container .jw-switch:after{content:attr(data-jw-switch-enabled);left:8px;opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]{background:#475470}.jw-shortcuts-container .jw-switch[aria-checked="true"]:before{opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]:after{opacity:1}.jw-shortcuts-container .jw-switch[aria-checked="true"] .jw-switch-knob{left:60px}.jw-idle-icon-text{display:none;line-height:1;position:absolute;text-align:center;text-indent:.35em;top:100%;white-space:nowrap;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.jw-idle-label{border-radius:50%;color:#fff;-webkit-filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));font:normal 16px/1 Arial,Helvetica,sans-serif;position:relative;transition:background-color 150ms cubic-bezier(0, .25, .25, 1);transition-property:background-color,-webkit-filter;transition-property:background-color,filter;transition-property:background-color,filter,-webkit-filter;-webkit-font-smoothing:antialiased}.jw-state-idle .jw-icon-display.jw-idle-label .jw-idle-icon-text{display:block}.jw-state-idle .jw-icon-display.jw-idle-label .jw-svg-icon-play{-webkit-transform:scale(.7, .7);transform:scale(.7, .7)}.jw-breakpoint-0.jw-state-idle .jw-icon-display.jw-idle-label,.jw-breakpoint--1.jw-state-idle .jw-icon-display.jw-idle-label{font-size:12px}.jw-info-overlay{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column}.jw-info-overlay .jw-info-close{flex:0 0 auto;margin:5px 5px 5px auto}.jw-info-open .jw-info-overlay{display:flex}.jw-info-container{display:flex;flex:1 1 auto;flex-flow:column;margin:0 20px 20px;overflow-y:auto;padding:5px}.jw-info-container [class*="jw-info"]:not(:first-of-type){color:rgba(255,255,255,0.8);padding-top:10px;font-size:12px}.jw-info-container .jw-info-description{margin-bottom:30px;text-align:start}.jw-info-container .jw-info-description:empty{display:none}.jw-info-container .jw-info-duration{text-align:start}.jw-info-container .jw-info-title{text-align:start;font-size:12px;font-weight:bold}.jw-info-container::-webkit-scrollbar{background-color:transparent;width:6px}.jw-info-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-info-clientid{align-self:flex-end;font-size:12px;color:rgba(255,255,255,0.8);margin:0 20px 20px 44px;text-align:right}.jw-flag-touch .jw-info-open .jw-display-container{display:none}@supports ((-webkit-filter: drop-shadow(0 0 3px #000)) or (filter: drop-shadow(0 0 3px #000))){.jwplayer.jw-ab-drop-shadow .jw-controls .jw-svg-icon,.jwplayer.jw-ab-drop-shadow .jw-controls .jw-icon.jw-text,.jwplayer.jw-ab-drop-shadow .jw-slider-container .jw-rail,.jwplayer.jw-ab-drop-shadow .jw-title{text-shadow:none;box-shadow:none;-webkit-filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3));filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3))}.jwplayer.jw-ab-drop-shadow .jw-button-color{opacity:.8;transition-property:color, opacity}.jwplayer.jw-ab-drop-shadow .jw-button-color:not(:hover){color:#fff;opacity:.8}.jwplayer.jw-ab-drop-shadow .jw-button-color:hover{opacity:1}.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0), hsla(0, 0%, 0%, 0.00787) 10.79%, hsla(0, 0%, 0%, 0.02963) 21.99%, hsla(0, 0%, 0%, 0.0625) 33.34%, hsla(0, 0%, 0%, 0.1037) 44.59%, hsla(0, 0%, 0%, 0.15046) 55.48%, hsla(0, 0%, 0%, 0.2) 65.75%, hsla(0, 0%, 0%, 0.24954) 75.14%, hsla(0, 0%, 0%, 0.2963) 83.41%, hsla(0, 0%, 0%, 0.3375) 90.28%, hsla(0, 0%, 0%, 0.37037) 95.51%, hsla(0, 0%, 0%, 0.39213) 98.83%, hsla(0, 0%, 0%, 0.4));mix-blend-mode:multiply;transition-property:opacity}.jw-state-idle.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0.2), hsla(0, 0%, 0%, 0.19606) 1.17%, hsla(0, 0%, 0%, 0.18519) 4.49%, hsla(0, 0%, 0%, 0.16875) 9.72%, hsla(0, 0%, 0%, 0.14815) 16.59%, hsla(0, 0%, 0%, 0.12477) 24.86%, hsla(0, 0%, 0%, 0.1) 34.25%, hsla(0, 0%, 0%, 0.07523) 44.52%, hsla(0, 0%, 0%, 0.05185) 55.41%, hsla(0, 0%, 0%, 0.03125) 66.66%, hsla(0, 0%, 0%, 0.01481) 78.01%, hsla(0, 0%, 0%, 0.00394) 89.21%, hsla(0, 0%, 0%, 0));background-size:100% 7rem;background-position:50% 0}.jwplayer.jw-ab-drop-shadow.jw-state-idle .jw-controls{background-color:transparent}}.jw-video-thumbnail-container{position:relative;overflow:hidden}.jw-video-thumbnail-container:not(.jw-related-shelf-item-image){height:100%;width:100%}.jw-video-thumbnail-container.jw-video-thumbnail-generated{position:absolute;top:0;left:0}.jw-video-thumbnail-container:hover,.jw-related-item-content:hover .jw-video-thumbnail-container,.jw-related-shelf-item:hover .jw-video-thumbnail-container{cursor:pointer}.jw-video-thumbnail-container:hover .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-item-content:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-shelf-item:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail{position:absolute;top:50%;left:50%;bottom:unset;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);width:100%;height:auto;min-width:100%;min-height:100%;opacity:0;transition:opacity .3s ease;object-fit:cover;background:#000}.jw-related-item-next-up .jw-video-thumbnail-container .jw-video-thumbnail{height:100%;width:auto}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-visible:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-completed{opacity:0}.jw-video-thumbnail-container .jw-video-thumbnail~.jw-svg-icon-play{display:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-shelf-item-aspect{pointer-events:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-item-poster-content{pointer-events:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-state-idle .jw-controls{background:rgba(0,0,0,0.4)}.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay),.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay){display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon:focus{border:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon .jw-svg-icon-buffer{-webkit-animation:jw-spin 2s linear infinite;animation:jw-spin 2s linear infinite;display:block}@-webkit-keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.jwplayer.jw-state-buffering .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-pause{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-pause{display:block}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-controls-backdrop{opacity:0}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-logo-bottom-left,.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio):not(.jw-flag-autostart) .jw-logo-bottom-right{bottom:0}.jwplayer .jw-icon-playback .jw-svg-icon-stop{display:none}.jwplayer.jw-state-paused .jw-svg-icon-pause,.jwplayer.jw-state-idle .jw-svg-icon-pause,.jwplayer.jw-state-error .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-svg-icon-pause{display:none}.jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-complete .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-play{display:none}.jwplayer:not(.jw-state-buffering) .jw-svg-icon-buffer{display:none}.jwplayer:not(.jw-state-complete) .jw-svg-icon-replay{display:none}.jwplayer:not(.jw-state-error) .jw-svg-icon-error{display:none}.jwplayer.jw-state-complete .jw-display .jw-icon-display .jw-svg-icon-replay{display:block}.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-state-complete .jw-controls{background:rgba(0,0,0,0.4);height:100%}.jw-state-idle .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-state-idle .jw-display-icon-rewind,.jwplayer.jw-state-buffering .jw-display-icon-rewind,.jwplayer.jw-state-complete .jw-display-icon-rewind,body .jw-error .jw-display-icon-rewind,body .jwplayer.jw-state-error .jw-display-icon-rewind,.jw-state-idle .jw-display-icon-next,.jwplayer.jw-state-buffering .jw-display-icon-next,.jwplayer.jw-state-complete .jw-display-icon-next,body .jw-error .jw-display-icon-next,body .jwplayer.jw-state-error .jw-display-icon-next{display:none}body .jw-error .jw-icon-display,body .jwplayer.jw-state-error .jw-icon-display{cursor:default}body .jw-error .jw-icon-display .jw-svg-icon-error,body .jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-error{display:block}body .jw-error .jw-icon-container{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-preview{display:none}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title{padding-top:4px}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-primary{width:auto;display:inline-block;padding-right:.5ch}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-secondary{width:auto;display:inline-block;padding-left:0}body .jwplayer.jw-state-error .jw-controlbar,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-controlbar{display:none}body .jwplayer.jw-state-error .jw-settings-menu,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-settings-menu{height:100%;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}body .jwplayer.jw-state-error .jw-display,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-display{padding:0}body .jwplayer.jw-state-error .jw-logo-bottom-left,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-left,body .jwplayer.jw-state-error .jw-logo-bottom-right,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-right{bottom:0}.jwplayer.jw-state-playing.jw-flag-user-inactive .jw-display{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-state-playing:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display,.jwplayer.jw-state-paused:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting):not(.jw-flag-play-rejected) .jw-display{display:none}.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-rewind,.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-next{display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-text,.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-flag-casting:not(.jw-flag-audio-player) .jw-cast{display:block}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-display-icon-container{display:none}.jwplayer.jw-flag-casting .jw-icon-hd,.jwplayer.jw-flag-casting .jw-captions,.jwplayer.jw-flag-casting .jw-icon-fullscreen,.jwplayer.jw-flag-casting .jw-icon-audio-tracks{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-volume{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-airplay{color:#fff}.jw-state-playing.jw-flag-casting:not(.jw-flag-audio-player) .jw-display,.jw-state-paused.jw-flag-casting:not(.jw-flag-audio-player) .jw-display{display:table}.jwplayer.jw-flag-cast-available .jw-icon-cast,.jwplayer.jw-flag-cast-available .jw-icon-airplay{display:flex}.jwplayer.jw-flag-cardboard-available .jw-icon-cardboard{display:flex}.jwplayer.jw-flag-live .jw-display-icon-rewind{visibility:hidden}.jwplayer.jw-flag-live .jw-controlbar .jw-text-elapsed,.jwplayer.jw-flag-live .jw-controlbar .jw-text-duration,.jwplayer.jw-flag-live .jw-controlbar .jw-text-countdown,.jwplayer.jw-flag-live .jw-controlbar .jw-slider-time{display:none}.jwplayer.jw-flag-live .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-live .jw-controlbar .jw-overlay:after{display:none}.jwplayer.jw-flag-live .jw-nextup-container{bottom:44px}.jwplayer.jw-flag-live .jw-text-elapsed,.jwplayer.jw-flag-live .jw-text-duration{display:none}.jwplayer.jw-flag-live .jw-text-live{cursor:default}.jwplayer.jw-flag-live .jw-text-live:hover{color:rgba(255,255,255,0.8)}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-stop,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-stop{display:block}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-text-live{height:24px;width:auto;align-items:center;border-radius:1px;color:rgba(255,255,255,0.8);display:flex;font-size:12px;font-weight:bold;margin-right:10px;padding:0 1ch;text-rendering:geometricPrecision;text-transform:uppercase;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:box-shadow,color}.jw-text-live::before{height:8px;width:8px;background-color:currentColor;border-radius:50%;margin-right:6px;opacity:1;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-text-live.jw-dvr-live{box-shadow:inset 0 0 0 2px currentColor}.jw-text-live.jw-dvr-live::before{opacity:.5}.jw-text-live.jw-dvr-live:hover{color:#fff}.jwplayer.jw-flag-controls-hidden .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-controls-hidden:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-controls-hidden .jw-plugin{bottom:.5em}.jwplayer.jw-flag-controls-hidden .jw-nextup-container{bottom:0}.jw-flag-controls-hidden .jw-controlbar,.jw-flag-controls-hidden .jw-display{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-controls-hidden .jw-controls-backdrop{opacity:0}.jw-flag-controls-hidden .jw-logo{visibility:visible}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-plugin{bottom:.5em}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-nextup-container{bottom:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-controls-hidden) .jw-media{cursor:none;-webkit-cursor-visibility:auto-hide}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing.jw-flag-casting .jw-display{display:table}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-ads) .jw-autostart-mute{display:flex}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting .jw-nextup-container{bottom:66px}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting.jw-state-idle .jw-nextup-container{display:none}.jw-flag-media-audio .jw-preview{display:block}.jwplayer.jw-flag-ads .jw-preview,.jwplayer.jw-flag-ads .jw-logo,.jwplayer.jw-flag-ads .jw-captions.jw-captions-enabled,.jwplayer.jw-flag-ads .jw-nextup-container,.jwplayer.jw-flag-ads .jw-text-duration,.jwplayer.jw-flag-ads .jw-text-elapsed{display:none}.jwplayer.jw-flag-ads video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-rewind,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-next,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-display{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player.jw-state-buffering .jw-display-icon-display{display:inline-block}.jwplayer.jw-flag-ads .jw-controlbar{flex-wrap:wrap-reverse}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time{height:auto;padding:0;pointer-events:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-slider-container{height:5px}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-rail,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-knob,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-buffer,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-cue,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-icon-settings{display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-progress{-webkit-transform:none;transform:none;top:auto}.jwplayer.jw-flag-ads .jw-controlbar .jw-tooltip,.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-tooltip:not(.jw-icon-volume),.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-inline:not(.jw-icon-playback):not(.jw-icon-fullscreen):not(.jw-icon-volume){display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-volume-tip{padding:13px 0}.jwplayer.jw-flag-ads .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid) .jw-controls .jw-controlbar,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart .jw-controls .jw-controlbar{display:flex;pointer-events:all;visibility:visible;opacity:1}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-user-inactive .jw-controls-backdrop,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart.jw-flag-user-inactive .jw-controls-backdrop{opacity:1;background-size:100% 60px}.jwplayer.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-ads-vpaid .jw-skip,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-skip{display:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls{background:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls::after{content:none}.jwplayer.jw-flag-ads-hide-controls .jw-controls-backdrop,.jwplayer.jw-flag-ads-hide-controls .jw-controls{display:none !important}.jw-flag-overlay-open-related .jw-controls,.jw-flag-overlay-open-related .jw-title,.jw-flag-overlay-open-related .jw-logo{display:none}.jwplayer.jw-flag-rightclick-open{overflow:visible}.jwplayer.jw-flag-rightclick-open .jw-rightclick{z-index:16777215}body .jwplayer.jw-flag-flash-blocked .jw-controls,body .jwplayer.jw-flag-flash-blocked .jw-overlays,body .jwplayer.jw-flag-flash-blocked .jw-controls-backdrop,body .jwplayer.jw-flag-flash-blocked .jw-preview{display:none}body .jwplayer.jw-flag-flash-blocked .jw-error-msg{top:25%}.jw-flag-touch.jw-breakpoint-7 .jw-captions,.jw-flag-touch.jw-breakpoint-6 .jw-captions,.jw-flag-touch.jw-breakpoint-5 .jw-captions,.jw-flag-touch.jw-breakpoint-4 .jw-captions,.jw-flag-touch.jw-breakpoint-7 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-6 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-5 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-4 .jw-nextup-container{bottom:4.25em}.jw-flag-touch .jw-controlbar .jw-icon-volume{display:flex}.jw-flag-touch .jw-display,.jw-flag-touch .jw-display-container,.jw-flag-touch .jw-display-controls{pointer-events:none}.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-rewind,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-rewind{display:none}.jw-flag-touch.jw-state-paused.jw-flag-dragging .jw-display{display:none}.jw-flag-audio-player{background-color:#000}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:44px}.jw-flag-audio-player:not(.jw-flag-live) .jw-spacer{display:none}.jw-flag-audio-player .jw-preview,.jw-flag-audio-player .jw-display,.jw-flag-audio-player .jw-title,.jw-flag-audio-player .jw-nextup-container{display:none}.jw-flag-audio-player .jw-controlbar{position:relative}.jw-flag-audio-player .jw-controlbar .jw-button-container{padding-right:3px;padding-left:0}.jw-flag-audio-player .jw-controlbar .jw-icon-tooltip,.jw-flag-audio-player .jw-controlbar .jw-icon-inline{display:none}.jw-flag-audio-player .jw-controlbar .jw-icon-volume,.jw-flag-audio-player .jw-controlbar .jw-icon-playback,.jw-flag-audio-player .jw-controlbar .jw-icon-next,.jw-flag-audio-player .jw-controlbar .jw-icon-rewind,.jw-flag-audio-player .jw-controlbar .jw-icon-cast,.jw-flag-audio-player .jw-controlbar .jw-text-live,.jw-flag-audio-player .jw-controlbar .jw-icon-airplay,.jw-flag-audio-player .jw-controlbar .jw-logo-button,.jw-flag-audio-player .jw-controlbar .jw-text-elapsed,.jw-flag-audio-player .jw-controlbar .jw-text-duration{display:flex;flex:0 0 auto}.jw-flag-audio-player .jw-controlbar .jw-text-duration,.jw-flag-audio-player .jw-controlbar .jw-text-countdown{padding-right:10px}.jw-flag-audio-player .jw-controlbar .jw-slider-time{flex:0 1 auto;align-items:center;display:flex;order:1}.jw-flag-audio-player .jw-controlbar .jw-icon-volume{margin-right:0;transition:margin-right 150ms cubic-bezier(0, .25, .25, 1)}.jw-flag-audio-player .jw-controlbar .jw-icon-volume .jw-overlay{display:none}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container{transition:width 300ms cubic-bezier(0, .25, .25, 1);width:0}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open{width:140px}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open .jw-slider-volume{padding-right:24px;transition:opacity 300ms;opacity:1}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open~.jw-slider-time{flex:1 1 auto;width:auto;transition:opacity 300ms, width 300ms}.jw-flag-audio-player .jw-controlbar .jw-slider-volume{opacity:0}.jw-flag-audio-player .jw-controlbar .jw-slider-volume .jw-knob{-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.jw-flag-audio-player .jw-controlbar .jw-slider-volume~.jw-icon-volume{margin-right:140px}.jw-flag-audio-player.jw-breakpoint-1 .jw-horizontal-volume-container.jw-open~.jw-slider-time,.jw-flag-audio-player.jw-breakpoint-2 .jw-horizontal-volume-container.jw-open~.jw-slider-time{opacity:0}.jw-flag-audio-player.jw-flag-small-player .jw-text-elapsed,.jw-flag-audio-player.jw-flag-small-player .jw-text-duration{display:none}.jw-flag-audio-player.jw-flag-ads .jw-slider-time{display:none}.jw-hidden{display:none}',""])}]]); \ No newline at end of file diff --git a/ui/v2.5/public/jwplayer/jwplayer.core.controls.html5.js b/ui/v2.5/public/jwplayer/jwplayer.core.controls.html5.js new file mode 100644 index 000000000..02b9604a1 --- /dev/null +++ b/ui/v2.5/public/jwplayer/jwplayer.core.controls.html5.js @@ -0,0 +1,95 @@ +/*! +JW Player version 8.11.5 +Copyright (c) 2019, JW Player, All Rights Reserved +https://github.com/jwplayer/jwplayer/blob/v8.11.5/README.md + +This source code and its use and distribution is subject to the terms and conditions of the applicable license agreement. +https://www.jwplayer.com/tos/ + +This product includes portions of other software. For the full text of licenses, see below: + +JW Player Third Party Software Notices and/or Additional Terms and Conditions + +************************************************************************************************** +The following software is used under Apache License 2.0 +************************************************************************************************** + +vtt.js v0.13.0 +Copyright (c) 2019 Mozilla (http://mozilla.org) +https://github.com/mozilla/vtt.js/blob/v0.13.0/LICENSE + +* * * + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. + +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. + +************************************************************************************************** +The following software is used under MIT license +************************************************************************************************** + +Underscore.js v1.6.0 +Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative +https://github.com/jashkenas/underscore/blob/1.6.0/LICENSE + +Backbone backbone.events.js v1.1.2 +Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud +https://github.com/jashkenas/backbone/blob/1.1.2/LICENSE + +Promise Polyfill v7.1.1 +Copyright (c) 2014 Taylor Hakes and Forbes Lindesay +https://github.com/taylorhakes/promise-polyfill/blob/v7.1.1/LICENSE + +can-autoplay.js v3.0.0 +Copyright (c) 2017 video-dev +https://github.com/video-dev/can-autoplay/blob/v3.0.0/LICENSE + +* * * + +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. + +************************************************************************************************** +The following software is used under W3C license +************************************************************************************************** + +Intersection Observer v0.5.0 +Copyright (c) 2016 Google Inc. (http://google.com) +https://github.com/w3c/IntersectionObserver/blob/v0.5.0/LICENSE.md + +* * * + +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. + +This work is being provided by the copyright holders under the following license. + +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. + +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. + +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. +*/ +(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[4,1,2,3,9],[,,,,,,,,,,,,,,,,,function(e,t,i){"use strict";i.r(t);var n,o=i(8),a=i(3),r=i(7),s=i(43),l=i(5),c=i(15),u=i(40);function d(e){return n||(n=new DOMParser),Object(l.r)(Object(l.s)(n.parseFromString(e,"image/svg+xml").documentElement))}var p=function(e,t,i,n){var o=document.createElement("div");o.className="jw-icon jw-icon-inline jw-button-color jw-reset "+e,o.setAttribute("role","button"),o.setAttribute("tabindex","0"),i&&o.setAttribute("aria-label",i),o.style.display="none";var a=new u.a(o).on("click tap enter",t||function(){});return n&&Array.prototype.forEach.call(n,(function(e){"string"==typeof e?o.appendChild(d(e)):o.appendChild(e)})),{ui:a,element:function(){return o},toggle:function(e){e?this.show():this.hide()},show:function(){o.style.display=""},hide:function(){o.style.display="none"}}},w=i(0),h=i(71),f=i.n(h),g=i(72),j=i.n(g),b=i(73),m=i.n(b),v=i(74),y=i.n(v),k=i(75),x=i.n(k),T=i(76),O=i.n(T),C=i(77),M=i.n(C),_=i(78),S=i.n(_),E=i(79),A=i.n(E),P=i(80),z=i.n(P),L=i(81),B=i.n(L),I=i(82),R=i.n(I),V=i(83),N=i.n(V),H=i(84),F=i.n(H),D=i(85),q=i.n(D),U=i(86),W=i.n(U),Q=i(62),Y=i.n(Q),X=i(87),K=i.n(X),J=i(88),Z=i.n(J),G=i(89),$=i.n(G),ee=i(90),te=i.n(ee),ie=i(91),ne=i.n(ie),oe=i(92),ae=i.n(oe),re=i(93),se=i.n(re),le=i(94),ce=i.n(le),ue=null;function de(e){var t=fe().querySelector(we(e));if(t)return he(t);throw new Error("Icon not found "+e)}function pe(e){var t=fe().querySelectorAll(e.split(",").map(we).join(","));if(!t.length)throw new Error("Icons not found "+e);return Array.prototype.map.call(t,(function(e){return he(e)}))}function we(e){return".jw-svg-icon-".concat(e)}function he(e){return e.cloneNode(!0)}function fe(){return ue||(ue=d(""+f.a+j.a+m.a+y.a+x.a+O.a+M.a+S.a+A.a+z.a+B.a+R.a+N.a+F.a+q.a+W.a+Y.a+K.a+Z.a+$.a+te.a+ne.a+ae.a+se.a+ce.a+"")),ue}var ge=i(10);function je(e,t){for(var i=0;i10&&delete be[t[0]];var i=d(e);be[e]=i}return be[e].cloneNode(!0)}(t):((r=document.createElement("div")).className="jw-icon jw-button-image jw-button-color jw-reset",t&&Object(ge.d)(r,{backgroundImage:"url(".concat(t,")")})),s.appendChild(r),new u.a(s).on("click tap enter",n,this),s.addEventListener("mousedown",(function(e){e.preventDefault()})),this.id=o,this.buttonElement=s}var t,i,n;return t=e,(i=[{key:"element",value:function(){return this.buttonElement}},{key:"toggle",value:function(e){e?this.show():this.hide()}},{key:"show",value:function(){this.buttonElement.style.display=""}},{key:"hide",value:function(){this.buttonElement.style.display="none"}}])&&je(t.prototype,i),n&&je(t,n),e}(),ve=i(11);function ye(e,t){for(var i=0;i=0&&(t.left-=i,t.right-=i),t},xe=function(){function e(t,i){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),Object(w.g)(this,r.a),this.className=t+" jw-background-color jw-reset",this.orientation=i}var t,i,n;return t=e,(i=[{key:"setup",value:function(){this.el=Object(l.e)(function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return''}(this.className,"jw-slider-"+this.orientation)),this.elementRail=this.el.getElementsByClassName("jw-slider-container")[0],this.elementBuffer=this.el.getElementsByClassName("jw-buffer")[0],this.elementProgress=this.el.getElementsByClassName("jw-progress")[0],this.elementThumb=this.el.getElementsByClassName("jw-knob")[0],this.ui=new u.a(this.element(),{preventScrolling:!0}).on("dragStart",this.dragStart,this).on("drag",this.dragMove,this).on("dragEnd",this.dragEnd,this).on("click tap",this.tap,this)}},{key:"dragStart",value:function(){this.trigger("dragStart"),this.railBounds=ke(this.elementRail)}},{key:"dragEnd",value:function(e){this.dragMove(e),this.trigger("dragEnd")}},{key:"dragMove",value:function(e){var t,i,n=this.railBounds=this.railBounds?this.railBounds:ke(this.elementRail);return i="horizontal"===this.orientation?(t=e.pageX)n.right?100:100*Object(s.a)((t-n.left)/n.width,0,1):(t=e.pageY)>=n.bottom?0:t<=n.top?100:100*Object(s.a)((n.height-(t-n.top))/n.height,0,1),this.render(i),this.update(i),!1}},{key:"tap",value:function(e){this.railBounds=ke(this.elementRail),this.dragMove(e)}},{key:"limit",value:function(e){return e}},{key:"update",value:function(e){this.trigger("update",{percentage:e})}},{key:"render",value:function(e){e=Math.max(0,Math.min(e,100)),"horizontal"===this.orientation?(this.elementThumb.style.left=e+"%",this.elementProgress.style.width=e+"%"):(this.elementThumb.style.bottom=e+"%",this.elementProgress.style.height=e+"%")}},{key:"updateBuffer",value:function(e){this.elementBuffer.style.width=e+"%"}},{key:"element",value:function(){return this.el}}])&&ye(t.prototype,i),n&&ye(t,n),e}(),Te=function(e,t){e&&t&&(e.setAttribute("aria-label",t),e.setAttribute("role","button"),e.setAttribute("tabindex","0"))};function Oe(e,t){for(var i=0;i0&&Array.prototype.forEach.call(o,(function(e){"string"==typeof e?a.el.appendChild(d(e)):a.el.appendChild(e)}))}var t,i,n;return t=e,(i=[{key:"addContent",value:function(e){this.content&&this.removeContent(),this.content=e,this.tooltip.appendChild(e)}},{key:"removeContent",value:function(){this.content&&(this.tooltip.removeChild(this.content),this.content=null)}},{key:"hasContent",value:function(){return!!this.content}},{key:"element",value:function(){return this.el}},{key:"openTooltip",value:function(e){this.isOpen||(this.trigger("open-"+this.componentType,e,{isOpen:!0}),this.isOpen=!0,Object(l.v)(this.el,this.openClass,this.isOpen))}},{key:"closeTooltip",value:function(e){this.isOpen&&(this.trigger("close-"+this.componentType,e,{isOpen:!1}),this.isOpen=!1,Object(l.v)(this.el,this.openClass,this.isOpen))}},{key:"toggleOpenState",value:function(e){this.isOpen?this.closeTooltip(e):this.openTooltip(e)}}])&&Oe(t.prototype,i),n&&Oe(t,n),e}(),Me=i(22),_e=i(57);function Se(e,t){for(var i=0;i=this.thumbnails.length&&(t=this.thumbnails.length-1);var i=this.thumbnails[t].img;return i.indexOf("://")<0&&(i=this.vttPath?this.vttPath+"/"+i:i),i},loadThumbnail:function(e){var t=this.chooseThumbnail(e),i={margin:"0 auto",backgroundPosition:"0 0"};if(t.indexOf("#xywh")>0)try{var n=/(.+)#xywh=(\d+),(\d+),(\d+),(\d+)/.exec(t);t=n[1],i.backgroundPosition=-1*n[2]+"px "+-1*n[3]+"px",i.width=n[4],this.timeTip.setWidth(+i.width),i.height=n[5]}catch(e){return}else this.individualImage||(this.individualImage=new Image,this.individualImage.onload=Object(w.a)((function(){this.individualImage.onload=null,this.timeTip.image({width:this.individualImage.width,height:this.individualImage.height}),this.timeTip.setWidth(this.individualImage.width)}),this),this.individualImage.src=t);return i.backgroundImage='url("'+t+'")',i},showThumbnail:function(e){this._model.get("containerWidth")<=420||this.thumbnails.length<1||this.timeTip.image(this.loadThumbnail(e))},resetThumbnails:function(){this.timeTip.image({backgroundImage:"",width:0,height:0}),this.thumbnails=[]}};function Le(e,t,i){return(Le="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(e,t,i){var n=function(e,t){for(;!Object.prototype.hasOwnProperty.call(e,t)&&null!==(e=He(e)););return e}(e,t);if(n){var o=Object.getOwnPropertyDescriptor(n,t);return o.get?o.get.call(i):o.value}})(e,t,i||e)}function Be(e){return(Be="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function Ie(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Re(e,t){for(var i=0;i-1&&(n="Live")}var d=this.timeTip;d.update(n),this.textLength!==n.length&&(this.textLength=n.length,d.resetWidth()),this.showThumbnail(u),Object(l.a)(d.el,"jw-open");var p=d.getWidth(),w=a.width/100,h=o-a.width,f=0;p>h&&(f=(p-h)/(200*w));var g=100*Math.min(1-f,Math.max(f,c)).toFixed(3);Object(ge.d)(d.el,{left:g+"%"})}}},{key:"hideTimeTooltip",value:function(){Object(l.o)(this.timeTip.el,"jw-open")}},{key:"updateCues",value:function(e,t){var i=this;this.resetCues(),t&&t.length&&(t.forEach((function(e){i.addCue(e)})),this.drawCues())}},{key:"updateAriaText",value:function(){var e=this._model;if(!e.get("seeking")){var t=e.get("position"),i=e.get("duration"),n=Object(ve.timeFormat)(t);"DVR"!==this.streamType&&(n+=" of ".concat(Object(ve.timeFormat)(i)));var o=this.el;document.activeElement!==o&&(this.timeUpdateKeeper.textContent=n),Object(l.t)(o,"aria-valuenow",t),Object(l.t)(o,"aria-valuetext",n)}}},{key:"reset",value:function(){this.resetThumbnails(),this.timeTip.resetWidth(),this.textLength=0}}]),t}(xe);Object(w.g)(Ue.prototype,Ae,ze);var We=Ue;function Qe(e,t){for(var i=0;i=75&&!e),Object(l.t)(r,"aria-valuenow",o),Object(l.t)(s,"aria-valuenow",o);var c="Volume ".concat(o,"%");Object(l.t)(r,"aria-valuetext",c),Object(l.t)(s,"aria-valuetext",c),document.activeElement!==r&&document.activeElement!==s&&(this._volumeAnnouncer.textContent=c)}}},{key:"onCastAvailable",value:function(e,t){this.elements.cast.toggle(t)}},{key:"onCastActive",value:function(e,t){this.elements.fullscreen.toggle(!t),this.elements.cast.button&&Object(l.v)(this.elements.cast.button,"jw-off",!t)}},{key:"onElapsed",value:function(e,t){var i,n,o=e.get("duration");if("DVR"===e.get("streamType")){var a=Math.ceil(t),r=this._model.get("dvrSeekLimit");i=n=a>=-r?"":"-"+Object(ve.timeFormat)(-(t+r)),e.set("dvrLive",a>=-r)}else i=Object(ve.timeFormat)(t),n=Object(ve.timeFormat)(o-t);this.elements.elapsed.textContent=i,this.elements.countdown.textContent=n}},{key:"onDuration",value:function(e,t){this.elements.duration.textContent=Object(ve.timeFormat)(Math.abs(t))}},{key:"onAudioMode",value:function(e,t){var i=this.elements.time.element();t?this.elements.buttonContainer.insertBefore(i,this.elements.elapsed):Object(l.m)(this.el,i)}},{key:"element",value:function(){return this.el}},{key:"setAltText",value:function(e,t){this.elements.alt.textContent=t}},{key:"closeMenus",value:function(e){this.menus.forEach((function(t){e&&e.target===t.el||t.closeTooltip(e)}))}},{key:"rewind",value:function(){var e,t=0,i=this._model.get("currentTime");i?e=i-10:(e=this._model.get("position")-10,"DVR"===this._model.get("streamType")&&(t=this._model.get("duration"))),this._api.seek(Math.max(e,t),{reason:"interaction"})}},{key:"onState",value:function(e,t){var i=e.get("localization"),n=i.play;this.setPlayText(n),t===a.pb&&("LIVE"!==e.get("streamType")?(n=i.pause,this.setPlayText(n)):(n=i.stop,this.setPlayText(n))),Object(l.t)(this.elements.play.element(),"aria-label",n)}},{key:"onStreamTypeChange",value:function(e,t){var i="LIVE"===t,n="DVR"===t;this.elements.rewind.toggle(!i),this.elements.live.toggle(i||n),Object(l.t)(this.elements.live.element(),"tabindex",i?"-1":"0"),this.elements.duration.style.display=n?"none":"",this.onDuration(e,e.get("duration")),this.onState(e,e.get("state"))}},{key:"addLogo",value:function(e){var t=this.elements.buttonContainer,i=new me(e.file,this._model.get("localization").logo,(function(){e.link&&Object(l.l)(e.link,"_blank",{rel:"noreferrer"})}),"logo","jw-logo-button");e.link||Object(l.t)(i.element(),"tabindex","-1"),t.insertBefore(i.element(),t.querySelector(".jw-spacer").nextSibling)}},{key:"goToLiveEdge",value:function(){if("DVR"===this._model.get("streamType")){var e=Math.min(this._model.get("position"),-1),t=this._model.get("dvrSeekLimit");this._api.seek(Math.max(-t,e),{reason:"interaction"}),this._api.play({reason:"interaction"})}}},{key:"updateButtons",value:function(e,t,i){if(t){var n,o,a=this.elements.buttonContainer;t!==i&&i?(n=ct(t,i),o=ct(i,t),this.removeButtons(a,o)):n=t;for(var r=n.length-1;r>=0;r--){var s=n[r],l=new me(s.img,s.tooltip,s.callback,s.id,s.btnClass);s.tooltip&&nt(l.element(),s.id,s.tooltip);var c=void 0;"related"===l.id?c=this.elements.settingsButton.element():"share"===l.id?c=a.querySelector('[button="related"]')||this.elements.settingsButton.element():(c=this.elements.spacer.nextSibling)&&"logo"===c.getAttribute("button")&&(c=c.nextSibling),a.insertBefore(l.element(),c)}}}},{key:"removeButtons",value:function(e,t){for(var i=t.length;i--;){var n=e.querySelector('[button="'.concat(t[i].id,'"]'));n&&e.removeChild(n)}}},{key:"toggleCaptionsButtonState",value:function(e){var t=this.elements.captionsButton;t&&Object(l.v)(t.element(),"jw-off",!e)}},{key:"destroy",value:function(){var e=this;this._model.off(null,null,this),Object.keys(this.elements).forEach((function(t){var i=e.elements[t];i&&"function"==typeof i.destroy&&e.elements[t].destroy()})),this.ui.forEach((function(e){e.destroy()})),this.ui=[]}}])&&at(t.prototype,i),n&&at(t,n),e}(),pt=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return'
    ')+'
    ')+"
    "},wt=function(e){return'
    '+pt("rewind",e.rewind)+pt("display",e.playback)+pt("next",e.next)+"
    "};function ht(e,t){for(var i=0;i'.concat(a.playback,"")),Object(l.a)(o.icon,"jw-idle-label"),o.icon.appendChild(s))}return o}var i,n,o;return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&vt(e,t)}(t,e),i=t,(n=[{key:"element",value:function(){return this.el}}])&&jt(i.prototype,n),o&&jt(i,o),t}(r.a);function kt(e,t){for(var i=0;i0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";return'
    '+'
    '.concat(e,"
    ")+'
    '.concat(t,"
    ")+'
    '.concat(i,"
    ")+"
    "+'')+"
    "}());t.querySelector(".jw-nextup-close").appendChild(de("close")),this.addContent(t),this.closeButton=this.content.querySelector(".jw-nextup-close"),this.closeButton.setAttribute("aria-label",this.localization.close),this.tooltip=this.content.querySelector(".jw-nextup-tooltip");var i=this._model,n=i.player;this.enabled=!1,i.on("change:nextUp",this.onNextUp,this),n.change("duration",this.onDuration,this),n.change("position",this.onElapsed,this),n.change("streamType",this.onStreamType,this),n.change("state",(function(e,t){"complete"===t&&this.toggle(!1)}),this),this.closeUi=new u.a(this.closeButton,{directSelect:!0}).on("click tap enter",(function(){this.nextUpSticky=!1,this.toggle(!1)}),this),this.tooltipUi=new u.a(this.tooltip).on("click tap",this.click,this)}},{key:"loadThumbnail",value:function(e){return this.nextUpImage=new Image,this.nextUpImage.onload=function(){this.nextUpImage.onload=null}.bind(this),this.nextUpImage.src=e,{backgroundImage:'url("'+e+'")'}}},{key:"click",value:function(){var e=this.feedShownId;this.reset(),this._api.next({feedShownId:e,reason:"interaction"})}},{key:"toggle",value:function(e,t){if(this.enabled&&(Object(l.v)(this.container,"jw-nextup-sticky",!!this.nextUpSticky),this.shown!==e)){this.shown=e,Object(l.v)(this.container,"jw-nextup-container-visible",e),Object(l.v)(this._playerElement,"jw-flag-nextup",e);var i=this._model.get("nextUp");e&&i?(this.feedShownId=Object(ot.b)(ot.a),this.trigger("nextShown",{mode:i.mode,ui:"nextup",itemsShown:[i],feedData:i.feedData,reason:t,feedShownId:this.feedShownId})):this.feedShownId=""}}},{key:"setNextUpItem",value:function(e){var t=this;setTimeout((function(){if(t.thumbnail=t.content.querySelector(".jw-nextup-thumbnail"),Object(l.v)(t.content,"jw-nextup-thumbnail-visible",!!e.image),e.image){var i=t.loadThumbnail(e.image);Object(ge.d)(t.thumbnail,i)}t.header=t.content.querySelector(".jw-nextup-header"),t.header.textContent=Object(l.e)(t.localization.nextUp).textContent,t.title=t.content.querySelector(".jw-nextup-title");var n=e.title;t.title.textContent=n?Object(l.e)(n).textContent:"";var o=e.duration;o&&(t.duration=t.content.querySelector(".jw-nextup-duration"),t.duration.textContent="number"==typeof o?Object(ve.timeFormat)(o):o)}),500)}},{key:"onNextUp",value:function(e,t){this.reset(),t||(t={showNextUp:!1}),this.enabled=!(!t.title&&!t.image),this.enabled&&(t.showNextUp||(this.nextUpSticky=!1,this.toggle(!1)),this.setNextUpItem(t))}},{key:"onDuration",value:function(e,t){if(t){var i=e.get("nextupoffset"),n=-10;i&&(n=Object(Mt.d)(i,t)),n<0&&(n+=t),Object(Mt.c)(i)&&t-5=this.offset;n&&void 0===i?(this.nextUpSticky=n,this.toggle(n,"time")):!n&&i&&this.reset()}}},{key:"onStreamType",value:function(e,t){"VOD"!==t&&(this.nextUpSticky=!1,this.toggle(!1))}},{key:"element",value:function(){return this.container}},{key:"addContent",value:function(e){this.content&&this.removeContent(),this.content=e,this.container.appendChild(e)}},{key:"removeContent",value:function(){this.content&&(this.container.removeChild(this.content),this.content=null)}},{key:"reset",value:function(){this.nextUpSticky=void 0,this.toggle(!1)}},{key:"destroy",value:function(){this.off(),this._model.off(null,null,this),this.closeUi&&this.closeUi.destroy(),this.tooltipUi&&this.tooltipUi.destroy()}}])&&_t(t.prototype,i),n&&_t(t,n),e}(),Et=function(e,t){var i=e.featured,n=e.showLogo,o=e.type;return e.logo=n?'':"",'
  • ').concat(At[o](e,t),"
  • ")},At={link:function(e){var t=e.link,i=e.title,n=e.logo;return'').concat(n).concat(i||"","")},info:function(e,t){return'")},share:function(e,t){return'")},keyboardShortcuts:function(e,t){return'")}},Pt=i(23),zt=i(6),Lt=i(13);function Bt(e,t){for(var i=0;iJW Player '.concat(e,""),a={items:[{type:"info"},{title:Object(Lt.e)(n)?"".concat(o," ").concat(n):"".concat(n," ").concat(o),type:"link",featured:!0,showLogo:!0,link:"https://jwplayer.com/learn-more?e=".concat(It[i])}]},r=t.get("provider"),s=a.items;if(r&&r.name.indexOf("flash")>=0){var l="Flash Version "+Object(zt.a)();s.push({title:l,type:"link",link:"http://www.adobe.com/software/flash/about/"})}return this.shortcutsTooltip&&s.splice(s.length-1,0,{type:"keyboardShortcuts"}),a}},{key:"rightClick",value:function(e){if(this.lazySetup(),this.mouseOverContext)return!1;this.hideMenu(),this.showMenu(e),this.addHideMenuHandlers()}},{key:"getOffset",value:function(e){var t=Object(l.c)(this.wrapperElement),i=e.pageX-t.left,n=e.pageY-t.top;return this.model.get("touchMode")&&(n-=100),{x:i,y:n}}},{key:"showMenu",value:function(e){var t=this,i=this.getOffset(e);return this.el.style.left=i.x+"px",this.el.style.top=i.y+"px",this.outCount=0,Object(l.a)(this.playerContainer,"jw-flag-rightclick-open"),Object(l.a)(this.el,"jw-open"),clearTimeout(this._menuTimeout),this._menuTimeout=setTimeout((function(){return t.hideMenu()}),3e3),!1}},{key:"hideMenu",value:function(e){e&&this.el&&this.el.contains(e.target)||(Object(l.o)(this.playerContainer,"jw-flag-rightclick-open"),Object(l.o)(this.el,"jw-open"))}},{key:"lazySetup",value:function(){var e,t,i,n,o=this,a=(e=this.buildArray(),t=this.model.get("localization"),i=e.items,n=(void 0===i?[]:i).map((function(e){return Et(e,t)})),'
    '+'
      '.concat(n.join(""),"
    ")+"
    ");if(this.el){if(this.html!==a){this.html=a;var r=Rt(a);Object(l.h)(this.el);for(var s=r.childNodes.length;s--;)this.el.appendChild(r.firstChild)}}else this.html=a,this.el=Rt(this.html),this.wrapperElement.appendChild(this.el),this.hideMenuHandler=function(e){return o.hideMenu(e)},this.overHandler=function(){o.mouseOverContext=!0},this.outHandler=function(e){o.mouseOverContext=!1,e.relatedTarget&&!o.el.contains(e.relatedTarget)&&++o.outCount>1&&o.hideMenu()},this.infoOverlayHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.infoOverlay.open()},this.shortcutsTooltipHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.shortcutsTooltip.open()}}},{key:"setup",value:function(e,t,i){this.wrapperElement=i,this.model=e,this.mouseOverContext=!1,this.playerContainer=t,this.ui=new u.a(i).on("longPress",this.rightClick,this)}},{key:"addHideMenuHandlers",value:function(){this.removeHideMenuHandlers(),this.wrapperElement.addEventListener("touchstart",this.hideMenuHandler),document.addEventListener("touchstart",this.hideMenuHandler),o.OS.mobile||(this.wrapperElement.addEventListener("click",this.hideMenuHandler),document.addEventListener("click",this.hideMenuHandler),this.el.addEventListener("mouseover",this.overHandler),this.el.addEventListener("mouseout",this.outHandler)),this.el.querySelector(".jw-info-overlay-item").addEventListener("click",this.infoOverlayHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").addEventListener("click",this.shortcutsTooltipHandler)}},{key:"removeHideMenuHandlers",value:function(){this.wrapperElement&&(this.wrapperElement.removeEventListener("click",this.hideMenuHandler),this.wrapperElement.removeEventListener("touchstart",this.hideMenuHandler)),this.el&&(this.el.querySelector(".jw-info-overlay-item").removeEventListener("click",this.infoOverlayHandler),this.el.removeEventListener("mouseover",this.overHandler),this.el.removeEventListener("mouseout",this.outHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").removeEventListener("click",this.shortcutsTooltipHandler)),document.removeEventListener("click",this.hideMenuHandler),document.removeEventListener("touchstart",this.hideMenuHandler)}},{key:"destroy",value:function(){clearTimeout(this._menuTimeout),this.removeHideMenuHandlers(),this.el&&(this.hideMenu(),this.hideMenuHandler=null,this.el=null),this.wrapperElement&&(this.wrapperElement.oncontextmenu=null,this.wrapperElement=null),this.model&&(this.model=null),this.ui&&(this.ui.destroy(),this.ui=null)}}])&&Bt(t.prototype,i),n&&Bt(t,n),e}(),Nt=function(e){return'")},Ht=function(e){return'"},Ft=function(e){return'"};function Dt(e){return(Dt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function qt(e,t){return!t||"object"!==Dt(t)&&"function"!=typeof t?function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(e):t}function Ut(e){return(Ut=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function Wt(e,t){return(Wt=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function Qt(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Yt(e,t){for(var i=0;i2&&void 0!==arguments[2]?arguments[2]:Nt;Qt(this,e),this.el=Object(l.e)(n(t)),this.ui=new u.a(this.el).on("click tap enter",i,this)}return Xt(e,[{key:"destroy",value:function(){this.ui.destroy()}}]),e}(),Zt=function(e){function t(e,i){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Ft;return Qt(this,t),qt(this,Ut(t).call(this,e,i,n))}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&Wt(e,t)}(t,e),Xt(t,[{key:"activate",value:function(){Object(l.v)(this.el,"jw-settings-item-active",!0),this.el.setAttribute("aria-checked","true"),this.active=!0}},{key:"deactivate",value:function(){Object(l.v)(this.el,"jw-settings-item-active",!1),this.el.setAttribute("aria-checked","false"),this.active=!1}}]),t}(Jt),Gt=function(e,t){return e?'':''},$t=function(e,t){var i=e.name,n={captions:"cc-off",audioTracks:"audio-tracks",quality:"quality-100",playbackRates:"playback-rate"}[i];if(n||e.icon){var o=p("jw-settings-".concat(i," jw-submenu-").concat(i),(function(t){e.open(t)}),i,[e.icon&&Object(l.e)(e.icon)||de(n)]),a=o.element();return a.setAttribute("role","menuitemradio"),a.setAttribute("aria-checked","false"),a.setAttribute("aria-label",t),"ontouchstart"in window||(o.tooltip=nt(a,i,t)),o}};function ei(e){return(ei="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function ti(e,t){for(var i=0;i3&&void 0!==arguments[3]?arguments[3]:Gt;return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),a=this,(o=!(r=ii(t).call(this))||"object"!==ei(r)&&"function"!=typeof r?oi(a):r).open=o.open.bind(oi(oi(o))),o.close=o.close.bind(oi(oi(o))),o.toggle=o.toggle.bind(oi(oi(o))),o.onDocumentClick=o.onDocumentClick.bind(oi(oi(o))),o.name=e,o.isSubmenu=!!i,o.el=Object(l.e)(s(o.isSubmenu,e)),o.topbar=o.el.querySelector(".jw-".concat(o.name,"-topbar")),o.buttonContainer=o.el.querySelector(".jw-".concat(o.name,"-topbar-buttons")),o.children={},o.openMenus=[],o.items=[],o.visible=!1,o.parentMenu=i,o.mainMenu=o.parentMenu?o.parentMenu.mainMenu:oi(oi(o)),o.categoryButton=null,o.closeButton=o.parentMenu&&o.parentMenu.closeButton||o.createCloseButton(n),o.isSubmenu?(o.categoryButton=o.parentMenu.categoryButton||o.createCategoryButton(n),o.parentMenu.parentMenu&&!o.mainMenu.backButton&&(o.mainMenu.backButton=o.createBackButton(n)),o.itemsContainer=o.createItemsContainer(),o.parentMenu.appendMenu(oi(oi(o)))):o.ui=ri(oi(oi(o))),o}var i,n,o;return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&ni(e,t)}(t,e),i=t,(n=[{key:"createItemsContainer",value:function(){var e,t,i=this,n=this.el.querySelector(".jw-settings-submenu-items"),o=new u.a(n),a=this.categoryButton&&this.categoryButton.element()||this.parentMenu.categoryButton&&this.parentMenu.categoryButton.element()||this.mainMenu.buttonContainer.firstChild;return this.parentMenu.isSubmenu&&(e=this.mainMenu.closeButton.element(),t=this.mainMenu.backButton.element()),o.on("keydown",(function(o){if(o.target.parentNode===n){var r=function(e,t){e?e.focus():void 0!==t&&n.childNodes[t].focus()},s=o.sourceEvent,c=s.target,u=n.firstChild===c,d=n.lastChild===c,p=i.topbar,w=e||Object(l.k)(a),h=t||Object(l.n)(a),f=Object(l.k)(s.target),g=Object(l.n)(s.target),j=s.key.replace(/(Arrow|ape)/,"");switch(j){case"Tab":r(s.shiftKey?h:w);break;case"Left":r(h||Object(l.n)(document.getElementsByClassName("jw-icon-settings")[0]));break;case"Up":p&&u?r(p.firstChild):r(g,n.childNodes.length-1);break;case"Right":r(w);break;case"Down":p&&d?r(p.firstChild):r(f,0)}s.preventDefault(),"Esc"!==j&&s.stopPropagation()}})),o}},{key:"createCloseButton",value:function(e){var t=p("jw-settings-close",this.close,e.close,[de("close")]);return this.topbar.appendChild(t.element()),t.show(),t.ui.on("keydown",(function(e){var t=e.sourceEvent,i=t.key.replace(/(Arrow|ape)/,"");("Enter"===i||"Right"===i||"Tab"===i&&!t.shiftKey)&&this.close(e)}),this),this.buttonContainer.appendChild(t.element()),t}},{key:"createCategoryButton",value:function(e){var t=e[{captions:"cc",audioTracks:"audioTracks",quality:"hd",playbackRates:"playbackRates"}[this.name]];"sharing"===this.name&&(t=e.sharing.heading);var i=$t(this,t);return i.element().setAttribute("name",this.name),i}},{key:"createBackButton",value:function(e){var t=p("jw-settings-back",(function(e){Kt&&Kt.open(e)}),e.close,[de("arrow-left")]);return Object(l.m)(this.mainMenu.topbar,t.element()),t}},{key:"createTopbar",value:function(){var e=Object(l.e)('
    ');return Object(l.m)(this.el,e),e}},{key:"createItems",value:function(e,t){var i=this,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Zt,a=this.name,r=e.map((function(e,r){var s,l;switch(a){case"quality":s="Auto"===e.label&&0===r?"".concat(n.defaultText,' '):e.label;break;case"captions":s="Off"!==e.label&&"off"!==e.id||0!==r?e.label:n.defaultText;break;case"playbackRates":l=e,s=Object(Lt.e)(n.tooltipText)?"x"+e:e+"x";break;case"audioTracks":s=e.name}s||(s=e,"object"===ei(e)&&(s.options=n));var c=new o(s,function(e){c.active||(t(l||r),c.deactivate&&(i.items.filter((function(e){return!0===e.active})).forEach((function(e){e.deactivate()})),Kt?Kt.open(e):i.mainMenu.close(e)),c.activate&&c.activate())}.bind(i));return c}));return r}},{key:"setMenuItems",value:function(e,t){var i=this;e?(this.items=[],Object(l.h)(this.itemsContainer.el),e.forEach((function(e){i.items.push(e),i.itemsContainer.el.appendChild(e.el)})),t>-1&&e[t].activate(),this.categoryButton.show()):this.removeMenu()}},{key:"appendMenu",value:function(e){if(e){var t=e.el,i=e.name,n=e.categoryButton;if(this.children[i]=e,n){var o=this.mainMenu.buttonContainer,a=o.querySelector(".jw-settings-sharing"),r="quality"===i?o.firstChild:a||this.closeButton.element();o.insertBefore(n.element(),r)}this.mainMenu.el.appendChild(t)}}},{key:"removeMenu",value:function(e){if(!e)return this.parentMenu.removeMenu(this.name);var t=this.children[e];t&&(delete this.children[e],t.destroy())}},{key:"open",value:function(e){if(!this.visible||this.openMenus){var t;if(Kt=null,this.isSubmenu){var i=this.mainMenu,n=this.parentMenu,o=this.categoryButton;if(n.openMenus.length&&n.closeChildren(),o&&o.element().setAttribute("aria-checked","true"),n.isSubmenu){n.el.classList.remove("jw-settings-submenu-active"),i.topbar.classList.add("jw-nested-menu-open");var a=i.topbar.querySelector(".jw-settings-topbar-text");a.setAttribute("name",this.name),a.innerText=this.title||this.name,i.backButton.show(),Kt=this.parentMenu,t=this.topbar?this.topbar.firstChild:e&&"enter"===e.type?this.items[0].el:a}else i.topbar.classList.remove("jw-nested-menu-open"),i.backButton&&i.backButton.hide();this.el.classList.add("jw-settings-submenu-active"),n.openMenus.push(this.name),i.visible||(i.open(e),this.items&&e&&"enter"===e.type?t=this.topbar?this.topbar.firstChild.focus():this.items[0].el:o.tooltip&&(o.tooltip.suppress=!0,t=o.element())),this.openMenus.length&&this.closeChildren(),t&&t.focus(),this.el.scrollTop=0}else this.el.parentNode.classList.add("jw-settings-open"),this.trigger("menuVisibility",{visible:!0,evt:e}),document.addEventListener("click",this.onDocumentClick);this.visible=!0,this.el.setAttribute("aria-expanded","true")}}},{key:"close",value:function(e){var t=this;this.visible&&(this.visible=!1,this.el.setAttribute("aria-expanded","false"),this.isSubmenu?(this.el.classList.remove("jw-settings-submenu-active"),this.categoryButton.element().setAttribute("aria-checked","false"),this.parentMenu.openMenus=this.parentMenu.openMenus.filter((function(e){return e!==t.name})),!this.mainMenu.openMenus.length&&this.mainMenu.visible&&this.mainMenu.close(e)):(this.el.parentNode.classList.remove("jw-settings-open"),this.trigger("menuVisibility",{visible:!1,evt:e}),document.removeEventListener("click",this.onDocumentClick)),this.openMenus.length&&this.closeChildren())}},{key:"closeChildren",value:function(){var e=this;this.openMenus.forEach((function(t){var i=e.children[t];i&&i.close()}))}},{key:"toggle",value:function(e){this.visible?this.close(e):this.open(e)}},{key:"onDocumentClick",value:function(e){/jw-(settings|video|nextup-close|sharing-link|share-item)/.test(e.target.className)||this.close()}},{key:"destroy",value:function(){var e=this;if(document.removeEventListener("click",this.onDocumentClick),Object.keys(this.children).map((function(t){e.children[t].destroy()})),this.isSubmenu){this.parentMenu.name===this.mainMenu.name&&this.categoryButton&&(this.parentMenu.buttonContainer.removeChild(this.categoryButton.element()),this.categoryButton.ui.destroy()),this.itemsContainer&&this.itemsContainer.destroy();var t=this.parentMenu.openMenus,i=t.indexOf(this.name);t.length&&i>-1&&this.openMenus.splice(i,1),delete this.parentMenu}else this.ui.destroy();this.visible=!1,this.el.parentNode&&this.el.parentNode.removeChild(this.el)}},{key:"defaultChild",get:function(){var e=this.children,t=e.quality,i=e.captions,n=e.audioTracks,o=e.sharing,a=e.playbackRates;return t||i||n||o||a}}])&&ti(i.prototype,n),o&&ti(i,o),t}(r.a),ri=function(e){var t=e.closeButton,i=e.el;return new u.a(i).on("keydown",(function(i){var n=i.sourceEvent,o=i.target,a=Object(l.k)(o),r=Object(l.n)(o),s=n.key.replace(/(Arrow|ape)/,""),c=function(t){r?t||r.focus():e.close(i)};switch(s){case"Esc":e.close(i);break;case"Left":c();break;case"Right":a&&t.element()&&o!==t.element()&&a.focus();break;case"Tab":n.shiftKey&&c(!0);break;case"Up":case"Down":!function(){var t=e.children[o.getAttribute("name")];if(!t&&Kt&&(t=Kt.children[Kt.openMenus]),t)return t.open(i),void(t.topbar?t.topbar.firstChild.focus():t.items&&t.items.length&&t.items[0].el.focus());if(i.target.parentNode.classList.contains("jw-submenu-topbar")){var n=i.target.parentNode.parentNode.querySelector(".jw-settings-submenu-items");("Down"===s?n.childNodes[0]:n.childNodes[n.childNodes.length-1]).focus()}}()}if(n.stopPropagation(),/13|32|37|38|39|40/.test(n.keyCode))return n.preventDefault(),!1}))},si=i(59),li=function(e){return wi[e]},ci=function(e){for(var t,i=Object.keys(wi),n=0;n1;i.elements.settingsButton.toggle(c)};t.change("levels",(function(e,t){r(t)}),o);var s=function(e,i,n){var o=t.get("levels");if(o&&"Auto"===o[0].label&&i&&i.items.length){var a=i.items[0].el.querySelector(".jw-auto-label"),r=o[e.index]||{label:""};a.textContent=n?"":r.label}};t.on("change:visualQuality",(function(e,i){var n=o.children.quality;i&&n&&s(i.level,n,t.get("currentLevel"))})),t.on("change:currentLevel",(function(e,i){var n=o.children.quality,a=t.get("visualQuality");a&&n&&s(a.level,n,i)}),o),t.change("captionsList",(function(i,r){var s={defaultText:n.off},l=t.get("captionsIndex");a("captions",r,(function(t){return e.setCurrentCaptions(t)}),l,s);var c=o.children.captions;if(c&&!c.children.captionsSettings){c.topbar=c.topbar||c.createTopbar();var u=new ai("captionsSettings",c,n);u.title="Subtitle Settings";var d=new Jt("Settings",u.open);c.topbar.appendChild(d.el);var p=new Zt("Reset",(function(){t.set("captions",si.a),f()}));p.el.classList.add("jw-settings-reset");var h=t.get("captions"),f=function(){var e=[];pi.forEach((function(i){h&&h[i.propertyName]&&(i.defaultVal=i.getOption(h[i.propertyName]));var o=new ai(i.name,u,n),a=new Jt({label:i.name,value:i.defaultVal},o.open,Ht),r=o.createItems(i.options,(function(e){var n=a.el.querySelector(".jw-settings-content-item-value");!function(e,i){var n=t.get("captions"),o=e.propertyName,a=e.options&&e.options[i],r=e.getTypedValue(a),s=Object(w.g)({},n);s[o]=r,t.set("captions",s)}(i,e),n.innerText=i.options[e]}),null);o.setMenuItems(r,i.options.indexOf(i.defaultVal)||0),e.push(a)})),e.push(p),u.setMenuItems(e)};f()}}));var l=function(e,t){e&&t>-1&&e.items[t].activate()};t.change("captionsIndex",(function(e,t){var n=o.children.captions;n&&l(n,t),i.toggleCaptionsButtonState(!!t)}),o);var c=function(i){if(t.get("supportsPlaybackRate")&&"LIVE"!==t.get("streamType")&&t.get("playbackRateControls")){var r=i.indexOf(t.get("playbackRate")),s={tooltipText:n.playbackRates};a("playbackRates",i,(function(t){return e.setPlaybackRate(t)}),r,s)}else o.children.playbackRates&&o.removeMenu("playbackRates")};t.on("change:playbackRates",(function(e,t){c(t)}),o);var u=function(i){a("audioTracks",i,(function(t){return e.setCurrentAudioTrack(t)}),t.get("currentAudioTrack"))};return t.on("change:audioTracks",(function(e,t){u(t)}),o),t.on("change:playbackRate",(function(e,i){var n=t.get("playbackRates"),a=-1;n&&(a=n.indexOf(i)),l(o.children.playbackRates,a)}),o),t.on("change:currentAudioTrack",(function(e,t){o.children.audioTracks.items[t].activate()}),o),t.on("change:playlistItem",(function(){o.removeMenu("captions"),i.elements.captionsButton.hide(),o.visible&&o.close()}),o),t.on("change:playbackRateControls",(function(){c(t.get("playbackRates"))})),t.on("change:castActive",(function(e,i,n){i!==n&&(i?(o.removeMenu("audioTracks"),o.removeMenu("quality"),o.removeMenu("playbackRates")):(u(t.get("audioTracks")),r(t.get("levels")),c(t.get("playbackRates"))))}),o),t.on("change:streamType",(function(){c(t.get("playbackRates"))}),o),o},fi=i(58),gi=i(35),ji=i(12),bi=function(e,t,i,n){var o=Object(l.e)('
    '),r=!1,s=null,c=!1,u=function(e){/jw-info/.test(e.target.className)||w.close()},d=function(){var n,a,s,c,u,d=p("jw-info-close",(function(){w.close()}),t.get("localization").close,[de("close")]);d.show(),Object(l.m)(o,d.element()),a=o.querySelector(".jw-info-title"),s=o.querySelector(".jw-info-duration"),c=o.querySelector(".jw-info-description"),u=o.querySelector(".jw-info-clientid"),t.change("playlistItem",(function(e,t){var i=t.description,n=t.title;Object(l.q)(c,i||""),Object(l.q)(a,n||"Unknown Title")})),t.change("duration",(function(e,i){var n="";switch(t.get("streamType")){case"LIVE":n="Live";break;case"DVR":n="DVR";break;default:i&&(n=Object(ve.timeFormat)(i))}s.textContent=n}),w),u.textContent=(n=i.getPlugin("jwpsrv"))&&"function"==typeof n.doNotTrackUser&&n.doNotTrackUser()?"":"Client ID: ".concat(function(){try{return window.localStorage.jwplayerLocalId}catch(e){return"none"}}()),e.appendChild(o),r=!0};var w={open:function(){r||d(),document.addEventListener("click",u),c=!0;var e=t.get("state");e===a.pb&&i.pause("infoOverlayInteraction"),s=e,n(!0)},close:function(){document.removeEventListener("click",u),c=!1,t.get("state")===a.ob&&s===a.pb&&i.play("infoOverlayInteraction"),s=null,n(!1)},destroy:function(){this.close(),t.off(null,null,this)}};return Object.defineProperties(w,{visible:{enumerable:!0,get:function(){return c}}}),w};var mi=function(e,t,i){var n,o=!1,r=null,s=i.get("localization").shortcuts,c=Object(l.e)(function(e,t){var i=e.map((function(e){return'
    '+''.concat(e.description,"")+''.concat(e.key,"")+"
    "})).join("");return'
    ')+'Press shift question mark to access a list of keyboard shortcuts
    '+''.concat(t,"")+'
    '+"".concat(i)+"
    "}(function(e){var t=e.playPause,i=e.volumeToggle,n=e.fullscreenToggle,o=e.seekPercent,a=e.increaseVolume,r=e.decreaseVolume,s=e.seekForward,l=e.seekBackward;return[{key:e.spacebar,description:t},{key:"↑",description:a},{key:"↓",description:r},{key:"→",description:s},{key:"←",description:l},{key:"c",description:e.captionsToggle},{key:"f",description:n},{key:"m",description:i},{key:"0-9",description:o}]}(s),s.keyboardShortcuts)),d={reason:"settingsInteraction"},w=new u.a(c.querySelector(".jw-switch")),h=function(){w.el.setAttribute("aria-checked",i.get("enableShortcuts")),Object(l.a)(c,"jw-open"),r=i.get("state"),c.querySelector(".jw-shortcuts-close").focus(),document.addEventListener("click",g),o=!0,t.pause(d)},f=function(){Object(l.o)(c,"jw-open"),document.removeEventListener("click",g),e.focus(),o=!1,r===a.pb&&t.play(d)},g=function(e){/jw-shortcuts|jw-switch/.test(e.target.className)||f()},j=function(e){var t=e.currentTarget,n="true"!==t.getAttribute("aria-checked");t.setAttribute("aria-checked",n),i.set("enableShortcuts",n)};return n=p("jw-shortcuts-close",f,i.get("localization").close,[de("close")]),Object(l.m)(c,n.element()),n.show(),e.appendChild(c),w.on("click tap enter",j),{el:c,open:h,close:f,destroy:function(){f(),w.destroy()},toggleVisibility:function(){o?f():h()}}},vi=function(e){return'
    ')+"
    "};function yi(e){return(yi="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function ki(e,t){for(var i=0;i16?n.activeTimeout=setTimeout(n.userInactiveTimeout,e):n.playerContainer.querySelector(".jw-tab-focus")?n.resetActiveTimeout():n.userInactive()},n}var i,n,r;return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&Ai(e,t)}(t,e),i=t,(n=[{key:"resetActiveTimeout",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.inactiveTime=0}},{key:"enable",value:function(e,t){var i=this,n=this.context.createElement("div");n.className="jw-controls jw-reset",this.div=n;var r=this.context.createElement("div");r.className="jw-controls-backdrop jw-reset",this.backdrop=r,this.logo=this.playerContainer.querySelector(".jw-logo");var c=t.get("touchMode"),u=function(){(t.get("isFloating")?i.wrapperElement:i.playerContainer).focus()};if(!this.displayContainer){var d=new Ot(t,e);d.buttons.display.on("click tap enter",(function(){i.trigger(a.p),i.userActive(1e3),e.playToggle(Li()),u()})),this.div.appendChild(d.element()),this.displayContainer=d}this.infoOverlay=new bi(n,t,e,(function(e){Object(l.v)(i.div,"jw-info-open",e),e&&i.div.querySelector(".jw-info-close").focus()})),o.OS.mobile||(this.shortcutsTooltip=new mi(this.wrapperElement,e,t)),this.rightClickMenu=new Vt(this.infoOverlay,this.shortcutsTooltip),c?(Object(l.a)(this.playerContainer,"jw-flag-touch"),this.rightClickMenu.setup(t,this.playerContainer,this.wrapperElement)):t.change("flashBlocked",(function(e,t){t?i.rightClickMenu.destroy():i.rightClickMenu.setup(e,i.playerContainer,i.wrapperElement)}),this);var w=t.get("floating");if(w){var h=new Ci(n,t.get("localization").close);h.on(a.sb,(function(){return i.trigger("dismissFloating",{doNotForward:!0})})),!1!==w.dismissible&&Object(l.a)(this.playerContainer,"jw-floating-dismissible")}var f=this.controlbar=new dt(e,t,this.playerContainer.querySelector(".jw-hidden-accessibility"));if(f.on(a.sb,(function(){return i.userActive()})),f.on("nextShown",(function(e){this.trigger("nextShown",e)}),this),f.on("adjustVolume",k,this),t.get("nextUpDisplay")&&!f.nextUpToolTip){var g=new St(t,e,this.playerContainer);g.on("all",this.trigger,this),g.setup(this.context),f.nextUpToolTip=g,this.div.appendChild(g.element())}this.div.appendChild(f.element());var j=t.get("localization"),b=this.settingsMenu=hi(e,t.player,this.controlbar,j),m=null;this.controlbar.on("menuVisibility",(function(n){var o=n.visible,r=n.evt,s=t.get("state"),l={reason:"settingsInteraction"},c=i.controlbar.elements.settingsButton,d="keydown"===(r&&r.sourceEvent||r||{}).type,p=o||d?0:Pi;i.userActive(p),m=s,Object(fi.a)(t.get("containerWidth"))<2&&(o&&s===a.pb?e.pause(l):o||s!==a.ob||m!==a.pb||e.play(l)),!o&&d&&c?c.element().focus():r&&u()})),b.on("menuVisibility",(function(e){return i.controlbar.trigger("menuVisibility",e)})),this.controlbar.on("settingsInteraction",(function(e,t,i){if(t)return b.defaultChild.toggle(i);b.children[e].toggle(i)})),o.OS.mobile?this.div.appendChild(b.el):(this.playerContainer.setAttribute("aria-describedby","jw-shortcuts-tooltip-explanation"),this.div.insertBefore(b.el,f.element()));var v=function(t){if(t.get("autostartMuted")){var n=function(){return i.unmuteAutoplay(e,t)},a=function(e,t){t||n()};o.OS.mobile&&(i.mute=p("jw-autostart-mute jw-off",n,t.get("localization").unmute,[de("volume-0")]),i.mute.show(),i.div.appendChild(i.mute.element())),f.renderVolume(!0,t.get("volume")),Object(l.a)(i.playerContainer,"jw-flag-autostart"),t.on("change:autostartFailed",n,i),t.on("change:autostartMuted change:mute",a,i),i.muteChangeCallback=a,i.unmuteCallback=n}};function y(i){var n=0,o=t.get("duration"),a=t.get("position");if("DVR"===t.get("streamType")){var r=t.get("dvrSeekLimit");n=o,o=Math.max(a,-r)}var l=Object(s.a)(a+i,n,o);e.seek(l,Li())}function k(i){var n=Object(s.a)(t.get("volume")+i,0,100);e.setVolume(n)}t.once("change:autostartMuted",v),v(t);var x=function(n){if(n.ctrlKey||n.metaKey)return!0;var o=!i.settingsMenu.visible,a=!0===t.get("enableShortcuts"),r=i.instreamState;if(a||-1!==zi.indexOf(n.keyCode)){switch(n.keyCode){case 27:if(t.get("fullscreen"))e.setFullscreen(!1),i.playerContainer.blur(),i.userInactive();else{var s=e.getPlugin("related");s&&s.close({type:"escape"})}i.rightClickMenu.el&&i.rightClickMenu.hideMenuHandler(),i.infoOverlay.visible&&i.infoOverlay.close(),i.shortcutsTooltip&&i.shortcutsTooltip.close();break;case 13:case 32:if(document.activeElement.classList.contains("jw-switch")&&13===n.keyCode)return!0;e.playToggle(Li());break;case 37:!r&&o&&y(-5);break;case 39:!r&&o&&y(5);break;case 38:o&&k(10);break;case 40:o&&k(-10);break;case 67:var l=e.getCaptionsList().length;if(l){var c=(e.getCurrentCaptions()+1)%l;e.setCurrentCaptions(c)}break;case 77:e.setMute();break;case 70:e.setFullscreen();break;case 191:i.shortcutsTooltip&&i.shortcutsTooltip.toggleVisibility();break;default:if(n.keyCode>=48&&n.keyCode<=59){var u=(n.keyCode-48)/10*t.get("duration");e.seek(u,Li())}}return/13|32|37|38|39|40/.test(n.keyCode)?(n.preventDefault(),!1):void 0}};this.playerContainer.addEventListener("keydown",x),this.keydownCallback=x;var T=function(e){switch(e.keyCode){case 9:var t=i.playerContainer.contains(e.target)?0:Pi;i.userActive(t);break;case 32:e.preventDefault()}};this.playerContainer.addEventListener("keyup",T),this.keyupCallback=T;var O=function(e){var t=e.relatedTarget||document.querySelector(":focus");t&&(i.playerContainer.contains(t)||i.userInactive())};this.playerContainer.addEventListener("blur",O,!0),this.blurCallback=O;var C=function e(){"jw-shortcuts-tooltip-explanation"===i.playerContainer.getAttribute("aria-describedby")&&i.playerContainer.removeAttribute("aria-describedby"),i.playerContainer.removeEventListener("blur",e,!0)};this.shortcutsTooltip&&(this.playerContainer.addEventListener("blur",C,!0),this.onRemoveShortcutsDescription=C),this.userActive(),this.addControls(),this.addBackdrop(),t.set("controlsEnabled",!0)}},{key:"addControls",value:function(){this.wrapperElement.appendChild(this.div)}},{key:"disable",value:function(e){var t=this.nextUpToolTip,i=this.settingsMenu,n=this.infoOverlay,o=this.controlbar,a=this.rightClickMenu,r=this.shortcutsTooltip,s=this.playerContainer,c=this.div;clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.off(),e.off(null,null,this),e.set("controlsEnabled",!1),c.parentNode&&(Object(l.o)(s,"jw-flag-touch"),c.parentNode.removeChild(c)),o&&o.destroy(),a&&a.destroy(),this.keydownCallback&&s.removeEventListener("keydown",this.keydownCallback),this.keyupCallback&&s.removeEventListener("keyup",this.keyupCallback),this.blurCallback&&s.removeEventListener("blur",this.blurCallback),this.onRemoveShortcutsDescription&&s.removeEventListener("blur",this.onRemoveShortcutsDescription),this.displayContainer&&this.displayContainer.destroy(),t&&t.destroy(),i&&i.destroy(),n&&n.destroy(),r&&r.destroy(),this.removeBackdrop()}},{key:"controlbarHeight",value:function(){return this.dimensions.cbHeight||(this.dimensions.cbHeight=this.controlbar.element().clientHeight),this.dimensions.cbHeight}},{key:"element",value:function(){return this.div}},{key:"resize",value:function(){this.dimensions={}}},{key:"unmuteAutoplay",value:function(e,t){var i=!t.get("autostartFailed"),n=t.get("mute");i?n=!1:t.set("playOnViewable",!1),this.muteChangeCallback&&(t.off("change:autostartMuted change:mute",this.muteChangeCallback),this.muteChangeCallback=null),this.unmuteCallback&&(t.off("change:autostartFailed",this.unmuteCallback),this.unmuteCallback=null),t.set("autostartFailed",void 0),t.set("autostartMuted",void 0),e.setMute(n),this.controlbar.renderVolume(n,t.get("volume")),this.mute&&this.mute.hide(),Object(l.o)(this.playerContainer,"jw-flag-autostart"),this.userActive()}},{key:"mouseMove",value:function(e){var t=this.controlbar.element().contains(e.target),i=this.controlbar.nextUpToolTip&&this.controlbar.nextUpToolTip.element().contains(e.target),n=this.logo&&this.logo.contains(e.target),o=t||i||n?0:Pi;this.userActive(o)}},{key:"userActive",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Pi;e>0?(this.inactiveTime=Object(c.a)()+e,-1===this.activeTimeout&&(this.activeTimeout=setTimeout(this.userInactiveTimeout,e))):this.resetActiveTimeout(),this.showing||(Object(l.o)(this.playerContainer,"jw-flag-user-inactive"),this.showing=!0,this.trigger("userActive"))}},{key:"userInactive",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.settingsMenu.visible||(this.inactiveTime=0,this.showing=!1,Object(l.a)(this.playerContainer,"jw-flag-user-inactive"),this.trigger("userInactive"))}},{key:"addBackdrop",value:function(){var e=this.instreamState?this.div:this.wrapperElement.querySelector(".jw-captions");this.wrapperElement.insertBefore(this.backdrop,e)}},{key:"removeBackdrop",value:function(){var e=this.backdrop.parentNode;e&&e.removeChild(this.backdrop)}},{key:"setupInstream",value:function(){this.instreamState=!0,this.userActive(),this.addBackdrop(),this.settingsMenu&&this.settingsMenu.close(),Object(l.o)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","-1")}},{key:"destroyInstream",value:function(e){this.instreamState=null,this.addBackdrop(),e.get("autostartMuted")&&Object(l.a)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","0")}}])&&_i(i.prototype,n),r&&_i(i,r),t}(r.a)},function(e,t,i){"use strict";i.r(t);var n=i(0),o=i(12),a=i(50),r=i(36);var s=i(44),l=i(51),c=i(26),u=i(25),d=i(3),p=i(46),w=i(2),h=i(7),f=i(34);function g(e){var t=!1;return{async:function(){var i=this,n=arguments;return Promise.resolve().then((function(){if(!t)return e.apply(i,n)}))},cancel:function(){t=!0},cancelled:function(){return t}}}var j=i(1);function b(e){return function(t,i){var o=e.mediaModel,a=Object(n.g)({},i,{type:t});switch(t){case d.T:if(o.get(d.T)===i.mediaType)return;o.set(d.T,i.mediaType);break;case d.U:return void o.set(d.U,Object(n.g)({},i));case d.M:if(i[t]===e.model.getMute())return;break;case d.bb:i.newstate===d.mb&&(e.thenPlayPromise.cancel(),o.srcReset());var r=o.attributes.mediaState;o.attributes.mediaState=i.newstate,o.trigger("change:mediaState",o,i.newstate,r);break;case d.F:return e.beforeComplete=!0,e.trigger(d.B,a),void(e.attached&&!e.background&&e._playbackComplete());case d.G:o.get("setup")?(e.thenPlayPromise.cancel(),o.srcReset()):(t=d.tb,a.code+=1e5);break;case d.K:a.metadataType||(a.metadataType="unknown");var s=i.duration;Object(n.u)(s)&&(o.set("seekRange",i.seekRange),o.set("duration",s));break;case d.D:o.set("buffer",i.bufferPercent);case d.S:o.set("seekRange",i.seekRange),o.set("position",i.position),o.set("currentTime",i.currentTime);var l=i.duration;Object(n.u)(l)&&o.set("duration",l),t===d.S&&Object(n.r)(e.item.starttime)&&delete e.item.starttime;break;case d.R:var c=e.mediaElement;c&&c.paused&&o.set("mediaState","paused");break;case d.I:o.set(d.I,i.levels);case d.J:var u=i.currentQuality,p=i.levels;u>-1&&p.length>1&&o.set("currentLevel",parseInt(u));break;case d.f:o.set(d.f,i.tracks);case d.g:var w=i.currentTrack,h=i.tracks;w>-1&&h.length>0&&w=Math.max(l,p.a)&&(e.preloadNextItem(),v=!0)}function P(e){var t={};b.tag&&(t.tag=b.tag),this.trigger(d.F,t),z.call(this,e)}function z(e){g={},a&&f+10?e:null,h&&h.model.set("skipOffset",s)}};Object(n.g)(le.prototype,h.a);var ce=le,ue=i(66),de=i(63),pe=function(e){var t=this,i=[],n={},o=0,a=0;function r(e){if(e.data=e.data||[],e.name=e.label||e.name||e.language,e._id=Object(de.a)(e,i.length),!e.name){var t=Object(de.b)(e,o);e.name=t.label,o=t.unknownCount}n[e._id]=e,i.push(e)}function s(){for(var e=[{id:"off",label:"Off"}],t=0;t')+'
    '},fe=i(35),ge=44,je=function(e){var t=e.get("height");if(e.get("aspectratio"))return!1;if("string"==typeof t&&t.indexOf("%")>-1)return!1;var i=1*t||NaN;return!!(i=isNaN(i)?e.get("containerHeight"):i)&&(i&&i<=ge)},be=i(54);function me(e,t){if(e.get("fullscreen"))return 1;if(!e.get("activeTab"))return 0;if(e.get("isFloating"))return 1;var i=e.get("intersectionRatio");return void 0===i&&(i=function(e){var t=document.documentElement,i=document.body,n={top:0,left:0,right:t.clientWidth||i.clientWidth,width:t.clientWidth||i.clientWidth,bottom:t.clientHeight||i.clientHeight,height:t.clientHeight||i.clientHeight};if(!i.contains(e))return 0;if("none"===window.getComputedStyle(e).display)return 0;var o=ve(e);if(!o)return 0;var a=o,r=e.parentNode,s=!1;for(;!s;){var l=null;if(r===i||r===t||1!==r.nodeType?(s=!0,l=n):"visible"!==window.getComputedStyle(r).overflow&&(l=ve(r)),l&&(c=l,u=a,d=void 0,p=void 0,w=void 0,h=void 0,f=void 0,g=void 0,d=Math.max(c.top,u.top),p=Math.min(c.bottom,u.bottom),w=Math.max(c.left,u.left),h=Math.min(c.right,u.right),g=p-d,!(a=(f=h-w)>=0&&g>=0&&{top:d,bottom:p,left:w,right:h,width:f,height:g})))return 0;r=r.parentNode}var c,u,d,p,w,h,f,g;var j=o.width*o.height,b=a.width*a.height;return j?b/j:0}(t),window.top!==window.self&&i)?0:i}function ve(e){try{return e.getBoundingClientRect()}catch(e){}}var ye=i(49),ke=i(42),xe=i(58),Te=i(10);var Oe=i(32),Ce=i(5),Me=i(6),_e=["fullscreenchange","webkitfullscreenchange","mozfullscreenchange","MSFullscreenChange"],Se=function(e,t,i){for(var n=e.requestFullscreen||e.webkitRequestFullscreen||e.webkitRequestFullScreen||e.mozRequestFullScreen||e.msRequestFullscreen,o=t.exitFullscreen||t.webkitExitFullscreen||t.webkitCancelFullScreen||t.mozCancelFullScreen||t.msExitFullscreen,a=!(!n||!o),r=_e.length;r--;)t.addEventListener(_e[r],i);return{events:_e,supportsDomFullscreen:function(){return a},requestFullscreen:function(){n.call(e,{navigationUI:"hide"})},exitFullscreen:function(){null!==this.fullscreenElement()&&o.apply(t)},fullscreenElement:function(){var e=t.fullscreenElement,i=t.webkitCurrentFullScreenElement,n=t.mozFullScreenElement,o=t.msFullscreenElement;return null===e?e:e||i||n||o},destroy:function(){for(var e=_e.length;e--;)t.removeEventListener(_e[e],i)}}},Ee=i(40);function Ae(e,t){for(var i=0;i')},Be={linktarget:"_blank",margin:8,hide:!1,position:"top-right"};function Ie(e){var t,i;Object(n.g)(this,h.a);var o=new Image;this.setup=function(){(i=Object(n.g)({},Be,e.get("logo"))).position=i.position||Be.position,i.hide="true"===i.hide.toString(),i.file&&"control-bar"!==i.position&&(t||(t=Object(Ce.e)(Le(i.position,i.hide))),e.set("logo",i),o.onload=function(){var n=this.height,o=this.width,a={backgroundImage:'url("'+this.src+'")'};if(i.margin!==Be.margin){var r=/(\w+)-(\w+)/.exec(i.position);3===r.length&&(a["margin-"+r[1]]=i.margin,a["margin-"+r[2]]=i.margin)}var s=.15*e.get("containerHeight"),l=.15*e.get("containerWidth");if(n>s||o>l){var c=o/n;l/s>c?(n=s,o=s*c):(o=l,n=l/c)}a.width=Math.round(o),a.height=Math.round(n),Object(Te.d)(t,a),e.set("logoWidth",a.width)},o.src=i.file,i.link&&(t.setAttribute("tabindex","0"),t.setAttribute("aria-label",e.get("localization").logo)),this.ui=new Ee.a(t).on("click tap enter",(function(e){e&&e.stopPropagation&&e.stopPropagation(),this.trigger(d.A,{link:i.link,linktarget:i.linktarget})}),this))},this.setContainer=function(e){t&&e.appendChild(t)},this.element=function(){return t},this.position=function(){return i.position},this.destroy=function(){o.onload=null,this.ui&&this.ui.destroy()}}var Re=function(e){this.model=e,this.image=null};Object(n.g)(Re.prototype,{setup:function(e){this.el=e},setImage:function(e){var t=this.image;t&&(t.onload=null),this.image=null;var i="";"string"==typeof e&&(i='url("'+e+'")',(t=this.image=new Image).src=e),Object(Te.d)(this.el,{backgroundImage:i})},resize:function(e,t,i){if("uniform"===i){if(e&&(this.playerAspectRatio=e/t),!this.playerAspectRatio||!this.image||"complete"!==(s=this.model.get("state"))&&"idle"!==s&&"error"!==s&&"buffering"!==s)return;var n=this.image,o=null;if(n){if(0===n.width){var a=this;return void(n.onload=function(){a.resize(e,t,i)})}var r=n.width/n.height;Math.abs(this.playerAspectRatio-r)<.09&&(o="cover")}Object(Te.d)(this.el,{backgroundSize:o})}var s},element:function(){return this.el}});var Ve=Re,Ne=function(e){this.model=e.player};Object(n.g)(Ne.prototype,{hide:function(){Object(Te.d)(this.el,{display:"none"})},show:function(){Object(Te.d)(this.el,{display:""})},setup:function(e){this.el=e;var t=this.el.getElementsByTagName("div");this.title=t[0],this.description=t[1],this.model.on("change:logoWidth",this.update,this),this.model.change("playlistItem",this.playlistItem,this)},update:function(e){var t={},i=e.get("logo");if(i){var n=1*(""+i.margin).replace("px",""),o=e.get("logoWidth")+(isNaN(n)?0:n+10);"top-left"===i.position?t.paddingLeft=o:"top-right"===i.position&&(t.paddingRight=o)}Object(Te.d)(this.el,t)},playlistItem:function(e,t){if(t)if(e.get("displaytitle")||e.get("displaydescription")){var i="",n="";t.title&&e.get("displaytitle")&&(i=t.title),t.description&&e.get("displaydescription")&&(n=t.description),this.updateText(i,n)}else this.hide()},updateText:function(e,t){Object(Ce.q)(this.title,e),Object(Ce.q)(this.description,t),this.title.firstChild||this.description.firstChild?this.show():this.hide()},element:function(){return this.el}});var He=Ne;function Fe(e,t){for(var i=0;ie)}if(t.get("controls")){var r=je(t);Object(Ce.v)(u,"jw-flag-audio-player",r),t.set("audioMode",r)}}function I(){t.set("visibility",me(t,u))}this.updateBounds=function(){Object(ke.a)(k);var e=t.get("isFloating")?p:u,i=document.body.contains(e),n=Object(Ce.c)(e),r=Math.round(n.width),s=Math.round(n.height);if(S=Object(Ce.c)(u),r===o&&s===a)return o&&a||z(),void t.set("inDom",i);r&&s||o&&a||z(),(r||s||i)&&(t.set("containerWidth",r),t.set("containerHeight",s)),t.set("inDom",i),i&&be.a.observe(u)},this.updateStyles=function(){var e=t.get("containerWidth"),i=t.get("containerHeight");B(e,i),A&&A.resize(e,i),$(e,i),v.resize(),T&&F()},this.checkResized=function(){var e=t.get("containerWidth"),i=t.get("containerHeight"),n=t.get("isFloating");if(e!==o||i!==a){this.resizeListener||(this.resizeListener=new Ue.a(p,this,t)),o=e,a=i,l.trigger(d.hb,{width:e,height:i});var s=Object(xe.a)(e);E!==s&&(E=s,l.trigger(d.j,{breakpoint:E}))}n!==r&&(r=n,l.trigger(d.x,{floating:n}),I())},this.responsiveListener=z,this.setup=function(){j.setup(u.querySelector(".jw-preview")),b.setup(u.querySelector(".jw-title")),(i=new Ie(t)).setup(),i.setContainer(p),i.on(d.A,J),v.setup(u.id,t.get("captions")),b.element().parentNode.insertBefore(v.element(),b.element()),O=function(e,t,i){var n=new Pe(t,i),o=t.get("controls");n.on({click:function(){l.trigger(d.p),A&&(ce()?A.settingsMenu.close():ue()?A.infoOverlay.close():e.playToggle({reason:"interaction"}))},tap:function(){l.trigger(d.p),ce()&&A.settingsMenu.close(),ue()&&A.infoOverlay.close();var i=t.get("state");if(o&&(i===d.mb||i===d.kb||t.get("instream")&&i===d.ob)&&e.playToggle({reason:"interaction"}),o&&i===d.ob){if(t.get("instream")||t.get("castActive")||"audio"===t.get("mediaType"))return;Object(Ce.v)(u,"jw-flag-controls-hidden"),l.dismissible&&Object(Ce.v)(u,"jw-floating-dismissible",Object(Ce.i)(u,"jw-flag-controls-hidden")),v.renderCues(!0)}else A&&(A.showing?A.userInactive():A.userActive())},doubleClick:function(){return A&&e.setFullscreen()}}),We||(u.addEventListener("mousemove",W),u.addEventListener("mouseover",Q),u.addEventListener("mouseout",Y));return n}(e,t,f),M=new Ee.a(u).on("click",(function(){})),C=Se(u,document,te),t.on("change:hideAdsControls",(function(e,t){Object(Ce.v)(u,"jw-flag-ads-hide-controls",t)})),t.on("change:scrubbing",(function(e,t){Object(Ce.v)(u,"jw-flag-dragging",t)})),t.on("change:playRejected",(function(e,t){Object(Ce.v)(u,"jw-flag-play-rejected",t)})),t.on(d.X,ee),t.on("change:".concat(d.U),(function(){$(),v.resize()})),t.player.on("change:errorEvent",ae),t.change("stretching",X);var n=t.get("width"),o=t.get("height"),a=G(n,o);Object(Te.d)(u,a),t.change("aspectratio",K),B(n,o),t.get("controls")||(Object(Ce.a)(u,"jw-flag-controls-hidden"),Object(Ce.o)(u,"jw-floating-dismissible")),Qe&&Object(Ce.a)(u,"jw-ie");var r=t.get("skin")||{};r.name&&Object(Ce.p)(u,/jw-skin-\S+/,"jw-skin-"+r.name);var s=function(e){e||(e={});var t=e.active,i=e.inactive,n=e.background,o={};return o.controlbar=function(e){if(e||t||i||n){var o={};return e=e||{},o.iconsActive=e.iconsActive||t,o.icons=e.icons||i,o.text=e.text||i,o.background=e.background||n,o}}(e.controlbar),o.timeslider=function(e){if(e||t){var i={};return e=e||{},i.progress=e.progress||t,i.rail=e.rail,i}}(e.timeslider),o.menus=function(e){if(e||t||i||n){var o={};return e=e||{},o.text=e.text||i,o.textActive=e.textActive||t,o.background=e.background||n,o}}(e.menus),o.tooltips=function(e){if(e||i||n){var t={};return e=e||{},t.text=e.text||i,t.background=e.background||n,t}}(e.tooltips),o}(r);!function(e,t){var i;function n(t,i,n,o){if(n){t=Object(w.f)(t,"#"+e+(o?"":" "));var a={};a[i]=n,Object(Te.b)(t.join(", "),a,e)}}t&&(t.controlbar&&function(t){n([".jw-controlbar .jw-icon-inline.jw-text",".jw-title-primary",".jw-title-secondary"],"color",t.text),t.icons&&(n([".jw-button-color:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:not(.jw-icon-cast)"],"color",t.icons),n([".jw-display-icon-container .jw-button-color"],"color",t.icons),Object(Te.b)("#".concat(e," .jw-icon-cast google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.icons,"}"),e));t.iconsActive&&(n([".jw-display-icon-container .jw-button-color:hover",".jw-display-icon-container .jw-button-color:focus"],"color",t.iconsActive),n([".jw-button-color.jw-toggle:not(.jw-icon-cast)",".jw-button-color:hover:not(.jw-icon-cast)",".jw-button-color:focus:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:hover:not(.jw-icon-cast)"],"color",t.iconsActive),n([".jw-svg-icon-buffer"],"fill",t.icons),Object(Te.b)("#".concat(e," .jw-icon-cast:hover google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(Te.b)("#".concat(e," .jw-icon-cast:focus google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(Te.b)("#".concat(e," .jw-icon-cast google-cast-launcher.jw-off:focus"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(Te.b)("#".concat(e," .jw-icon-cast google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(Te.b)("#".concat(e," .jw-icon-cast google-cast-launcher:focus"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(Te.b)("#".concat(e," .jw-icon-cast:hover google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(Te.b)("#".concat(e," .jw-icon-cast:focus google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e));n([" .jw-settings-topbar",":not(.jw-state-idle) .jw-controlbar",".jw-flag-audio-player .jw-controlbar"],"background",t.background,!0)}(t.controlbar),t.timeslider&&function(e){var t=e.progress;"none"!==t&&(n([".jw-progress",".jw-knob"],"background-color",t),n([".jw-buffer"],"background-color",Object(Te.c)(t,50)));n([".jw-rail"],"background-color",e.rail),n([".jw-background-color.jw-slider-time",".jw-slider-time .jw-cue"],"background-color",e.background)}(t.timeslider),t.menus&&(n([".jw-option",".jw-toggle.jw-off",".jw-skip .jw-skip-icon",".jw-nextup-tooltip",".jw-nextup-close",".jw-settings-content-item",".jw-related-title"],"color",(i=t.menus).text),n([".jw-option.jw-active-option",".jw-option:not(.jw-active-option):hover",".jw-option:not(.jw-active-option):focus",".jw-settings-content-item:hover",".jw-nextup-tooltip:hover",".jw-nextup-tooltip:focus",".jw-nextup-close:hover"],"color",i.textActive),n([".jw-nextup",".jw-settings-menu"],"background",i.background)),t.tooltips&&function(e){n([".jw-skip",".jw-tooltip .jw-text",".jw-time-tip .jw-text"],"background-color",e.background),n([".jw-time-tip",".jw-tooltip"],"color",e.background),n([".jw-skip"],"border","none"),n([".jw-skip .jw-text",".jw-skip .jw-icon",".jw-time-tip .jw-text",".jw-tooltip .jw-text"],"color",e.text)}(t.tooltips),t.menus&&function(t){if(t.textActive){var i={color:t.textActive,borderColor:t.textActive,stroke:t.textActive};Object(Te.b)("#".concat(e," .jw-color-active"),i,e),Object(Te.b)("#".concat(e," .jw-color-active-hover:hover"),i,e)}if(t.text){var n={color:t.text,borderColor:t.text,stroke:t.text};Object(Te.b)("#".concat(e," .jw-color-inactive"),n,e),Object(Te.b)("#".concat(e," .jw-color-inactive-hover:hover"),n,e)}}(t.menus))}(t.get("id"),s),t.set("mediaContainer",f),t.set("iFrame",m.Features.iframe),t.set("activeTab",Object(ye.a)()),t.set("touchMode",We&&("string"==typeof o||o>=ge)),be.a.add(this),t.get("enableGradient")&&!Qe&&Object(Ce.a)(u,"jw-ab-drop-shadow"),this.isSetup=!0,t.trigger("viewSetup",u);var c=document.body.contains(u);c&&be.a.observe(u),t.set("inDom",c)},this.init=function(){this.updateBounds(),t.on("change:fullscreen",Z),t.on("change:activeTab",I),t.on("change:fullscreen",I),t.on("change:intersectionRatio",I),t.on("change:visibility",U),t.on("instreamMode",(function(e){e?de():pe()})),I(),1!==be.a.size()||t.get("visibility")||U(t,1,0);var e=t.player;t.change("state",re),e.change("controls",D),t.change("streamType",ne),t.change("mediaType",oe),e.change("playlistItem",(function(e,t){le(e,t)})),o=a=null,T&&We&&be.a.addScrollHandler(F),this.checkResized()};var R,V=62,N=!0;function H(){var e=t.get("isFloating"),i=S.top0&&void 0!==arguments[0])||arguments[0],t={x:0,y:0,width:o||0,height:a||0};return A&&e&&(t.height-=A.controlbarHeight()),t},this.setCaptions=function(e){v.clear(),v.setup(t.get("id"),e),v.resize()},this.setIntersection=function(e){var i=Math.round(100*e.intersectionRatio)/100;t.set("intersectionRatio",i),T&&!P()&&(_=_||i>=.5)&&we(i)},this.stopFloating=function(e,i){if(e&&(T=null,be.a.removeScrollHandler(F)),Ye===u){Ye=null,t.set("isFloating",!1);var n=function(){Object(Ce.o)(u,"jw-flag-floating"),K(t,t.get("aspectratio")),Object(Te.d)(u,{backgroundImage:null}),Object(Te.d)(p,{maxWidth:null,width:null,height:null,left:null,right:null,top:null,bottom:null,margin:null,transform:null,transition:null,"transition-timing-function":null})};i?(Object(Te.d)(p,{transform:"translateY(-".concat(V-S.top,"px)"),"transition-timing-function":"ease-out"}),setTimeout(n,150)):n(),g.disable(),z()}},this.destroy=function(){t.destroy(),be.a.unobserve(u),be.a.remove(this),this.isSetup=!1,this.off(),Object(ke.a)(k),clearTimeout(y),Ye===u&&(Ye=null),M&&(M.destroy(),M=null),C&&(C.destroy(),C=null),A&&A.disable(t),O&&(O.destroy(),u.removeEventListener("mousemove",W),u.removeEventListener("mouseout",Y),u.removeEventListener("mouseover",Q),O=null),v.destroy(),i&&(i.destroy(),i=null),Object(Te.a)(t.get("id")),this.resizeListener&&(this.resizeListener.destroy(),delete this.resizeListener),T&&We&&be.a.removeScrollHandler(F)}};function Ke(e,t,i){return(Ke="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(e,t,i){var n=function(e,t){for(;!Object.prototype.hasOwnProperty.call(e,t)&&null!==(e=tt(e)););return e}(e,t);if(n){var o=Object.getOwnPropertyDescriptor(n,t);return o.get?o.get.call(i):o.value}})(e,t,i||e)}function Je(e){return(Je="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function Ze(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Ge(e,t){for(var i=0;it&&e(),t=n}};function Ot(e,t){t.off(d.N,e._onPlayAttempt),t.off(d.fb,e._triggerFirstFrame),t.off(d.S,e._onTime),e.off("change:activeTab",e._onTabVisible)}var Ct=function(e,t){e.change("mediaModel",(function(e,i,n){e._qoeItem&&n&&e._qoeItem.end(n.get("mediaState")),e._qoeItem=new yt.a,e._qoeItem.getFirstFrame=function(){var e=this.between(d.N,d.H),t=this.between(xt,d.H);return t>0&&t0&&re(t,e.tracks)}),O).on(d.F,(function(){Promise.resolve().then(ae)}),O).on(d.G,O.triggerError,O),Ct(C,R),C.on(d.w,O.triggerError,O),C.on("change:state",(function(e,t,i){X()||K.call(T,e,t,i)}),this),C.on("change:castState",(function(e,t){O.trigger(d.m,t)})),C.on("change:fullscreen",(function(e,t){O.trigger(d.y,{fullscreen:t}),t&&e.set("playOnViewable",!1)})),C.on("change:volume",(function(e,t){O.trigger(d.V,{volume:t})})),C.on("change:mute",(function(e){O.trigger(d.M,{mute:e.getMute()})})),C.on("change:playbackRate",(function(e,t){O.trigger(d.ab,{playbackRate:t,position:e.get("position")})}));var V=function e(t,i){"clickthrough"!==i&&"interaction"!==i&&"external"!==i||(C.set("playOnViewable",!1),C.off("change:playReason change:pauseReason",e))};function N(e,t){Object(n.t)(t)||C.set("viewable",Math.round(t))}function H(){de&&(!0!==C.get("autostart")||C.get("playOnViewable")||$("autostart"),de.flush())}function F(e,t){O.trigger("viewable",{viewable:t}),D()}function D(){if((o.a[0]===t||1===C.get("viewable"))&&"idle"===C.get("state")&&!1===C.get("autostart"))if(!b.primed()&&m.OS.android){var e=b.getTestElement(),i=O.getMute();Promise.resolve().then((function(){return ht(e,{muted:i})})).then((function(){"idle"===C.get("state")&&R.preloadVideo()})).catch(St)}else R.preloadVideo()}function q(e){O._instreamAdapter.noResume=!e,e||te({reason:"viewable"})}function U(e){e||(O.pause({reason:"viewable"}),C.set("playOnViewable",!e))}function W(e,t){var i=X();if(e.get("playOnViewable")){if(t){var n=e.get("autoPause").pauseAds,o=e.get("pauseReason");J()===d.mb?$("viewable"):i&&!n||"interaction"===o||Z({reason:"viewable"})}else m.OS.mobile&&!i&&(O.pause({reason:"autostart"}),C.set("playOnViewable",!0));m.OS.mobile&&i&&q(t)}}function Q(e,t){var i=e.get("state"),n=X(),o=e.get("playReason");n?e.get("autoPause").pauseAds?U(t):q(t):i===d.pb||i===d.jb?U(t):i===d.mb&&"playlist"===o&&e.once("change:state",(function(){U(t)}))}function X(){var e=O._instreamAdapter;return!!e&&e.getState()}function J(){var e=X();return e||C.get("state")}function Z(e){if(E.cancel(),_=!1,C.get("state")===d.lb)return Promise.resolve();var i=G(e);return C.set("playReason",i),X()?(t.pauseAd(!1,e),Promise.resolve()):(C.get("state")===d.kb&&(ee(!0),O.setItemIndex(0)),!M&&(M=!0,O.trigger(d.C,{playReason:i,startTime:e&&e.startTime?e.startTime:C.get("playlistItem").starttime}),M=!1,vt()&&!b.primed()&&b.prime(),"playlist"===i&&C.get("autoPause").viewability&&Q(C,C.get("viewable")),x)?(vt()&&!B&&C.get("mediaElement").load(),x=!1,k=null,Promise.resolve()):R.playVideo(i).then(b.played))}function G(e){return e&&e.reason?e.reason:"unknown"}function $(e){if(J()===d.mb){E=g(H);var t=C.get("advertising");(function(e,t){var i=t.cancelable,n=t.muted,o=void 0!==n&&n,a=t.allowMuted,r=void 0!==a&&a,s=t.timeout,l=void 0===s?1e4:s,c=e.getTestElement(),u=o?"muted":"".concat(r);bt[u]||(bt[u]=ht(c,{muted:o}).catch((function(e){if(!i.cancelled()&&!1===o&&r)return ht(c,{muted:o=!0});throw e})).then((function(){return o?(bt[u]=null,gt):ft})).catch((function(e){throw clearTimeout(d),bt[u]=null,e.reason=jt,e})));var d,p=bt[u].then((function(e){if(clearTimeout(d),i.cancelled()){var t=new Error("Autoplay test was cancelled");throw t.reason="cancelled",t}return e})),w=new Promise((function(e,t){d=setTimeout((function(){bt[u]=null;var e=new Error("Autoplay test timed out");e.reason="timeout",t(e)}),l)}));return Promise.race([p,w])})(b,{cancelable:E,muted:O.getMute(),allowMuted:!t||t.autoplayadsmuted}).then((function(t){return C.set("canAutoplay",t),t!==gt||O.getMute()||(C.set("autostartMuted",!0),ue(),C.once("change:autostartMuted",(function(e){e.off("change:viewable",W),O.trigger(d.M,{mute:C.getMute()})}))),O.getMute()&&C.get("enableDefaultCaptions")&&y.selectDefaultIndex(1),Z({reason:e}).catch((function(){O._instreamAdapter||C.set("autostartFailed",!0),k=null}))})).catch((function(e){if(C.set("canAutoplay",jt),C.set("autostart",!1),!E.cancelled()){var t=Object(j.w)(e);O.trigger(d.h,{reason:e.reason,code:t,error:e})}}))}}function ee(e){if(E.cancel(),de.empty(),X()){var t=O._instreamAdapter;return t&&(t.noResume=!0),void(k=function(){return R.stopVideo()})}k=null,!e&&(_=!0),M&&(x=!0),C.set("errorEvent",void 0),R.stopVideo()}function te(e){var t=G(e);C.set("pauseReason",t),C.set("playOnViewable","viewable"===t)}function ie(e){k=null,E.cancel();var i=X();if(i&&i!==d.ob)return te(e),void t.pauseAd(!0,e);switch(C.get("state")){case d.lb:return;case d.pb:case d.jb:te(e),R.pause();break;default:M&&(x=!0)}}function ne(e,t){ee(!0),O.setItemIndex(e),O.play(t)}function oe(e){ne(C.get("item")+1,e)}function ae(){O.completeCancelled()||(k=O.completeHandler,O.shouldAutoAdvance()?O.nextItem():C.get("repeat")?oe({reason:"repeat"}):(m.OS.iOS&&le(!1),C.set("playOnViewable",!1),C.set("state",d.kb),O.trigger(d.cb,{})))}function re(e,t){e=parseInt(e,10)||0,C.persistVideoSubtitleTrack(e,t),R.subtitles=e,O.trigger(d.k,{tracks:se(),track:e})}function se(){return y.getCaptionsList()}function le(e){Object(n.n)(e)||(e=!C.get("fullscreen")),C.set("fullscreen",e),O._instreamAdapter&&O._instreamAdapter._adModel&&O._instreamAdapter._adModel.set("fullscreen",e)}function ue(){R.mute=C.getMute(),R.volume=C.get("volume")}C.on("change:playReason change:pauseReason",V),O.on(d.c,(function(e){return V(0,e.playReason)})),O.on(d.b,(function(e){return V(0,e.pauseReason)})),C.on("change:scrubbing",(function(e,t){t?(S=C.get("state")!==d.ob,ie()):S&&Z({reason:"interaction"})})),C.on("change:captionsList",(function(e,t){O.trigger(d.l,{tracks:t,track:C.get("captionsIndex")||0})})),C.on("change:mediaModel",(function(e,t){var i=this;e.set("errorEvent",void 0),t.change("mediaState",(function(t,i){var n;e.get("errorEvent")||e.set(d.bb,(n=i)===d.nb||n===d.qb?d.jb:n)}),this),t.change("duration",(function(t,i){if(0!==i){var n=e.get("minDvrWindow"),o=Object(mt.b)(i,n);e.setStreamType(o)}}),this);var n=e.get("item")+1,o="autoplay"===(e.get("related")||{}).oncomplete,a=e.get("playlist")[n];if((a||o)&&B){t.on("change:position",(function e(n,r){var s=a&&!a.daiSetting,l=t.get("duration");s&&r&&l>0&&r>=l-p.b?(t.off("change:position",e,i),R.backgroundLoad(a)):o&&(a=C.get("nextUp"))}),this)}})),(y=new we(C)).on("all",L,O),I.on("viewSetup",(function(e){Object(a.b)(T,e)})),this.playerReady=function(){v.once(d.hb,(function(){try{!function(){C.change("visibility",N),P.off(),O.trigger(d.gb,{setupTime:0}),C.change("playlist",(function(e,t){if(t.length){var i={playlist:t},o=C.get("feedData");o&&(i.feedData=Object(n.g)({},o)),O.trigger(d.eb,i)}})),C.change("playlistItem",(function(e,t){if(t){var i=t.title,n=t.image;if("mediaSession"in navigator&&window.MediaMetadata&&(i||n))try{navigator.mediaSession.metadata=new window.MediaMetadata({title:i,artist:window.location.hostname,artwork:[{src:n||""}]})}catch(e){}e.set("cues",[]),O.trigger(d.db,{index:C.get("item"),item:t})}})),P.flush(),P.destroy(),P=null,C.change("viewable",F),C.change("viewable",W),C.get("autoPause").viewability?C.change("viewable",Q):C.once("change:autostartFailed change:mute",(function(e){e.off("change:viewable",W)}));H(),C.on("change:itemReady",(function(e,t){t&&de.flush()}))}()}catch(e){O.triggerError(Object(j.v)(j.m,j.a,e))}})),v.init()},this.preload=D,this.load=function(e,t){var i,n=O._instreamAdapter;switch(n&&(n.noResume=!0),O.trigger("destroyPlugin",{}),ee(!0),E.cancel(),E=g(H),A.cancel(),vt()&&b.prime(),Mt(e)){case"string":C.attributes.item=0,C.attributes.itemReady=!1,A=g((function(e){if(e)return O.updatePlaylist(Object(c.a)(e.playlist),e)})),i=function(e){var t=this;return new Promise((function(i,n){var o=new l.a;o.on(d.eb,(function(e){i(e)})),o.on(d.w,n,t),o.load(e)}))}(e).then(A.async);break;case"object":C.attributes.item=0,i=O.updatePlaylist(Object(c.a)(e),t||{});break;case"number":i=O.setItemIndex(e);break;default:return}i.catch((function(e){O.triggerError(Object(j.u)(e,j.c))})),i.then(E.async).catch(St)},this.play=function(e){return Z(e).catch(St)},this.pause=ie,this.seek=function(e,t){var i=C.get("state");if(i!==d.lb){R.position=e;var n=i===d.mb;C.get("scrubbing")||!n&&i!==d.kb||(n&&((t=t||{}).startTime=e),this.play(t))}},this.stop=ee,this.playlistItem=ne,this.playlistNext=oe,this.playlistPrev=function(e){ne(C.get("item")-1,e)},this.setCurrentCaptions=re,this.setCurrentQuality=function(e){R.quality=e},this.setFullscreen=le,this.getCurrentQuality=function(){return R.quality},this.getQualityLevels=function(){return R.qualities},this.setCurrentAudioTrack=function(e){R.audioTrack=e},this.getCurrentAudioTrack=function(){return R.audioTrack},this.getAudioTracks=function(){return R.audioTracks},this.getCurrentCaptions=function(){return y.getCurrentIndex()},this.getCaptionsList=se,this.getVisualQuality=function(){var e=this._model.get("mediaModel");return e?e.get(d.U):null},this.getConfig=function(){return this._model?this._model.getConfiguration():void 0},this.getState=J,this.next=St,this.completeHandler=ae,this.completeCancelled=function(){return(e=C.get("state"))!==d.mb&&e!==d.kb&&e!==d.lb||!!_&&(_=!1,!0);var e},this.shouldAutoAdvance=function(){return C.get("item")!==C.get("playlist").length-1},this.nextItem=function(){oe({reason:"playlist"})},this.setConfig=function(e){!function(e,t){var i=e._model,n=i.attributes;t.height&&(t.height=Object(r.b)(t.height),t.width=t.width||n.width),t.width&&(t.width=Object(r.b)(t.width),t.aspectratio?(n.width=t.width,delete t.width):t.height=n.height),t.width&&t.height&&!t.aspectratio&&e._view.resize(t.width,t.height),Object.keys(t).forEach((function(o){var a=t[o];if(void 0!==a)switch(o){case"aspectratio":i.set(o,Object(r.a)(a,n.width));break;case"autostart":!function(e,t,i){e.setAutoStart(i),"idle"===e.get("state")&&!0===i&&t.play({reason:"autostart"})}(i,e,a);break;case"mute":e.setMute(a);break;case"volume":e.setVolume(a);break;case"playbackRateControls":case"playbackRates":case"repeat":case"stretching":i.set(o,a)}}))}(O,e)},this.setItemIndex=function(e){R.stopVideo();var t=C.get("playlist").length;return(e=(parseInt(e,10)||0)%t)<0&&(e+=t),R.setActiveItem(e).catch((function(e){e.code>=151&&e.code<=162&&(e=Object(j.u)(e,j.e)),T.triggerError(Object(j.v)(j.k,j.d,e))}))},this.detachMedia=function(){if(M&&(x=!0),C.get("autoPause").viewability&&Q(C,C.get("viewable")),!B)return R.setAttached(!1);R.backgroundActiveMedia()},this.attachMedia=function(){B?R.restoreBackgroundMedia():R.setAttached(!0),"function"==typeof k&&k()},this.routeEvents=function(e){return R.routeEvents(e)},this.forwardEvents=function(){return R.forwardEvents()},this.playVideo=function(e){return R.playVideo(e)},this.stopVideo=function(){return R.stopVideo()},this.castVideo=function(e,t){return R.castVideo(e,t)},this.stopCast=function(){return R.stopCast()},this.backgroundActiveMedia=function(){return R.backgroundActiveMedia()},this.restoreBackgroundMedia=function(){return R.restoreBackgroundMedia()},this.preloadNextItem=function(){R.background.currentMedia&&R.preloadVideo()},this.isBeforeComplete=function(){return R.beforeComplete},this.setVolume=function(e){C.setVolume(e),ue()},this.setMute=function(e){C.setMute(e),ue()},this.setPlaybackRate=function(e){C.setPlaybackRate(e)},this.getProvider=function(){return C.get("provider")},this.getWidth=function(){return C.get("containerWidth")},this.getHeight=function(){return C.get("containerHeight")},this.getItemQoe=function(){return C._qoeItem},this.addButton=function(e,t,i,n,o){var a=C.get("customButtons")||[],r=!1,s={img:e,tooltip:t,callback:i,id:n,btnClass:o};a=a.reduce((function(e,t){return t.id===n?(r=!0,e.push(s)):e.push(t),e}),[]),r||a.unshift(s),C.set("customButtons",a)},this.removeButton=function(e){var t=C.get("customButtons")||[];t=t.filter((function(t){return t.id!==e})),C.set("customButtons",t)},this.resize=v.resize,this.getSafeRegion=v.getSafeRegion,this.setCaptions=v.setCaptions,this.checkBeforePlay=function(){return M},this.setControls=function(e){Object(n.n)(e)||(e=!C.get("controls")),C.set("controls",e),R.controls=e},this.addCues=function(e){this.setCues(C.get("cues").concat(e))},this.setCues=function(e){C.set("cues",e)},this.updatePlaylist=function(e,t){try{var i=Object(c.b)(e,C,t);Object(c.e)(i);var o=Object(n.g)({},t);delete o.playlist,C.set("feedData",o),C.set("playlist",i)}catch(e){return Promise.reject(e)}return this.setItemIndex(C.get("item"))},this.setPlaylistItem=function(e,t){(t=Object(c.d)(C,new u.a(t),t.feedData||{}))&&(C.get("playlist")[e]=t,e===C.get("item")&&"idle"===C.get("state")&&this.setItemIndex(e))},this.playerDestroy=function(){this.off(),this.stop(),Object(a.b)(this,this.originalContainer),v&&v.destroy(),C&&C.destroy(),de&&de.destroy(),y&&y.destroy(),R&&R.destroy(),this.instreamDestroy()},this.isBeforePlay=this.checkBeforePlay,this.createInstream=function(){return this.instreamDestroy(),this._instreamAdapter=new ce(this,C,v,b),this._instreamAdapter},this.instreamDestroy=function(){O._instreamAdapter&&(O._instreamAdapter.destroy(),O._instreamAdapter=null)};var de=new s.a(this,["play","pause","setCurrentAudioTrack","setCurrentCaptions","setCurrentQuality","setFullscreen"],(function(){return!T._model.get("itemReady")||P}));de.queue.push.apply(de.queue,f),v.setup()},get:function(e){if(e in y.a){var t=this._model.get("mediaModel");return t?t.get(e):y.a[e]}return this._model.get(e)},getContainer:function(){return this.currentContainer||this.originalContainer},getMute:function(){return this._model.getMute()},triggerError:function(e){var t=this._model;e.message=t.get("localization").errors[e.key],delete e.key,t.set("errorEvent",e),t.set("state",d.lb),t.once("change:state",(function(){this.set("errorEvent",void 0)}),t),this.trigger(d.w,e)}});t.default=_t},,,,,,,,,,,,,function(e,t,i){"use strict";i.r(t);var n=i(0);var o=i(8),a=i(52),r=i(3),s=i(43),l={canplay:function(){this.trigger(r.E)},play:function(){this.stallTime=-1,this.video.paused||this.state===r.pb||this.setState(r.nb)},loadedmetadata:function(){var e={metadataType:"media",duration:this.getDuration(),height:this.video.videoHeight,width:this.video.videoWidth,seekRange:this.getSeekRange()},t=this.drmUsed;t&&(e.drm=t),this.trigger(r.K,e)},timeupdate:function(){var e=this.getVideoCurrentTime(),t=this.getCurrentTime(),i=this.getDuration();if(!isNaN(i)){this.seeking||this.video.paused||this.state!==r.qb&&this.state!==r.nb||this.stallTime===e||(this.stallTime=-1,this.setState(r.pb),this.trigger(r.fb));var n={position:t,duration:i,currentTime:e,seekRange:this.getSeekRange(),metadata:{currentTime:e}};if(this.getPtsOffset){var o=this.getPtsOffset();o>=0&&(n.metadata.mpegts=o+t)}var a=this.getLiveLatency();null!==a&&(n.latency=a),(this.state===r.pb||this.seeking)&&this.trigger(r.S,n)}},click:function(e){this.trigger(r.n,e)},volumechange:function(){var e=this.video;this.trigger(r.V,{volume:Math.round(100*e.volume)}),this.trigger(r.M,{mute:e.muted})},seeked:function(){this.seeking&&(this.seeking=!1,this.trigger(r.R))},playing:function(){-1===this.stallTime&&this.setState(r.pb),this.trigger(r.fb)},pause:function(){this.state!==r.kb&&(this.video.ended||this.video.error||this.getVideoCurrentTime()!==this.getDuration()&&this.setState(r.ob))},progress:function(){var e=this.getDuration();if(!(e<=0||e===1/0)){var t=this.video.buffered;if(t&&0!==t.length){var i=Object(s.a)(t.end(t.length-1)/e,0,1);this.trigger(r.D,{bufferPercent:100*i,position:this.getCurrentTime(),duration:e,currentTime:this.getVideoCurrentTime(),seekRange:this.getSeekRange()})}}},ratechange:function(){this.trigger(r.P,{playbackRate:this.video.playbackRate})},ended:function(){this.videoHeight=0,this.streamBitrate=-1,this.state!==r.mb&&this.state!==r.kb&&this.trigger(r.F)},loadeddata:function(){this.renderNatively&&this.setTextTracks(this.video.textTracks)}},c=i(10);function u(e){return e&&e.length?e.end(e.length-1):0}var d={container:null,volume:function(e){this.video.volume=Math.min(Math.max(0,e/100),1)},mute:function(e){this.video.muted=!!e,this.video.muted||this.video.removeAttribute("muted")},resize:function(e,t,i){var n=this.video,a=n.videoWidth,r=n.videoHeight;if(e&&t&&a&&r){var s={objectFit:"",width:"",height:""};if("uniform"===i){var l=e/t,u=a/r,d=Math.abs(l-u);d<.09&&d>.0025&&(s.objectFit="fill",i="exactfit")}if(o.Browser.ie||o.OS.iOS&&o.OS.version.major<9||o.Browser.androidNative)if("uniform"!==i){s.objectFit="contain";var p=e/t,w=a/r,h=1,f=1;"none"===i?h=f=p>w?Math.ceil(100*r/t)/100:Math.ceil(100*a/e)/100:"fill"===i?h=f=p>w?p/w:w/p:"exactfit"===i&&(p>w?(h=p/w,f=1):(h=1,f=w/p)),Object(c.e)(n,"matrix(".concat(h.toFixed(2),", 0, 0, ").concat(f.toFixed(2),", 0, 0)"))}else s.top=s.left=s.margin="",Object(c.e)(n,"");Object(c.d)(n,s)}},getContainer:function(){return this.container},setContainer:function(e){this.container=e,this.video.parentNode!==e&&e.appendChild(this.video)},remove:function(){this.stop(),this.destroy();var e=this.container;e&&e===this.video.parentNode&&e.removeChild(this.video)},atEdgeOfLiveStream:function(){if(!this.isLive())return!1;return u(this.video.buffered)-this.video.currentTime<=2}},p={eventsOn_:function(){},eventsOff_:function(){},attachMedia:function(){this.eventsOn_()},detachMedia:function(){return this.eventsOff_()}},w=i(65),h=i(5),f=i(53),g=i(7),j=i(66),b=i(63),m={TIT2:"title",TT2:"title",WXXX:"url",TPE1:"artist",TP1:"artist",TALB:"album",TAL:"album"};function v(e,t){for(var i,n,o,a=e.length,r="",s=t||0;s>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:r+=String.fromCharCode(i);break;case 12:case 13:n=e[s++],r+=String.fromCharCode((31&i)<<6|63&n);break;case 14:n=e[s++],o=e[s++],r+=String.fromCharCode((15&i)<<12|(63&n)<<6|(63&o)<<0)}return r}function y(e){var t=function(e){for(var t="0x",i=0;i>1|(8323072&t)>>2|(2130706432&t)>>3}function k(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:[]).reduce((function(e,t){if(!("value"in t)&&"data"in t&&t.data instanceof ArrayBuffer){var i=new Uint8Array(t.data),n=i.length;t={value:{key:"",data:""}};for(var o=10;o<14&&o0){var c=v(i.subarray(a,a+=s),0);if("PRIV"===t.value.key){if("com.apple.streaming.transportStreamTimestamp"===c){var u=1&y(i.subarray(a,a+=4)),d=y(i.subarray(a,a+=4))+(u?4294967296:0);t.value.data=d}else t.value.data=v(i,a+1);t.value.info=c}else t.value.info=c,t.value.data=v(i,a+1)}else{var p=i[a];t.value.data=1===p||2===p?function(e,t){for(var i=e.length-1,n="",o=t||0;o=0&&o[a].startTime>t.startTime;a--)i.unshift(o[a]),e.removeCue(o[a]);try{e.addCue(t),i.forEach((function(t){return e.addCue(t)}))}catch(e){console.error(e)}e.mode=n}(t,n)}else try{t.addCue(i)}catch(e){console.error(e)}}function _(e,t){t&&t.length&&Object(n.f)(t,(function(t){if(!(o.Browser.ie&&e&&/^(native|subtitle|cc)/.test(t._id))){o.Browser.ie&&"disabled"===t.mode||(t.mode="disabled",t.mode="hidden");for(var i=t.cues.length;i--;)t.removeCue(t.cues[i]);t.embedded||(t.mode="disabled"),t.inuse=!1}}))}function S(e){return"subtitles"===e||"captions"===e}function E(e){var t,i=Object(b.b)(e,this._unknownCount),o=i.label;if(this._unknownCount=i.unknownCount,this.renderNatively||"metadata"===e.kind){var a=this.video.textTracks;(t=Object(n.j)(a,{label:o}))||(t=this.video.addTextTrack(e.kind,o,e.language||"")),t.default=e.default,t.mode="disabled",t.inuse=!0}else(t=e).data=t.data||[];return t._id||(t._id=Object(b.a)(e,this._textTracks.length)),t}function A(e){this._textTracks.push(e),this._tracksById[e._id]=e}function P(){if(this._textTracks){var e=this._textTracks.filter((function(e){return e.embedded||"subs"===e.groupid}));this._initTextTracks(),e.forEach((function(e){this._tracksById[e._id]=e})),this._textTracks=e}}function z(e){this.triggerActiveCues(e.currentTarget.activeCues)}function L(e,t,i){var n=e.kind;this._cachedVTTCues[e._id]||(this._cachedVTTCues[e._id]={});var o,a=this._cachedVTTCues[e._id];switch(n){case"captions":case"subtitles":o=i||Math.floor(20*t.startTime);var r="_"+t.line,s=Math.floor(20*t.endTime),l=a[o+r]||a[o+1+r]||a[o-1+r];return!(l&&Math.abs(l-s)<=1)&&(a[o+r]=s,!0);case"metadata":var c=t.data?new Uint8Array(t.data).join(""):t.text;return!a[o=i||t.startTime+c]&&(a[o]=t.endTime,!0);default:return!1}}function B(e){if(e.length>this._textTracks.length)return!0;for(var t=0;t=0&&(f.retries=0);var e=f.getVideoCurrentTime();f.currentTime=e,_&&C!==e&&$(e),l.timeupdate.call(f),he(),o.Browser.ie&&G()},resize:G,ended:function(){M=-1,fe(),l.ended.call(f)},loadedmetadata:function(){var e=f.getDuration();B&&e===1/0&&(e=0);var t={metadataType:"media",duration:e,height:v.videoHeight,width:v.videoWidth,seekRange:f.getSeekRange()};f.trigger(r.K,t),G()},durationchange:function(){B||l.progress.call(f)},loadeddata:function(){var e;!function(){if(v.getStartDate){var e=v.getStartDate(),t=e.getTime?e.getTime():NaN;if(t!==f.startDateTime&&!isNaN(t)){f.startDateTime=t;var i=e.toISOString(),n=f.getSeekRange(),o=n.start,a=n.end,s={metadataType:"program-date-time",programDateTime:i,start:o,end:a},l=f.createCue(o,a,JSON.stringify(s));f.addVTTCue({type:"metadata",cue:l}),delete s.metadataType,f.trigger(r.L,{metadataType:"program-date-time",metadata:s})}}}(),l.loadeddata.call(f),function(e){if(E=null,!e)return;if(e.length){for(var t=0;t0&&(t=e.map((function(e,t){return{label:e.label||t}}))),t}function ie(e){f.currentTime=-1,j=e.minDvrWindow,m=e.sources,M=function(e){var i=Math.max(0,M),n=t.qualityLabel;if(e)for(var o=0;o0&&(T=-1,f.seek(e)),e>0&&f.getVideoCurrentTime()!==e&&f.seek(e);var n=te(m);n&&f.trigger(r.I,{levels:n,currentQuality:M}),m.length&&"hls"!==m[0].type&&we()}function ae(e){E=null,A=-1,y.reason||(y.reason="initial choice",y.level={}),x=!1;var t=document.createElement("source");t.src=e.file,v.src!==t.src&&(v.src=e.file)}function re(){v&&(f.disableTextTrack(),v.removeAttribute("preload"),v.removeAttribute("src"),Object(h.h)(v),Object(c.d)(v,{objectFit:""}),M=-1,!o.Browser.msie&&"load"in v&&v.load())}function se(){var e=1/0;return["buffered","seekable"].forEach((function(t){for(var i=v[t],o=i?i.length:0;o--;){var a=Math.min(e,i.start(o));Object(n.o)(a)&&(e=a)}})),e}function le(){var e=0;return["buffered","seekable"].forEach((function(t){for(var i=v[t],o=i?i.length:0;o--;){var a=Math.max(e,i.end(o));Object(n.o)(a)&&(e=a)}})),e}function ce(){for(var e=-1,t=0;t-1&&e1)&&function(e){X=e.end,J=Math.min(0,f.getVideoCurrentTime()-X),Z=Object(V.a)()}(t),Object(w.a)(t.end-t.start,j))return J}return e}(f.getVideoCurrentTime())},f.getDuration=function(){if(t.getDurationHook)return t.getDurationHook();var e=v.duration;if(B&&e===1/0&&0===f.getVideoCurrentTime()||isNaN(e))return 0;var i=le();if(v.duration===1/0&&i){var n=i-se();Object(w.a)(n,j)&&(e=-n)}return e},f.getSeekRange=function(){var e={start:0,end:f.getDuration()};return v.seekable.length&&(e.end=le(),e.start=se()),e},f.getLiveLatency=function(){var e=null,t=le();return f.isLive()&&t&&(e=t+(Object(V.a)()-Z)/1e3-f.getVideoCurrentTime()),e},this.stop=function(){fe(),re(),this.clearTracks(),o.Browser.ie&&v.pause(),this.setState(r.mb)},this.destroy=function(){S=Q,Y(b,v),this.removeTracksListener(v.audioTracks,"change",ce),this.removeTracksListener(v.textTracks,"change",f.textTrackChangeHandler),this.off()},this.init=function(e){f.retries=0,f.maxRetries=e.adType?0:3,ie(e);var t=m[M];(B=Object(a.a)(t))&&(f.supportsPlaybackRate=!1,b.waiting=Q),f.eventsOn_(),m.length&&"hls"!==m[0].type&&this.sendMediaType(m),y.reason=""},this.preload=function(e){ie(e);var t=m[M],i=t.preload||"metadata";"none"!==i&&(v.setAttribute("preload",i),ae(t))},this.load=function(e){ie(e),oe(e.starttime),this.setupSideloadedTracks(e.tracks)},this.play=function(){return S(),ne()},this.pause=function(){fe(),S=function(){if(v.paused&&f.getVideoCurrentTime()&&f.isLive()){var e=le(),t=e-se(),i=!Object(w.a)(t,j),o=e-f.getVideoCurrentTime();if(i&&e&&(o>15||o<0)){if(O=Math.max(e-10,e-t),!Object(n.o)(O))return;$(f.getVideoCurrentTime()),v.currentTime=O}}},v.pause()},this.seek=function(e){if(t.seekHook)return t.seekHook(e,v);var i=f.getSeekRange(),n=e;if(e<0&&(n+=i.end),x||(x=!!le()),x){T=0;try{if(f.seeking=!0,f.isLive()&&Object(w.a)(i.end-i.start,j))if(J=Math.min(0,n-X),e<0)n+=Math.min(12,(Object(V.a)()-Z)/1e3);O=n,$(f.getVideoCurrentTime()),v.currentTime=n}catch(e){f.seeking=!1,T=n}}else T=n,o.Browser.firefox&&v.paused&&ne()},this.setVisibility=function(e){(e=!!e)||o.OS.android?Object(c.d)(f.container,{visibility:"visible",opacity:1}):Object(c.d)(f.container,{visibility:"",opacity:0})},this.setFullscreen=function(e){if(e=!!e){try{var t=v.webkitEnterFullscreen||v.webkitEnterFullScreen;t&&t.apply(v)}catch(e){return!1}return f.getFullScreen()}var i=v.webkitExitFullscreen||v.webkitExitFullScreen;return i&&i.apply(v),e},f.getFullScreen=function(){return _||!!v.webkitDisplayingFullscreen},this.setCurrentQuality=function(e){M!==e&&e>=0&&m&&m.length>e&&(M=e,y.reason="api",y.level={},this.trigger(r.J,{currentQuality:e,levels:te(m)}),t.qualityLabel=m[e].label,oe(f.getVideoCurrentTime()||0),ne())},this.setPlaybackRate=function(e){v.playbackRate=v.defaultPlaybackRate=e},this.getPlaybackRate=function(){return v.playbackRate},this.getCurrentQuality=function(){return M},this.getQualityLevels=function(){return Array.isArray(m)?m.map((function(e){return function(e){return{bitrate:e.bitrate,label:e.label,width:e.width,height:e.height}}(e)})):[]},this.getName=function(){return{name:W}},this.setCurrentAudioTrack=de,this.getAudioTracks=function(){return E||[]},this.getCurrentAudioTrack=function(){return A}}Object(n.g)(X.prototype,f.a),X.getName=function(){return{name:"html5"}};t.default=X;var K=220001},,,,,,,,,,,,,,,,,,,,,,,,,,function(e,t,i){"use strict";i.d(t,"a",(function(){return o}));var n=i(2);function o(e){var t=[],i=(e=Object(n.i)(e)).split("\r\n\r\n");1===i.length&&(i=e.split("\n\n"));for(var o=0;o0&&(o=0),i.length>o+1&&i[o+1]){var a=i[o],r=a.indexOf(" --\x3e ");r>0&&(t.begin=Object(n.g)(a.substr(0,r)),t.end=Object(n.g)(a.substr(r+5)),t.text=i.slice(o+1).join("\r\n"))}return t}},function(e,t,i){"use strict";i.d(t,"a",(function(){return o})),i.d(t,"b",(function(){return a}));var n=i(5);function o(e){var t=-1;return e>=1280?t=7:e>=960?t=6:e>=800?t=5:e>=640?t=4:e>=540?t=3:e>=420?t=2:e>=320?t=1:e>=250&&(t=0),t}function a(e,t){var i="jw-breakpoint-"+t;Object(n.p)(e,/jw-breakpoint--?\d+/,i)}},function(e,t,i){"use strict";i.d(t,"a",(function(){return d}));var n,o=i(0),a=i(8),r=i(16),s=i(7),l=i(3),c=i(10),u=i(5),d={back:!0,backgroundOpacity:50,edgeStyle:null,fontSize:14,fontOpacity:100,fontScale:.05,preprocessor:o.k,windowOpacity:0},p=function(e){var t,s,p,w,h,f,g,j,b,m=this,v=e.player;function y(){Object(o.o)(t.fontSize)&&(v.get("containerHeight")?j=d.fontScale*(t.userFontScale||1)*t.fontSize/d.fontSize:v.once("change:containerHeight",y,this))}function k(){var e=v.get("containerHeight");if(e){var t;if(v.get("fullscreen")&&a.OS.iOS)t=null;else{var i=e*j;t=Math.round(10*function(e){var t=v.get("mediaElement");if(t&&t.videoHeight){var i=t.videoWidth,n=t.videoHeight,o=i/n,r=v.get("containerHeight"),s=v.get("containerWidth");if(v.get("fullscreen")&&a.OS.mobile){var l=window.screen;l.orientation&&(r=l.availHeight,s=l.availWidth)}if(s&&r&&i&&n)return(s/r>o?r:n*s/i)*j}return e}(i))/10}v.get("renderCaptionsNatively")?function(e,t){var i="#".concat(e," .jw-video::-webkit-media-text-track-display");t&&(t+="px",a.OS.iOS&&Object(c.b)(i,{fontSize:"inherit"},e,!0));b.fontSize=t,Object(c.b)(i,b,e,!0)}(v.get("id"),t):Object(c.d)(h,{fontSize:t})}}function x(e,t,i){var n=Object(c.c)("#000000",i);"dropshadow"===e?t.textShadow="0 2px 1px "+n:"raised"===e?t.textShadow="0 0 5px "+n+", 0 1px 5px "+n+", 0 2px 5px "+n:"depressed"===e?t.textShadow="0 -2px 1px "+n:"uniform"===e&&(t.textShadow="-2px 0 1px "+n+",2px 0 1px "+n+",0 -2px 1px "+n+",0 2px 1px "+n+",-1px 1px 1px "+n+",1px 1px 1px "+n+",1px -1px 1px "+n+",1px 1px 1px "+n)}(h=document.createElement("div")).className="jw-captions jw-reset",this.show=function(){Object(u.a)(h,"jw-captions-enabled")},this.hide=function(){Object(u.o)(h,"jw-captions-enabled")},this.populate=function(e){v.get("renderCaptionsNatively")||(p=[],s=e,e?this.selectCues(e,w):this.renderCues())},this.resize=function(){k(),this.renderCues(!0)},this.renderCues=function(e){e=!!e,n&&n.processCues(window,p,h,e)},this.selectCues=function(e,t){if(e&&e.data&&t&&!v.get("renderCaptionsNatively")){var i=this.getAlignmentPosition(e,t);!1!==i&&(p=this.getCurrentCues(e.data,i),this.renderCues(!0))}},this.getCurrentCues=function(e,t){return Object(o.h)(e,(function(e){return t>=e.startTime&&(!e.endTime||t<=e.endTime)}))},this.getAlignmentPosition=function(e,t){var i=e.source,n=t.metadata,a=t.currentTime;return i&&n&&Object(o.r)(n[i])&&(a=n[i]),a},this.clear=function(){Object(u.g)(h)},this.setup=function(e,i){f=document.createElement("div"),g=document.createElement("span"),f.className="jw-captions-window jw-reset",g.className="jw-captions-text jw-reset",t=Object(o.g)({},d,i),j=d.fontScale;var n=function(){if(!v.get("renderCaptionsNatively")){y(t.fontSize);var i=t.windowColor,n=t.windowOpacity,o=t.edgeStyle;b={};var r={};!function(e,t){var i=t.color,n=t.fontOpacity;(i||n!==d.fontOpacity)&&(e.color=Object(c.c)(i||"#ffffff",n));if(t.back){var o=t.backgroundColor,a=t.backgroundOpacity;o===d.backgroundColor&&a===d.backgroundOpacity||(e.backgroundColor=Object(c.c)(o,a))}else e.background="transparent";t.fontFamily&&(e.fontFamily=t.fontFamily);t.fontStyle&&(e.fontStyle=t.fontStyle);t.fontWeight&&(e.fontWeight=t.fontWeight);t.textDecoration&&(e.textDecoration=t.textDecoration)}(r,t),(i||n!==d.windowOpacity)&&(b.backgroundColor=Object(c.c)(i||"#000000",n)),x(o,r,t.fontOpacity),t.back||null!==o||x("uniform",r),Object(c.d)(f,b),Object(c.d)(g,r),function(e,t){k(),function(e,t){a.Browser.safari&&Object(c.b)("#"+e+" .jw-video::-webkit-media-text-track-display-backdrop",{backgroundColor:t.backgroundColor},e,!0);Object(c.b)("#"+e+" .jw-video::-webkit-media-text-track-display",b,e,!0),Object(c.b)("#"+e+" .jw-video::cue",t,e,!0)}(e,t),function(e,t){Object(c.b)("#"+e+" .jw-text-track-display",b,e),Object(c.b)("#"+e+" .jw-text-track-cue",t,e)}(e,t)}(e,r)}};n(),f.appendChild(g),h.appendChild(f),v.change("captionsTrack",(function(e,t){this.populate(t)}),this),v.set("captions",t),v.on("change:captions",(function(e,i){t=i,n()}))},this.element=function(){return h},this.destroy=function(){v.off(null,null,this),this.off()};var T=function(e){w=e,m.selectCues(s,w)};v.on("change:playlistItem",(function(){w=null,p=[]}),this),v.on(l.Q,(function(e){p=[],T(e)}),this),v.on(l.S,T,this),v.on("subtitlesTrackData",(function(){this.selectCues(s,w)}),this),v.on("change:captionsList",(function e(t,o){var a=this;1!==o.length&&(t.get("renderCaptionsNatively")||n||(i.e(8).then(function(e){n=i(68).default}.bind(null,i)).catch(Object(r.c)(301121)).catch((function(e){a.trigger(l.tb,e)})),t.off("change:captionsList",e,this)))}),this)};Object(o.g)(p.prototype,s.a),t.b=p},function(e,t,i){"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var i=function(e,t){var i=e[1]||"",n=e[3];if(!n)return i;if(t&&"function"==typeof btoa){var o=(r=n,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */"),a=n.sources.map((function(e){return"/*# sourceURL="+n.sourceRoot+e+" */"}));return[i].concat(a).concat([o]).join("\n")}var r;return[i].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+i+"}":i})).join("")},t.i=function(e,i){"string"==typeof e&&(e=[[null,e,""]]);for(var n={},o=0;o'},function(e,t,i){"use strict";function n(e,t){var i=e.kind||"cc";return e.default||e.defaulttrack?"default":e._id||e.file||i+t}function o(e,t){var i=e.label||e.name||e.language;return i||(i="Unknown CC",(t+=1)>1&&(i+=" ["+t+"]")),{label:i,unknownCount:t}}i.d(t,"a",(function(){return n})),i.d(t,"b",(function(){return o}))},function(e,t,i){"use strict";function n(e){return new Promise((function(t,i){if(e.paused)return i(o("NotAllowedError",0,"play() failed."));var n=function(){e.removeEventListener("play",a),e.removeEventListener("playing",r),e.removeEventListener("pause",r),e.removeEventListener("abort",r),e.removeEventListener("error",r)},a=function(){e.addEventListener("playing",r),e.addEventListener("abort",r),e.addEventListener("error",r),e.addEventListener("pause",r)},r=function(e){if(n(),"playing"===e.type)t();else{var a='The play() request was interrupted by a "'.concat(e.type,'" event.');"error"===e.type?i(o("NotSupportedError",9,a)):i(o("AbortError",20,a))}};e.addEventListener("play",a)}))}function o(e,t,i){var n=new Error(i);return n.name=e,n.code=t,n}i.d(t,"a",(function(){return n}))},function(e,t,i){"use strict";function n(e,t){return e!==1/0&&Math.abs(e)>=Math.max(a(t),0)}function o(e,t){var i="VOD";return e===1/0?i="LIVE":e<0&&(i=n(e,a(t))?"DVR":"LIVE"),i}function a(e){return void 0===e?120:Math.max(e,0)}i.d(t,"a",(function(){return n})),i.d(t,"b",(function(){return o}))},function(e,t,i){"use strict";var n=i(67),o=i(16),a=i(22),r=i(4),s=i(57),l=i(2),c=i(1);function u(e){throw new c.n(null,e)}function d(e,t,n){e.xhr=Object(a.a)(e.file,(function(a){!function(e,t,n,a){var d,p,h=e.responseXML?e.responseXML.firstChild:null;if(h)for("xml"===Object(r.b)(h)&&(h=h.nextSibling);h.nodeType===h.COMMENT_NODE;)h=h.nextSibling;try{if(h&&"tt"===Object(r.b)(h))d=function(e){e||u(306007);var t=[],i=e.getElementsByTagName("p"),n=30,o=e.getElementsByTagName("tt");if(o&&o[0]){var a=parseFloat(o[0].getAttribute("ttp:frameRate"));isNaN(a)||(n=a)}i||u(306005),i.length||(i=e.getElementsByTagName("tt:p")).length||(i=e.getElementsByTagName("tts:p"));for(var r=0;r\s+<").replace(/(<\/?)tts?:/g,"$1").replace(//g,"\r\n");if(h){var f=s.getAttribute("begin"),g=s.getAttribute("dur"),j=s.getAttribute("end"),b={begin:Object(l.g)(f,n),text:h};j?b.end=Object(l.g)(j,n):g&&(b.end=b.begin+Object(l.g)(g,n)),t.push(b)}}return t.length||u(306005),t}(e.responseXML),p=w(d),delete t.xhr,n(p);else{var f=e.responseText;f.indexOf("WEBVTT")>=0?i.e(10).then(function(e){return i(97).default}.bind(null,i)).catch(Object(o.c)(301131)).then((function(e){var i=new e(window);p=[],i.oncue=function(e){p.push(e)},i.onflush=function(){delete t.xhr,n(p)},i.parse(f)})).catch((function(e){delete t.xhr,a(Object(c.v)(null,c.b,e))})):(d=Object(s.a)(f),p=w(d),delete t.xhr,n(p))}}catch(e){delete t.xhr,a(Object(c.v)(null,c.b,e))}}(a,e,t,n)}),(function(e,t,i,o){n(Object(c.u)(o,c.b))}))}function p(e){e&&e.forEach((function(e){var t=e.xhr;t&&(t.onload=null,t.onreadystatechange=null,t.onerror=null,"abort"in t&&t.abort()),delete e.xhr}))}function w(e){return e.map((function(e){return new n.a(e.begin,e.end,e.text)}))}i.d(t,"c",(function(){return d})),i.d(t,"a",(function(){return p})),i.d(t,"b",(function(){return w}))},function(e,t,i){"use strict";var n=window.VTTCue;function o(e){if("string"!=typeof e)return!1;return!!{start:!0,middle:!0,end:!0,left:!0,right:!0}[e.toLowerCase()]&&e.toLowerCase()}if(!n){(n=function(e,t,i){var n=this;n.hasBeenReset=!1;var a="",r=!1,s=e,l=t,c=i,u=null,d="",p=!0,w="auto",h="start",f="auto",g=100,j="middle";Object.defineProperty(n,"id",{enumerable:!0,get:function(){return a},set:function(e){a=""+e}}),Object.defineProperty(n,"pauseOnExit",{enumerable:!0,get:function(){return r},set:function(e){r=!!e}}),Object.defineProperty(n,"startTime",{enumerable:!0,get:function(){return s},set:function(e){if("number"!=typeof e)throw new TypeError("Start time must be set to a number.");s=e,this.hasBeenReset=!0}}),Object.defineProperty(n,"endTime",{enumerable:!0,get:function(){return l},set:function(e){if("number"!=typeof e)throw new TypeError("End time must be set to a number.");l=e,this.hasBeenReset=!0}}),Object.defineProperty(n,"text",{enumerable:!0,get:function(){return c},set:function(e){c=""+e,this.hasBeenReset=!0}}),Object.defineProperty(n,"region",{enumerable:!0,get:function(){return u},set:function(e){u=e,this.hasBeenReset=!0}}),Object.defineProperty(n,"vertical",{enumerable:!0,get:function(){return d},set:function(e){var t=function(e){return"string"==typeof e&&(!!{"":!0,lr:!0,rl:!0}[e.toLowerCase()]&&e.toLowerCase())}(e);if(!1===t)throw new SyntaxError("An invalid or illegal string was specified.");d=t,this.hasBeenReset=!0}}),Object.defineProperty(n,"snapToLines",{enumerable:!0,get:function(){return p},set:function(e){p=!!e,this.hasBeenReset=!0}}),Object.defineProperty(n,"line",{enumerable:!0,get:function(){return w},set:function(e){if("number"!=typeof e&&"auto"!==e)throw new SyntaxError("An invalid number or illegal string was specified.");w=e,this.hasBeenReset=!0}}),Object.defineProperty(n,"lineAlign",{enumerable:!0,get:function(){return h},set:function(e){var t=o(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");h=t,this.hasBeenReset=!0}}),Object.defineProperty(n,"position",{enumerable:!0,get:function(){return f},set:function(e){if(e<0||e>100)throw new Error("Position must be between 0 and 100.");f=e,this.hasBeenReset=!0}}),Object.defineProperty(n,"size",{enumerable:!0,get:function(){return g},set:function(e){if(e<0||e>100)throw new Error("Size must be between 0 and 100.");g=e,this.hasBeenReset=!0}}),Object.defineProperty(n,"align",{enumerable:!0,get:function(){return j},set:function(e){var t=o(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");j=t,this.hasBeenReset=!0}}),n.displayState=void 0}).prototype.getCueAsHTML=function(){return window.WebVTT.convertCueToDOMTree(window,this.text)}}t.a=n},,function(e,t,i){var n=i(70);"string"==typeof n&&(n=[["all-players",n,""]]),i(61).style(n,"all-players"),n.locals&&(e.exports=n.locals)},function(e,t,i){(e.exports=i(60)(!1)).push([e.i,'.jw-reset{text-align:left;direction:ltr}.jw-reset-text,.jw-reset{color:inherit;background-color:transparent;padding:0;margin:0;float:none;font-family:Arial,Helvetica,sans-serif;font-size:1em;line-height:1em;list-style:none;text-transform:none;vertical-align:baseline;border:0;font-variant:inherit;font-stretch:inherit;-webkit-tap-highlight-color:rgba(255,255,255,0)}body .jw-error,body .jwplayer.jw-state-error{height:100%;width:100%}.jw-title{position:absolute;top:0}.jw-background-color{background:rgba(0,0,0,0.4)}.jw-text{color:rgba(255,255,255,0.8)}.jw-knob{color:rgba(255,255,255,0.8);background-color:#fff}.jw-button-color{color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):focus,:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):hover{color:#fff}.jw-toggle{color:#fff}.jw-toggle.jw-off{color:rgba(255,255,255,0.8)}.jw-toggle.jw-off:focus{color:#fff}.jw-toggle:focus{outline:none}:not(.jw-flag-touch) .jw-toggle.jw-off:hover{color:#fff}.jw-rail{background:rgba(255,255,255,0.3)}.jw-buffer{background:rgba(255,255,255,0.3)}.jw-progress{background:#f2f2f2}.jw-time-tip,.jw-volume-tip{border:0}.jw-slider-volume.jw-volume-tip.jw-background-color.jw-slider-vertical{background:none}.jw-skip{padding:.5em;outline:none}.jw-skip .jw-skiptext,.jw-skip .jw-skip-icon{color:rgba(255,255,255,0.8)}.jw-skip.jw-skippable:hover .jw-skip-icon,.jw-skip.jw-skippable:focus .jw-skip-icon{color:#fff}.jw-icon-cast google-cast-launcher{--connected-color:#fff;--disconnected-color:rgba(255,255,255,0.8)}.jw-icon-cast google-cast-launcher:focus{outline:none}.jw-icon-cast google-cast-launcher.jw-off{--connected-color:rgba(255,255,255,0.8)}.jw-icon-cast:focus google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-icon-cast:hover google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-nextup-container{bottom:2.5em;padding:5px .5em}.jw-nextup{border-radius:0}.jw-color-active{color:#fff;stroke:#fff;border-color:#fff}:not(.jw-flag-touch) .jw-color-active-hover:hover,:not(.jw-flag-touch) .jw-color-active-hover:focus{color:#fff;stroke:#fff;border-color:#fff}.jw-color-inactive{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-color-inactive-hover:hover{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}.jw-option{color:rgba(255,255,255,0.8)}.jw-option.jw-active-option{color:#fff;background-color:rgba(255,255,255,0.1)}:not(.jw-flag-touch) .jw-option:hover{color:#fff}.jwplayer{width:100%;font-size:16px;position:relative;display:block;min-height:0;overflow:hidden;box-sizing:border-box;font-family:Arial,Helvetica,sans-serif;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:none}.jwplayer *{box-sizing:inherit}.jwplayer.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jwplayer.jw-flag-aspect-mode{height:auto !important}.jwplayer.jw-flag-aspect-mode .jw-aspect{display:block}.jwplayer .jw-aspect{display:none}.jwplayer .jw-swf{outline:none}.jw-media,.jw-preview{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}.jw-media{overflow:hidden;cursor:pointer}.jw-plugin{position:absolute;bottom:66px}.jw-breakpoint-7 .jw-plugin{bottom:132px}.jw-plugin .jw-banner{max-width:100%;opacity:0;cursor:pointer;position:absolute;margin:auto auto 0;left:0;right:0;bottom:0;display:block}.jw-preview,.jw-captions,.jw-title{pointer-events:none}.jw-media,.jw-logo{pointer-events:all}.jw-wrapper{background-color:#000;position:absolute;top:0;left:0;right:0;bottom:0}.jw-hidden-accessibility{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.jw-contract-trigger::before{content:"";overflow:hidden;width:200%;height:200%;display:block;position:absolute;top:0;left:0}.jwplayer .jw-media video{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;margin:auto;background:transparent}.jwplayer .jw-media video::-webkit-media-controls-start-playback-button{display:none}.jwplayer.jw-stretch-uniform .jw-media video{object-fit:contain}.jwplayer.jw-stretch-none .jw-media video{object-fit:none}.jwplayer.jw-stretch-fill .jw-media video{object-fit:cover}.jwplayer.jw-stretch-exactfit .jw-media video{object-fit:fill}.jw-preview{position:absolute;display:none;opacity:1;visibility:visible;width:100%;height:100%;background:#000 no-repeat 50% 50%}.jwplayer .jw-preview,.jw-error .jw-preview{background-size:contain}.jw-stretch-none .jw-preview{background-size:auto auto}.jw-stretch-fill .jw-preview{background-size:cover}.jw-stretch-exactfit .jw-preview{background-size:100% 100%}.jw-title{display:none;padding-top:20px;width:100%;z-index:1}.jw-title-primary,.jw-title-secondary{color:#fff;padding-left:20px;padding-right:20px;padding-bottom:.5em;overflow:hidden;text-overflow:ellipsis;direction:unset;white-space:nowrap;width:100%}.jw-title-primary{font-size:1.625em}.jw-breakpoint-2 .jw-title-primary,.jw-breakpoint-3 .jw-title-primary{font-size:1.5em}.jw-flag-small-player .jw-title-primary{font-size:1.25em}.jw-flag-small-player .jw-title-secondary,.jw-title-secondary:empty{display:none}.jw-captions{position:absolute;width:100%;height:100%;text-align:center;display:none;letter-spacing:normal;word-spacing:normal;text-transform:none;text-indent:0;text-decoration:none;pointer-events:none;overflow:hidden;top:0}.jw-captions.jw-captions-enabled{display:block}.jw-captions-window{display:none;padding:.25em;border-radius:.25em}.jw-captions-window.jw-captions-window-active{display:inline-block}.jw-captions-text{display:inline-block;color:#fff;background-color:#000;word-wrap:normal;word-break:normal;white-space:pre-line;font-style:normal;font-weight:normal;text-align:center;text-decoration:none}.jw-text-track-display{font-size:inherit;line-height:1.5}.jw-text-track-cue{background-color:rgba(0,0,0,0.5);color:#fff;padding:.1em .3em}.jwplayer video::-webkit-media-controls{display:none;justify-content:flex-start}.jwplayer video::-webkit-media-text-track-display{min-width:-webkit-min-content}.jwplayer video::cue{background-color:rgba(0,0,0,0.5)}.jwplayer video::-webkit-media-controls-panel-container{display:none}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing) .jw-captions,.jwplayer.jw-flag-media-audio.jw-state-playing .jw-captions,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden) .jw-captions{max-height:calc(100% - 60px)}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-flag-media-audio.jw-state-playing:not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container{max-height:calc(100% - 60px)}.jw-logo{position:absolute;margin:20px;cursor:pointer;pointer-events:all;background-repeat:no-repeat;background-size:contain;top:auto;right:auto;left:auto;bottom:auto;outline:none}.jw-logo.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-flag-audio-player .jw-logo{display:none}.jw-logo-top-right{top:0;right:0}.jw-logo-top-left{top:0;left:0}.jw-logo-bottom-left{left:0}.jw-logo-bottom-right{right:0}.jw-logo-bottom-left,.jw-logo-bottom-right{bottom:44px;transition:bottom 150ms cubic-bezier(0, .25, .25, 1)}.jw-state-idle .jw-logo{z-index:1}.jw-state-setup .jw-wrapper{background-color:inherit}.jw-state-setup .jw-logo,.jw-state-setup .jw-controls,.jw-state-setup .jw-controls-backdrop{visibility:hidden}span.jw-break{display:block}body .jw-error,body .jwplayer.jw-state-error{background-color:#333;color:#fff;font-size:16px;display:table;opacity:1;position:relative}body .jw-error .jw-display,body .jwplayer.jw-state-error .jw-display{display:none}body .jw-error .jw-media,body .jwplayer.jw-state-error .jw-media{cursor:default}body .jw-error .jw-preview,body .jwplayer.jw-state-error .jw-preview{background-color:#333}body .jw-error .jw-error-msg,body .jwplayer.jw-state-error .jw-error-msg{background-color:#000;border-radius:2px;display:flex;flex-direction:row;align-items:stretch;padding:20px}body .jw-error .jw-error-msg .jw-icon,body .jwplayer.jw-state-error .jw-error-msg .jw-icon{height:30px;width:30px;margin-right:20px;flex:0 0 auto;align-self:center}body .jw-error .jw-error-msg .jw-icon:empty,body .jwplayer.jw-state-error .jw-error-msg .jw-icon:empty{display:none}body .jw-error .jw-error-msg .jw-info-container,body .jwplayer.jw-state-error .jw-error-msg .jw-info-container{margin:0;padding:0}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg{flex-direction:column}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text{text-align:center}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon{flex:.5 0 auto;margin-right:0;margin-bottom:20px}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break{display:inline}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break:before{content:" "}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg{height:100%;width:100%;top:0;position:absolute;left:0;background:#000;-webkit-transform:none;transform:none;padding:4px 16px;z-index:1}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg.jw-info-overlay{max-width:none;max-height:none}body .jwplayer.jw-state-error .jw-title,.jw-state-idle .jw-title,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-title{display:block}body .jwplayer.jw-state-error .jw-preview,.jw-state-idle .jw-preview,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-preview{display:block}.jw-state-idle .jw-captions,.jwplayer.jw-state-complete .jw-captions,body .jwplayer.jw-state-error .jw-captions{display:none}.jw-state-idle video::-webkit-media-text-track-container,.jwplayer.jw-state-complete video::-webkit-media-text-track-container,body .jwplayer.jw-state-error video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-fullscreen{width:100% !important;height:100% !important;top:0;right:0;bottom:0;left:0;z-index:1000;margin:0;position:fixed}body .jwplayer.jw-flag-flash-blocked .jw-title{display:block}.jwplayer.jw-flag-controls-hidden .jw-media{cursor:default}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:45px}.jw-flag-floating{background-size:cover;background-color:#000}.jw-flag-floating .jw-wrapper{position:fixed;z-index:2147483647;-webkit-animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;top:auto;bottom:1rem;left:auto;right:1rem;max-width:400px;max-height:400px;margin:0 auto}@media screen and (max-width:480px){.jw-flag-floating .jw-wrapper{width:100%;left:0;right:0}}.jw-flag-floating .jw-wrapper .jw-media{touch-action:none}@media screen and (max-device-width:480px) and (orientation:portrait){.jw-flag-touch.jw-flag-floating .jw-wrapper{-webkit-animation:none;animation:none;top:62px;bottom:auto;left:0;right:0;max-width:none;max-height:none}}.jw-flag-floating .jw-float-icon{pointer-events:all;cursor:pointer;display:none}.jw-flag-floating .jw-float-icon .jw-svg-icon{-webkit-filter:drop-shadow(0 0 1px #000);filter:drop-shadow(0 0 1px #000)}.jw-flag-floating.jw-floating-dismissible .jw-dismiss-icon{display:none}.jw-flag-floating.jw-floating-dismissible.jw-flag-ads .jw-float-icon{display:flex}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-logo,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-logo{display:none}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-float-icon,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-float-icon{display:flex}.jw-float-icon{display:none;position:absolute;top:3px;right:5px;align-items:center;justify-content:center}@-webkit-keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}.jw-flag-top{margin-top:2em;overflow:visible}.jw-top{height:2em;line-height:2;pointer-events:none;text-align:center;opacity:.8;position:absolute;top:-2em;width:100%}.jw-top .jw-icon{cursor:pointer;pointer-events:all;height:auto;width:auto}.jw-top .jw-text{color:#555}',""])},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t,i){var n=i(96);"string"==typeof n&&(n=[["all-players",n,""]]),i(61).style(n,"all-players"),n.locals&&(e.exports=n.locals)},function(e,t,i){(e.exports=i(60)(!1)).push([e.i,'.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-flag-small-player .jw-settings-menu,.jw-settings-submenu{height:100%;width:100%}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;right:0}.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-settings-item-active::before{top:0;position:absolute;left:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;bottom:0;left:0}.jw-nextup-close{position:absolute;top:0;right:0}.jw-overlays,.jw-controls,.jw-flag-small-player .jw-settings-menu{position:absolute;bottom:0;right:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-time-tip::after,.jw-settings-menu .jw-icon.jw-button-color::after,.jw-text-live::before,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{content:"";display:block}.jw-svg-icon{height:24px;width:24px;fill:currentColor;pointer-events:none}.jw-icon{height:44px;width:44px;background-color:transparent;outline:none}.jw-icon.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-icon-airplay .jw-svg-icon-airplay-off{display:none}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-off{display:block}.jw-icon-airplay .jw-svg-icon-airplay-on{display:block}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-on{display:none}.jw-icon-cc .jw-svg-icon-cc-off{display:none}.jw-off.jw-icon-cc .jw-svg-icon-cc-off{display:block}.jw-icon-cc .jw-svg-icon-cc-on{display:block}.jw-off.jw-icon-cc .jw-svg-icon-cc-on{display:none}.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:none}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:block}.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:block}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:none}.jw-icon-volume .jw-svg-icon-volume-0{display:none}.jw-off.jw-icon-volume .jw-svg-icon-volume-0{display:block}.jw-icon-volume .jw-svg-icon-volume-100{display:none}.jw-full.jw-icon-volume .jw-svg-icon-volume-100{display:block}.jw-icon-volume .jw-svg-icon-volume-50{display:block}.jw-off.jw-icon-volume .jw-svg-icon-volume-50,.jw-full.jw-icon-volume .jw-svg-icon-volume-50{display:none}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon[aria-checked="true"]::after,.jw-settings-open .jw-icon-settings::after,.jw-icon-volume.jw-open::after{opacity:1}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-cc,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-settings,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-audio-tracks,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-hd,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-settings-sharing,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-fullscreen,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-airplay,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-cast{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-text-live{bottom:6px}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume::after{display:none}.jw-overlays,.jw-controls{pointer-events:none}.jw-controls-backdrop{display:block;background:linear-gradient(to bottom, transparent, rgba(0,0,0,0.4) 77%, rgba(0,0,0,0.4) 100%) 100% 100% / 100% 240px no-repeat transparent;transition:opacity 250ms cubic-bezier(0, .25, .25, 1),background-size 250ms cubic-bezier(0, .25, .25, 1);pointer-events:none}.jw-overlays{cursor:auto}.jw-controls{overflow:hidden}.jw-flag-small-player .jw-controls{text-align:center}.jw-text{height:1em;font-family:Arial,Helvetica,sans-serif;font-size:.75em;font-style:normal;font-weight:normal;color:#fff;text-align:center;font-variant:normal;font-stretch:normal}.jw-controlbar,.jw-skip,.jw-display-icon-container .jw-icon,.jw-nextup-container,.jw-autostart-mute,.jw-overlays .jw-plugin{pointer-events:all}.jwplayer .jw-display-icon-container,.jw-error .jw-display-icon-container{width:auto;height:auto;box-sizing:content-box}.jw-display{display:table;height:100%;padding:57px 0;position:relative;width:100%}.jw-flag-dragging .jw-display{display:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-display-container{display:table-cell;height:100%;text-align:center;vertical-align:middle}.jw-display-controls{display:inline-block}.jwplayer .jw-display-icon-container{float:left}.jw-display-icon-container{display:inline-block;padding:5.5px;margin:0 22px}.jw-display-icon-container .jw-icon{height:75px;width:75px;cursor:pointer;display:flex;justify-content:center;align-items:center}.jw-display-icon-container .jw-icon .jw-svg-icon{height:33px;width:33px;padding:0;position:relative}.jw-display-icon-container .jw-icon .jw-svg-icon-rewind{padding:.2em .05em}.jw-breakpoint--1 .jw-nextup-container{display:none}.jw-breakpoint-0 .jw-display-icon-next,.jw-breakpoint--1 .jw-display-icon-next,.jw-breakpoint-0 .jw-display-icon-rewind,.jw-breakpoint--1 .jw-display-icon-rewind{display:none}.jw-breakpoint-0 .jw-display .jw-icon,.jw-breakpoint--1 .jw-display .jw-icon,.jw-breakpoint-0 .jw-display .jw-svg-icon,.jw-breakpoint--1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-0 .jw-display .jw-icon:before,.jw-breakpoint--1 .jw-display .jw-icon:before,.jw-breakpoint-0 .jw-display .jw-svg-icon:before,.jw-breakpoint--1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon,.jw-breakpoint-1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-1 .jw-display .jw-icon:before,.jw-breakpoint-1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon.jw-icon-rewind:before{width:33px;height:33px}.jw-breakpoint-2 .jw-display .jw-icon,.jw-breakpoint-3 .jw-display .jw-icon,.jw-breakpoint-2 .jw-display .jw-svg-icon,.jw-breakpoint-3 .jw-display .jw-svg-icon{width:77px;height:77px;line-height:77px}.jw-breakpoint-2 .jw-display .jw-icon:before,.jw-breakpoint-3 .jw-display .jw-icon:before,.jw-breakpoint-2 .jw-display .jw-svg-icon:before,.jw-breakpoint-3 .jw-display .jw-svg-icon:before{width:38.5px;height:38.5px}.jw-breakpoint-4 .jw-display .jw-icon,.jw-breakpoint-5 .jw-display .jw-icon,.jw-breakpoint-6 .jw-display .jw-icon,.jw-breakpoint-7 .jw-display .jw-icon,.jw-breakpoint-4 .jw-display .jw-svg-icon,.jw-breakpoint-5 .jw-display .jw-svg-icon,.jw-breakpoint-6 .jw-display .jw-svg-icon,.jw-breakpoint-7 .jw-display .jw-svg-icon{width:88px;height:88px;line-height:88px}.jw-breakpoint-4 .jw-display .jw-icon:before,.jw-breakpoint-5 .jw-display .jw-icon:before,.jw-breakpoint-6 .jw-display .jw-icon:before,.jw-breakpoint-7 .jw-display .jw-icon:before,.jw-breakpoint-4 .jw-display .jw-svg-icon:before,.jw-breakpoint-5 .jw-display .jw-svg-icon:before,.jw-breakpoint-6 .jw-display .jw-svg-icon:before,.jw-breakpoint-7 .jw-display .jw-svg-icon:before{width:44px;height:44px}.jw-controlbar{display:flex;flex-flow:row wrap;align-items:center;justify-content:center;position:absolute;left:0;bottom:0;width:100%;border:none;border-radius:0;background-size:auto;box-shadow:none;max-height:72px;transition:250ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s}.jw-breakpoint-7 .jw-controlbar{max-height:140px}.jw-breakpoint-7 .jw-controlbar .jw-button-container{padding:0 48px 20px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-tooltip{margin-bottom:-7px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-overlay{padding-bottom:40%}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text{font-size:1em}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text.jw-text-elapsed{justify-content:flex-end}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume{height:60px;width:60px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline .jw-svg-icon,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time{padding:0 60px;height:34px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time .jw-slider-container{height:10px}.jw-controlbar .jw-button-image{background:no-repeat 50% 50%;background-size:contain;max-height:24px}.jw-controlbar .jw-spacer{flex:1 1 auto;align-self:stretch}.jw-controlbar .jw-icon.jw-button-color:hover{color:#fff}.jw-button-container{display:flex;flex-flow:row nowrap;flex:1 1 auto;align-items:center;justify-content:center;width:100%;padding:0 12px}.jw-slider-horizontal{background-color:transparent}.jw-icon-inline{position:relative}.jw-icon-inline,.jw-icon-tooltip{height:44px;width:44px;align-items:center;display:flex;justify-content:center}.jw-icon-inline:not(.jw-text),.jw-icon-tooltip,.jw-slider-horizontal{cursor:pointer}.jw-text-elapsed,.jw-text-duration{justify-content:flex-start;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.jw-icon-tooltip{position:relative}.jw-knob:hover,.jw-icon-inline:hover,.jw-icon-tooltip:hover,.jw-icon-display:hover,.jw-option:before:hover{color:#fff}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{pointer-events:none}.jw-icon-cast{display:none;margin:0;padding:0}.jw-icon-cast google-cast-launcher{background-color:transparent;border:none;padding:0;width:24px;height:24px;cursor:pointer}.jw-icon-inline.jw-icon-volume{display:none}.jwplayer .jw-text-countdown{display:none}.jw-flag-small-player .jw-display{padding-top:0;padding-bottom:0}.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-rewind,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-next,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-playback{display:none}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop{opacity:0}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-countdown{display:flex}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-duration,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-duration{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-text-countdown,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-related-btn,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-slider-volume{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-controlbar{flex-direction:column-reverse}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-button-container{height:30px}.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-volume,.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-fullscreen{display:none}.jwplayer:not(.jw-breakpoint-0) .jw-text-duration:before,.jwplayer:not(.jw-breakpoint--1) .jw-text-duration:before{content:"/";padding-right:1ch;padding-left:1ch}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar{will-change:transform}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar .jw-text{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.jw-slider-container{display:flex;align-items:center;position:relative;touch-action:none}.jw-rail,.jw-buffer,.jw-progress{position:absolute;cursor:pointer}.jw-progress{background-color:#f2f2f2}.jw-rail{background-color:rgba(255,255,255,0.3)}.jw-buffer{background-color:rgba(255,255,255,0.3)}.jw-knob{height:13px;width:13px;background-color:#fff;border-radius:50%;box-shadow:0 0 10px rgba(0,0,0,0.4);opacity:1;pointer-events:none;position:absolute;-webkit-transform:translate(-50%, -50%) scale(0);transform:translate(-50%, -50%) scale(0);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform}.jw-flag-dragging .jw-slider-time .jw-knob,.jw-icon-volume:active .jw-slider-volume .jw-knob{box-shadow:0 0 26px rgba(0,0,0,0.2),0 0 10px rgba(0,0,0,0.4),0 0 0 6px rgba(255,255,255,0.2)}.jw-slider-horizontal,.jw-slider-vertical{display:flex}.jw-slider-horizontal .jw-slider-container{height:5px;width:100%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue,.jw-slider-horizontal .jw-knob{top:50%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue{-webkit-transform:translate(0, -50%);transform:translate(0, -50%)}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress{height:5px}.jw-slider-horizontal .jw-rail{width:100%}.jw-slider-vertical{align-items:center;flex-direction:column}.jw-slider-vertical .jw-slider-container{height:88px;width:5px}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress,.jw-slider-vertical .jw-knob{left:50%}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress{height:100%;width:5px;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out;bottom:0}.jw-slider-vertical .jw-knob{-webkit-transform:translate(-50%, 50%);transform:translate(-50%, 50%)}.jw-slider-time.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-slider-time,.jw-flag-audio-player .jw-slider-volume{height:17px;width:100%;align-items:center;background:transparent none;padding:0 12px}.jw-slider-time .jw-cue{background-color:rgba(33,33,33,0.8);cursor:pointer;position:absolute;width:6px}.jw-slider-time,.jw-horizontal-volume-container{z-index:1;outline:none}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail,.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer,.jw-slider-time .jw-progress,.jw-horizontal-volume-container .jw-progress,.jw-slider-time .jw-cue,.jw-horizontal-volume-container .jw-cue{-webkit-backface-visibility:hidden;backface-visibility:hidden;height:100%;-webkit-transform:translate(0, -50%) scale(1, .6);transform:translate(0, -50%) scale(1, .6);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out}.jw-slider-time:hover .jw-rail,.jw-horizontal-volume-container:hover .jw-rail,.jw-slider-time:focus .jw-rail,.jw-horizontal-volume-container:focus .jw-rail,.jw-flag-dragging .jw-slider-time .jw-rail,.jw-flag-dragging .jw-horizontal-volume-container .jw-rail,.jw-flag-touch .jw-slider-time .jw-rail,.jw-flag-touch .jw-horizontal-volume-container .jw-rail,.jw-slider-time:hover .jw-buffer,.jw-horizontal-volume-container:hover .jw-buffer,.jw-slider-time:focus .jw-buffer,.jw-horizontal-volume-container:focus .jw-buffer,.jw-flag-dragging .jw-slider-time .jw-buffer,.jw-flag-dragging .jw-horizontal-volume-container .jw-buffer,.jw-flag-touch .jw-slider-time .jw-buffer,.jw-flag-touch .jw-horizontal-volume-container .jw-buffer,.jw-slider-time:hover .jw-progress,.jw-horizontal-volume-container:hover .jw-progress,.jw-slider-time:focus .jw-progress,.jw-horizontal-volume-container:focus .jw-progress,.jw-flag-dragging .jw-slider-time .jw-progress,.jw-flag-dragging .jw-horizontal-volume-container .jw-progress,.jw-flag-touch .jw-slider-time .jw-progress,.jw-flag-touch .jw-horizontal-volume-container .jw-progress,.jw-slider-time:hover .jw-cue,.jw-horizontal-volume-container:hover .jw-cue,.jw-slider-time:focus .jw-cue,.jw-horizontal-volume-container:focus .jw-cue,.jw-flag-dragging .jw-slider-time .jw-cue,.jw-flag-dragging .jw-horizontal-volume-container .jw-cue,.jw-flag-touch .jw-slider-time .jw-cue,.jw-flag-touch .jw-horizontal-volume-container .jw-cue{-webkit-transform:translate(0, -50%) scale(1, 1);transform:translate(0, -50%) scale(1, 1)}.jw-slider-time:hover .jw-knob,.jw-horizontal-volume-container:hover .jw-knob,.jw-slider-time:focus .jw-knob,.jw-horizontal-volume-container:focus .jw-knob{-webkit-transform:translate(-50%, -50%) scale(1);transform:translate(-50%, -50%) scale(1)}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail{background-color:rgba(255,255,255,0.2)}.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer{background-color:rgba(255,255,255,0.4)}.jw-flag-touch .jw-slider-time::before,.jw-flag-touch .jw-horizontal-volume-container::before{height:44px;width:100%;content:"";position:absolute;display:block;bottom:calc(100% - 17px);left:0}.jw-slider-time.jw-tab-focus:focus .jw-rail,.jw-horizontal-volume-container.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time{height:17px;padding:0}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-slider-container{height:10px}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-knob{border-radius:0;border:1px solid rgba(0,0,0,0.75);height:12px;width:10px}.jw-modal{width:284px}.jw-breakpoint-7 .jw-modal,.jw-breakpoint-6 .jw-modal,.jw-breakpoint-5 .jw-modal{height:232px}.jw-breakpoint-4 .jw-modal,.jw-breakpoint-3 .jw-modal{height:192px}.jw-breakpoint-2 .jw-modal,.jw-flag-small-player .jw-modal{bottom:0;right:0;height:100%;width:100%;max-height:none;max-width:none;z-index:2}.jwplayer .jw-rightclick{display:none;position:absolute;white-space:nowrap}.jwplayer .jw-rightclick.jw-open{display:block}.jwplayer .jw-rightclick .jw-rightclick-list{border-radius:1px;list-style:none;margin:0;padding:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item{background-color:rgba(0,0,0,0.8);border-bottom:1px solid #444;margin:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo{color:#fff;display:inline-flex;padding:0 10px 0 0;vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo .jw-svg-icon{height:20px;width:20px}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-link{border:none;color:#fff;display:block;font-size:11px;line-height:1em;padding:15px 23px;text-align:start;text-decoration:none;width:100%}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:last-child{border-bottom:none}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:hover{cursor:pointer}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured{vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link{color:#fff}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link span{color:#fff}.jwplayer .jw-rightclick .jw-info-overlay-item,.jwplayer .jw-rightclick .jw-share-item,.jwplayer .jw-rightclick .jw-shortcuts-item{border:none;background-color:transparent;outline:none;cursor:pointer}.jw-icon-tooltip.jw-open .jw-overlay{opacity:1;pointer-events:auto;transition-delay:0s}.jw-icon-tooltip.jw-open .jw-overlay:focus{outline:none}.jw-icon-tooltip.jw-open .jw-overlay:focus.jw-tab-focus{outline:solid 2px #4d90fe}.jw-slider-time .jw-overlay:before{height:1em;top:auto}.jw-slider-time .jw-icon-tooltip.jw-open .jw-overlay{pointer-events:none}.jw-volume-tip{padding:13px 0 26px}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{height:auto;width:100%;box-shadow:0 0 10px rgba(0,0,0,0.4);color:#fff;display:block;margin:0 0 14px;pointer-events:none;position:relative;z-index:0}.jw-time-tip::after,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{top:100%;position:absolute;left:50%;height:14px;width:14px;border-radius:1px;background-color:currentColor;-webkit-transform-origin:75% 50%;transform-origin:75% 50%;-webkit-transform:translate(-50%, -50%) rotate(45deg);transform:translate(-50%, -50%) rotate(45deg);z-index:-1}.jw-time-tip .jw-text,.jw-controlbar .jw-tooltip .jw-text,.jw-settings-menu .jw-tooltip .jw-text{background-color:#fff;border-radius:1px;color:#000;font-size:10px;height:auto;line-height:1;padding:7px 10px;display:inline-block;min-width:100%;vertical-align:middle}.jw-controlbar .jw-overlay{position:absolute;bottom:100%;left:50%;margin:0;min-height:44px;min-width:44px;opacity:0;pointer-events:none;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s, 150ms;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);width:100%;z-index:1}.jw-controlbar .jw-overlay .jw-contents{position:relative}.jw-controlbar .jw-option{position:relative;white-space:nowrap;cursor:pointer;list-style:none;height:1.5em;font-family:inherit;line-height:1.5em;padding:0 .5em;font-size:.8em;margin:0}.jw-controlbar .jw-option::before{padding-right:.125em}.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{position:absolute;bottom:100%;left:50%;opacity:0;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:100ms 0s cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility, -webkit-transform;transition-property:opacity, transform, visibility;transition-property:opacity, transform, visibility, -webkit-transform;visibility:hidden;white-space:nowrap;width:auto;z-index:1}.jw-controlbar .jw-tooltip.jw-open,.jw-settings-menu .jw-tooltip.jw-open{opacity:1;-webkit-transform:translate(-50%, -10px);transform:translate(-50%, -10px);transition-duration:150ms;transition-delay:500ms,0s,500ms;visibility:visible}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen{left:auto;right:0;-webkit-transform:translate(0, 0);transform:translate(0, 0)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen.jw-open,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen.jw-open{-webkit-transform:translate(0, -10px);transform:translate(0, -10px)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen::after,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen::after{left:auto;right:9px}.jw-tooltip-time{height:auto;width:0;bottom:100%;line-height:normal;padding:0;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.jw-tooltip-time .jw-overlay{bottom:0;min-height:0;width:auto}.jw-tooltip{bottom:57px;display:none;position:absolute}.jw-tooltip .jw-text{height:100%;white-space:nowrap;text-overflow:ellipsis;direction:unset;max-width:246px;overflow:hidden}.jw-flag-audio-player .jw-tooltip{display:none}.jw-flag-small-player .jw-time-thumb{display:none}.jwplayer .jw-shortcuts-tooltip{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column;z-index:1}.jwplayer .jw-shortcuts-tooltip.jw-open{display:flex}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-close{flex:0 0 auto;margin:5px 5px 5px auto}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container{display:flex;flex:1 1 auto;flex-flow:column;font-size:12px;margin:0 20px 20px;overflow-y:auto;padding:5px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar{background-color:transparent;width:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-title{font-weight:bold}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list{display:flex;max-width:340px;margin:0 10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-tooltip-descriptions{width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row{display:flex;align-items:center;justify-content:space-between;margin:10px 0;width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-description{margin-right:10px;max-width:70%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-key{background:#fefefe;color:#333;overflow:hidden;padding:7px 10px;text-overflow:ellipsis;white-space:nowrap}.jw-skip{color:rgba(255,255,255,0.8);cursor:default;position:absolute;display:flex;right:.75em;bottom:56px;padding:.5em;border:1px solid #333;background-color:#000;align-items:center;height:2em}.jw-skip.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-skip.jw-skippable{cursor:pointer;padding:.25em .75em}.jw-skip.jw-skippable:hover{cursor:pointer;color:#fff}.jw-skip.jw-skippable .jw-skip-icon{display:inline;height:24px;width:24px;margin:0}.jw-breakpoint-7 .jw-skip{padding:1.35em 1em;bottom:130px}.jw-breakpoint-7 .jw-skip .jw-text{font-size:1em;font-weight:normal}.jw-breakpoint-7 .jw-skip .jw-icon-inline{height:30px;width:30px}.jw-breakpoint-7 .jw-skip .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-skip .jw-skip-icon{display:none;margin-left:-0.75em;padding:0 .5em;pointer-events:none}.jw-skip .jw-skip-icon .jw-svg-icon-next{display:block;padding:0}.jw-skip .jw-text,.jw-skip .jw-skip-icon{vertical-align:middle;font-size:.7em}.jw-skip .jw-text{font-weight:bold}.jw-cast{background-size:cover;display:none;height:100%;position:relative;width:100%}.jw-cast-container{background:linear-gradient(180deg, rgba(25,25,25,0.75), rgba(25,25,25,0.25), rgba(25,25,25,0));left:0;padding:20px 20px 80px;position:absolute;top:0;width:100%}.jw-cast-text{color:#fff;font-size:1.6em}.jw-breakpoint--1 .jw-cast-text,.jw-breakpoint-0 .jw-cast-text{font-size:1.15em}.jw-breakpoint-1 .jw-cast-text,.jw-breakpoint-2 .jw-cast-text,.jw-breakpoint-3 .jw-cast-text{font-size:1.3em}.jw-nextup-container{position:absolute;bottom:66px;left:0;background-color:transparent;cursor:pointer;margin:0 auto;padding:12px;pointer-events:none;right:0;text-align:right;visibility:hidden;width:100%}.jw-settings-open .jw-nextup-container,.jw-info-open .jw-nextup-container{display:none}.jw-breakpoint-7 .jw-nextup-container{padding:60px}.jw-flag-small-player .jw-nextup-container{padding:0 12px 0 0}.jw-flag-small-player .jw-nextup-container .jw-nextup-title,.jw-flag-small-player .jw-nextup-container .jw-nextup-duration,.jw-flag-small-player .jw-nextup-container .jw-nextup-close{display:none}.jw-flag-small-player .jw-nextup-container .jw-nextup-tooltip{height:30px}.jw-flag-small-player .jw-nextup-container .jw-nextup-header{font-size:12px}.jw-flag-small-player .jw-nextup-container .jw-nextup-body{justify-content:center;align-items:center;padding:.75em .3em}.jw-flag-small-player .jw-nextup-container .jw-nextup-thumbnail{width:50%}.jw-flag-small-player .jw-nextup-container .jw-nextup{max-width:65px}.jw-flag-small-player .jw-nextup-container .jw-nextup.jw-nextup-thumbnail-visible{max-width:120px}.jw-nextup{background:#333;border-radius:0;box-shadow:0 0 10px rgba(0,0,0,0.5);color:rgba(255,255,255,0.8);display:inline-block;max-width:280px;overflow:hidden;opacity:0;position:relative;width:64%;pointer-events:all;-webkit-transform:translate(0, -5px);transform:translate(0, -5px);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform;transition-delay:0s}.jw-nextup:hover .jw-nextup-tooltip{color:#fff}.jw-nextup.jw-nextup-thumbnail-visible{max-width:400px}.jw-nextup.jw-nextup-thumbnail-visible .jw-nextup-thumbnail{display:block}.jw-nextup-container-visible{visibility:visible}.jw-nextup-container-visible .jw-nextup{opacity:1;-webkit-transform:translate(0, 0);transform:translate(0, 0);transition-delay:0s, 0s, 150ms}.jw-nextup-tooltip{display:flex;height:80px}.jw-nextup-thumbnail{width:120px;background-position:center;background-size:cover;flex:0 0 auto;display:none}.jw-nextup-body{flex:1 1 auto;overflow:hidden;padding:.75em .875em;display:flex;flex-flow:column wrap;justify-content:space-between}.jw-nextup-header,.jw-nextup-title{font-size:14px;line-height:1.35}.jw-nextup-header{font-weight:bold}.jw-nextup-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.jw-nextup-duration{align-self:flex-end;text-align:right;font-size:12px}.jw-nextup-close{height:24px;width:24px;border:none;color:rgba(255,255,255,0.8);cursor:pointer;margin:6px;visibility:hidden}.jw-nextup-close:hover{color:#fff}.jw-nextup-sticky .jw-nextup-close{visibility:visible}.jw-autostart-mute{position:absolute;bottom:0;right:12px;height:44px;width:44px;background-color:rgba(33,33,33,0.4);padding:5px 4px 5px 6px;display:none}.jwplayer.jw-flag-autostart:not(.jw-flag-media-audio) .jw-nextup{display:none}.jw-settings-menu{position:absolute;bottom:57px;right:12px;align-items:flex-start;background-color:#333;display:none;flex-flow:column nowrap;max-width:284px;pointer-events:auto}.jw-settings-open .jw-settings-menu{display:flex}.jw-breakpoint-7 .jw-settings-menu{bottom:130px;right:60px;max-height:none;max-width:none;height:35%;width:25%}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline{height:60px;width:60px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-tooltip .jw-text{font-size:1em}.jw-breakpoint-7 .jw-settings-menu .jw-settings-back{min-width:60px}.jw-breakpoint-6 .jw-settings-menu,.jw-breakpoint-5 .jw-settings-menu{height:232px;width:284px;max-height:232px}.jw-breakpoint-4 .jw-settings-menu,.jw-breakpoint-3 .jw-settings-menu{height:192px;width:284px;max-height:192px}.jw-breakpoint-2 .jw-settings-menu{height:179px;width:284px;max-height:179px}.jw-flag-small-player .jw-settings-menu{max-width:none}.jw-settings-menu .jw-icon.jw-button-color::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon.jw-button-color[aria-checked="true"]::after{opacity:1}.jw-settings-menu .jw-settings-reset{text-decoration:underline}.jw-settings-topbar{align-items:center;background-color:rgba(0,0,0,0.4);display:flex;flex:0 0 auto;padding:3px 5px 0;width:100%}.jw-settings-topbar.jw-nested-menu-open{padding:0}.jw-settings-topbar.jw-nested-menu-open .jw-icon:not(.jw-settings-close):not(.jw-settings-back){display:none}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-close{width:20px}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-arrow-left{height:12px}.jw-settings-topbar.jw-nested-menu-open .jw-settings-topbar-text{display:block;outline:none}.jw-settings-topbar .jw-settings-back{min-width:44px}.jw-settings-topbar .jw-settings-topbar-buttons{display:inherit;width:100%;height:100%}.jw-settings-topbar .jw-settings-topbar-text{display:none;color:#fff;font-size:13px;width:100%}.jw-settings-topbar .jw-settings-close{margin-left:auto}.jw-settings-submenu{display:none;flex:1 1 auto;overflow-y:auto;padding:8px 20px 0 5px}.jw-settings-submenu::-webkit-scrollbar{background-color:transparent;width:6px}.jw-settings-submenu::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-settings-submenu.jw-settings-submenu-active{display:block}.jw-settings-submenu .jw-submenu-topbar{box-shadow:0 2px 9px 0 #1d1d1d;background-color:#2f2d2d;margin:-8px -20px 0 -5px}.jw-settings-submenu .jw-submenu-topbar .jw-settings-content-item{cursor:pointer;text-align:right;padding-right:15px;text-decoration:underline}.jw-settings-submenu .jw-settings-value-wrapper{float:right;display:flex;align-items:center}.jw-settings-submenu .jw-settings-value-wrapper .jw-settings-content-item-arrow{display:flex}.jw-settings-submenu .jw-settings-value-wrapper .jw-svg-icon-arrow-right{width:8px;margin-left:5px;height:12px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item{font-size:1em;padding:11px 15px 11px 30px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-settings-item-active::before{justify-content:flex-end}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-auto-label{font-size:.85em;padding-left:10px}.jw-flag-touch .jw-settings-submenu{overflow-y:scroll;-webkit-overflow-scrolling:touch}.jw-auto-label{font-size:10px;font-weight:initial;opacity:.75;padding-left:5px}.jw-settings-content-item{position:relative;color:rgba(255,255,255,0.8);cursor:pointer;font-size:12px;line-height:1;padding:7px 0 7px 15px;width:100%;text-align:left;outline:none}.jw-settings-content-item:hover{color:#fff}.jw-settings-content-item:focus{font-weight:bold}.jw-flag-small-player .jw-settings-content-item{line-height:1.75}.jw-settings-content-item.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-settings-item-active{font-weight:bold;position:relative}.jw-settings-item-active::before{height:100%;width:1em;align-items:center;content:"\\2022";display:inline-flex;justify-content:center}.jw-breakpoint-2 .jw-settings-open .jw-display-container,.jw-flag-small-player .jw-settings-open .jw-display-container,.jw-flag-touch .jw-settings-open .jw-display-container{display:none}.jw-breakpoint-2 .jw-settings-open.jw-controls,.jw-flag-small-player .jw-settings-open.jw-controls,.jw-flag-touch .jw-settings-open.jw-controls{z-index:1}.jw-flag-small-player .jw-settings-open .jw-controlbar{display:none}.jw-settings-open .jw-icon-settings::after{opacity:1}.jw-settings-open .jw-tooltip-settings{display:none}.jw-sharing-link{cursor:pointer}.jw-shortcuts-container .jw-switch{position:relative;display:inline-block;transition:ease-out .15s;transition-property:opacity, background;border-radius:18px;width:80px;height:20px;padding:10px;background:rgba(80,80,80,0.8);cursor:pointer;font-size:inherit;vertical-align:middle}.jw-shortcuts-container .jw-switch.jw-tab-focus{outline:solid 2px #4d90fe}.jw-shortcuts-container .jw-switch .jw-switch-knob{position:absolute;top:2px;left:1px;transition:ease-out .15s;box-shadow:0 0 10px rgba(0,0,0,0.4);border-radius:13px;width:15px;height:15px;background:#fefefe}.jw-shortcuts-container .jw-switch:before,.jw-shortcuts-container .jw-switch:after{position:absolute;top:3px;transition:inherit;color:#fefefe}.jw-shortcuts-container .jw-switch:before{content:attr(data-jw-switch-disabled);right:8px}.jw-shortcuts-container .jw-switch:after{content:attr(data-jw-switch-enabled);left:8px;opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]{background:#475470}.jw-shortcuts-container .jw-switch[aria-checked="true"]:before{opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]:after{opacity:1}.jw-shortcuts-container .jw-switch[aria-checked="true"] .jw-switch-knob{left:60px}.jw-idle-icon-text{display:none;line-height:1;position:absolute;text-align:center;text-indent:.35em;top:100%;white-space:nowrap;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.jw-idle-label{border-radius:50%;color:#fff;-webkit-filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));font:normal 16px/1 Arial,Helvetica,sans-serif;position:relative;transition:background-color 150ms cubic-bezier(0, .25, .25, 1);transition-property:background-color,-webkit-filter;transition-property:background-color,filter;transition-property:background-color,filter,-webkit-filter;-webkit-font-smoothing:antialiased}.jw-state-idle .jw-icon-display.jw-idle-label .jw-idle-icon-text{display:block}.jw-state-idle .jw-icon-display.jw-idle-label .jw-svg-icon-play{-webkit-transform:scale(.7, .7);transform:scale(.7, .7)}.jw-breakpoint-0.jw-state-idle .jw-icon-display.jw-idle-label,.jw-breakpoint--1.jw-state-idle .jw-icon-display.jw-idle-label{font-size:12px}.jw-info-overlay{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column}.jw-info-overlay .jw-info-close{flex:0 0 auto;margin:5px 5px 5px auto}.jw-info-open .jw-info-overlay{display:flex}.jw-info-container{display:flex;flex:1 1 auto;flex-flow:column;margin:0 20px 20px;overflow-y:auto;padding:5px}.jw-info-container [class*="jw-info"]:not(:first-of-type){color:rgba(255,255,255,0.8);padding-top:10px;font-size:12px}.jw-info-container .jw-info-description{margin-bottom:30px;text-align:start}.jw-info-container .jw-info-description:empty{display:none}.jw-info-container .jw-info-duration{text-align:start}.jw-info-container .jw-info-title{text-align:start;font-size:12px;font-weight:bold}.jw-info-container::-webkit-scrollbar{background-color:transparent;width:6px}.jw-info-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-info-clientid{align-self:flex-end;font-size:12px;color:rgba(255,255,255,0.8);margin:0 20px 20px 44px;text-align:right}.jw-flag-touch .jw-info-open .jw-display-container{display:none}@supports ((-webkit-filter: drop-shadow(0 0 3px #000)) or (filter: drop-shadow(0 0 3px #000))){.jwplayer.jw-ab-drop-shadow .jw-controls .jw-svg-icon,.jwplayer.jw-ab-drop-shadow .jw-controls .jw-icon.jw-text,.jwplayer.jw-ab-drop-shadow .jw-slider-container .jw-rail,.jwplayer.jw-ab-drop-shadow .jw-title{text-shadow:none;box-shadow:none;-webkit-filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3));filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3))}.jwplayer.jw-ab-drop-shadow .jw-button-color{opacity:.8;transition-property:color, opacity}.jwplayer.jw-ab-drop-shadow .jw-button-color:not(:hover){color:#fff;opacity:.8}.jwplayer.jw-ab-drop-shadow .jw-button-color:hover{opacity:1}.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0), hsla(0, 0%, 0%, 0.00787) 10.79%, hsla(0, 0%, 0%, 0.02963) 21.99%, hsla(0, 0%, 0%, 0.0625) 33.34%, hsla(0, 0%, 0%, 0.1037) 44.59%, hsla(0, 0%, 0%, 0.15046) 55.48%, hsla(0, 0%, 0%, 0.2) 65.75%, hsla(0, 0%, 0%, 0.24954) 75.14%, hsla(0, 0%, 0%, 0.2963) 83.41%, hsla(0, 0%, 0%, 0.3375) 90.28%, hsla(0, 0%, 0%, 0.37037) 95.51%, hsla(0, 0%, 0%, 0.39213) 98.83%, hsla(0, 0%, 0%, 0.4));mix-blend-mode:multiply;transition-property:opacity}.jw-state-idle.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0.2), hsla(0, 0%, 0%, 0.19606) 1.17%, hsla(0, 0%, 0%, 0.18519) 4.49%, hsla(0, 0%, 0%, 0.16875) 9.72%, hsla(0, 0%, 0%, 0.14815) 16.59%, hsla(0, 0%, 0%, 0.12477) 24.86%, hsla(0, 0%, 0%, 0.1) 34.25%, hsla(0, 0%, 0%, 0.07523) 44.52%, hsla(0, 0%, 0%, 0.05185) 55.41%, hsla(0, 0%, 0%, 0.03125) 66.66%, hsla(0, 0%, 0%, 0.01481) 78.01%, hsla(0, 0%, 0%, 0.00394) 89.21%, hsla(0, 0%, 0%, 0));background-size:100% 7rem;background-position:50% 0}.jwplayer.jw-ab-drop-shadow.jw-state-idle .jw-controls{background-color:transparent}}.jw-video-thumbnail-container{position:relative;overflow:hidden}.jw-video-thumbnail-container:not(.jw-related-shelf-item-image){height:100%;width:100%}.jw-video-thumbnail-container.jw-video-thumbnail-generated{position:absolute;top:0;left:0}.jw-video-thumbnail-container:hover,.jw-related-item-content:hover .jw-video-thumbnail-container,.jw-related-shelf-item:hover .jw-video-thumbnail-container{cursor:pointer}.jw-video-thumbnail-container:hover .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-item-content:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-shelf-item:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail{position:absolute;top:50%;left:50%;bottom:unset;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);width:100%;height:auto;min-width:100%;min-height:100%;opacity:0;transition:opacity .3s ease;object-fit:cover;background:#000}.jw-related-item-next-up .jw-video-thumbnail-container .jw-video-thumbnail{height:100%;width:auto}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-visible:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-completed{opacity:0}.jw-video-thumbnail-container .jw-video-thumbnail~.jw-svg-icon-play{display:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-shelf-item-aspect{pointer-events:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-item-poster-content{pointer-events:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-state-idle .jw-controls{background:rgba(0,0,0,0.4)}.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay),.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay){display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon:focus{border:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon .jw-svg-icon-buffer{-webkit-animation:jw-spin 2s linear infinite;animation:jw-spin 2s linear infinite;display:block}@-webkit-keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.jwplayer.jw-state-buffering .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-pause{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-pause{display:block}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-controls-backdrop{opacity:0}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-logo-bottom-left,.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio):not(.jw-flag-autostart) .jw-logo-bottom-right{bottom:0}.jwplayer .jw-icon-playback .jw-svg-icon-stop{display:none}.jwplayer.jw-state-paused .jw-svg-icon-pause,.jwplayer.jw-state-idle .jw-svg-icon-pause,.jwplayer.jw-state-error .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-svg-icon-pause{display:none}.jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-complete .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-play{display:none}.jwplayer:not(.jw-state-buffering) .jw-svg-icon-buffer{display:none}.jwplayer:not(.jw-state-complete) .jw-svg-icon-replay{display:none}.jwplayer:not(.jw-state-error) .jw-svg-icon-error{display:none}.jwplayer.jw-state-complete .jw-display .jw-icon-display .jw-svg-icon-replay{display:block}.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-state-complete .jw-controls{background:rgba(0,0,0,0.4);height:100%}.jw-state-idle .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-state-idle .jw-display-icon-rewind,.jwplayer.jw-state-buffering .jw-display-icon-rewind,.jwplayer.jw-state-complete .jw-display-icon-rewind,body .jw-error .jw-display-icon-rewind,body .jwplayer.jw-state-error .jw-display-icon-rewind,.jw-state-idle .jw-display-icon-next,.jwplayer.jw-state-buffering .jw-display-icon-next,.jwplayer.jw-state-complete .jw-display-icon-next,body .jw-error .jw-display-icon-next,body .jwplayer.jw-state-error .jw-display-icon-next{display:none}body .jw-error .jw-icon-display,body .jwplayer.jw-state-error .jw-icon-display{cursor:default}body .jw-error .jw-icon-display .jw-svg-icon-error,body .jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-error{display:block}body .jw-error .jw-icon-container{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-preview{display:none}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title{padding-top:4px}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-primary{width:auto;display:inline-block;padding-right:.5ch}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-secondary{width:auto;display:inline-block;padding-left:0}body .jwplayer.jw-state-error .jw-controlbar,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-controlbar{display:none}body .jwplayer.jw-state-error .jw-settings-menu,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-settings-menu{height:100%;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}body .jwplayer.jw-state-error .jw-display,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-display{padding:0}body .jwplayer.jw-state-error .jw-logo-bottom-left,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-left,body .jwplayer.jw-state-error .jw-logo-bottom-right,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-right{bottom:0}.jwplayer.jw-state-playing.jw-flag-user-inactive .jw-display{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-state-playing:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display,.jwplayer.jw-state-paused:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting):not(.jw-flag-play-rejected) .jw-display{display:none}.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-rewind,.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-next{display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-text,.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-flag-casting:not(.jw-flag-audio-player) .jw-cast{display:block}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-display-icon-container{display:none}.jwplayer.jw-flag-casting .jw-icon-hd,.jwplayer.jw-flag-casting .jw-captions,.jwplayer.jw-flag-casting .jw-icon-fullscreen,.jwplayer.jw-flag-casting .jw-icon-audio-tracks{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-volume{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-airplay{color:#fff}.jw-state-playing.jw-flag-casting:not(.jw-flag-audio-player) .jw-display,.jw-state-paused.jw-flag-casting:not(.jw-flag-audio-player) .jw-display{display:table}.jwplayer.jw-flag-cast-available .jw-icon-cast,.jwplayer.jw-flag-cast-available .jw-icon-airplay{display:flex}.jwplayer.jw-flag-cardboard-available .jw-icon-cardboard{display:flex}.jwplayer.jw-flag-live .jw-display-icon-rewind{visibility:hidden}.jwplayer.jw-flag-live .jw-controlbar .jw-text-elapsed,.jwplayer.jw-flag-live .jw-controlbar .jw-text-duration,.jwplayer.jw-flag-live .jw-controlbar .jw-text-countdown,.jwplayer.jw-flag-live .jw-controlbar .jw-slider-time{display:none}.jwplayer.jw-flag-live .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-live .jw-controlbar .jw-overlay:after{display:none}.jwplayer.jw-flag-live .jw-nextup-container{bottom:44px}.jwplayer.jw-flag-live .jw-text-elapsed,.jwplayer.jw-flag-live .jw-text-duration{display:none}.jwplayer.jw-flag-live .jw-text-live{cursor:default}.jwplayer.jw-flag-live .jw-text-live:hover{color:rgba(255,255,255,0.8)}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-stop,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-stop{display:block}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-text-live{height:24px;width:auto;align-items:center;border-radius:1px;color:rgba(255,255,255,0.8);display:flex;font-size:12px;font-weight:bold;margin-right:10px;padding:0 1ch;text-rendering:geometricPrecision;text-transform:uppercase;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:box-shadow,color}.jw-text-live::before{height:8px;width:8px;background-color:currentColor;border-radius:50%;margin-right:6px;opacity:1;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-text-live.jw-dvr-live{box-shadow:inset 0 0 0 2px currentColor}.jw-text-live.jw-dvr-live::before{opacity:.5}.jw-text-live.jw-dvr-live:hover{color:#fff}.jwplayer.jw-flag-controls-hidden .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-controls-hidden:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-controls-hidden .jw-plugin{bottom:.5em}.jwplayer.jw-flag-controls-hidden .jw-nextup-container{bottom:0}.jw-flag-controls-hidden .jw-controlbar,.jw-flag-controls-hidden .jw-display{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-controls-hidden .jw-controls-backdrop{opacity:0}.jw-flag-controls-hidden .jw-logo{visibility:visible}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-plugin{bottom:.5em}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-nextup-container{bottom:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-controls-hidden) .jw-media{cursor:none;-webkit-cursor-visibility:auto-hide}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing.jw-flag-casting .jw-display{display:table}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-ads) .jw-autostart-mute{display:flex}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting .jw-nextup-container{bottom:66px}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting.jw-state-idle .jw-nextup-container{display:none}.jw-flag-media-audio .jw-preview{display:block}.jwplayer.jw-flag-ads .jw-preview,.jwplayer.jw-flag-ads .jw-logo,.jwplayer.jw-flag-ads .jw-captions.jw-captions-enabled,.jwplayer.jw-flag-ads .jw-nextup-container,.jwplayer.jw-flag-ads .jw-text-duration,.jwplayer.jw-flag-ads .jw-text-elapsed{display:none}.jwplayer.jw-flag-ads video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-rewind,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-next,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-display{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player.jw-state-buffering .jw-display-icon-display{display:inline-block}.jwplayer.jw-flag-ads .jw-controlbar{flex-wrap:wrap-reverse}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time{height:auto;padding:0;pointer-events:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-slider-container{height:5px}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-rail,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-knob,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-buffer,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-cue,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-icon-settings{display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-progress{-webkit-transform:none;transform:none;top:auto}.jwplayer.jw-flag-ads .jw-controlbar .jw-tooltip,.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-tooltip:not(.jw-icon-volume),.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-inline:not(.jw-icon-playback):not(.jw-icon-fullscreen):not(.jw-icon-volume){display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-volume-tip{padding:13px 0}.jwplayer.jw-flag-ads .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid) .jw-controls .jw-controlbar,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart .jw-controls .jw-controlbar{display:flex;pointer-events:all;visibility:visible;opacity:1}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-user-inactive .jw-controls-backdrop,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart.jw-flag-user-inactive .jw-controls-backdrop{opacity:1;background-size:100% 60px}.jwplayer.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-ads-vpaid .jw-skip,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-skip{display:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls{background:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls::after{content:none}.jwplayer.jw-flag-ads-hide-controls .jw-controls-backdrop,.jwplayer.jw-flag-ads-hide-controls .jw-controls{display:none !important}.jw-flag-overlay-open-related .jw-controls,.jw-flag-overlay-open-related .jw-title,.jw-flag-overlay-open-related .jw-logo{display:none}.jwplayer.jw-flag-rightclick-open{overflow:visible}.jwplayer.jw-flag-rightclick-open .jw-rightclick{z-index:16777215}body .jwplayer.jw-flag-flash-blocked .jw-controls,body .jwplayer.jw-flag-flash-blocked .jw-overlays,body .jwplayer.jw-flag-flash-blocked .jw-controls-backdrop,body .jwplayer.jw-flag-flash-blocked .jw-preview{display:none}body .jwplayer.jw-flag-flash-blocked .jw-error-msg{top:25%}.jw-flag-touch.jw-breakpoint-7 .jw-captions,.jw-flag-touch.jw-breakpoint-6 .jw-captions,.jw-flag-touch.jw-breakpoint-5 .jw-captions,.jw-flag-touch.jw-breakpoint-4 .jw-captions,.jw-flag-touch.jw-breakpoint-7 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-6 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-5 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-4 .jw-nextup-container{bottom:4.25em}.jw-flag-touch .jw-controlbar .jw-icon-volume{display:flex}.jw-flag-touch .jw-display,.jw-flag-touch .jw-display-container,.jw-flag-touch .jw-display-controls{pointer-events:none}.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-rewind,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-rewind{display:none}.jw-flag-touch.jw-state-paused.jw-flag-dragging .jw-display{display:none}.jw-flag-audio-player{background-color:#000}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:44px}.jw-flag-audio-player:not(.jw-flag-live) .jw-spacer{display:none}.jw-flag-audio-player .jw-preview,.jw-flag-audio-player .jw-display,.jw-flag-audio-player .jw-title,.jw-flag-audio-player .jw-nextup-container{display:none}.jw-flag-audio-player .jw-controlbar{position:relative}.jw-flag-audio-player .jw-controlbar .jw-button-container{padding-right:3px;padding-left:0}.jw-flag-audio-player .jw-controlbar .jw-icon-tooltip,.jw-flag-audio-player .jw-controlbar .jw-icon-inline{display:none}.jw-flag-audio-player .jw-controlbar .jw-icon-volume,.jw-flag-audio-player .jw-controlbar .jw-icon-playback,.jw-flag-audio-player .jw-controlbar .jw-icon-next,.jw-flag-audio-player .jw-controlbar .jw-icon-rewind,.jw-flag-audio-player .jw-controlbar .jw-icon-cast,.jw-flag-audio-player .jw-controlbar .jw-text-live,.jw-flag-audio-player .jw-controlbar .jw-icon-airplay,.jw-flag-audio-player .jw-controlbar .jw-logo-button,.jw-flag-audio-player .jw-controlbar .jw-text-elapsed,.jw-flag-audio-player .jw-controlbar .jw-text-duration{display:flex;flex:0 0 auto}.jw-flag-audio-player .jw-controlbar .jw-text-duration,.jw-flag-audio-player .jw-controlbar .jw-text-countdown{padding-right:10px}.jw-flag-audio-player .jw-controlbar .jw-slider-time{flex:0 1 auto;align-items:center;display:flex;order:1}.jw-flag-audio-player .jw-controlbar .jw-icon-volume{margin-right:0;transition:margin-right 150ms cubic-bezier(0, .25, .25, 1)}.jw-flag-audio-player .jw-controlbar .jw-icon-volume .jw-overlay{display:none}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container{transition:width 300ms cubic-bezier(0, .25, .25, 1);width:0}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open{width:140px}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open .jw-slider-volume{padding-right:24px;transition:opacity 300ms;opacity:1}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open~.jw-slider-time{flex:1 1 auto;width:auto;transition:opacity 300ms, width 300ms}.jw-flag-audio-player .jw-controlbar .jw-slider-volume{opacity:0}.jw-flag-audio-player .jw-controlbar .jw-slider-volume .jw-knob{-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.jw-flag-audio-player .jw-controlbar .jw-slider-volume~.jw-icon-volume{margin-right:140px}.jw-flag-audio-player.jw-breakpoint-1 .jw-horizontal-volume-container.jw-open~.jw-slider-time,.jw-flag-audio-player.jw-breakpoint-2 .jw-horizontal-volume-container.jw-open~.jw-slider-time{opacity:0}.jw-flag-audio-player.jw-flag-small-player .jw-text-elapsed,.jw-flag-audio-player.jw-flag-small-player .jw-text-duration{display:none}.jw-flag-audio-player.jw-flag-ads .jw-slider-time{display:none}.jw-hidden{display:none}',""])}]]); \ No newline at end of file diff --git a/ui/v2.5/public/jwplayer/jwplayer.core.controls.js b/ui/v2.5/public/jwplayer/jwplayer.core.controls.js new file mode 100644 index 000000000..974fc20af --- /dev/null +++ b/ui/v2.5/public/jwplayer/jwplayer.core.controls.js @@ -0,0 +1,95 @@ +/*! +JW Player version 8.11.5 +Copyright (c) 2019, JW Player, All Rights Reserved +https://github.com/jwplayer/jwplayer/blob/v8.11.5/README.md + +This source code and its use and distribution is subject to the terms and conditions of the applicable license agreement. +https://www.jwplayer.com/tos/ + +This product includes portions of other software. For the full text of licenses, see below: + +JW Player Third Party Software Notices and/or Additional Terms and Conditions + +************************************************************************************************** +The following software is used under Apache License 2.0 +************************************************************************************************** + +vtt.js v0.13.0 +Copyright (c) 2019 Mozilla (http://mozilla.org) +https://github.com/mozilla/vtt.js/blob/v0.13.0/LICENSE + +* * * + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. + +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. + +************************************************************************************************** +The following software is used under MIT license +************************************************************************************************** + +Underscore.js v1.6.0 +Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative +https://github.com/jashkenas/underscore/blob/1.6.0/LICENSE + +Backbone backbone.events.js v1.1.2 +Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud +https://github.com/jashkenas/backbone/blob/1.1.2/LICENSE + +Promise Polyfill v7.1.1 +Copyright (c) 2014 Taylor Hakes and Forbes Lindesay +https://github.com/taylorhakes/promise-polyfill/blob/v7.1.1/LICENSE + +can-autoplay.js v3.0.0 +Copyright (c) 2017 video-dev +https://github.com/video-dev/can-autoplay/blob/v3.0.0/LICENSE + +* * * + +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. + +************************************************************************************************** +The following software is used under W3C license +************************************************************************************************** + +Intersection Observer v0.5.0 +Copyright (c) 2016 Google Inc. (http://google.com) +https://github.com/w3c/IntersectionObserver/blob/v0.5.0/LICENSE.md + +* * * + +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. + +This work is being provided by the copyright holders under the following license. + +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. + +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. + +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. +*/ +(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[3,1,2],[,,,,,,,,,,,,,,,,,function(e,t,n){"use strict";n.r(t);var i,o=n(8),a=n(3),r=n(7),s=n(43),l=n(5),c=n(15),u=n(40);function d(e){return i||(i=new DOMParser),Object(l.r)(Object(l.s)(i.parseFromString(e,"image/svg+xml").documentElement))}var p=function(e,t,n,i){var o=document.createElement("div");o.className="jw-icon jw-icon-inline jw-button-color jw-reset "+e,o.setAttribute("role","button"),o.setAttribute("tabindex","0"),n&&o.setAttribute("aria-label",n),o.style.display="none";var a=new u.a(o).on("click tap enter",t||function(){});return i&&Array.prototype.forEach.call(i,(function(e){"string"==typeof e?o.appendChild(d(e)):o.appendChild(e)})),{ui:a,element:function(){return o},toggle:function(e){e?this.show():this.hide()},show:function(){o.style.display=""},hide:function(){o.style.display="none"}}},w=n(0),f=n(71),h=n.n(f),j=n(72),g=n.n(j),b=n(73),m=n.n(b),v=n(74),y=n.n(v),k=n(75),x=n.n(k),O=n(76),C=n.n(O),M=n(77),S=n.n(M),T=n(78),E=n.n(T),_=n(79),z=n.n(_),P=n(80),A=n.n(P),L=n(81),R=n.n(L),I=n(82),B=n.n(I),V=n(83),N=n.n(V),H=n(84),F=n.n(H),q=n(85),D=n.n(q),U=n(86),W=n.n(U),Q=n(62),Y=n.n(Q),X=n(87),Z=n.n(X),K=n(88),J=n.n(K),G=n(89),$=n.n(G),ee=n(90),te=n.n(ee),ne=n(91),ie=n.n(ne),oe=n(92),ae=n.n(oe),re=n(93),se=n.n(re),le=n(94),ce=n.n(le),ue=null;function de(e){var t=he().querySelector(we(e));if(t)return fe(t);throw new Error("Icon not found "+e)}function pe(e){var t=he().querySelectorAll(e.split(",").map(we).join(","));if(!t.length)throw new Error("Icons not found "+e);return Array.prototype.map.call(t,(function(e){return fe(e)}))}function we(e){return".jw-svg-icon-".concat(e)}function fe(e){return e.cloneNode(!0)}function he(){return ue||(ue=d(""+h.a+g.a+m.a+y.a+x.a+C.a+S.a+E.a+z.a+A.a+R.a+B.a+N.a+F.a+D.a+W.a+Y.a+Z.a+J.a+$.a+te.a+ie.a+ae.a+se.a+ce.a+"")),ue}var je=n(10);function ge(e,t){for(var n=0;n10&&delete be[t[0]];var n=d(e);be[e]=n}return be[e].cloneNode(!0)}(t):((r=document.createElement("div")).className="jw-icon jw-button-image jw-button-color jw-reset",t&&Object(je.d)(r,{backgroundImage:"url(".concat(t,")")})),s.appendChild(r),new u.a(s).on("click tap enter",i,this),s.addEventListener("mousedown",(function(e){e.preventDefault()})),this.id=o,this.buttonElement=s}var t,n,i;return t=e,(n=[{key:"element",value:function(){return this.buttonElement}},{key:"toggle",value:function(e){e?this.show():this.hide()}},{key:"show",value:function(){this.buttonElement.style.display=""}},{key:"hide",value:function(){this.buttonElement.style.display="none"}}])&&ge(t.prototype,n),i&&ge(t,i),e}(),ve=n(11);function ye(e,t){for(var n=0;n=0&&(t.left-=n,t.right-=n),t},xe=function(){function e(t,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),Object(w.g)(this,r.a),this.className=t+" jw-background-color jw-reset",this.orientation=n}var t,n,i;return t=e,(n=[{key:"setup",value:function(){this.el=Object(l.e)(function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return''}(this.className,"jw-slider-"+this.orientation)),this.elementRail=this.el.getElementsByClassName("jw-slider-container")[0],this.elementBuffer=this.el.getElementsByClassName("jw-buffer")[0],this.elementProgress=this.el.getElementsByClassName("jw-progress")[0],this.elementThumb=this.el.getElementsByClassName("jw-knob")[0],this.ui=new u.a(this.element(),{preventScrolling:!0}).on("dragStart",this.dragStart,this).on("drag",this.dragMove,this).on("dragEnd",this.dragEnd,this).on("click tap",this.tap,this)}},{key:"dragStart",value:function(){this.trigger("dragStart"),this.railBounds=ke(this.elementRail)}},{key:"dragEnd",value:function(e){this.dragMove(e),this.trigger("dragEnd")}},{key:"dragMove",value:function(e){var t,n,i=this.railBounds=this.railBounds?this.railBounds:ke(this.elementRail);return n="horizontal"===this.orientation?(t=e.pageX)i.right?100:100*Object(s.a)((t-i.left)/i.width,0,1):(t=e.pageY)>=i.bottom?0:t<=i.top?100:100*Object(s.a)((i.height-(t-i.top))/i.height,0,1),this.render(n),this.update(n),!1}},{key:"tap",value:function(e){this.railBounds=ke(this.elementRail),this.dragMove(e)}},{key:"limit",value:function(e){return e}},{key:"update",value:function(e){this.trigger("update",{percentage:e})}},{key:"render",value:function(e){e=Math.max(0,Math.min(e,100)),"horizontal"===this.orientation?(this.elementThumb.style.left=e+"%",this.elementProgress.style.width=e+"%"):(this.elementThumb.style.bottom=e+"%",this.elementProgress.style.height=e+"%")}},{key:"updateBuffer",value:function(e){this.elementBuffer.style.width=e+"%"}},{key:"element",value:function(){return this.el}}])&&ye(t.prototype,n),i&&ye(t,i),e}(),Oe=function(e,t){e&&t&&(e.setAttribute("aria-label",t),e.setAttribute("role","button"),e.setAttribute("tabindex","0"))};function Ce(e,t){for(var n=0;n0&&Array.prototype.forEach.call(o,(function(e){"string"==typeof e?a.el.appendChild(d(e)):a.el.appendChild(e)}))}var t,n,i;return t=e,(n=[{key:"addContent",value:function(e){this.content&&this.removeContent(),this.content=e,this.tooltip.appendChild(e)}},{key:"removeContent",value:function(){this.content&&(this.tooltip.removeChild(this.content),this.content=null)}},{key:"hasContent",value:function(){return!!this.content}},{key:"element",value:function(){return this.el}},{key:"openTooltip",value:function(e){this.isOpen||(this.trigger("open-"+this.componentType,e,{isOpen:!0}),this.isOpen=!0,Object(l.v)(this.el,this.openClass,this.isOpen))}},{key:"closeTooltip",value:function(e){this.isOpen&&(this.trigger("close-"+this.componentType,e,{isOpen:!1}),this.isOpen=!1,Object(l.v)(this.el,this.openClass,this.isOpen))}},{key:"toggleOpenState",value:function(e){this.isOpen?this.closeTooltip(e):this.openTooltip(e)}}])&&Ce(t.prototype,n),i&&Ce(t,i),e}(),Se=n(22),Te=n(57);function Ee(e,t){for(var n=0;n=this.thumbnails.length&&(t=this.thumbnails.length-1);var n=this.thumbnails[t].img;return n.indexOf("://")<0&&(n=this.vttPath?this.vttPath+"/"+n:n),n},loadThumbnail:function(e){var t=this.chooseThumbnail(e),n={margin:"0 auto",backgroundPosition:"0 0"};if(t.indexOf("#xywh")>0)try{var i=/(.+)#xywh=(\d+),(\d+),(\d+),(\d+)/.exec(t);t=i[1],n.backgroundPosition=-1*i[2]+"px "+-1*i[3]+"px",n.width=i[4],this.timeTip.setWidth(+n.width),n.height=i[5]}catch(e){return}else this.individualImage||(this.individualImage=new Image,this.individualImage.onload=Object(w.a)((function(){this.individualImage.onload=null,this.timeTip.image({width:this.individualImage.width,height:this.individualImage.height}),this.timeTip.setWidth(this.individualImage.width)}),this),this.individualImage.src=t);return n.backgroundImage='url("'+t+'")',n},showThumbnail:function(e){this._model.get("containerWidth")<=420||this.thumbnails.length<1||this.timeTip.image(this.loadThumbnail(e))},resetThumbnails:function(){this.timeTip.image({backgroundImage:"",width:0,height:0}),this.thumbnails=[]}};function Le(e,t,n){return(Le="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(e,t,n){var i=function(e,t){for(;!Object.prototype.hasOwnProperty.call(e,t)&&null!==(e=He(e)););return e}(e,t);if(i){var o=Object.getOwnPropertyDescriptor(i,t);return o.get?o.get.call(n):o.value}})(e,t,n||e)}function Re(e){return(Re="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function Ie(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Be(e,t){for(var n=0;n-1&&(i="Live")}var d=this.timeTip;d.update(i),this.textLength!==i.length&&(this.textLength=i.length,d.resetWidth()),this.showThumbnail(u),Object(l.a)(d.el,"jw-open");var p=d.getWidth(),w=a.width/100,f=o-a.width,h=0;p>f&&(h=(p-f)/(200*w));var j=100*Math.min(1-h,Math.max(h,c)).toFixed(3);Object(je.d)(d.el,{left:j+"%"})}}},{key:"hideTimeTooltip",value:function(){Object(l.o)(this.timeTip.el,"jw-open")}},{key:"updateCues",value:function(e,t){var n=this;this.resetCues(),t&&t.length&&(t.forEach((function(e){n.addCue(e)})),this.drawCues())}},{key:"updateAriaText",value:function(){var e=this._model;if(!e.get("seeking")){var t=e.get("position"),n=e.get("duration"),i=Object(ve.timeFormat)(t);"DVR"!==this.streamType&&(i+=" of ".concat(Object(ve.timeFormat)(n)));var o=this.el;document.activeElement!==o&&(this.timeUpdateKeeper.textContent=i),Object(l.t)(o,"aria-valuenow",t),Object(l.t)(o,"aria-valuetext",i)}}},{key:"reset",value:function(){this.resetThumbnails(),this.timeTip.resetWidth(),this.textLength=0}}]),t}(xe);Object(w.g)(Ue.prototype,ze,Ae);var We=Ue;function Qe(e,t){for(var n=0;n=75&&!e),Object(l.t)(r,"aria-valuenow",o),Object(l.t)(s,"aria-valuenow",o);var c="Volume ".concat(o,"%");Object(l.t)(r,"aria-valuetext",c),Object(l.t)(s,"aria-valuetext",c),document.activeElement!==r&&document.activeElement!==s&&(this._volumeAnnouncer.textContent=c)}}},{key:"onCastAvailable",value:function(e,t){this.elements.cast.toggle(t)}},{key:"onCastActive",value:function(e,t){this.elements.fullscreen.toggle(!t),this.elements.cast.button&&Object(l.v)(this.elements.cast.button,"jw-off",!t)}},{key:"onElapsed",value:function(e,t){var n,i,o=e.get("duration");if("DVR"===e.get("streamType")){var a=Math.ceil(t),r=this._model.get("dvrSeekLimit");n=i=a>=-r?"":"-"+Object(ve.timeFormat)(-(t+r)),e.set("dvrLive",a>=-r)}else n=Object(ve.timeFormat)(t),i=Object(ve.timeFormat)(o-t);this.elements.elapsed.textContent=n,this.elements.countdown.textContent=i}},{key:"onDuration",value:function(e,t){this.elements.duration.textContent=Object(ve.timeFormat)(Math.abs(t))}},{key:"onAudioMode",value:function(e,t){var n=this.elements.time.element();t?this.elements.buttonContainer.insertBefore(n,this.elements.elapsed):Object(l.m)(this.el,n)}},{key:"element",value:function(){return this.el}},{key:"setAltText",value:function(e,t){this.elements.alt.textContent=t}},{key:"closeMenus",value:function(e){this.menus.forEach((function(t){e&&e.target===t.el||t.closeTooltip(e)}))}},{key:"rewind",value:function(){var e,t=0,n=this._model.get("currentTime");n?e=n-10:(e=this._model.get("position")-10,"DVR"===this._model.get("streamType")&&(t=this._model.get("duration"))),this._api.seek(Math.max(e,t),{reason:"interaction"})}},{key:"onState",value:function(e,t){var n=e.get("localization"),i=n.play;this.setPlayText(i),t===a.pb&&("LIVE"!==e.get("streamType")?(i=n.pause,this.setPlayText(i)):(i=n.stop,this.setPlayText(i))),Object(l.t)(this.elements.play.element(),"aria-label",i)}},{key:"onStreamTypeChange",value:function(e,t){var n="LIVE"===t,i="DVR"===t;this.elements.rewind.toggle(!n),this.elements.live.toggle(n||i),Object(l.t)(this.elements.live.element(),"tabindex",n?"-1":"0"),this.elements.duration.style.display=i?"none":"",this.onDuration(e,e.get("duration")),this.onState(e,e.get("state"))}},{key:"addLogo",value:function(e){var t=this.elements.buttonContainer,n=new me(e.file,this._model.get("localization").logo,(function(){e.link&&Object(l.l)(e.link,"_blank",{rel:"noreferrer"})}),"logo","jw-logo-button");e.link||Object(l.t)(n.element(),"tabindex","-1"),t.insertBefore(n.element(),t.querySelector(".jw-spacer").nextSibling)}},{key:"goToLiveEdge",value:function(){if("DVR"===this._model.get("streamType")){var e=Math.min(this._model.get("position"),-1),t=this._model.get("dvrSeekLimit");this._api.seek(Math.max(-t,e),{reason:"interaction"}),this._api.play({reason:"interaction"})}}},{key:"updateButtons",value:function(e,t,n){if(t){var i,o,a=this.elements.buttonContainer;t!==n&&n?(i=ct(t,n),o=ct(n,t),this.removeButtons(a,o)):i=t;for(var r=i.length-1;r>=0;r--){var s=i[r],l=new me(s.img,s.tooltip,s.callback,s.id,s.btnClass);s.tooltip&&it(l.element(),s.id,s.tooltip);var c=void 0;"related"===l.id?c=this.elements.settingsButton.element():"share"===l.id?c=a.querySelector('[button="related"]')||this.elements.settingsButton.element():(c=this.elements.spacer.nextSibling)&&"logo"===c.getAttribute("button")&&(c=c.nextSibling),a.insertBefore(l.element(),c)}}}},{key:"removeButtons",value:function(e,t){for(var n=t.length;n--;){var i=e.querySelector('[button="'.concat(t[n].id,'"]'));i&&e.removeChild(i)}}},{key:"toggleCaptionsButtonState",value:function(e){var t=this.elements.captionsButton;t&&Object(l.v)(t.element(),"jw-off",!e)}},{key:"destroy",value:function(){var e=this;this._model.off(null,null,this),Object.keys(this.elements).forEach((function(t){var n=e.elements[t];n&&"function"==typeof n.destroy&&e.elements[t].destroy()})),this.ui.forEach((function(e){e.destroy()})),this.ui=[]}}])&&at(t.prototype,n),i&&at(t,i),e}(),pt=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return'
    ')+'
    ')+"
    "},wt=function(e){return'
    '+pt("rewind",e.rewind)+pt("display",e.playback)+pt("next",e.next)+"
    "};function ft(e,t){for(var n=0;n'.concat(a.playback,"")),Object(l.a)(o.icon,"jw-idle-label"),o.icon.appendChild(s))}return o}var n,i,o;return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&vt(e,t)}(t,e),n=t,(i=[{key:"element",value:function(){return this.el}}])&>(n.prototype,i),o&>(n,o),t}(r.a);function kt(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";return'
    '+'
    '.concat(e,"
    ")+'
    '.concat(t,"
    ")+'
    '.concat(n,"
    ")+"
    "+'')+"
    "}());t.querySelector(".jw-nextup-close").appendChild(de("close")),this.addContent(t),this.closeButton=this.content.querySelector(".jw-nextup-close"),this.closeButton.setAttribute("aria-label",this.localization.close),this.tooltip=this.content.querySelector(".jw-nextup-tooltip");var n=this._model,i=n.player;this.enabled=!1,n.on("change:nextUp",this.onNextUp,this),i.change("duration",this.onDuration,this),i.change("position",this.onElapsed,this),i.change("streamType",this.onStreamType,this),i.change("state",(function(e,t){"complete"===t&&this.toggle(!1)}),this),this.closeUi=new u.a(this.closeButton,{directSelect:!0}).on("click tap enter",(function(){this.nextUpSticky=!1,this.toggle(!1)}),this),this.tooltipUi=new u.a(this.tooltip).on("click tap",this.click,this)}},{key:"loadThumbnail",value:function(e){return this.nextUpImage=new Image,this.nextUpImage.onload=function(){this.nextUpImage.onload=null}.bind(this),this.nextUpImage.src=e,{backgroundImage:'url("'+e+'")'}}},{key:"click",value:function(){var e=this.feedShownId;this.reset(),this._api.next({feedShownId:e,reason:"interaction"})}},{key:"toggle",value:function(e,t){if(this.enabled&&(Object(l.v)(this.container,"jw-nextup-sticky",!!this.nextUpSticky),this.shown!==e)){this.shown=e,Object(l.v)(this.container,"jw-nextup-container-visible",e),Object(l.v)(this._playerElement,"jw-flag-nextup",e);var n=this._model.get("nextUp");e&&n?(this.feedShownId=Object(ot.b)(ot.a),this.trigger("nextShown",{mode:n.mode,ui:"nextup",itemsShown:[n],feedData:n.feedData,reason:t,feedShownId:this.feedShownId})):this.feedShownId=""}}},{key:"setNextUpItem",value:function(e){var t=this;setTimeout((function(){if(t.thumbnail=t.content.querySelector(".jw-nextup-thumbnail"),Object(l.v)(t.content,"jw-nextup-thumbnail-visible",!!e.image),e.image){var n=t.loadThumbnail(e.image);Object(je.d)(t.thumbnail,n)}t.header=t.content.querySelector(".jw-nextup-header"),t.header.textContent=Object(l.e)(t.localization.nextUp).textContent,t.title=t.content.querySelector(".jw-nextup-title");var i=e.title;t.title.textContent=i?Object(l.e)(i).textContent:"";var o=e.duration;o&&(t.duration=t.content.querySelector(".jw-nextup-duration"),t.duration.textContent="number"==typeof o?Object(ve.timeFormat)(o):o)}),500)}},{key:"onNextUp",value:function(e,t){this.reset(),t||(t={showNextUp:!1}),this.enabled=!(!t.title&&!t.image),this.enabled&&(t.showNextUp||(this.nextUpSticky=!1,this.toggle(!1)),this.setNextUpItem(t))}},{key:"onDuration",value:function(e,t){if(t){var n=e.get("nextupoffset"),i=-10;n&&(i=Object(St.d)(n,t)),i<0&&(i+=t),Object(St.c)(n)&&t-5=this.offset;i&&void 0===n?(this.nextUpSticky=i,this.toggle(i,"time")):!i&&n&&this.reset()}}},{key:"onStreamType",value:function(e,t){"VOD"!==t&&(this.nextUpSticky=!1,this.toggle(!1))}},{key:"element",value:function(){return this.container}},{key:"addContent",value:function(e){this.content&&this.removeContent(),this.content=e,this.container.appendChild(e)}},{key:"removeContent",value:function(){this.content&&(this.container.removeChild(this.content),this.content=null)}},{key:"reset",value:function(){this.nextUpSticky=void 0,this.toggle(!1)}},{key:"destroy",value:function(){this.off(),this._model.off(null,null,this),this.closeUi&&this.closeUi.destroy(),this.tooltipUi&&this.tooltipUi.destroy()}}])&&Tt(t.prototype,n),i&&Tt(t,i),e}(),_t=function(e,t){var n=e.featured,i=e.showLogo,o=e.type;return e.logo=i?'':"",'
  • ').concat(zt[o](e,t),"
  • ")},zt={link:function(e){var t=e.link,n=e.title,i=e.logo;return'').concat(i).concat(n||"","")},info:function(e,t){return'")},share:function(e,t){return'")},keyboardShortcuts:function(e,t){return'")}},Pt=n(23),At=n(6),Lt=n(13);function Rt(e,t){for(var n=0;nJW Player '.concat(e,""),a={items:[{type:"info"},{title:Object(Lt.e)(i)?"".concat(o," ").concat(i):"".concat(i," ").concat(o),type:"link",featured:!0,showLogo:!0,link:"https://jwplayer.com/learn-more?e=".concat(It[n])}]},r=t.get("provider"),s=a.items;if(r&&r.name.indexOf("flash")>=0){var l="Flash Version "+Object(At.a)();s.push({title:l,type:"link",link:"http://www.adobe.com/software/flash/about/"})}return this.shortcutsTooltip&&s.splice(s.length-1,0,{type:"keyboardShortcuts"}),a}},{key:"rightClick",value:function(e){if(this.lazySetup(),this.mouseOverContext)return!1;this.hideMenu(),this.showMenu(e),this.addHideMenuHandlers()}},{key:"getOffset",value:function(e){var t=Object(l.c)(this.wrapperElement),n=e.pageX-t.left,i=e.pageY-t.top;return this.model.get("touchMode")&&(i-=100),{x:n,y:i}}},{key:"showMenu",value:function(e){var t=this,n=this.getOffset(e);return this.el.style.left=n.x+"px",this.el.style.top=n.y+"px",this.outCount=0,Object(l.a)(this.playerContainer,"jw-flag-rightclick-open"),Object(l.a)(this.el,"jw-open"),clearTimeout(this._menuTimeout),this._menuTimeout=setTimeout((function(){return t.hideMenu()}),3e3),!1}},{key:"hideMenu",value:function(e){e&&this.el&&this.el.contains(e.target)||(Object(l.o)(this.playerContainer,"jw-flag-rightclick-open"),Object(l.o)(this.el,"jw-open"))}},{key:"lazySetup",value:function(){var e,t,n,i,o=this,a=(e=this.buildArray(),t=this.model.get("localization"),n=e.items,i=(void 0===n?[]:n).map((function(e){return _t(e,t)})),'
    '+'
      '.concat(i.join(""),"
    ")+"
    ");if(this.el){if(this.html!==a){this.html=a;var r=Bt(a);Object(l.h)(this.el);for(var s=r.childNodes.length;s--;)this.el.appendChild(r.firstChild)}}else this.html=a,this.el=Bt(this.html),this.wrapperElement.appendChild(this.el),this.hideMenuHandler=function(e){return o.hideMenu(e)},this.overHandler=function(){o.mouseOverContext=!0},this.outHandler=function(e){o.mouseOverContext=!1,e.relatedTarget&&!o.el.contains(e.relatedTarget)&&++o.outCount>1&&o.hideMenu()},this.infoOverlayHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.infoOverlay.open()},this.shortcutsTooltipHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.shortcutsTooltip.open()}}},{key:"setup",value:function(e,t,n){this.wrapperElement=n,this.model=e,this.mouseOverContext=!1,this.playerContainer=t,this.ui=new u.a(n).on("longPress",this.rightClick,this)}},{key:"addHideMenuHandlers",value:function(){this.removeHideMenuHandlers(),this.wrapperElement.addEventListener("touchstart",this.hideMenuHandler),document.addEventListener("touchstart",this.hideMenuHandler),o.OS.mobile||(this.wrapperElement.addEventListener("click",this.hideMenuHandler),document.addEventListener("click",this.hideMenuHandler),this.el.addEventListener("mouseover",this.overHandler),this.el.addEventListener("mouseout",this.outHandler)),this.el.querySelector(".jw-info-overlay-item").addEventListener("click",this.infoOverlayHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").addEventListener("click",this.shortcutsTooltipHandler)}},{key:"removeHideMenuHandlers",value:function(){this.wrapperElement&&(this.wrapperElement.removeEventListener("click",this.hideMenuHandler),this.wrapperElement.removeEventListener("touchstart",this.hideMenuHandler)),this.el&&(this.el.querySelector(".jw-info-overlay-item").removeEventListener("click",this.infoOverlayHandler),this.el.removeEventListener("mouseover",this.overHandler),this.el.removeEventListener("mouseout",this.outHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").removeEventListener("click",this.shortcutsTooltipHandler)),document.removeEventListener("click",this.hideMenuHandler),document.removeEventListener("touchstart",this.hideMenuHandler)}},{key:"destroy",value:function(){clearTimeout(this._menuTimeout),this.removeHideMenuHandlers(),this.el&&(this.hideMenu(),this.hideMenuHandler=null,this.el=null),this.wrapperElement&&(this.wrapperElement.oncontextmenu=null,this.wrapperElement=null),this.model&&(this.model=null),this.ui&&(this.ui.destroy(),this.ui=null)}}])&&Rt(t.prototype,n),i&&Rt(t,i),e}(),Nt=function(e){return'")},Ht=function(e){return'"},Ft=function(e){return'"};function qt(e){return(qt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function Dt(e,t){return!t||"object"!==qt(t)&&"function"!=typeof t?function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(e):t}function Ut(e){return(Ut=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function Wt(e,t){return(Wt=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function Qt(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Yt(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:Nt;Qt(this,e),this.el=Object(l.e)(i(t)),this.ui=new u.a(this.el).on("click tap enter",n,this)}return Xt(e,[{key:"destroy",value:function(){this.ui.destroy()}}]),e}(),Jt=function(e){function t(e,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Ft;return Qt(this,t),Dt(this,Ut(t).call(this,e,n,i))}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&Wt(e,t)}(t,e),Xt(t,[{key:"activate",value:function(){Object(l.v)(this.el,"jw-settings-item-active",!0),this.el.setAttribute("aria-checked","true"),this.active=!0}},{key:"deactivate",value:function(){Object(l.v)(this.el,"jw-settings-item-active",!1),this.el.setAttribute("aria-checked","false"),this.active=!1}}]),t}(Kt),Gt=function(e,t){return e?'':''},$t=function(e,t){var n=e.name,i={captions:"cc-off",audioTracks:"audio-tracks",quality:"quality-100",playbackRates:"playback-rate"}[n];if(i||e.icon){var o=p("jw-settings-".concat(n," jw-submenu-").concat(n),(function(t){e.open(t)}),n,[e.icon&&Object(l.e)(e.icon)||de(i)]),a=o.element();return a.setAttribute("role","menuitemradio"),a.setAttribute("aria-checked","false"),a.setAttribute("aria-label",t),"ontouchstart"in window||(o.tooltip=it(a,n,t)),o}};function en(e){return(en="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function tn(e,t){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:Gt;return function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),a=this,(o=!(r=nn(t).call(this))||"object"!==en(r)&&"function"!=typeof r?an(a):r).open=o.open.bind(an(an(o))),o.close=o.close.bind(an(an(o))),o.toggle=o.toggle.bind(an(an(o))),o.onDocumentClick=o.onDocumentClick.bind(an(an(o))),o.name=e,o.isSubmenu=!!n,o.el=Object(l.e)(s(o.isSubmenu,e)),o.topbar=o.el.querySelector(".jw-".concat(o.name,"-topbar")),o.buttonContainer=o.el.querySelector(".jw-".concat(o.name,"-topbar-buttons")),o.children={},o.openMenus=[],o.items=[],o.visible=!1,o.parentMenu=n,o.mainMenu=o.parentMenu?o.parentMenu.mainMenu:an(an(o)),o.categoryButton=null,o.closeButton=o.parentMenu&&o.parentMenu.closeButton||o.createCloseButton(i),o.isSubmenu?(o.categoryButton=o.parentMenu.categoryButton||o.createCategoryButton(i),o.parentMenu.parentMenu&&!o.mainMenu.backButton&&(o.mainMenu.backButton=o.createBackButton(i)),o.itemsContainer=o.createItemsContainer(),o.parentMenu.appendMenu(an(an(o)))):o.ui=sn(an(an(o))),o}var n,i,o;return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&on(e,t)}(t,e),n=t,(i=[{key:"createItemsContainer",value:function(){var e,t,n=this,i=this.el.querySelector(".jw-settings-submenu-items"),o=new u.a(i),a=this.categoryButton&&this.categoryButton.element()||this.parentMenu.categoryButton&&this.parentMenu.categoryButton.element()||this.mainMenu.buttonContainer.firstChild;return this.parentMenu.isSubmenu&&(e=this.mainMenu.closeButton.element(),t=this.mainMenu.backButton.element()),o.on("keydown",(function(o){if(o.target.parentNode===i){var r=function(e,t){e?e.focus():void 0!==t&&i.childNodes[t].focus()},s=o.sourceEvent,c=s.target,u=i.firstChild===c,d=i.lastChild===c,p=n.topbar,w=e||Object(l.k)(a),f=t||Object(l.n)(a),h=Object(l.k)(s.target),j=Object(l.n)(s.target),g=s.key.replace(/(Arrow|ape)/,"");switch(g){case"Tab":r(s.shiftKey?f:w);break;case"Left":r(f||Object(l.n)(document.getElementsByClassName("jw-icon-settings")[0]));break;case"Up":p&&u?r(p.firstChild):r(j,i.childNodes.length-1);break;case"Right":r(w);break;case"Down":p&&d?r(p.firstChild):r(h,0)}s.preventDefault(),"Esc"!==g&&s.stopPropagation()}})),o}},{key:"createCloseButton",value:function(e){var t=p("jw-settings-close",this.close,e.close,[de("close")]);return this.topbar.appendChild(t.element()),t.show(),t.ui.on("keydown",(function(e){var t=e.sourceEvent,n=t.key.replace(/(Arrow|ape)/,"");("Enter"===n||"Right"===n||"Tab"===n&&!t.shiftKey)&&this.close(e)}),this),this.buttonContainer.appendChild(t.element()),t}},{key:"createCategoryButton",value:function(e){var t=e[{captions:"cc",audioTracks:"audioTracks",quality:"hd",playbackRates:"playbackRates"}[this.name]];"sharing"===this.name&&(t=e.sharing.heading);var n=$t(this,t);return n.element().setAttribute("name",this.name),n}},{key:"createBackButton",value:function(e){var t=p("jw-settings-back",(function(e){Zt&&Zt.open(e)}),e.close,[de("arrow-left")]);return Object(l.m)(this.mainMenu.topbar,t.element()),t}},{key:"createTopbar",value:function(){var e=Object(l.e)('
    ');return Object(l.m)(this.el,e),e}},{key:"createItems",value:function(e,t){var n=this,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Jt,a=this.name,r=e.map((function(e,r){var s,l;switch(a){case"quality":s="Auto"===e.label&&0===r?"".concat(i.defaultText,' '):e.label;break;case"captions":s="Off"!==e.label&&"off"!==e.id||0!==r?e.label:i.defaultText;break;case"playbackRates":l=e,s=Object(Lt.e)(i.tooltipText)?"x"+e:e+"x";break;case"audioTracks":s=e.name}s||(s=e,"object"===en(e)&&(s.options=i));var c=new o(s,function(e){c.active||(t(l||r),c.deactivate&&(n.items.filter((function(e){return!0===e.active})).forEach((function(e){e.deactivate()})),Zt?Zt.open(e):n.mainMenu.close(e)),c.activate&&c.activate())}.bind(n));return c}));return r}},{key:"setMenuItems",value:function(e,t){var n=this;e?(this.items=[],Object(l.h)(this.itemsContainer.el),e.forEach((function(e){n.items.push(e),n.itemsContainer.el.appendChild(e.el)})),t>-1&&e[t].activate(),this.categoryButton.show()):this.removeMenu()}},{key:"appendMenu",value:function(e){if(e){var t=e.el,n=e.name,i=e.categoryButton;if(this.children[n]=e,i){var o=this.mainMenu.buttonContainer,a=o.querySelector(".jw-settings-sharing"),r="quality"===n?o.firstChild:a||this.closeButton.element();o.insertBefore(i.element(),r)}this.mainMenu.el.appendChild(t)}}},{key:"removeMenu",value:function(e){if(!e)return this.parentMenu.removeMenu(this.name);var t=this.children[e];t&&(delete this.children[e],t.destroy())}},{key:"open",value:function(e){if(!this.visible||this.openMenus){var t;if(Zt=null,this.isSubmenu){var n=this.mainMenu,i=this.parentMenu,o=this.categoryButton;if(i.openMenus.length&&i.closeChildren(),o&&o.element().setAttribute("aria-checked","true"),i.isSubmenu){i.el.classList.remove("jw-settings-submenu-active"),n.topbar.classList.add("jw-nested-menu-open");var a=n.topbar.querySelector(".jw-settings-topbar-text");a.setAttribute("name",this.name),a.innerText=this.title||this.name,n.backButton.show(),Zt=this.parentMenu,t=this.topbar?this.topbar.firstChild:e&&"enter"===e.type?this.items[0].el:a}else n.topbar.classList.remove("jw-nested-menu-open"),n.backButton&&n.backButton.hide();this.el.classList.add("jw-settings-submenu-active"),i.openMenus.push(this.name),n.visible||(n.open(e),this.items&&e&&"enter"===e.type?t=this.topbar?this.topbar.firstChild.focus():this.items[0].el:o.tooltip&&(o.tooltip.suppress=!0,t=o.element())),this.openMenus.length&&this.closeChildren(),t&&t.focus(),this.el.scrollTop=0}else this.el.parentNode.classList.add("jw-settings-open"),this.trigger("menuVisibility",{visible:!0,evt:e}),document.addEventListener("click",this.onDocumentClick);this.visible=!0,this.el.setAttribute("aria-expanded","true")}}},{key:"close",value:function(e){var t=this;this.visible&&(this.visible=!1,this.el.setAttribute("aria-expanded","false"),this.isSubmenu?(this.el.classList.remove("jw-settings-submenu-active"),this.categoryButton.element().setAttribute("aria-checked","false"),this.parentMenu.openMenus=this.parentMenu.openMenus.filter((function(e){return e!==t.name})),!this.mainMenu.openMenus.length&&this.mainMenu.visible&&this.mainMenu.close(e)):(this.el.parentNode.classList.remove("jw-settings-open"),this.trigger("menuVisibility",{visible:!1,evt:e}),document.removeEventListener("click",this.onDocumentClick)),this.openMenus.length&&this.closeChildren())}},{key:"closeChildren",value:function(){var e=this;this.openMenus.forEach((function(t){var n=e.children[t];n&&n.close()}))}},{key:"toggle",value:function(e){this.visible?this.close(e):this.open(e)}},{key:"onDocumentClick",value:function(e){/jw-(settings|video|nextup-close|sharing-link|share-item)/.test(e.target.className)||this.close()}},{key:"destroy",value:function(){var e=this;if(document.removeEventListener("click",this.onDocumentClick),Object.keys(this.children).map((function(t){e.children[t].destroy()})),this.isSubmenu){this.parentMenu.name===this.mainMenu.name&&this.categoryButton&&(this.parentMenu.buttonContainer.removeChild(this.categoryButton.element()),this.categoryButton.ui.destroy()),this.itemsContainer&&this.itemsContainer.destroy();var t=this.parentMenu.openMenus,n=t.indexOf(this.name);t.length&&n>-1&&this.openMenus.splice(n,1),delete this.parentMenu}else this.ui.destroy();this.visible=!1,this.el.parentNode&&this.el.parentNode.removeChild(this.el)}},{key:"defaultChild",get:function(){var e=this.children,t=e.quality,n=e.captions,i=e.audioTracks,o=e.sharing,a=e.playbackRates;return t||n||i||o||a}}])&&tn(n.prototype,i),o&&tn(n,o),t}(r.a),sn=function(e){var t=e.closeButton,n=e.el;return new u.a(n).on("keydown",(function(n){var i=n.sourceEvent,o=n.target,a=Object(l.k)(o),r=Object(l.n)(o),s=i.key.replace(/(Arrow|ape)/,""),c=function(t){r?t||r.focus():e.close(n)};switch(s){case"Esc":e.close(n);break;case"Left":c();break;case"Right":a&&t.element()&&o!==t.element()&&a.focus();break;case"Tab":i.shiftKey&&c(!0);break;case"Up":case"Down":!function(){var t=e.children[o.getAttribute("name")];if(!t&&Zt&&(t=Zt.children[Zt.openMenus]),t)return t.open(n),void(t.topbar?t.topbar.firstChild.focus():t.items&&t.items.length&&t.items[0].el.focus());if(n.target.parentNode.classList.contains("jw-submenu-topbar")){var i=n.target.parentNode.parentNode.querySelector(".jw-settings-submenu-items");("Down"===s?i.childNodes[0]:i.childNodes[i.childNodes.length-1]).focus()}}()}if(i.stopPropagation(),/13|32|37|38|39|40/.test(i.keyCode))return i.preventDefault(),!1}))},ln=n(59),cn=function(e){return fn[e]},un=function(e){for(var t,n=Object.keys(fn),i=0;i1;n.elements.settingsButton.toggle(c)};t.change("levels",(function(e,t){r(t)}),o);var s=function(e,n,i){var o=t.get("levels");if(o&&"Auto"===o[0].label&&n&&n.items.length){var a=n.items[0].el.querySelector(".jw-auto-label"),r=o[e.index]||{label:""};a.textContent=i?"":r.label}};t.on("change:visualQuality",(function(e,n){var i=o.children.quality;n&&i&&s(n.level,i,t.get("currentLevel"))})),t.on("change:currentLevel",(function(e,n){var i=o.children.quality,a=t.get("visualQuality");a&&i&&s(a.level,i,n)}),o),t.change("captionsList",(function(n,r){var s={defaultText:i.off},l=t.get("captionsIndex");a("captions",r,(function(t){return e.setCurrentCaptions(t)}),l,s);var c=o.children.captions;if(c&&!c.children.captionsSettings){c.topbar=c.topbar||c.createTopbar();var u=new rn("captionsSettings",c,i);u.title="Subtitle Settings";var d=new Kt("Settings",u.open);c.topbar.appendChild(d.el);var p=new Jt("Reset",(function(){t.set("captions",ln.a),h()}));p.el.classList.add("jw-settings-reset");var f=t.get("captions"),h=function(){var e=[];wn.forEach((function(n){f&&f[n.propertyName]&&(n.defaultVal=n.getOption(f[n.propertyName]));var o=new rn(n.name,u,i),a=new Kt({label:n.name,value:n.defaultVal},o.open,Ht),r=o.createItems(n.options,(function(e){var i=a.el.querySelector(".jw-settings-content-item-value");!function(e,n){var i=t.get("captions"),o=e.propertyName,a=e.options&&e.options[n],r=e.getTypedValue(a),s=Object(w.g)({},i);s[o]=r,t.set("captions",s)}(n,e),i.innerText=n.options[e]}),null);o.setMenuItems(r,n.options.indexOf(n.defaultVal)||0),e.push(a)})),e.push(p),u.setMenuItems(e)};h()}}));var l=function(e,t){e&&t>-1&&e.items[t].activate()};t.change("captionsIndex",(function(e,t){var i=o.children.captions;i&&l(i,t),n.toggleCaptionsButtonState(!!t)}),o);var c=function(n){if(t.get("supportsPlaybackRate")&&"LIVE"!==t.get("streamType")&&t.get("playbackRateControls")){var r=n.indexOf(t.get("playbackRate")),s={tooltipText:i.playbackRates};a("playbackRates",n,(function(t){return e.setPlaybackRate(t)}),r,s)}else o.children.playbackRates&&o.removeMenu("playbackRates")};t.on("change:playbackRates",(function(e,t){c(t)}),o);var u=function(n){a("audioTracks",n,(function(t){return e.setCurrentAudioTrack(t)}),t.get("currentAudioTrack"))};return t.on("change:audioTracks",(function(e,t){u(t)}),o),t.on("change:playbackRate",(function(e,n){var i=t.get("playbackRates"),a=-1;i&&(a=i.indexOf(n)),l(o.children.playbackRates,a)}),o),t.on("change:currentAudioTrack",(function(e,t){o.children.audioTracks.items[t].activate()}),o),t.on("change:playlistItem",(function(){o.removeMenu("captions"),n.elements.captionsButton.hide(),o.visible&&o.close()}),o),t.on("change:playbackRateControls",(function(){c(t.get("playbackRates"))})),t.on("change:castActive",(function(e,n,i){n!==i&&(n?(o.removeMenu("audioTracks"),o.removeMenu("quality"),o.removeMenu("playbackRates")):(u(t.get("audioTracks")),r(t.get("levels")),c(t.get("playbackRates"))))}),o),t.on("change:streamType",(function(){c(t.get("playbackRates"))}),o),o},jn=n(58),gn=n(35),bn=n(12),mn=function(e,t,n,i){var o=Object(l.e)('
    '),r=!1,s=null,c=!1,u=function(e){/jw-info/.test(e.target.className)||w.close()},d=function(){var i,a,s,c,u,d=p("jw-info-close",(function(){w.close()}),t.get("localization").close,[de("close")]);d.show(),Object(l.m)(o,d.element()),a=o.querySelector(".jw-info-title"),s=o.querySelector(".jw-info-duration"),c=o.querySelector(".jw-info-description"),u=o.querySelector(".jw-info-clientid"),t.change("playlistItem",(function(e,t){var n=t.description,i=t.title;Object(l.q)(c,n||""),Object(l.q)(a,i||"Unknown Title")})),t.change("duration",(function(e,n){var i="";switch(t.get("streamType")){case"LIVE":i="Live";break;case"DVR":i="DVR";break;default:n&&(i=Object(ve.timeFormat)(n))}s.textContent=i}),w),u.textContent=(i=n.getPlugin("jwpsrv"))&&"function"==typeof i.doNotTrackUser&&i.doNotTrackUser()?"":"Client ID: ".concat(function(){try{return window.localStorage.jwplayerLocalId}catch(e){return"none"}}()),e.appendChild(o),r=!0};var w={open:function(){r||d(),document.addEventListener("click",u),c=!0;var e=t.get("state");e===a.pb&&n.pause("infoOverlayInteraction"),s=e,i(!0)},close:function(){document.removeEventListener("click",u),c=!1,t.get("state")===a.ob&&s===a.pb&&n.play("infoOverlayInteraction"),s=null,i(!1)},destroy:function(){this.close(),t.off(null,null,this)}};return Object.defineProperties(w,{visible:{enumerable:!0,get:function(){return c}}}),w};var vn=function(e,t,n){var i,o=!1,r=null,s=n.get("localization").shortcuts,c=Object(l.e)(function(e,t){var n=e.map((function(e){return'
    '+''.concat(e.description,"")+''.concat(e.key,"")+"
    "})).join("");return'
    ')+'Press shift question mark to access a list of keyboard shortcuts
    '+''.concat(t,"")+'
    '+"".concat(n)+"
    "}(function(e){var t=e.playPause,n=e.volumeToggle,i=e.fullscreenToggle,o=e.seekPercent,a=e.increaseVolume,r=e.decreaseVolume,s=e.seekForward,l=e.seekBackward;return[{key:e.spacebar,description:t},{key:"↑",description:a},{key:"↓",description:r},{key:"→",description:s},{key:"←",description:l},{key:"c",description:e.captionsToggle},{key:"f",description:i},{key:"m",description:n},{key:"0-9",description:o}]}(s),s.keyboardShortcuts)),d={reason:"settingsInteraction"},w=new u.a(c.querySelector(".jw-switch")),f=function(){w.el.setAttribute("aria-checked",n.get("enableShortcuts")),Object(l.a)(c,"jw-open"),r=n.get("state"),c.querySelector(".jw-shortcuts-close").focus(),document.addEventListener("click",j),o=!0,t.pause(d)},h=function(){Object(l.o)(c,"jw-open"),document.removeEventListener("click",j),e.focus(),o=!1,r===a.pb&&t.play(d)},j=function(e){/jw-shortcuts|jw-switch/.test(e.target.className)||h()},g=function(e){var t=e.currentTarget,i="true"!==t.getAttribute("aria-checked");t.setAttribute("aria-checked",i),n.set("enableShortcuts",i)};return i=p("jw-shortcuts-close",h,n.get("localization").close,[de("close")]),Object(l.m)(c,i.element()),i.show(),e.appendChild(c),w.on("click tap enter",g),{el:c,open:f,close:h,destroy:function(){h(),w.destroy()},toggleVisibility:function(){o?h():f()}}},yn=function(e){return'
    ')+"
    "};function kn(e){return(kn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function xn(e,t){for(var n=0;n16?i.activeTimeout=setTimeout(i.userInactiveTimeout,e):i.playerContainer.querySelector(".jw-tab-focus")?i.resetActiveTimeout():i.userInactive()},i}var n,i,r;return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&Pn(e,t)}(t,e),n=t,(i=[{key:"resetActiveTimeout",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.inactiveTime=0}},{key:"enable",value:function(e,t){var n=this,i=this.context.createElement("div");i.className="jw-controls jw-reset",this.div=i;var r=this.context.createElement("div");r.className="jw-controls-backdrop jw-reset",this.backdrop=r,this.logo=this.playerContainer.querySelector(".jw-logo");var c=t.get("touchMode"),u=function(){(t.get("isFloating")?n.wrapperElement:n.playerContainer).focus()};if(!this.displayContainer){var d=new Ct(t,e);d.buttons.display.on("click tap enter",(function(){n.trigger(a.p),n.userActive(1e3),e.playToggle(Rn()),u()})),this.div.appendChild(d.element()),this.displayContainer=d}this.infoOverlay=new mn(i,t,e,(function(e){Object(l.v)(n.div,"jw-info-open",e),e&&n.div.querySelector(".jw-info-close").focus()})),o.OS.mobile||(this.shortcutsTooltip=new vn(this.wrapperElement,e,t)),this.rightClickMenu=new Vt(this.infoOverlay,this.shortcutsTooltip),c?(Object(l.a)(this.playerContainer,"jw-flag-touch"),this.rightClickMenu.setup(t,this.playerContainer,this.wrapperElement)):t.change("flashBlocked",(function(e,t){t?n.rightClickMenu.destroy():n.rightClickMenu.setup(e,n.playerContainer,n.wrapperElement)}),this);var w=t.get("floating");if(w){var f=new Sn(i,t.get("localization").close);f.on(a.sb,(function(){return n.trigger("dismissFloating",{doNotForward:!0})})),!1!==w.dismissible&&Object(l.a)(this.playerContainer,"jw-floating-dismissible")}var h=this.controlbar=new dt(e,t,this.playerContainer.querySelector(".jw-hidden-accessibility"));if(h.on(a.sb,(function(){return n.userActive()})),h.on("nextShown",(function(e){this.trigger("nextShown",e)}),this),h.on("adjustVolume",k,this),t.get("nextUpDisplay")&&!h.nextUpToolTip){var j=new Et(t,e,this.playerContainer);j.on("all",this.trigger,this),j.setup(this.context),h.nextUpToolTip=j,this.div.appendChild(j.element())}this.div.appendChild(h.element());var g=t.get("localization"),b=this.settingsMenu=hn(e,t.player,this.controlbar,g),m=null;this.controlbar.on("menuVisibility",(function(i){var o=i.visible,r=i.evt,s=t.get("state"),l={reason:"settingsInteraction"},c=n.controlbar.elements.settingsButton,d="keydown"===(r&&r.sourceEvent||r||{}).type,p=o||d?0:An;n.userActive(p),m=s,Object(jn.a)(t.get("containerWidth"))<2&&(o&&s===a.pb?e.pause(l):o||s!==a.ob||m!==a.pb||e.play(l)),!o&&d&&c?c.element().focus():r&&u()})),b.on("menuVisibility",(function(e){return n.controlbar.trigger("menuVisibility",e)})),this.controlbar.on("settingsInteraction",(function(e,t,n){if(t)return b.defaultChild.toggle(n);b.children[e].toggle(n)})),o.OS.mobile?this.div.appendChild(b.el):(this.playerContainer.setAttribute("aria-describedby","jw-shortcuts-tooltip-explanation"),this.div.insertBefore(b.el,h.element()));var v=function(t){if(t.get("autostartMuted")){var i=function(){return n.unmuteAutoplay(e,t)},a=function(e,t){t||i()};o.OS.mobile&&(n.mute=p("jw-autostart-mute jw-off",i,t.get("localization").unmute,[de("volume-0")]),n.mute.show(),n.div.appendChild(n.mute.element())),h.renderVolume(!0,t.get("volume")),Object(l.a)(n.playerContainer,"jw-flag-autostart"),t.on("change:autostartFailed",i,n),t.on("change:autostartMuted change:mute",a,n),n.muteChangeCallback=a,n.unmuteCallback=i}};function y(n){var i=0,o=t.get("duration"),a=t.get("position");if("DVR"===t.get("streamType")){var r=t.get("dvrSeekLimit");i=o,o=Math.max(a,-r)}var l=Object(s.a)(a+n,i,o);e.seek(l,Rn())}function k(n){var i=Object(s.a)(t.get("volume")+n,0,100);e.setVolume(i)}t.once("change:autostartMuted",v),v(t);var x=function(i){if(i.ctrlKey||i.metaKey)return!0;var o=!n.settingsMenu.visible,a=!0===t.get("enableShortcuts"),r=n.instreamState;if(a||-1!==Ln.indexOf(i.keyCode)){switch(i.keyCode){case 27:if(t.get("fullscreen"))e.setFullscreen(!1),n.playerContainer.blur(),n.userInactive();else{var s=e.getPlugin("related");s&&s.close({type:"escape"})}n.rightClickMenu.el&&n.rightClickMenu.hideMenuHandler(),n.infoOverlay.visible&&n.infoOverlay.close(),n.shortcutsTooltip&&n.shortcutsTooltip.close();break;case 13:case 32:if(document.activeElement.classList.contains("jw-switch")&&13===i.keyCode)return!0;e.playToggle(Rn());break;case 37:!r&&o&&y(-5);break;case 39:!r&&o&&y(5);break;case 38:o&&k(10);break;case 40:o&&k(-10);break;case 67:var l=e.getCaptionsList().length;if(l){var c=(e.getCurrentCaptions()+1)%l;e.setCurrentCaptions(c)}break;case 77:e.setMute();break;case 70:e.setFullscreen();break;case 191:n.shortcutsTooltip&&n.shortcutsTooltip.toggleVisibility();break;default:if(i.keyCode>=48&&i.keyCode<=59){var u=(i.keyCode-48)/10*t.get("duration");e.seek(u,Rn())}}return/13|32|37|38|39|40/.test(i.keyCode)?(i.preventDefault(),!1):void 0}};this.playerContainer.addEventListener("keydown",x),this.keydownCallback=x;var O=function(e){switch(e.keyCode){case 9:var t=n.playerContainer.contains(e.target)?0:An;n.userActive(t);break;case 32:e.preventDefault()}};this.playerContainer.addEventListener("keyup",O),this.keyupCallback=O;var C=function(e){var t=e.relatedTarget||document.querySelector(":focus");t&&(n.playerContainer.contains(t)||n.userInactive())};this.playerContainer.addEventListener("blur",C,!0),this.blurCallback=C;var M=function e(){"jw-shortcuts-tooltip-explanation"===n.playerContainer.getAttribute("aria-describedby")&&n.playerContainer.removeAttribute("aria-describedby"),n.playerContainer.removeEventListener("blur",e,!0)};this.shortcutsTooltip&&(this.playerContainer.addEventListener("blur",M,!0),this.onRemoveShortcutsDescription=M),this.userActive(),this.addControls(),this.addBackdrop(),t.set("controlsEnabled",!0)}},{key:"addControls",value:function(){this.wrapperElement.appendChild(this.div)}},{key:"disable",value:function(e){var t=this.nextUpToolTip,n=this.settingsMenu,i=this.infoOverlay,o=this.controlbar,a=this.rightClickMenu,r=this.shortcutsTooltip,s=this.playerContainer,c=this.div;clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.off(),e.off(null,null,this),e.set("controlsEnabled",!1),c.parentNode&&(Object(l.o)(s,"jw-flag-touch"),c.parentNode.removeChild(c)),o&&o.destroy(),a&&a.destroy(),this.keydownCallback&&s.removeEventListener("keydown",this.keydownCallback),this.keyupCallback&&s.removeEventListener("keyup",this.keyupCallback),this.blurCallback&&s.removeEventListener("blur",this.blurCallback),this.onRemoveShortcutsDescription&&s.removeEventListener("blur",this.onRemoveShortcutsDescription),this.displayContainer&&this.displayContainer.destroy(),t&&t.destroy(),n&&n.destroy(),i&&i.destroy(),r&&r.destroy(),this.removeBackdrop()}},{key:"controlbarHeight",value:function(){return this.dimensions.cbHeight||(this.dimensions.cbHeight=this.controlbar.element().clientHeight),this.dimensions.cbHeight}},{key:"element",value:function(){return this.div}},{key:"resize",value:function(){this.dimensions={}}},{key:"unmuteAutoplay",value:function(e,t){var n=!t.get("autostartFailed"),i=t.get("mute");n?i=!1:t.set("playOnViewable",!1),this.muteChangeCallback&&(t.off("change:autostartMuted change:mute",this.muteChangeCallback),this.muteChangeCallback=null),this.unmuteCallback&&(t.off("change:autostartFailed",this.unmuteCallback),this.unmuteCallback=null),t.set("autostartFailed",void 0),t.set("autostartMuted",void 0),e.setMute(i),this.controlbar.renderVolume(i,t.get("volume")),this.mute&&this.mute.hide(),Object(l.o)(this.playerContainer,"jw-flag-autostart"),this.userActive()}},{key:"mouseMove",value:function(e){var t=this.controlbar.element().contains(e.target),n=this.controlbar.nextUpToolTip&&this.controlbar.nextUpToolTip.element().contains(e.target),i=this.logo&&this.logo.contains(e.target),o=t||n||i?0:An;this.userActive(o)}},{key:"userActive",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:An;e>0?(this.inactiveTime=Object(c.a)()+e,-1===this.activeTimeout&&(this.activeTimeout=setTimeout(this.userInactiveTimeout,e))):this.resetActiveTimeout(),this.showing||(Object(l.o)(this.playerContainer,"jw-flag-user-inactive"),this.showing=!0,this.trigger("userActive"))}},{key:"userInactive",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.settingsMenu.visible||(this.inactiveTime=0,this.showing=!1,Object(l.a)(this.playerContainer,"jw-flag-user-inactive"),this.trigger("userInactive"))}},{key:"addBackdrop",value:function(){var e=this.instreamState?this.div:this.wrapperElement.querySelector(".jw-captions");this.wrapperElement.insertBefore(this.backdrop,e)}},{key:"removeBackdrop",value:function(){var e=this.backdrop.parentNode;e&&e.removeChild(this.backdrop)}},{key:"setupInstream",value:function(){this.instreamState=!0,this.userActive(),this.addBackdrop(),this.settingsMenu&&this.settingsMenu.close(),Object(l.o)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","-1")}},{key:"destroyInstream",value:function(e){this.instreamState=null,this.addBackdrop(),e.get("autostartMuted")&&Object(l.a)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","0")}}])&&En(n.prototype,i),r&&En(n,r),t}(r.a)},function(e,t,n){"use strict";n.r(t);var i=n(0),o=n(12),a=n(50),r=n(36);var s=n(44),l=n(51),c=n(26),u=n(25),d=n(3),p=n(46),w=n(2),f=n(7),h=n(34);function j(e){var t=!1;return{async:function(){var n=this,i=arguments;return Promise.resolve().then((function(){if(!t)return e.apply(n,i)}))},cancel:function(){t=!0},cancelled:function(){return t}}}var g=n(1);function b(e){return function(t,n){var o=e.mediaModel,a=Object(i.g)({},n,{type:t});switch(t){case d.T:if(o.get(d.T)===n.mediaType)return;o.set(d.T,n.mediaType);break;case d.U:return void o.set(d.U,Object(i.g)({},n));case d.M:if(n[t]===e.model.getMute())return;break;case d.bb:n.newstate===d.mb&&(e.thenPlayPromise.cancel(),o.srcReset());var r=o.attributes.mediaState;o.attributes.mediaState=n.newstate,o.trigger("change:mediaState",o,n.newstate,r);break;case d.F:return e.beforeComplete=!0,e.trigger(d.B,a),void(e.attached&&!e.background&&e._playbackComplete());case d.G:o.get("setup")?(e.thenPlayPromise.cancel(),o.srcReset()):(t=d.tb,a.code+=1e5);break;case d.K:a.metadataType||(a.metadataType="unknown");var s=n.duration;Object(i.u)(s)&&(o.set("seekRange",n.seekRange),o.set("duration",s));break;case d.D:o.set("buffer",n.bufferPercent);case d.S:o.set("seekRange",n.seekRange),o.set("position",n.position),o.set("currentTime",n.currentTime);var l=n.duration;Object(i.u)(l)&&o.set("duration",l),t===d.S&&Object(i.r)(e.item.starttime)&&delete e.item.starttime;break;case d.R:var c=e.mediaElement;c&&c.paused&&o.set("mediaState","paused");break;case d.I:o.set(d.I,n.levels);case d.J:var u=n.currentQuality,p=n.levels;u>-1&&p.length>1&&o.set("currentLevel",parseInt(u));break;case d.f:o.set(d.f,n.tracks);case d.g:var w=n.currentTrack,f=n.tracks;w>-1&&f.length>0&&w=Math.max(l,p.a)&&(e.preloadNextItem(),v=!0)}function P(e){var t={};b.tag&&(t.tag=b.tag),this.trigger(d.F,t),A.call(this,e)}function A(e){j={},a&&h+10?e:null,f&&f.model.set("skipOffset",s)}};Object(i.g)(le.prototype,f.a);var ce=le,ue=n(66),de=n(63),pe=function(e){var t=this,n=[],i={},o=0,a=0;function r(e){if(e.data=e.data||[],e.name=e.label||e.name||e.language,e._id=Object(de.a)(e,n.length),!e.name){var t=Object(de.b)(e,o);e.name=t.label,o=t.unknownCount}i[e._id]=e,n.push(e)}function s(){for(var e=[{id:"off",label:"Off"}],t=0;t')+'
    '},he=n(35),je=44,ge=function(e){var t=e.get("height");if(e.get("aspectratio"))return!1;if("string"==typeof t&&t.indexOf("%")>-1)return!1;var n=1*t||NaN;return!!(n=isNaN(n)?e.get("containerHeight"):n)&&(n&&n<=je)},be=n(54);function me(e,t){if(e.get("fullscreen"))return 1;if(!e.get("activeTab"))return 0;if(e.get("isFloating"))return 1;var n=e.get("intersectionRatio");return void 0===n&&(n=function(e){var t=document.documentElement,n=document.body,i={top:0,left:0,right:t.clientWidth||n.clientWidth,width:t.clientWidth||n.clientWidth,bottom:t.clientHeight||n.clientHeight,height:t.clientHeight||n.clientHeight};if(!n.contains(e))return 0;if("none"===window.getComputedStyle(e).display)return 0;var o=ve(e);if(!o)return 0;var a=o,r=e.parentNode,s=!1;for(;!s;){var l=null;if(r===n||r===t||1!==r.nodeType?(s=!0,l=i):"visible"!==window.getComputedStyle(r).overflow&&(l=ve(r)),l&&(c=l,u=a,d=void 0,p=void 0,w=void 0,f=void 0,h=void 0,j=void 0,d=Math.max(c.top,u.top),p=Math.min(c.bottom,u.bottom),w=Math.max(c.left,u.left),f=Math.min(c.right,u.right),j=p-d,!(a=(h=f-w)>=0&&j>=0&&{top:d,bottom:p,left:w,right:f,width:h,height:j})))return 0;r=r.parentNode}var c,u,d,p,w,f,h,j;var g=o.width*o.height,b=a.width*a.height;return g?b/g:0}(t),window.top!==window.self&&n)?0:n}function ve(e){try{return e.getBoundingClientRect()}catch(e){}}var ye=n(49),ke=n(42),xe=n(58),Oe=n(10);var Ce=n(32),Me=n(5),Se=n(6),Te=["fullscreenchange","webkitfullscreenchange","mozfullscreenchange","MSFullscreenChange"],Ee=function(e,t,n){for(var i=e.requestFullscreen||e.webkitRequestFullscreen||e.webkitRequestFullScreen||e.mozRequestFullScreen||e.msRequestFullscreen,o=t.exitFullscreen||t.webkitExitFullscreen||t.webkitCancelFullScreen||t.mozCancelFullScreen||t.msExitFullscreen,a=!(!i||!o),r=Te.length;r--;)t.addEventListener(Te[r],n);return{events:Te,supportsDomFullscreen:function(){return a},requestFullscreen:function(){i.call(e,{navigationUI:"hide"})},exitFullscreen:function(){null!==this.fullscreenElement()&&o.apply(t)},fullscreenElement:function(){var e=t.fullscreenElement,n=t.webkitCurrentFullScreenElement,i=t.mozFullScreenElement,o=t.msFullscreenElement;return null===e?e:e||n||i||o},destroy:function(){for(var e=Te.length;e--;)t.removeEventListener(Te[e],n)}}},_e=n(40);function ze(e,t){for(var n=0;n')},Re={linktarget:"_blank",margin:8,hide:!1,position:"top-right"};function Ie(e){var t,n;Object(i.g)(this,f.a);var o=new Image;this.setup=function(){(n=Object(i.g)({},Re,e.get("logo"))).position=n.position||Re.position,n.hide="true"===n.hide.toString(),n.file&&"control-bar"!==n.position&&(t||(t=Object(Me.e)(Le(n.position,n.hide))),e.set("logo",n),o.onload=function(){var i=this.height,o=this.width,a={backgroundImage:'url("'+this.src+'")'};if(n.margin!==Re.margin){var r=/(\w+)-(\w+)/.exec(n.position);3===r.length&&(a["margin-"+r[1]]=n.margin,a["margin-"+r[2]]=n.margin)}var s=.15*e.get("containerHeight"),l=.15*e.get("containerWidth");if(i>s||o>l){var c=o/i;l/s>c?(i=s,o=s*c):(o=l,i=l/c)}a.width=Math.round(o),a.height=Math.round(i),Object(Oe.d)(t,a),e.set("logoWidth",a.width)},o.src=n.file,n.link&&(t.setAttribute("tabindex","0"),t.setAttribute("aria-label",e.get("localization").logo)),this.ui=new _e.a(t).on("click tap enter",(function(e){e&&e.stopPropagation&&e.stopPropagation(),this.trigger(d.A,{link:n.link,linktarget:n.linktarget})}),this))},this.setContainer=function(e){t&&e.appendChild(t)},this.element=function(){return t},this.position=function(){return n.position},this.destroy=function(){o.onload=null,this.ui&&this.ui.destroy()}}var Be=function(e){this.model=e,this.image=null};Object(i.g)(Be.prototype,{setup:function(e){this.el=e},setImage:function(e){var t=this.image;t&&(t.onload=null),this.image=null;var n="";"string"==typeof e&&(n='url("'+e+'")',(t=this.image=new Image).src=e),Object(Oe.d)(this.el,{backgroundImage:n})},resize:function(e,t,n){if("uniform"===n){if(e&&(this.playerAspectRatio=e/t),!this.playerAspectRatio||!this.image||"complete"!==(s=this.model.get("state"))&&"idle"!==s&&"error"!==s&&"buffering"!==s)return;var i=this.image,o=null;if(i){if(0===i.width){var a=this;return void(i.onload=function(){a.resize(e,t,n)})}var r=i.width/i.height;Math.abs(this.playerAspectRatio-r)<.09&&(o="cover")}Object(Oe.d)(this.el,{backgroundSize:o})}var s},element:function(){return this.el}});var Ve=Be,Ne=function(e){this.model=e.player};Object(i.g)(Ne.prototype,{hide:function(){Object(Oe.d)(this.el,{display:"none"})},show:function(){Object(Oe.d)(this.el,{display:""})},setup:function(e){this.el=e;var t=this.el.getElementsByTagName("div");this.title=t[0],this.description=t[1],this.model.on("change:logoWidth",this.update,this),this.model.change("playlistItem",this.playlistItem,this)},update:function(e){var t={},n=e.get("logo");if(n){var i=1*(""+n.margin).replace("px",""),o=e.get("logoWidth")+(isNaN(i)?0:i+10);"top-left"===n.position?t.paddingLeft=o:"top-right"===n.position&&(t.paddingRight=o)}Object(Oe.d)(this.el,t)},playlistItem:function(e,t){if(t)if(e.get("displaytitle")||e.get("displaydescription")){var n="",i="";t.title&&e.get("displaytitle")&&(n=t.title),t.description&&e.get("displaydescription")&&(i=t.description),this.updateText(n,i)}else this.hide()},updateText:function(e,t){Object(Me.q)(this.title,e),Object(Me.q)(this.description,t),this.title.firstChild||this.description.firstChild?this.show():this.hide()},element:function(){return this.el}});var He=Ne;function Fe(e,t){for(var n=0;ne)}if(t.get("controls")){var r=ge(t);Object(Me.v)(u,"jw-flag-audio-player",r),t.set("audioMode",r)}}function I(){t.set("visibility",me(t,u))}this.updateBounds=function(){Object(ke.a)(k);var e=t.get("isFloating")?p:u,n=document.body.contains(e),i=Object(Me.c)(e),r=Math.round(i.width),s=Math.round(i.height);if(E=Object(Me.c)(u),r===o&&s===a)return o&&a||A(),void t.set("inDom",n);r&&s||o&&a||A(),(r||s||n)&&(t.set("containerWidth",r),t.set("containerHeight",s)),t.set("inDom",n),n&&be.a.observe(u)},this.updateStyles=function(){var e=t.get("containerWidth"),n=t.get("containerHeight");R(e,n),z&&z.resize(e,n),$(e,n),v.resize(),O&&F()},this.checkResized=function(){var e=t.get("containerWidth"),n=t.get("containerHeight"),i=t.get("isFloating");if(e!==o||n!==a){this.resizeListener||(this.resizeListener=new Ue.a(p,this,t)),o=e,a=n,l.trigger(d.hb,{width:e,height:n});var s=Object(xe.a)(e);_!==s&&(_=s,l.trigger(d.j,{breakpoint:_}))}i!==r&&(r=i,l.trigger(d.x,{floating:i}),I())},this.responsiveListener=A,this.setup=function(){g.setup(u.querySelector(".jw-preview")),b.setup(u.querySelector(".jw-title")),(n=new Ie(t)).setup(),n.setContainer(p),n.on(d.A,K),v.setup(u.id,t.get("captions")),b.element().parentNode.insertBefore(v.element(),b.element()),C=function(e,t,n){var i=new Pe(t,n),o=t.get("controls");i.on({click:function(){l.trigger(d.p),z&&(ce()?z.settingsMenu.close():ue()?z.infoOverlay.close():e.playToggle({reason:"interaction"}))},tap:function(){l.trigger(d.p),ce()&&z.settingsMenu.close(),ue()&&z.infoOverlay.close();var n=t.get("state");if(o&&(n===d.mb||n===d.kb||t.get("instream")&&n===d.ob)&&e.playToggle({reason:"interaction"}),o&&n===d.ob){if(t.get("instream")||t.get("castActive")||"audio"===t.get("mediaType"))return;Object(Me.v)(u,"jw-flag-controls-hidden"),l.dismissible&&Object(Me.v)(u,"jw-floating-dismissible",Object(Me.i)(u,"jw-flag-controls-hidden")),v.renderCues(!0)}else z&&(z.showing?z.userInactive():z.userActive())},doubleClick:function(){return z&&e.setFullscreen()}}),We||(u.addEventListener("mousemove",W),u.addEventListener("mouseover",Q),u.addEventListener("mouseout",Y));return i}(e,t,h),S=new _e.a(u).on("click",(function(){})),M=Ee(u,document,te),t.on("change:hideAdsControls",(function(e,t){Object(Me.v)(u,"jw-flag-ads-hide-controls",t)})),t.on("change:scrubbing",(function(e,t){Object(Me.v)(u,"jw-flag-dragging",t)})),t.on("change:playRejected",(function(e,t){Object(Me.v)(u,"jw-flag-play-rejected",t)})),t.on(d.X,ee),t.on("change:".concat(d.U),(function(){$(),v.resize()})),t.player.on("change:errorEvent",ae),t.change("stretching",X);var i=t.get("width"),o=t.get("height"),a=G(i,o);Object(Oe.d)(u,a),t.change("aspectratio",Z),R(i,o),t.get("controls")||(Object(Me.a)(u,"jw-flag-controls-hidden"),Object(Me.o)(u,"jw-floating-dismissible")),Qe&&Object(Me.a)(u,"jw-ie");var r=t.get("skin")||{};r.name&&Object(Me.p)(u,/jw-skin-\S+/,"jw-skin-"+r.name);var s=function(e){e||(e={});var t=e.active,n=e.inactive,i=e.background,o={};return o.controlbar=function(e){if(e||t||n||i){var o={};return e=e||{},o.iconsActive=e.iconsActive||t,o.icons=e.icons||n,o.text=e.text||n,o.background=e.background||i,o}}(e.controlbar),o.timeslider=function(e){if(e||t){var n={};return e=e||{},n.progress=e.progress||t,n.rail=e.rail,n}}(e.timeslider),o.menus=function(e){if(e||t||n||i){var o={};return e=e||{},o.text=e.text||n,o.textActive=e.textActive||t,o.background=e.background||i,o}}(e.menus),o.tooltips=function(e){if(e||n||i){var t={};return e=e||{},t.text=e.text||n,t.background=e.background||i,t}}(e.tooltips),o}(r);!function(e,t){var n;function i(t,n,i,o){if(i){t=Object(w.f)(t,"#"+e+(o?"":" "));var a={};a[n]=i,Object(Oe.b)(t.join(", "),a,e)}}t&&(t.controlbar&&function(t){i([".jw-controlbar .jw-icon-inline.jw-text",".jw-title-primary",".jw-title-secondary"],"color",t.text),t.icons&&(i([".jw-button-color:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:not(.jw-icon-cast)"],"color",t.icons),i([".jw-display-icon-container .jw-button-color"],"color",t.icons),Object(Oe.b)("#".concat(e," .jw-icon-cast google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.icons,"}"),e));t.iconsActive&&(i([".jw-display-icon-container .jw-button-color:hover",".jw-display-icon-container .jw-button-color:focus"],"color",t.iconsActive),i([".jw-button-color.jw-toggle:not(.jw-icon-cast)",".jw-button-color:hover:not(.jw-icon-cast)",".jw-button-color:focus:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:hover:not(.jw-icon-cast)"],"color",t.iconsActive),i([".jw-svg-icon-buffer"],"fill",t.icons),Object(Oe.b)("#".concat(e," .jw-icon-cast:hover google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(Oe.b)("#".concat(e," .jw-icon-cast:focus google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(Oe.b)("#".concat(e," .jw-icon-cast google-cast-launcher.jw-off:focus"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(Oe.b)("#".concat(e," .jw-icon-cast google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(Oe.b)("#".concat(e," .jw-icon-cast google-cast-launcher:focus"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(Oe.b)("#".concat(e," .jw-icon-cast:hover google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(Oe.b)("#".concat(e," .jw-icon-cast:focus google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e));i([" .jw-settings-topbar",":not(.jw-state-idle) .jw-controlbar",".jw-flag-audio-player .jw-controlbar"],"background",t.background,!0)}(t.controlbar),t.timeslider&&function(e){var t=e.progress;"none"!==t&&(i([".jw-progress",".jw-knob"],"background-color",t),i([".jw-buffer"],"background-color",Object(Oe.c)(t,50)));i([".jw-rail"],"background-color",e.rail),i([".jw-background-color.jw-slider-time",".jw-slider-time .jw-cue"],"background-color",e.background)}(t.timeslider),t.menus&&(i([".jw-option",".jw-toggle.jw-off",".jw-skip .jw-skip-icon",".jw-nextup-tooltip",".jw-nextup-close",".jw-settings-content-item",".jw-related-title"],"color",(n=t.menus).text),i([".jw-option.jw-active-option",".jw-option:not(.jw-active-option):hover",".jw-option:not(.jw-active-option):focus",".jw-settings-content-item:hover",".jw-nextup-tooltip:hover",".jw-nextup-tooltip:focus",".jw-nextup-close:hover"],"color",n.textActive),i([".jw-nextup",".jw-settings-menu"],"background",n.background)),t.tooltips&&function(e){i([".jw-skip",".jw-tooltip .jw-text",".jw-time-tip .jw-text"],"background-color",e.background),i([".jw-time-tip",".jw-tooltip"],"color",e.background),i([".jw-skip"],"border","none"),i([".jw-skip .jw-text",".jw-skip .jw-icon",".jw-time-tip .jw-text",".jw-tooltip .jw-text"],"color",e.text)}(t.tooltips),t.menus&&function(t){if(t.textActive){var n={color:t.textActive,borderColor:t.textActive,stroke:t.textActive};Object(Oe.b)("#".concat(e," .jw-color-active"),n,e),Object(Oe.b)("#".concat(e," .jw-color-active-hover:hover"),n,e)}if(t.text){var i={color:t.text,borderColor:t.text,stroke:t.text};Object(Oe.b)("#".concat(e," .jw-color-inactive"),i,e),Object(Oe.b)("#".concat(e," .jw-color-inactive-hover:hover"),i,e)}}(t.menus))}(t.get("id"),s),t.set("mediaContainer",h),t.set("iFrame",m.Features.iframe),t.set("activeTab",Object(ye.a)()),t.set("touchMode",We&&("string"==typeof o||o>=je)),be.a.add(this),t.get("enableGradient")&&!Qe&&Object(Me.a)(u,"jw-ab-drop-shadow"),this.isSetup=!0,t.trigger("viewSetup",u);var c=document.body.contains(u);c&&be.a.observe(u),t.set("inDom",c)},this.init=function(){this.updateBounds(),t.on("change:fullscreen",J),t.on("change:activeTab",I),t.on("change:fullscreen",I),t.on("change:intersectionRatio",I),t.on("change:visibility",U),t.on("instreamMode",(function(e){e?de():pe()})),I(),1!==be.a.size()||t.get("visibility")||U(t,1,0);var e=t.player;t.change("state",re),e.change("controls",q),t.change("streamType",ie),t.change("mediaType",oe),e.change("playlistItem",(function(e,t){le(e,t)})),o=a=null,O&&We&&be.a.addScrollHandler(F),this.checkResized()};var B,V=62,N=!0;function H(){var e=t.get("isFloating"),n=E.top0&&void 0!==arguments[0])||arguments[0],t={x:0,y:0,width:o||0,height:a||0};return z&&e&&(t.height-=z.controlbarHeight()),t},this.setCaptions=function(e){v.clear(),v.setup(t.get("id"),e),v.resize()},this.setIntersection=function(e){var n=Math.round(100*e.intersectionRatio)/100;t.set("intersectionRatio",n),O&&!P()&&(T=T||n>=.5)&&we(n)},this.stopFloating=function(e,n){if(e&&(O=null,be.a.removeScrollHandler(F)),Ye===u){Ye=null,t.set("isFloating",!1);var i=function(){Object(Me.o)(u,"jw-flag-floating"),Z(t,t.get("aspectratio")),Object(Oe.d)(u,{backgroundImage:null}),Object(Oe.d)(p,{maxWidth:null,width:null,height:null,left:null,right:null,top:null,bottom:null,margin:null,transform:null,transition:null,"transition-timing-function":null})};n?(Object(Oe.d)(p,{transform:"translateY(-".concat(V-E.top,"px)"),"transition-timing-function":"ease-out"}),setTimeout(i,150)):i(),j.disable(),A()}},this.destroy=function(){t.destroy(),be.a.unobserve(u),be.a.remove(this),this.isSetup=!1,this.off(),Object(ke.a)(k),clearTimeout(y),Ye===u&&(Ye=null),S&&(S.destroy(),S=null),M&&(M.destroy(),M=null),z&&z.disable(t),C&&(C.destroy(),u.removeEventListener("mousemove",W),u.removeEventListener("mouseout",Y),u.removeEventListener("mouseover",Q),C=null),v.destroy(),n&&(n.destroy(),n=null),Object(Oe.a)(t.get("id")),this.resizeListener&&(this.resizeListener.destroy(),delete this.resizeListener),O&&We&&be.a.removeScrollHandler(F)}};function Ze(e,t,n){return(Ze="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(e,t,n){var i=function(e,t){for(;!Object.prototype.hasOwnProperty.call(e,t)&&null!==(e=tt(e)););return e}(e,t);if(i){var o=Object.getOwnPropertyDescriptor(i,t);return o.get?o.get.call(n):o.value}})(e,t,n||e)}function Ke(e){return(Ke="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function Je(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function Ge(e,t){for(var n=0;nt&&e(),t=i}};function Ct(e,t){t.off(d.N,e._onPlayAttempt),t.off(d.fb,e._triggerFirstFrame),t.off(d.S,e._onTime),e.off("change:activeTab",e._onTabVisible)}var Mt=function(e,t){e.change("mediaModel",(function(e,n,i){e._qoeItem&&i&&e._qoeItem.end(i.get("mediaState")),e._qoeItem=new yt.a,e._qoeItem.getFirstFrame=function(){var e=this.between(d.N,d.H),t=this.between(xt,d.H);return t>0&&t0&&re(t,e.tracks)}),C).on(d.F,(function(){Promise.resolve().then(ae)}),C).on(d.G,C.triggerError,C),Mt(M,B),M.on(d.w,C.triggerError,C),M.on("change:state",(function(e,t,n){X()||Z.call(O,e,t,n)}),this),M.on("change:castState",(function(e,t){C.trigger(d.m,t)})),M.on("change:fullscreen",(function(e,t){C.trigger(d.y,{fullscreen:t}),t&&e.set("playOnViewable",!1)})),M.on("change:volume",(function(e,t){C.trigger(d.V,{volume:t})})),M.on("change:mute",(function(e){C.trigger(d.M,{mute:e.getMute()})})),M.on("change:playbackRate",(function(e,t){C.trigger(d.ab,{playbackRate:t,position:e.get("position")})}));var V=function e(t,n){"clickthrough"!==n&&"interaction"!==n&&"external"!==n||(M.set("playOnViewable",!1),M.off("change:playReason change:pauseReason",e))};function N(e,t){Object(i.t)(t)||M.set("viewable",Math.round(t))}function H(){de&&(!0!==M.get("autostart")||M.get("playOnViewable")||$("autostart"),de.flush())}function F(e,t){C.trigger("viewable",{viewable:t}),q()}function q(){if((o.a[0]===t||1===M.get("viewable"))&&"idle"===M.get("state")&&!1===M.get("autostart"))if(!b.primed()&&m.OS.android){var e=b.getTestElement(),n=C.getMute();Promise.resolve().then((function(){return ft(e,{muted:n})})).then((function(){"idle"===M.get("state")&&B.preloadVideo()})).catch(Et)}else B.preloadVideo()}function D(e){C._instreamAdapter.noResume=!e,e||te({reason:"viewable"})}function U(e){e||(C.pause({reason:"viewable"}),M.set("playOnViewable",!e))}function W(e,t){var n=X();if(e.get("playOnViewable")){if(t){var i=e.get("autoPause").pauseAds,o=e.get("pauseReason");K()===d.mb?$("viewable"):n&&!i||"interaction"===o||J({reason:"viewable"})}else m.OS.mobile&&!n&&(C.pause({reason:"autostart"}),M.set("playOnViewable",!0));m.OS.mobile&&n&&D(t)}}function Q(e,t){var n=e.get("state"),i=X(),o=e.get("playReason");i?e.get("autoPause").pauseAds?U(t):D(t):n===d.pb||n===d.jb?U(t):n===d.mb&&"playlist"===o&&e.once("change:state",(function(){U(t)}))}function X(){var e=C._instreamAdapter;return!!e&&e.getState()}function K(){var e=X();return e||M.get("state")}function J(e){if(_.cancel(),T=!1,M.get("state")===d.lb)return Promise.resolve();var n=G(e);return M.set("playReason",n),X()?(t.pauseAd(!1,e),Promise.resolve()):(M.get("state")===d.kb&&(ee(!0),C.setItemIndex(0)),!S&&(S=!0,C.trigger(d.C,{playReason:n,startTime:e&&e.startTime?e.startTime:M.get("playlistItem").starttime}),S=!1,vt()&&!b.primed()&&b.prime(),"playlist"===n&&M.get("autoPause").viewability&&Q(M,M.get("viewable")),x)?(vt()&&!R&&M.get("mediaElement").load(),x=!1,k=null,Promise.resolve()):B.playVideo(n).then(b.played))}function G(e){return e&&e.reason?e.reason:"unknown"}function $(e){if(K()===d.mb){_=j(H);var t=M.get("advertising");(function(e,t){var n=t.cancelable,i=t.muted,o=void 0!==i&&i,a=t.allowMuted,r=void 0!==a&&a,s=t.timeout,l=void 0===s?1e4:s,c=e.getTestElement(),u=o?"muted":"".concat(r);bt[u]||(bt[u]=ft(c,{muted:o}).catch((function(e){if(!n.cancelled()&&!1===o&&r)return ft(c,{muted:o=!0});throw e})).then((function(){return o?(bt[u]=null,jt):ht})).catch((function(e){throw clearTimeout(d),bt[u]=null,e.reason=gt,e})));var d,p=bt[u].then((function(e){if(clearTimeout(d),n.cancelled()){var t=new Error("Autoplay test was cancelled");throw t.reason="cancelled",t}return e})),w=new Promise((function(e,t){d=setTimeout((function(){bt[u]=null;var e=new Error("Autoplay test timed out");e.reason="timeout",t(e)}),l)}));return Promise.race([p,w])})(b,{cancelable:_,muted:C.getMute(),allowMuted:!t||t.autoplayadsmuted}).then((function(t){return M.set("canAutoplay",t),t!==jt||C.getMute()||(M.set("autostartMuted",!0),ue(),M.once("change:autostartMuted",(function(e){e.off("change:viewable",W),C.trigger(d.M,{mute:M.getMute()})}))),C.getMute()&&M.get("enableDefaultCaptions")&&y.selectDefaultIndex(1),J({reason:e}).catch((function(){C._instreamAdapter||M.set("autostartFailed",!0),k=null}))})).catch((function(e){if(M.set("canAutoplay",gt),M.set("autostart",!1),!_.cancelled()){var t=Object(g.w)(e);C.trigger(d.h,{reason:e.reason,code:t,error:e})}}))}}function ee(e){if(_.cancel(),de.empty(),X()){var t=C._instreamAdapter;return t&&(t.noResume=!0),void(k=function(){return B.stopVideo()})}k=null,!e&&(T=!0),S&&(x=!0),M.set("errorEvent",void 0),B.stopVideo()}function te(e){var t=G(e);M.set("pauseReason",t),M.set("playOnViewable","viewable"===t)}function ne(e){k=null,_.cancel();var n=X();if(n&&n!==d.ob)return te(e),void t.pauseAd(!0,e);switch(M.get("state")){case d.lb:return;case d.pb:case d.jb:te(e),B.pause();break;default:S&&(x=!0)}}function ie(e,t){ee(!0),C.setItemIndex(e),C.play(t)}function oe(e){ie(M.get("item")+1,e)}function ae(){C.completeCancelled()||(k=C.completeHandler,C.shouldAutoAdvance()?C.nextItem():M.get("repeat")?oe({reason:"repeat"}):(m.OS.iOS&&le(!1),M.set("playOnViewable",!1),M.set("state",d.kb),C.trigger(d.cb,{})))}function re(e,t){e=parseInt(e,10)||0,M.persistVideoSubtitleTrack(e,t),B.subtitles=e,C.trigger(d.k,{tracks:se(),track:e})}function se(){return y.getCaptionsList()}function le(e){Object(i.n)(e)||(e=!M.get("fullscreen")),M.set("fullscreen",e),C._instreamAdapter&&C._instreamAdapter._adModel&&C._instreamAdapter._adModel.set("fullscreen",e)}function ue(){B.mute=M.getMute(),B.volume=M.get("volume")}M.on("change:playReason change:pauseReason",V),C.on(d.c,(function(e){return V(0,e.playReason)})),C.on(d.b,(function(e){return V(0,e.pauseReason)})),M.on("change:scrubbing",(function(e,t){t?(E=M.get("state")!==d.ob,ne()):E&&J({reason:"interaction"})})),M.on("change:captionsList",(function(e,t){C.trigger(d.l,{tracks:t,track:M.get("captionsIndex")||0})})),M.on("change:mediaModel",(function(e,t){var n=this;e.set("errorEvent",void 0),t.change("mediaState",(function(t,n){var i;e.get("errorEvent")||e.set(d.bb,(i=n)===d.nb||i===d.qb?d.jb:i)}),this),t.change("duration",(function(t,n){if(0!==n){var i=e.get("minDvrWindow"),o=Object(mt.b)(n,i);e.setStreamType(o)}}),this);var i=e.get("item")+1,o="autoplay"===(e.get("related")||{}).oncomplete,a=e.get("playlist")[i];if((a||o)&&R){t.on("change:position",(function e(i,r){var s=a&&!a.daiSetting,l=t.get("duration");s&&r&&l>0&&r>=l-p.b?(t.off("change:position",e,n),B.backgroundLoad(a)):o&&(a=M.get("nextUp"))}),this)}})),(y=new we(M)).on("all",L,C),I.on("viewSetup",(function(e){Object(a.b)(O,e)})),this.playerReady=function(){v.once(d.hb,(function(){try{!function(){M.change("visibility",N),P.off(),C.trigger(d.gb,{setupTime:0}),M.change("playlist",(function(e,t){if(t.length){var n={playlist:t},o=M.get("feedData");o&&(n.feedData=Object(i.g)({},o)),C.trigger(d.eb,n)}})),M.change("playlistItem",(function(e,t){if(t){var n=t.title,i=t.image;if("mediaSession"in navigator&&window.MediaMetadata&&(n||i))try{navigator.mediaSession.metadata=new window.MediaMetadata({title:n,artist:window.location.hostname,artwork:[{src:i||""}]})}catch(e){}e.set("cues",[]),C.trigger(d.db,{index:M.get("item"),item:t})}})),P.flush(),P.destroy(),P=null,M.change("viewable",F),M.change("viewable",W),M.get("autoPause").viewability?M.change("viewable",Q):M.once("change:autostartFailed change:mute",(function(e){e.off("change:viewable",W)}));H(),M.on("change:itemReady",(function(e,t){t&&de.flush()}))}()}catch(e){C.triggerError(Object(g.v)(g.m,g.a,e))}})),v.init()},this.preload=q,this.load=function(e,t){var n,i=C._instreamAdapter;switch(i&&(i.noResume=!0),C.trigger("destroyPlugin",{}),ee(!0),_.cancel(),_=j(H),z.cancel(),vt()&&b.prime(),St(e)){case"string":M.attributes.item=0,M.attributes.itemReady=!1,z=j((function(e){if(e)return C.updatePlaylist(Object(c.a)(e.playlist),e)})),n=function(e){var t=this;return new Promise((function(n,i){var o=new l.a;o.on(d.eb,(function(e){n(e)})),o.on(d.w,i,t),o.load(e)}))}(e).then(z.async);break;case"object":M.attributes.item=0,n=C.updatePlaylist(Object(c.a)(e),t||{});break;case"number":n=C.setItemIndex(e);break;default:return}n.catch((function(e){C.triggerError(Object(g.u)(e,g.c))})),n.then(_.async).catch(Et)},this.play=function(e){return J(e).catch(Et)},this.pause=ne,this.seek=function(e,t){var n=M.get("state");if(n!==d.lb){B.position=e;var i=n===d.mb;M.get("scrubbing")||!i&&n!==d.kb||(i&&((t=t||{}).startTime=e),this.play(t))}},this.stop=ee,this.playlistItem=ie,this.playlistNext=oe,this.playlistPrev=function(e){ie(M.get("item")-1,e)},this.setCurrentCaptions=re,this.setCurrentQuality=function(e){B.quality=e},this.setFullscreen=le,this.getCurrentQuality=function(){return B.quality},this.getQualityLevels=function(){return B.qualities},this.setCurrentAudioTrack=function(e){B.audioTrack=e},this.getCurrentAudioTrack=function(){return B.audioTrack},this.getAudioTracks=function(){return B.audioTracks},this.getCurrentCaptions=function(){return y.getCurrentIndex()},this.getCaptionsList=se,this.getVisualQuality=function(){var e=this._model.get("mediaModel");return e?e.get(d.U):null},this.getConfig=function(){return this._model?this._model.getConfiguration():void 0},this.getState=K,this.next=Et,this.completeHandler=ae,this.completeCancelled=function(){return(e=M.get("state"))!==d.mb&&e!==d.kb&&e!==d.lb||!!T&&(T=!1,!0);var e},this.shouldAutoAdvance=function(){return M.get("item")!==M.get("playlist").length-1},this.nextItem=function(){oe({reason:"playlist"})},this.setConfig=function(e){!function(e,t){var n=e._model,i=n.attributes;t.height&&(t.height=Object(r.b)(t.height),t.width=t.width||i.width),t.width&&(t.width=Object(r.b)(t.width),t.aspectratio?(i.width=t.width,delete t.width):t.height=i.height),t.width&&t.height&&!t.aspectratio&&e._view.resize(t.width,t.height),Object.keys(t).forEach((function(o){var a=t[o];if(void 0!==a)switch(o){case"aspectratio":n.set(o,Object(r.a)(a,i.width));break;case"autostart":!function(e,t,n){e.setAutoStart(n),"idle"===e.get("state")&&!0===n&&t.play({reason:"autostart"})}(n,e,a);break;case"mute":e.setMute(a);break;case"volume":e.setVolume(a);break;case"playbackRateControls":case"playbackRates":case"repeat":case"stretching":n.set(o,a)}}))}(C,e)},this.setItemIndex=function(e){B.stopVideo();var t=M.get("playlist").length;return(e=(parseInt(e,10)||0)%t)<0&&(e+=t),B.setActiveItem(e).catch((function(e){e.code>=151&&e.code<=162&&(e=Object(g.u)(e,g.e)),O.triggerError(Object(g.v)(g.k,g.d,e))}))},this.detachMedia=function(){if(S&&(x=!0),M.get("autoPause").viewability&&Q(M,M.get("viewable")),!R)return B.setAttached(!1);B.backgroundActiveMedia()},this.attachMedia=function(){R?B.restoreBackgroundMedia():B.setAttached(!0),"function"==typeof k&&k()},this.routeEvents=function(e){return B.routeEvents(e)},this.forwardEvents=function(){return B.forwardEvents()},this.playVideo=function(e){return B.playVideo(e)},this.stopVideo=function(){return B.stopVideo()},this.castVideo=function(e,t){return B.castVideo(e,t)},this.stopCast=function(){return B.stopCast()},this.backgroundActiveMedia=function(){return B.backgroundActiveMedia()},this.restoreBackgroundMedia=function(){return B.restoreBackgroundMedia()},this.preloadNextItem=function(){B.background.currentMedia&&B.preloadVideo()},this.isBeforeComplete=function(){return B.beforeComplete},this.setVolume=function(e){M.setVolume(e),ue()},this.setMute=function(e){M.setMute(e),ue()},this.setPlaybackRate=function(e){M.setPlaybackRate(e)},this.getProvider=function(){return M.get("provider")},this.getWidth=function(){return M.get("containerWidth")},this.getHeight=function(){return M.get("containerHeight")},this.getItemQoe=function(){return M._qoeItem},this.addButton=function(e,t,n,i,o){var a=M.get("customButtons")||[],r=!1,s={img:e,tooltip:t,callback:n,id:i,btnClass:o};a=a.reduce((function(e,t){return t.id===i?(r=!0,e.push(s)):e.push(t),e}),[]),r||a.unshift(s),M.set("customButtons",a)},this.removeButton=function(e){var t=M.get("customButtons")||[];t=t.filter((function(t){return t.id!==e})),M.set("customButtons",t)},this.resize=v.resize,this.getSafeRegion=v.getSafeRegion,this.setCaptions=v.setCaptions,this.checkBeforePlay=function(){return S},this.setControls=function(e){Object(i.n)(e)||(e=!M.get("controls")),M.set("controls",e),B.controls=e},this.addCues=function(e){this.setCues(M.get("cues").concat(e))},this.setCues=function(e){M.set("cues",e)},this.updatePlaylist=function(e,t){try{var n=Object(c.b)(e,M,t);Object(c.e)(n);var o=Object(i.g)({},t);delete o.playlist,M.set("feedData",o),M.set("playlist",n)}catch(e){return Promise.reject(e)}return this.setItemIndex(M.get("item"))},this.setPlaylistItem=function(e,t){(t=Object(c.d)(M,new u.a(t),t.feedData||{}))&&(M.get("playlist")[e]=t,e===M.get("item")&&"idle"===M.get("state")&&this.setItemIndex(e))},this.playerDestroy=function(){this.off(),this.stop(),Object(a.b)(this,this.originalContainer),v&&v.destroy(),M&&M.destroy(),de&&de.destroy(),y&&y.destroy(),B&&B.destroy(),this.instreamDestroy()},this.isBeforePlay=this.checkBeforePlay,this.createInstream=function(){return this.instreamDestroy(),this._instreamAdapter=new ce(this,M,v,b),this._instreamAdapter},this.instreamDestroy=function(){C._instreamAdapter&&(C._instreamAdapter.destroy(),C._instreamAdapter=null)};var de=new s.a(this,["play","pause","setCurrentAudioTrack","setCurrentCaptions","setCurrentQuality","setFullscreen"],(function(){return!O._model.get("itemReady")||P}));de.queue.push.apply(de.queue,h),v.setup()},get:function(e){if(e in y.a){var t=this._model.get("mediaModel");return t?t.get(e):y.a[e]}return this._model.get(e)},getContainer:function(){return this.currentContainer||this.originalContainer},getMute:function(){return this._model.getMute()},triggerError:function(e){var t=this._model;e.message=t.get("localization").errors[e.key],delete e.key,t.set("errorEvent",e),t.set("state",d.lb),t.once("change:state",(function(){this.set("errorEvent",void 0)}),t),this.trigger(d.w,e)}});t.default=Tt},,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n(2);function o(e){var t=[],n=(e=Object(i.i)(e)).split("\r\n\r\n");1===n.length&&(n=e.split("\n\n"));for(var o=0;o0&&(o=0),n.length>o+1&&n[o+1]){var a=n[o],r=a.indexOf(" --\x3e ");r>0&&(t.begin=Object(i.g)(a.substr(0,r)),t.end=Object(i.g)(a.substr(r+5)),t.text=n.slice(o+1).join("\r\n"))}return t}},function(e,t,n){"use strict";n.d(t,"a",(function(){return o})),n.d(t,"b",(function(){return a}));var i=n(5);function o(e){var t=-1;return e>=1280?t=7:e>=960?t=6:e>=800?t=5:e>=640?t=4:e>=540?t=3:e>=420?t=2:e>=320?t=1:e>=250&&(t=0),t}function a(e,t){var n="jw-breakpoint-"+t;Object(i.p)(e,/jw-breakpoint--?\d+/,n)}},function(e,t,n){"use strict";n.d(t,"a",(function(){return d}));var i,o=n(0),a=n(8),r=n(16),s=n(7),l=n(3),c=n(10),u=n(5),d={back:!0,backgroundOpacity:50,edgeStyle:null,fontSize:14,fontOpacity:100,fontScale:.05,preprocessor:o.k,windowOpacity:0},p=function(e){var t,s,p,w,f,h,j,g,b,m=this,v=e.player;function y(){Object(o.o)(t.fontSize)&&(v.get("containerHeight")?g=d.fontScale*(t.userFontScale||1)*t.fontSize/d.fontSize:v.once("change:containerHeight",y,this))}function k(){var e=v.get("containerHeight");if(e){var t;if(v.get("fullscreen")&&a.OS.iOS)t=null;else{var n=e*g;t=Math.round(10*function(e){var t=v.get("mediaElement");if(t&&t.videoHeight){var n=t.videoWidth,i=t.videoHeight,o=n/i,r=v.get("containerHeight"),s=v.get("containerWidth");if(v.get("fullscreen")&&a.OS.mobile){var l=window.screen;l.orientation&&(r=l.availHeight,s=l.availWidth)}if(s&&r&&n&&i)return(s/r>o?r:i*s/n)*g}return e}(n))/10}v.get("renderCaptionsNatively")?function(e,t){var n="#".concat(e," .jw-video::-webkit-media-text-track-display");t&&(t+="px",a.OS.iOS&&Object(c.b)(n,{fontSize:"inherit"},e,!0));b.fontSize=t,Object(c.b)(n,b,e,!0)}(v.get("id"),t):Object(c.d)(f,{fontSize:t})}}function x(e,t,n){var i=Object(c.c)("#000000",n);"dropshadow"===e?t.textShadow="0 2px 1px "+i:"raised"===e?t.textShadow="0 0 5px "+i+", 0 1px 5px "+i+", 0 2px 5px "+i:"depressed"===e?t.textShadow="0 -2px 1px "+i:"uniform"===e&&(t.textShadow="-2px 0 1px "+i+",2px 0 1px "+i+",0 -2px 1px "+i+",0 2px 1px "+i+",-1px 1px 1px "+i+",1px 1px 1px "+i+",1px -1px 1px "+i+",1px 1px 1px "+i)}(f=document.createElement("div")).className="jw-captions jw-reset",this.show=function(){Object(u.a)(f,"jw-captions-enabled")},this.hide=function(){Object(u.o)(f,"jw-captions-enabled")},this.populate=function(e){v.get("renderCaptionsNatively")||(p=[],s=e,e?this.selectCues(e,w):this.renderCues())},this.resize=function(){k(),this.renderCues(!0)},this.renderCues=function(e){e=!!e,i&&i.processCues(window,p,f,e)},this.selectCues=function(e,t){if(e&&e.data&&t&&!v.get("renderCaptionsNatively")){var n=this.getAlignmentPosition(e,t);!1!==n&&(p=this.getCurrentCues(e.data,n),this.renderCues(!0))}},this.getCurrentCues=function(e,t){return Object(o.h)(e,(function(e){return t>=e.startTime&&(!e.endTime||t<=e.endTime)}))},this.getAlignmentPosition=function(e,t){var n=e.source,i=t.metadata,a=t.currentTime;return n&&i&&Object(o.r)(i[n])&&(a=i[n]),a},this.clear=function(){Object(u.g)(f)},this.setup=function(e,n){h=document.createElement("div"),j=document.createElement("span"),h.className="jw-captions-window jw-reset",j.className="jw-captions-text jw-reset",t=Object(o.g)({},d,n),g=d.fontScale;var i=function(){if(!v.get("renderCaptionsNatively")){y(t.fontSize);var n=t.windowColor,i=t.windowOpacity,o=t.edgeStyle;b={};var r={};!function(e,t){var n=t.color,i=t.fontOpacity;(n||i!==d.fontOpacity)&&(e.color=Object(c.c)(n||"#ffffff",i));if(t.back){var o=t.backgroundColor,a=t.backgroundOpacity;o===d.backgroundColor&&a===d.backgroundOpacity||(e.backgroundColor=Object(c.c)(o,a))}else e.background="transparent";t.fontFamily&&(e.fontFamily=t.fontFamily);t.fontStyle&&(e.fontStyle=t.fontStyle);t.fontWeight&&(e.fontWeight=t.fontWeight);t.textDecoration&&(e.textDecoration=t.textDecoration)}(r,t),(n||i!==d.windowOpacity)&&(b.backgroundColor=Object(c.c)(n||"#000000",i)),x(o,r,t.fontOpacity),t.back||null!==o||x("uniform",r),Object(c.d)(h,b),Object(c.d)(j,r),function(e,t){k(),function(e,t){a.Browser.safari&&Object(c.b)("#"+e+" .jw-video::-webkit-media-text-track-display-backdrop",{backgroundColor:t.backgroundColor},e,!0);Object(c.b)("#"+e+" .jw-video::-webkit-media-text-track-display",b,e,!0),Object(c.b)("#"+e+" .jw-video::cue",t,e,!0)}(e,t),function(e,t){Object(c.b)("#"+e+" .jw-text-track-display",b,e),Object(c.b)("#"+e+" .jw-text-track-cue",t,e)}(e,t)}(e,r)}};i(),h.appendChild(j),f.appendChild(h),v.change("captionsTrack",(function(e,t){this.populate(t)}),this),v.set("captions",t),v.on("change:captions",(function(e,n){t=n,i()}))},this.element=function(){return f},this.destroy=function(){v.off(null,null,this),this.off()};var O=function(e){w=e,m.selectCues(s,w)};v.on("change:playlistItem",(function(){w=null,p=[]}),this),v.on(l.Q,(function(e){p=[],O(e)}),this),v.on(l.S,O,this),v.on("subtitlesTrackData",(function(){this.selectCues(s,w)}),this),v.on("change:captionsList",(function e(t,o){var a=this;1!==o.length&&(t.get("renderCaptionsNatively")||i||(n.e(8).then(function(e){i=n(68).default}.bind(null,n)).catch(Object(r.c)(301121)).catch((function(e){a.trigger(l.tb,e)})),t.off("change:captionsList",e,this)))}),this)};Object(o.g)(p.prototype,s.a),t.b=p},function(e,t,n){"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=function(e,t){var n=e[1]||"",i=e[3];if(!i)return n;if(t&&"function"==typeof btoa){var o=(r=i,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */"),a=i.sources.map((function(e){return"/*# sourceURL="+i.sourceRoot+e+" */"}));return[n].concat(a).concat([o]).join("\n")}var r;return[n].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n})).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var i={},o=0;o'},function(e,t,n){"use strict";function i(e,t){var n=e.kind||"cc";return e.default||e.defaulttrack?"default":e._id||e.file||n+t}function o(e,t){var n=e.label||e.name||e.language;return n||(n="Unknown CC",(t+=1)>1&&(n+=" ["+t+"]")),{label:n,unknownCount:t}}n.d(t,"a",(function(){return i})),n.d(t,"b",(function(){return o}))},function(e,t,n){"use strict";function i(e){return new Promise((function(t,n){if(e.paused)return n(o("NotAllowedError",0,"play() failed."));var i=function(){e.removeEventListener("play",a),e.removeEventListener("playing",r),e.removeEventListener("pause",r),e.removeEventListener("abort",r),e.removeEventListener("error",r)},a=function(){e.addEventListener("playing",r),e.addEventListener("abort",r),e.addEventListener("error",r),e.addEventListener("pause",r)},r=function(e){if(i(),"playing"===e.type)t();else{var a='The play() request was interrupted by a "'.concat(e.type,'" event.');"error"===e.type?n(o("NotSupportedError",9,a)):n(o("AbortError",20,a))}};e.addEventListener("play",a)}))}function o(e,t,n){var i=new Error(n);return i.name=e,i.code=t,i}n.d(t,"a",(function(){return i}))},function(e,t,n){"use strict";function i(e,t){return e!==1/0&&Math.abs(e)>=Math.max(a(t),0)}function o(e,t){var n="VOD";return e===1/0?n="LIVE":e<0&&(n=i(e,a(t))?"DVR":"LIVE"),n}function a(e){return void 0===e?120:Math.max(e,0)}n.d(t,"a",(function(){return i})),n.d(t,"b",(function(){return o}))},function(e,t,n){"use strict";var i=n(67),o=n(16),a=n(22),r=n(4),s=n(57),l=n(2),c=n(1);function u(e){throw new c.n(null,e)}function d(e,t,i){e.xhr=Object(a.a)(e.file,(function(a){!function(e,t,i,a){var d,p,f=e.responseXML?e.responseXML.firstChild:null;if(f)for("xml"===Object(r.b)(f)&&(f=f.nextSibling);f.nodeType===f.COMMENT_NODE;)f=f.nextSibling;try{if(f&&"tt"===Object(r.b)(f))d=function(e){e||u(306007);var t=[],n=e.getElementsByTagName("p"),i=30,o=e.getElementsByTagName("tt");if(o&&o[0]){var a=parseFloat(o[0].getAttribute("ttp:frameRate"));isNaN(a)||(i=a)}n||u(306005),n.length||(n=e.getElementsByTagName("tt:p")).length||(n=e.getElementsByTagName("tts:p"));for(var r=0;r\s+<").replace(/(<\/?)tts?:/g,"$1").replace(//g,"\r\n");if(f){var h=s.getAttribute("begin"),j=s.getAttribute("dur"),g=s.getAttribute("end"),b={begin:Object(l.g)(h,i),text:f};g?b.end=Object(l.g)(g,i):j&&(b.end=b.begin+Object(l.g)(j,i)),t.push(b)}}return t.length||u(306005),t}(e.responseXML),p=w(d),delete t.xhr,i(p);else{var h=e.responseText;h.indexOf("WEBVTT")>=0?n.e(10).then(function(e){return n(97).default}.bind(null,n)).catch(Object(o.c)(301131)).then((function(e){var n=new e(window);p=[],n.oncue=function(e){p.push(e)},n.onflush=function(){delete t.xhr,i(p)},n.parse(h)})).catch((function(e){delete t.xhr,a(Object(c.v)(null,c.b,e))})):(d=Object(s.a)(h),p=w(d),delete t.xhr,i(p))}}catch(e){delete t.xhr,a(Object(c.v)(null,c.b,e))}}(a,e,t,i)}),(function(e,t,n,o){i(Object(c.u)(o,c.b))}))}function p(e){e&&e.forEach((function(e){var t=e.xhr;t&&(t.onload=null,t.onreadystatechange=null,t.onerror=null,"abort"in t&&t.abort()),delete e.xhr}))}function w(e){return e.map((function(e){return new i.a(e.begin,e.end,e.text)}))}n.d(t,"c",(function(){return d})),n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return w}))},function(e,t,n){"use strict";var i=window.VTTCue;function o(e){if("string"!=typeof e)return!1;return!!{start:!0,middle:!0,end:!0,left:!0,right:!0}[e.toLowerCase()]&&e.toLowerCase()}if(!i){(i=function(e,t,n){var i=this;i.hasBeenReset=!1;var a="",r=!1,s=e,l=t,c=n,u=null,d="",p=!0,w="auto",f="start",h="auto",j=100,g="middle";Object.defineProperty(i,"id",{enumerable:!0,get:function(){return a},set:function(e){a=""+e}}),Object.defineProperty(i,"pauseOnExit",{enumerable:!0,get:function(){return r},set:function(e){r=!!e}}),Object.defineProperty(i,"startTime",{enumerable:!0,get:function(){return s},set:function(e){if("number"!=typeof e)throw new TypeError("Start time must be set to a number.");s=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"endTime",{enumerable:!0,get:function(){return l},set:function(e){if("number"!=typeof e)throw new TypeError("End time must be set to a number.");l=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"text",{enumerable:!0,get:function(){return c},set:function(e){c=""+e,this.hasBeenReset=!0}}),Object.defineProperty(i,"region",{enumerable:!0,get:function(){return u},set:function(e){u=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"vertical",{enumerable:!0,get:function(){return d},set:function(e){var t=function(e){return"string"==typeof e&&(!!{"":!0,lr:!0,rl:!0}[e.toLowerCase()]&&e.toLowerCase())}(e);if(!1===t)throw new SyntaxError("An invalid or illegal string was specified.");d=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"snapToLines",{enumerable:!0,get:function(){return p},set:function(e){p=!!e,this.hasBeenReset=!0}}),Object.defineProperty(i,"line",{enumerable:!0,get:function(){return w},set:function(e){if("number"!=typeof e&&"auto"!==e)throw new SyntaxError("An invalid number or illegal string was specified.");w=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"lineAlign",{enumerable:!0,get:function(){return f},set:function(e){var t=o(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");f=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"position",{enumerable:!0,get:function(){return h},set:function(e){if(e<0||e>100)throw new Error("Position must be between 0 and 100.");h=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"size",{enumerable:!0,get:function(){return j},set:function(e){if(e<0||e>100)throw new Error("Size must be between 0 and 100.");j=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"align",{enumerable:!0,get:function(){return g},set:function(e){var t=o(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");g=t,this.hasBeenReset=!0}}),i.displayState=void 0}).prototype.getCueAsHTML=function(){return window.WebVTT.convertCueToDOMTree(window,this.text)}}t.a=i},,function(e,t,n){var i=n(70);"string"==typeof i&&(i=[["all-players",i,""]]),n(61).style(i,"all-players"),i.locals&&(e.exports=i.locals)},function(e,t,n){(e.exports=n(60)(!1)).push([e.i,'.jw-reset{text-align:left;direction:ltr}.jw-reset-text,.jw-reset{color:inherit;background-color:transparent;padding:0;margin:0;float:none;font-family:Arial,Helvetica,sans-serif;font-size:1em;line-height:1em;list-style:none;text-transform:none;vertical-align:baseline;border:0;font-variant:inherit;font-stretch:inherit;-webkit-tap-highlight-color:rgba(255,255,255,0)}body .jw-error,body .jwplayer.jw-state-error{height:100%;width:100%}.jw-title{position:absolute;top:0}.jw-background-color{background:rgba(0,0,0,0.4)}.jw-text{color:rgba(255,255,255,0.8)}.jw-knob{color:rgba(255,255,255,0.8);background-color:#fff}.jw-button-color{color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):focus,:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):hover{color:#fff}.jw-toggle{color:#fff}.jw-toggle.jw-off{color:rgba(255,255,255,0.8)}.jw-toggle.jw-off:focus{color:#fff}.jw-toggle:focus{outline:none}:not(.jw-flag-touch) .jw-toggle.jw-off:hover{color:#fff}.jw-rail{background:rgba(255,255,255,0.3)}.jw-buffer{background:rgba(255,255,255,0.3)}.jw-progress{background:#f2f2f2}.jw-time-tip,.jw-volume-tip{border:0}.jw-slider-volume.jw-volume-tip.jw-background-color.jw-slider-vertical{background:none}.jw-skip{padding:.5em;outline:none}.jw-skip .jw-skiptext,.jw-skip .jw-skip-icon{color:rgba(255,255,255,0.8)}.jw-skip.jw-skippable:hover .jw-skip-icon,.jw-skip.jw-skippable:focus .jw-skip-icon{color:#fff}.jw-icon-cast google-cast-launcher{--connected-color:#fff;--disconnected-color:rgba(255,255,255,0.8)}.jw-icon-cast google-cast-launcher:focus{outline:none}.jw-icon-cast google-cast-launcher.jw-off{--connected-color:rgba(255,255,255,0.8)}.jw-icon-cast:focus google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-icon-cast:hover google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-nextup-container{bottom:2.5em;padding:5px .5em}.jw-nextup{border-radius:0}.jw-color-active{color:#fff;stroke:#fff;border-color:#fff}:not(.jw-flag-touch) .jw-color-active-hover:hover,:not(.jw-flag-touch) .jw-color-active-hover:focus{color:#fff;stroke:#fff;border-color:#fff}.jw-color-inactive{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-color-inactive-hover:hover{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}.jw-option{color:rgba(255,255,255,0.8)}.jw-option.jw-active-option{color:#fff;background-color:rgba(255,255,255,0.1)}:not(.jw-flag-touch) .jw-option:hover{color:#fff}.jwplayer{width:100%;font-size:16px;position:relative;display:block;min-height:0;overflow:hidden;box-sizing:border-box;font-family:Arial,Helvetica,sans-serif;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:none}.jwplayer *{box-sizing:inherit}.jwplayer.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jwplayer.jw-flag-aspect-mode{height:auto !important}.jwplayer.jw-flag-aspect-mode .jw-aspect{display:block}.jwplayer .jw-aspect{display:none}.jwplayer .jw-swf{outline:none}.jw-media,.jw-preview{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}.jw-media{overflow:hidden;cursor:pointer}.jw-plugin{position:absolute;bottom:66px}.jw-breakpoint-7 .jw-plugin{bottom:132px}.jw-plugin .jw-banner{max-width:100%;opacity:0;cursor:pointer;position:absolute;margin:auto auto 0;left:0;right:0;bottom:0;display:block}.jw-preview,.jw-captions,.jw-title{pointer-events:none}.jw-media,.jw-logo{pointer-events:all}.jw-wrapper{background-color:#000;position:absolute;top:0;left:0;right:0;bottom:0}.jw-hidden-accessibility{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.jw-contract-trigger::before{content:"";overflow:hidden;width:200%;height:200%;display:block;position:absolute;top:0;left:0}.jwplayer .jw-media video{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;margin:auto;background:transparent}.jwplayer .jw-media video::-webkit-media-controls-start-playback-button{display:none}.jwplayer.jw-stretch-uniform .jw-media video{object-fit:contain}.jwplayer.jw-stretch-none .jw-media video{object-fit:none}.jwplayer.jw-stretch-fill .jw-media video{object-fit:cover}.jwplayer.jw-stretch-exactfit .jw-media video{object-fit:fill}.jw-preview{position:absolute;display:none;opacity:1;visibility:visible;width:100%;height:100%;background:#000 no-repeat 50% 50%}.jwplayer .jw-preview,.jw-error .jw-preview{background-size:contain}.jw-stretch-none .jw-preview{background-size:auto auto}.jw-stretch-fill .jw-preview{background-size:cover}.jw-stretch-exactfit .jw-preview{background-size:100% 100%}.jw-title{display:none;padding-top:20px;width:100%;z-index:1}.jw-title-primary,.jw-title-secondary{color:#fff;padding-left:20px;padding-right:20px;padding-bottom:.5em;overflow:hidden;text-overflow:ellipsis;direction:unset;white-space:nowrap;width:100%}.jw-title-primary{font-size:1.625em}.jw-breakpoint-2 .jw-title-primary,.jw-breakpoint-3 .jw-title-primary{font-size:1.5em}.jw-flag-small-player .jw-title-primary{font-size:1.25em}.jw-flag-small-player .jw-title-secondary,.jw-title-secondary:empty{display:none}.jw-captions{position:absolute;width:100%;height:100%;text-align:center;display:none;letter-spacing:normal;word-spacing:normal;text-transform:none;text-indent:0;text-decoration:none;pointer-events:none;overflow:hidden;top:0}.jw-captions.jw-captions-enabled{display:block}.jw-captions-window{display:none;padding:.25em;border-radius:.25em}.jw-captions-window.jw-captions-window-active{display:inline-block}.jw-captions-text{display:inline-block;color:#fff;background-color:#000;word-wrap:normal;word-break:normal;white-space:pre-line;font-style:normal;font-weight:normal;text-align:center;text-decoration:none}.jw-text-track-display{font-size:inherit;line-height:1.5}.jw-text-track-cue{background-color:rgba(0,0,0,0.5);color:#fff;padding:.1em .3em}.jwplayer video::-webkit-media-controls{display:none;justify-content:flex-start}.jwplayer video::-webkit-media-text-track-display{min-width:-webkit-min-content}.jwplayer video::cue{background-color:rgba(0,0,0,0.5)}.jwplayer video::-webkit-media-controls-panel-container{display:none}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing) .jw-captions,.jwplayer.jw-flag-media-audio.jw-state-playing .jw-captions,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden) .jw-captions{max-height:calc(100% - 60px)}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-flag-media-audio.jw-state-playing:not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container{max-height:calc(100% - 60px)}.jw-logo{position:absolute;margin:20px;cursor:pointer;pointer-events:all;background-repeat:no-repeat;background-size:contain;top:auto;right:auto;left:auto;bottom:auto;outline:none}.jw-logo.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-flag-audio-player .jw-logo{display:none}.jw-logo-top-right{top:0;right:0}.jw-logo-top-left{top:0;left:0}.jw-logo-bottom-left{left:0}.jw-logo-bottom-right{right:0}.jw-logo-bottom-left,.jw-logo-bottom-right{bottom:44px;transition:bottom 150ms cubic-bezier(0, .25, .25, 1)}.jw-state-idle .jw-logo{z-index:1}.jw-state-setup .jw-wrapper{background-color:inherit}.jw-state-setup .jw-logo,.jw-state-setup .jw-controls,.jw-state-setup .jw-controls-backdrop{visibility:hidden}span.jw-break{display:block}body .jw-error,body .jwplayer.jw-state-error{background-color:#333;color:#fff;font-size:16px;display:table;opacity:1;position:relative}body .jw-error .jw-display,body .jwplayer.jw-state-error .jw-display{display:none}body .jw-error .jw-media,body .jwplayer.jw-state-error .jw-media{cursor:default}body .jw-error .jw-preview,body .jwplayer.jw-state-error .jw-preview{background-color:#333}body .jw-error .jw-error-msg,body .jwplayer.jw-state-error .jw-error-msg{background-color:#000;border-radius:2px;display:flex;flex-direction:row;align-items:stretch;padding:20px}body .jw-error .jw-error-msg .jw-icon,body .jwplayer.jw-state-error .jw-error-msg .jw-icon{height:30px;width:30px;margin-right:20px;flex:0 0 auto;align-self:center}body .jw-error .jw-error-msg .jw-icon:empty,body .jwplayer.jw-state-error .jw-error-msg .jw-icon:empty{display:none}body .jw-error .jw-error-msg .jw-info-container,body .jwplayer.jw-state-error .jw-error-msg .jw-info-container{margin:0;padding:0}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg{flex-direction:column}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text{text-align:center}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon{flex:.5 0 auto;margin-right:0;margin-bottom:20px}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break{display:inline}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break:before{content:" "}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg{height:100%;width:100%;top:0;position:absolute;left:0;background:#000;-webkit-transform:none;transform:none;padding:4px 16px;z-index:1}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg.jw-info-overlay{max-width:none;max-height:none}body .jwplayer.jw-state-error .jw-title,.jw-state-idle .jw-title,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-title{display:block}body .jwplayer.jw-state-error .jw-preview,.jw-state-idle .jw-preview,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-preview{display:block}.jw-state-idle .jw-captions,.jwplayer.jw-state-complete .jw-captions,body .jwplayer.jw-state-error .jw-captions{display:none}.jw-state-idle video::-webkit-media-text-track-container,.jwplayer.jw-state-complete video::-webkit-media-text-track-container,body .jwplayer.jw-state-error video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-fullscreen{width:100% !important;height:100% !important;top:0;right:0;bottom:0;left:0;z-index:1000;margin:0;position:fixed}body .jwplayer.jw-flag-flash-blocked .jw-title{display:block}.jwplayer.jw-flag-controls-hidden .jw-media{cursor:default}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:45px}.jw-flag-floating{background-size:cover;background-color:#000}.jw-flag-floating .jw-wrapper{position:fixed;z-index:2147483647;-webkit-animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;top:auto;bottom:1rem;left:auto;right:1rem;max-width:400px;max-height:400px;margin:0 auto}@media screen and (max-width:480px){.jw-flag-floating .jw-wrapper{width:100%;left:0;right:0}}.jw-flag-floating .jw-wrapper .jw-media{touch-action:none}@media screen and (max-device-width:480px) and (orientation:portrait){.jw-flag-touch.jw-flag-floating .jw-wrapper{-webkit-animation:none;animation:none;top:62px;bottom:auto;left:0;right:0;max-width:none;max-height:none}}.jw-flag-floating .jw-float-icon{pointer-events:all;cursor:pointer;display:none}.jw-flag-floating .jw-float-icon .jw-svg-icon{-webkit-filter:drop-shadow(0 0 1px #000);filter:drop-shadow(0 0 1px #000)}.jw-flag-floating.jw-floating-dismissible .jw-dismiss-icon{display:none}.jw-flag-floating.jw-floating-dismissible.jw-flag-ads .jw-float-icon{display:flex}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-logo,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-logo{display:none}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-float-icon,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-float-icon{display:flex}.jw-float-icon{display:none;position:absolute;top:3px;right:5px;align-items:center;justify-content:center}@-webkit-keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}.jw-flag-top{margin-top:2em;overflow:visible}.jw-top{height:2em;line-height:2;pointer-events:none;text-align:center;opacity:.8;position:absolute;top:-2em;width:100%}.jw-top .jw-icon{cursor:pointer;pointer-events:all;height:auto;width:auto}.jw-top .jw-text{color:#555}',""])},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t){e.exports=''},function(e,t,n){var i=n(96);"string"==typeof i&&(i=[["all-players",i,""]]),n(61).style(i,"all-players"),i.locals&&(e.exports=i.locals)},function(e,t,n){(e.exports=n(60)(!1)).push([e.i,'.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-flag-small-player .jw-settings-menu,.jw-settings-submenu{height:100%;width:100%}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;right:0}.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-settings-item-active::before{top:0;position:absolute;left:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;bottom:0;left:0}.jw-nextup-close{position:absolute;top:0;right:0}.jw-overlays,.jw-controls,.jw-flag-small-player .jw-settings-menu{position:absolute;bottom:0;right:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-time-tip::after,.jw-settings-menu .jw-icon.jw-button-color::after,.jw-text-live::before,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{content:"";display:block}.jw-svg-icon{height:24px;width:24px;fill:currentColor;pointer-events:none}.jw-icon{height:44px;width:44px;background-color:transparent;outline:none}.jw-icon.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-icon-airplay .jw-svg-icon-airplay-off{display:none}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-off{display:block}.jw-icon-airplay .jw-svg-icon-airplay-on{display:block}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-on{display:none}.jw-icon-cc .jw-svg-icon-cc-off{display:none}.jw-off.jw-icon-cc .jw-svg-icon-cc-off{display:block}.jw-icon-cc .jw-svg-icon-cc-on{display:block}.jw-off.jw-icon-cc .jw-svg-icon-cc-on{display:none}.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:none}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:block}.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:block}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:none}.jw-icon-volume .jw-svg-icon-volume-0{display:none}.jw-off.jw-icon-volume .jw-svg-icon-volume-0{display:block}.jw-icon-volume .jw-svg-icon-volume-100{display:none}.jw-full.jw-icon-volume .jw-svg-icon-volume-100{display:block}.jw-icon-volume .jw-svg-icon-volume-50{display:block}.jw-off.jw-icon-volume .jw-svg-icon-volume-50,.jw-full.jw-icon-volume .jw-svg-icon-volume-50{display:none}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon[aria-checked="true"]::after,.jw-settings-open .jw-icon-settings::after,.jw-icon-volume.jw-open::after{opacity:1}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-cc,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-settings,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-audio-tracks,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-hd,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-settings-sharing,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-fullscreen,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-airplay,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-cast{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-text-live{bottom:6px}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume::after{display:none}.jw-overlays,.jw-controls{pointer-events:none}.jw-controls-backdrop{display:block;background:linear-gradient(to bottom, transparent, rgba(0,0,0,0.4) 77%, rgba(0,0,0,0.4) 100%) 100% 100% / 100% 240px no-repeat transparent;transition:opacity 250ms cubic-bezier(0, .25, .25, 1),background-size 250ms cubic-bezier(0, .25, .25, 1);pointer-events:none}.jw-overlays{cursor:auto}.jw-controls{overflow:hidden}.jw-flag-small-player .jw-controls{text-align:center}.jw-text{height:1em;font-family:Arial,Helvetica,sans-serif;font-size:.75em;font-style:normal;font-weight:normal;color:#fff;text-align:center;font-variant:normal;font-stretch:normal}.jw-controlbar,.jw-skip,.jw-display-icon-container .jw-icon,.jw-nextup-container,.jw-autostart-mute,.jw-overlays .jw-plugin{pointer-events:all}.jwplayer .jw-display-icon-container,.jw-error .jw-display-icon-container{width:auto;height:auto;box-sizing:content-box}.jw-display{display:table;height:100%;padding:57px 0;position:relative;width:100%}.jw-flag-dragging .jw-display{display:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-display-container{display:table-cell;height:100%;text-align:center;vertical-align:middle}.jw-display-controls{display:inline-block}.jwplayer .jw-display-icon-container{float:left}.jw-display-icon-container{display:inline-block;padding:5.5px;margin:0 22px}.jw-display-icon-container .jw-icon{height:75px;width:75px;cursor:pointer;display:flex;justify-content:center;align-items:center}.jw-display-icon-container .jw-icon .jw-svg-icon{height:33px;width:33px;padding:0;position:relative}.jw-display-icon-container .jw-icon .jw-svg-icon-rewind{padding:.2em .05em}.jw-breakpoint--1 .jw-nextup-container{display:none}.jw-breakpoint-0 .jw-display-icon-next,.jw-breakpoint--1 .jw-display-icon-next,.jw-breakpoint-0 .jw-display-icon-rewind,.jw-breakpoint--1 .jw-display-icon-rewind{display:none}.jw-breakpoint-0 .jw-display .jw-icon,.jw-breakpoint--1 .jw-display .jw-icon,.jw-breakpoint-0 .jw-display .jw-svg-icon,.jw-breakpoint--1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-0 .jw-display .jw-icon:before,.jw-breakpoint--1 .jw-display .jw-icon:before,.jw-breakpoint-0 .jw-display .jw-svg-icon:before,.jw-breakpoint--1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon,.jw-breakpoint-1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-1 .jw-display .jw-icon:before,.jw-breakpoint-1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon.jw-icon-rewind:before{width:33px;height:33px}.jw-breakpoint-2 .jw-display .jw-icon,.jw-breakpoint-3 .jw-display .jw-icon,.jw-breakpoint-2 .jw-display .jw-svg-icon,.jw-breakpoint-3 .jw-display .jw-svg-icon{width:77px;height:77px;line-height:77px}.jw-breakpoint-2 .jw-display .jw-icon:before,.jw-breakpoint-3 .jw-display .jw-icon:before,.jw-breakpoint-2 .jw-display .jw-svg-icon:before,.jw-breakpoint-3 .jw-display .jw-svg-icon:before{width:38.5px;height:38.5px}.jw-breakpoint-4 .jw-display .jw-icon,.jw-breakpoint-5 .jw-display .jw-icon,.jw-breakpoint-6 .jw-display .jw-icon,.jw-breakpoint-7 .jw-display .jw-icon,.jw-breakpoint-4 .jw-display .jw-svg-icon,.jw-breakpoint-5 .jw-display .jw-svg-icon,.jw-breakpoint-6 .jw-display .jw-svg-icon,.jw-breakpoint-7 .jw-display .jw-svg-icon{width:88px;height:88px;line-height:88px}.jw-breakpoint-4 .jw-display .jw-icon:before,.jw-breakpoint-5 .jw-display .jw-icon:before,.jw-breakpoint-6 .jw-display .jw-icon:before,.jw-breakpoint-7 .jw-display .jw-icon:before,.jw-breakpoint-4 .jw-display .jw-svg-icon:before,.jw-breakpoint-5 .jw-display .jw-svg-icon:before,.jw-breakpoint-6 .jw-display .jw-svg-icon:before,.jw-breakpoint-7 .jw-display .jw-svg-icon:before{width:44px;height:44px}.jw-controlbar{display:flex;flex-flow:row wrap;align-items:center;justify-content:center;position:absolute;left:0;bottom:0;width:100%;border:none;border-radius:0;background-size:auto;box-shadow:none;max-height:72px;transition:250ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s}.jw-breakpoint-7 .jw-controlbar{max-height:140px}.jw-breakpoint-7 .jw-controlbar .jw-button-container{padding:0 48px 20px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-tooltip{margin-bottom:-7px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-overlay{padding-bottom:40%}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text{font-size:1em}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text.jw-text-elapsed{justify-content:flex-end}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume{height:60px;width:60px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline .jw-svg-icon,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time{padding:0 60px;height:34px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time .jw-slider-container{height:10px}.jw-controlbar .jw-button-image{background:no-repeat 50% 50%;background-size:contain;max-height:24px}.jw-controlbar .jw-spacer{flex:1 1 auto;align-self:stretch}.jw-controlbar .jw-icon.jw-button-color:hover{color:#fff}.jw-button-container{display:flex;flex-flow:row nowrap;flex:1 1 auto;align-items:center;justify-content:center;width:100%;padding:0 12px}.jw-slider-horizontal{background-color:transparent}.jw-icon-inline{position:relative}.jw-icon-inline,.jw-icon-tooltip{height:44px;width:44px;align-items:center;display:flex;justify-content:center}.jw-icon-inline:not(.jw-text),.jw-icon-tooltip,.jw-slider-horizontal{cursor:pointer}.jw-text-elapsed,.jw-text-duration{justify-content:flex-start;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.jw-icon-tooltip{position:relative}.jw-knob:hover,.jw-icon-inline:hover,.jw-icon-tooltip:hover,.jw-icon-display:hover,.jw-option:before:hover{color:#fff}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{pointer-events:none}.jw-icon-cast{display:none;margin:0;padding:0}.jw-icon-cast google-cast-launcher{background-color:transparent;border:none;padding:0;width:24px;height:24px;cursor:pointer}.jw-icon-inline.jw-icon-volume{display:none}.jwplayer .jw-text-countdown{display:none}.jw-flag-small-player .jw-display{padding-top:0;padding-bottom:0}.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-rewind,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-next,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-playback{display:none}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop{opacity:0}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-countdown{display:flex}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-duration,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-duration{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-text-countdown,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-related-btn,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-slider-volume{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-controlbar{flex-direction:column-reverse}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-button-container{height:30px}.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-volume,.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-fullscreen{display:none}.jwplayer:not(.jw-breakpoint-0) .jw-text-duration:before,.jwplayer:not(.jw-breakpoint--1) .jw-text-duration:before{content:"/";padding-right:1ch;padding-left:1ch}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar{will-change:transform}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar .jw-text{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.jw-slider-container{display:flex;align-items:center;position:relative;touch-action:none}.jw-rail,.jw-buffer,.jw-progress{position:absolute;cursor:pointer}.jw-progress{background-color:#f2f2f2}.jw-rail{background-color:rgba(255,255,255,0.3)}.jw-buffer{background-color:rgba(255,255,255,0.3)}.jw-knob{height:13px;width:13px;background-color:#fff;border-radius:50%;box-shadow:0 0 10px rgba(0,0,0,0.4);opacity:1;pointer-events:none;position:absolute;-webkit-transform:translate(-50%, -50%) scale(0);transform:translate(-50%, -50%) scale(0);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform}.jw-flag-dragging .jw-slider-time .jw-knob,.jw-icon-volume:active .jw-slider-volume .jw-knob{box-shadow:0 0 26px rgba(0,0,0,0.2),0 0 10px rgba(0,0,0,0.4),0 0 0 6px rgba(255,255,255,0.2)}.jw-slider-horizontal,.jw-slider-vertical{display:flex}.jw-slider-horizontal .jw-slider-container{height:5px;width:100%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue,.jw-slider-horizontal .jw-knob{top:50%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue{-webkit-transform:translate(0, -50%);transform:translate(0, -50%)}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress{height:5px}.jw-slider-horizontal .jw-rail{width:100%}.jw-slider-vertical{align-items:center;flex-direction:column}.jw-slider-vertical .jw-slider-container{height:88px;width:5px}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress,.jw-slider-vertical .jw-knob{left:50%}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress{height:100%;width:5px;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out;bottom:0}.jw-slider-vertical .jw-knob{-webkit-transform:translate(-50%, 50%);transform:translate(-50%, 50%)}.jw-slider-time.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-slider-time,.jw-flag-audio-player .jw-slider-volume{height:17px;width:100%;align-items:center;background:transparent none;padding:0 12px}.jw-slider-time .jw-cue{background-color:rgba(33,33,33,0.8);cursor:pointer;position:absolute;width:6px}.jw-slider-time,.jw-horizontal-volume-container{z-index:1;outline:none}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail,.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer,.jw-slider-time .jw-progress,.jw-horizontal-volume-container .jw-progress,.jw-slider-time .jw-cue,.jw-horizontal-volume-container .jw-cue{-webkit-backface-visibility:hidden;backface-visibility:hidden;height:100%;-webkit-transform:translate(0, -50%) scale(1, .6);transform:translate(0, -50%) scale(1, .6);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out}.jw-slider-time:hover .jw-rail,.jw-horizontal-volume-container:hover .jw-rail,.jw-slider-time:focus .jw-rail,.jw-horizontal-volume-container:focus .jw-rail,.jw-flag-dragging .jw-slider-time .jw-rail,.jw-flag-dragging .jw-horizontal-volume-container .jw-rail,.jw-flag-touch .jw-slider-time .jw-rail,.jw-flag-touch .jw-horizontal-volume-container .jw-rail,.jw-slider-time:hover .jw-buffer,.jw-horizontal-volume-container:hover .jw-buffer,.jw-slider-time:focus .jw-buffer,.jw-horizontal-volume-container:focus .jw-buffer,.jw-flag-dragging .jw-slider-time .jw-buffer,.jw-flag-dragging .jw-horizontal-volume-container .jw-buffer,.jw-flag-touch .jw-slider-time .jw-buffer,.jw-flag-touch .jw-horizontal-volume-container .jw-buffer,.jw-slider-time:hover .jw-progress,.jw-horizontal-volume-container:hover .jw-progress,.jw-slider-time:focus .jw-progress,.jw-horizontal-volume-container:focus .jw-progress,.jw-flag-dragging .jw-slider-time .jw-progress,.jw-flag-dragging .jw-horizontal-volume-container .jw-progress,.jw-flag-touch .jw-slider-time .jw-progress,.jw-flag-touch .jw-horizontal-volume-container .jw-progress,.jw-slider-time:hover .jw-cue,.jw-horizontal-volume-container:hover .jw-cue,.jw-slider-time:focus .jw-cue,.jw-horizontal-volume-container:focus .jw-cue,.jw-flag-dragging .jw-slider-time .jw-cue,.jw-flag-dragging .jw-horizontal-volume-container .jw-cue,.jw-flag-touch .jw-slider-time .jw-cue,.jw-flag-touch .jw-horizontal-volume-container .jw-cue{-webkit-transform:translate(0, -50%) scale(1, 1);transform:translate(0, -50%) scale(1, 1)}.jw-slider-time:hover .jw-knob,.jw-horizontal-volume-container:hover .jw-knob,.jw-slider-time:focus .jw-knob,.jw-horizontal-volume-container:focus .jw-knob{-webkit-transform:translate(-50%, -50%) scale(1);transform:translate(-50%, -50%) scale(1)}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail{background-color:rgba(255,255,255,0.2)}.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer{background-color:rgba(255,255,255,0.4)}.jw-flag-touch .jw-slider-time::before,.jw-flag-touch .jw-horizontal-volume-container::before{height:44px;width:100%;content:"";position:absolute;display:block;bottom:calc(100% - 17px);left:0}.jw-slider-time.jw-tab-focus:focus .jw-rail,.jw-horizontal-volume-container.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time{height:17px;padding:0}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-slider-container{height:10px}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-knob{border-radius:0;border:1px solid rgba(0,0,0,0.75);height:12px;width:10px}.jw-modal{width:284px}.jw-breakpoint-7 .jw-modal,.jw-breakpoint-6 .jw-modal,.jw-breakpoint-5 .jw-modal{height:232px}.jw-breakpoint-4 .jw-modal,.jw-breakpoint-3 .jw-modal{height:192px}.jw-breakpoint-2 .jw-modal,.jw-flag-small-player .jw-modal{bottom:0;right:0;height:100%;width:100%;max-height:none;max-width:none;z-index:2}.jwplayer .jw-rightclick{display:none;position:absolute;white-space:nowrap}.jwplayer .jw-rightclick.jw-open{display:block}.jwplayer .jw-rightclick .jw-rightclick-list{border-radius:1px;list-style:none;margin:0;padding:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item{background-color:rgba(0,0,0,0.8);border-bottom:1px solid #444;margin:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo{color:#fff;display:inline-flex;padding:0 10px 0 0;vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo .jw-svg-icon{height:20px;width:20px}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-link{border:none;color:#fff;display:block;font-size:11px;line-height:1em;padding:15px 23px;text-align:start;text-decoration:none;width:100%}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:last-child{border-bottom:none}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:hover{cursor:pointer}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured{vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link{color:#fff}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link span{color:#fff}.jwplayer .jw-rightclick .jw-info-overlay-item,.jwplayer .jw-rightclick .jw-share-item,.jwplayer .jw-rightclick .jw-shortcuts-item{border:none;background-color:transparent;outline:none;cursor:pointer}.jw-icon-tooltip.jw-open .jw-overlay{opacity:1;pointer-events:auto;transition-delay:0s}.jw-icon-tooltip.jw-open .jw-overlay:focus{outline:none}.jw-icon-tooltip.jw-open .jw-overlay:focus.jw-tab-focus{outline:solid 2px #4d90fe}.jw-slider-time .jw-overlay:before{height:1em;top:auto}.jw-slider-time .jw-icon-tooltip.jw-open .jw-overlay{pointer-events:none}.jw-volume-tip{padding:13px 0 26px}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{height:auto;width:100%;box-shadow:0 0 10px rgba(0,0,0,0.4);color:#fff;display:block;margin:0 0 14px;pointer-events:none;position:relative;z-index:0}.jw-time-tip::after,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{top:100%;position:absolute;left:50%;height:14px;width:14px;border-radius:1px;background-color:currentColor;-webkit-transform-origin:75% 50%;transform-origin:75% 50%;-webkit-transform:translate(-50%, -50%) rotate(45deg);transform:translate(-50%, -50%) rotate(45deg);z-index:-1}.jw-time-tip .jw-text,.jw-controlbar .jw-tooltip .jw-text,.jw-settings-menu .jw-tooltip .jw-text{background-color:#fff;border-radius:1px;color:#000;font-size:10px;height:auto;line-height:1;padding:7px 10px;display:inline-block;min-width:100%;vertical-align:middle}.jw-controlbar .jw-overlay{position:absolute;bottom:100%;left:50%;margin:0;min-height:44px;min-width:44px;opacity:0;pointer-events:none;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s, 150ms;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);width:100%;z-index:1}.jw-controlbar .jw-overlay .jw-contents{position:relative}.jw-controlbar .jw-option{position:relative;white-space:nowrap;cursor:pointer;list-style:none;height:1.5em;font-family:inherit;line-height:1.5em;padding:0 .5em;font-size:.8em;margin:0}.jw-controlbar .jw-option::before{padding-right:.125em}.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{position:absolute;bottom:100%;left:50%;opacity:0;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:100ms 0s cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility, -webkit-transform;transition-property:opacity, transform, visibility;transition-property:opacity, transform, visibility, -webkit-transform;visibility:hidden;white-space:nowrap;width:auto;z-index:1}.jw-controlbar .jw-tooltip.jw-open,.jw-settings-menu .jw-tooltip.jw-open{opacity:1;-webkit-transform:translate(-50%, -10px);transform:translate(-50%, -10px);transition-duration:150ms;transition-delay:500ms,0s,500ms;visibility:visible}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen{left:auto;right:0;-webkit-transform:translate(0, 0);transform:translate(0, 0)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen.jw-open,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen.jw-open{-webkit-transform:translate(0, -10px);transform:translate(0, -10px)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen::after,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen::after{left:auto;right:9px}.jw-tooltip-time{height:auto;width:0;bottom:100%;line-height:normal;padding:0;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.jw-tooltip-time .jw-overlay{bottom:0;min-height:0;width:auto}.jw-tooltip{bottom:57px;display:none;position:absolute}.jw-tooltip .jw-text{height:100%;white-space:nowrap;text-overflow:ellipsis;direction:unset;max-width:246px;overflow:hidden}.jw-flag-audio-player .jw-tooltip{display:none}.jw-flag-small-player .jw-time-thumb{display:none}.jwplayer .jw-shortcuts-tooltip{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column;z-index:1}.jwplayer .jw-shortcuts-tooltip.jw-open{display:flex}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-close{flex:0 0 auto;margin:5px 5px 5px auto}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container{display:flex;flex:1 1 auto;flex-flow:column;font-size:12px;margin:0 20px 20px;overflow-y:auto;padding:5px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar{background-color:transparent;width:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-title{font-weight:bold}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list{display:flex;max-width:340px;margin:0 10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-tooltip-descriptions{width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row{display:flex;align-items:center;justify-content:space-between;margin:10px 0;width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-description{margin-right:10px;max-width:70%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-key{background:#fefefe;color:#333;overflow:hidden;padding:7px 10px;text-overflow:ellipsis;white-space:nowrap}.jw-skip{color:rgba(255,255,255,0.8);cursor:default;position:absolute;display:flex;right:.75em;bottom:56px;padding:.5em;border:1px solid #333;background-color:#000;align-items:center;height:2em}.jw-skip.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-skip.jw-skippable{cursor:pointer;padding:.25em .75em}.jw-skip.jw-skippable:hover{cursor:pointer;color:#fff}.jw-skip.jw-skippable .jw-skip-icon{display:inline;height:24px;width:24px;margin:0}.jw-breakpoint-7 .jw-skip{padding:1.35em 1em;bottom:130px}.jw-breakpoint-7 .jw-skip .jw-text{font-size:1em;font-weight:normal}.jw-breakpoint-7 .jw-skip .jw-icon-inline{height:30px;width:30px}.jw-breakpoint-7 .jw-skip .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-skip .jw-skip-icon{display:none;margin-left:-0.75em;padding:0 .5em;pointer-events:none}.jw-skip .jw-skip-icon .jw-svg-icon-next{display:block;padding:0}.jw-skip .jw-text,.jw-skip .jw-skip-icon{vertical-align:middle;font-size:.7em}.jw-skip .jw-text{font-weight:bold}.jw-cast{background-size:cover;display:none;height:100%;position:relative;width:100%}.jw-cast-container{background:linear-gradient(180deg, rgba(25,25,25,0.75), rgba(25,25,25,0.25), rgba(25,25,25,0));left:0;padding:20px 20px 80px;position:absolute;top:0;width:100%}.jw-cast-text{color:#fff;font-size:1.6em}.jw-breakpoint--1 .jw-cast-text,.jw-breakpoint-0 .jw-cast-text{font-size:1.15em}.jw-breakpoint-1 .jw-cast-text,.jw-breakpoint-2 .jw-cast-text,.jw-breakpoint-3 .jw-cast-text{font-size:1.3em}.jw-nextup-container{position:absolute;bottom:66px;left:0;background-color:transparent;cursor:pointer;margin:0 auto;padding:12px;pointer-events:none;right:0;text-align:right;visibility:hidden;width:100%}.jw-settings-open .jw-nextup-container,.jw-info-open .jw-nextup-container{display:none}.jw-breakpoint-7 .jw-nextup-container{padding:60px}.jw-flag-small-player .jw-nextup-container{padding:0 12px 0 0}.jw-flag-small-player .jw-nextup-container .jw-nextup-title,.jw-flag-small-player .jw-nextup-container .jw-nextup-duration,.jw-flag-small-player .jw-nextup-container .jw-nextup-close{display:none}.jw-flag-small-player .jw-nextup-container .jw-nextup-tooltip{height:30px}.jw-flag-small-player .jw-nextup-container .jw-nextup-header{font-size:12px}.jw-flag-small-player .jw-nextup-container .jw-nextup-body{justify-content:center;align-items:center;padding:.75em .3em}.jw-flag-small-player .jw-nextup-container .jw-nextup-thumbnail{width:50%}.jw-flag-small-player .jw-nextup-container .jw-nextup{max-width:65px}.jw-flag-small-player .jw-nextup-container .jw-nextup.jw-nextup-thumbnail-visible{max-width:120px}.jw-nextup{background:#333;border-radius:0;box-shadow:0 0 10px rgba(0,0,0,0.5);color:rgba(255,255,255,0.8);display:inline-block;max-width:280px;overflow:hidden;opacity:0;position:relative;width:64%;pointer-events:all;-webkit-transform:translate(0, -5px);transform:translate(0, -5px);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform;transition-delay:0s}.jw-nextup:hover .jw-nextup-tooltip{color:#fff}.jw-nextup.jw-nextup-thumbnail-visible{max-width:400px}.jw-nextup.jw-nextup-thumbnail-visible .jw-nextup-thumbnail{display:block}.jw-nextup-container-visible{visibility:visible}.jw-nextup-container-visible .jw-nextup{opacity:1;-webkit-transform:translate(0, 0);transform:translate(0, 0);transition-delay:0s, 0s, 150ms}.jw-nextup-tooltip{display:flex;height:80px}.jw-nextup-thumbnail{width:120px;background-position:center;background-size:cover;flex:0 0 auto;display:none}.jw-nextup-body{flex:1 1 auto;overflow:hidden;padding:.75em .875em;display:flex;flex-flow:column wrap;justify-content:space-between}.jw-nextup-header,.jw-nextup-title{font-size:14px;line-height:1.35}.jw-nextup-header{font-weight:bold}.jw-nextup-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.jw-nextup-duration{align-self:flex-end;text-align:right;font-size:12px}.jw-nextup-close{height:24px;width:24px;border:none;color:rgba(255,255,255,0.8);cursor:pointer;margin:6px;visibility:hidden}.jw-nextup-close:hover{color:#fff}.jw-nextup-sticky .jw-nextup-close{visibility:visible}.jw-autostart-mute{position:absolute;bottom:0;right:12px;height:44px;width:44px;background-color:rgba(33,33,33,0.4);padding:5px 4px 5px 6px;display:none}.jwplayer.jw-flag-autostart:not(.jw-flag-media-audio) .jw-nextup{display:none}.jw-settings-menu{position:absolute;bottom:57px;right:12px;align-items:flex-start;background-color:#333;display:none;flex-flow:column nowrap;max-width:284px;pointer-events:auto}.jw-settings-open .jw-settings-menu{display:flex}.jw-breakpoint-7 .jw-settings-menu{bottom:130px;right:60px;max-height:none;max-width:none;height:35%;width:25%}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline{height:60px;width:60px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-tooltip .jw-text{font-size:1em}.jw-breakpoint-7 .jw-settings-menu .jw-settings-back{min-width:60px}.jw-breakpoint-6 .jw-settings-menu,.jw-breakpoint-5 .jw-settings-menu{height:232px;width:284px;max-height:232px}.jw-breakpoint-4 .jw-settings-menu,.jw-breakpoint-3 .jw-settings-menu{height:192px;width:284px;max-height:192px}.jw-breakpoint-2 .jw-settings-menu{height:179px;width:284px;max-height:179px}.jw-flag-small-player .jw-settings-menu{max-width:none}.jw-settings-menu .jw-icon.jw-button-color::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon.jw-button-color[aria-checked="true"]::after{opacity:1}.jw-settings-menu .jw-settings-reset{text-decoration:underline}.jw-settings-topbar{align-items:center;background-color:rgba(0,0,0,0.4);display:flex;flex:0 0 auto;padding:3px 5px 0;width:100%}.jw-settings-topbar.jw-nested-menu-open{padding:0}.jw-settings-topbar.jw-nested-menu-open .jw-icon:not(.jw-settings-close):not(.jw-settings-back){display:none}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-close{width:20px}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-arrow-left{height:12px}.jw-settings-topbar.jw-nested-menu-open .jw-settings-topbar-text{display:block;outline:none}.jw-settings-topbar .jw-settings-back{min-width:44px}.jw-settings-topbar .jw-settings-topbar-buttons{display:inherit;width:100%;height:100%}.jw-settings-topbar .jw-settings-topbar-text{display:none;color:#fff;font-size:13px;width:100%}.jw-settings-topbar .jw-settings-close{margin-left:auto}.jw-settings-submenu{display:none;flex:1 1 auto;overflow-y:auto;padding:8px 20px 0 5px}.jw-settings-submenu::-webkit-scrollbar{background-color:transparent;width:6px}.jw-settings-submenu::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-settings-submenu.jw-settings-submenu-active{display:block}.jw-settings-submenu .jw-submenu-topbar{box-shadow:0 2px 9px 0 #1d1d1d;background-color:#2f2d2d;margin:-8px -20px 0 -5px}.jw-settings-submenu .jw-submenu-topbar .jw-settings-content-item{cursor:pointer;text-align:right;padding-right:15px;text-decoration:underline}.jw-settings-submenu .jw-settings-value-wrapper{float:right;display:flex;align-items:center}.jw-settings-submenu .jw-settings-value-wrapper .jw-settings-content-item-arrow{display:flex}.jw-settings-submenu .jw-settings-value-wrapper .jw-svg-icon-arrow-right{width:8px;margin-left:5px;height:12px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item{font-size:1em;padding:11px 15px 11px 30px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-settings-item-active::before{justify-content:flex-end}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-auto-label{font-size:.85em;padding-left:10px}.jw-flag-touch .jw-settings-submenu{overflow-y:scroll;-webkit-overflow-scrolling:touch}.jw-auto-label{font-size:10px;font-weight:initial;opacity:.75;padding-left:5px}.jw-settings-content-item{position:relative;color:rgba(255,255,255,0.8);cursor:pointer;font-size:12px;line-height:1;padding:7px 0 7px 15px;width:100%;text-align:left;outline:none}.jw-settings-content-item:hover{color:#fff}.jw-settings-content-item:focus{font-weight:bold}.jw-flag-small-player .jw-settings-content-item{line-height:1.75}.jw-settings-content-item.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-settings-item-active{font-weight:bold;position:relative}.jw-settings-item-active::before{height:100%;width:1em;align-items:center;content:"\\2022";display:inline-flex;justify-content:center}.jw-breakpoint-2 .jw-settings-open .jw-display-container,.jw-flag-small-player .jw-settings-open .jw-display-container,.jw-flag-touch .jw-settings-open .jw-display-container{display:none}.jw-breakpoint-2 .jw-settings-open.jw-controls,.jw-flag-small-player .jw-settings-open.jw-controls,.jw-flag-touch .jw-settings-open.jw-controls{z-index:1}.jw-flag-small-player .jw-settings-open .jw-controlbar{display:none}.jw-settings-open .jw-icon-settings::after{opacity:1}.jw-settings-open .jw-tooltip-settings{display:none}.jw-sharing-link{cursor:pointer}.jw-shortcuts-container .jw-switch{position:relative;display:inline-block;transition:ease-out .15s;transition-property:opacity, background;border-radius:18px;width:80px;height:20px;padding:10px;background:rgba(80,80,80,0.8);cursor:pointer;font-size:inherit;vertical-align:middle}.jw-shortcuts-container .jw-switch.jw-tab-focus{outline:solid 2px #4d90fe}.jw-shortcuts-container .jw-switch .jw-switch-knob{position:absolute;top:2px;left:1px;transition:ease-out .15s;box-shadow:0 0 10px rgba(0,0,0,0.4);border-radius:13px;width:15px;height:15px;background:#fefefe}.jw-shortcuts-container .jw-switch:before,.jw-shortcuts-container .jw-switch:after{position:absolute;top:3px;transition:inherit;color:#fefefe}.jw-shortcuts-container .jw-switch:before{content:attr(data-jw-switch-disabled);right:8px}.jw-shortcuts-container .jw-switch:after{content:attr(data-jw-switch-enabled);left:8px;opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]{background:#475470}.jw-shortcuts-container .jw-switch[aria-checked="true"]:before{opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]:after{opacity:1}.jw-shortcuts-container .jw-switch[aria-checked="true"] .jw-switch-knob{left:60px}.jw-idle-icon-text{display:none;line-height:1;position:absolute;text-align:center;text-indent:.35em;top:100%;white-space:nowrap;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.jw-idle-label{border-radius:50%;color:#fff;-webkit-filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));font:normal 16px/1 Arial,Helvetica,sans-serif;position:relative;transition:background-color 150ms cubic-bezier(0, .25, .25, 1);transition-property:background-color,-webkit-filter;transition-property:background-color,filter;transition-property:background-color,filter,-webkit-filter;-webkit-font-smoothing:antialiased}.jw-state-idle .jw-icon-display.jw-idle-label .jw-idle-icon-text{display:block}.jw-state-idle .jw-icon-display.jw-idle-label .jw-svg-icon-play{-webkit-transform:scale(.7, .7);transform:scale(.7, .7)}.jw-breakpoint-0.jw-state-idle .jw-icon-display.jw-idle-label,.jw-breakpoint--1.jw-state-idle .jw-icon-display.jw-idle-label{font-size:12px}.jw-info-overlay{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column}.jw-info-overlay .jw-info-close{flex:0 0 auto;margin:5px 5px 5px auto}.jw-info-open .jw-info-overlay{display:flex}.jw-info-container{display:flex;flex:1 1 auto;flex-flow:column;margin:0 20px 20px;overflow-y:auto;padding:5px}.jw-info-container [class*="jw-info"]:not(:first-of-type){color:rgba(255,255,255,0.8);padding-top:10px;font-size:12px}.jw-info-container .jw-info-description{margin-bottom:30px;text-align:start}.jw-info-container .jw-info-description:empty{display:none}.jw-info-container .jw-info-duration{text-align:start}.jw-info-container .jw-info-title{text-align:start;font-size:12px;font-weight:bold}.jw-info-container::-webkit-scrollbar{background-color:transparent;width:6px}.jw-info-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-info-clientid{align-self:flex-end;font-size:12px;color:rgba(255,255,255,0.8);margin:0 20px 20px 44px;text-align:right}.jw-flag-touch .jw-info-open .jw-display-container{display:none}@supports ((-webkit-filter: drop-shadow(0 0 3px #000)) or (filter: drop-shadow(0 0 3px #000))){.jwplayer.jw-ab-drop-shadow .jw-controls .jw-svg-icon,.jwplayer.jw-ab-drop-shadow .jw-controls .jw-icon.jw-text,.jwplayer.jw-ab-drop-shadow .jw-slider-container .jw-rail,.jwplayer.jw-ab-drop-shadow .jw-title{text-shadow:none;box-shadow:none;-webkit-filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3));filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3))}.jwplayer.jw-ab-drop-shadow .jw-button-color{opacity:.8;transition-property:color, opacity}.jwplayer.jw-ab-drop-shadow .jw-button-color:not(:hover){color:#fff;opacity:.8}.jwplayer.jw-ab-drop-shadow .jw-button-color:hover{opacity:1}.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0), hsla(0, 0%, 0%, 0.00787) 10.79%, hsla(0, 0%, 0%, 0.02963) 21.99%, hsla(0, 0%, 0%, 0.0625) 33.34%, hsla(0, 0%, 0%, 0.1037) 44.59%, hsla(0, 0%, 0%, 0.15046) 55.48%, hsla(0, 0%, 0%, 0.2) 65.75%, hsla(0, 0%, 0%, 0.24954) 75.14%, hsla(0, 0%, 0%, 0.2963) 83.41%, hsla(0, 0%, 0%, 0.3375) 90.28%, hsla(0, 0%, 0%, 0.37037) 95.51%, hsla(0, 0%, 0%, 0.39213) 98.83%, hsla(0, 0%, 0%, 0.4));mix-blend-mode:multiply;transition-property:opacity}.jw-state-idle.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0.2), hsla(0, 0%, 0%, 0.19606) 1.17%, hsla(0, 0%, 0%, 0.18519) 4.49%, hsla(0, 0%, 0%, 0.16875) 9.72%, hsla(0, 0%, 0%, 0.14815) 16.59%, hsla(0, 0%, 0%, 0.12477) 24.86%, hsla(0, 0%, 0%, 0.1) 34.25%, hsla(0, 0%, 0%, 0.07523) 44.52%, hsla(0, 0%, 0%, 0.05185) 55.41%, hsla(0, 0%, 0%, 0.03125) 66.66%, hsla(0, 0%, 0%, 0.01481) 78.01%, hsla(0, 0%, 0%, 0.00394) 89.21%, hsla(0, 0%, 0%, 0));background-size:100% 7rem;background-position:50% 0}.jwplayer.jw-ab-drop-shadow.jw-state-idle .jw-controls{background-color:transparent}}.jw-video-thumbnail-container{position:relative;overflow:hidden}.jw-video-thumbnail-container:not(.jw-related-shelf-item-image){height:100%;width:100%}.jw-video-thumbnail-container.jw-video-thumbnail-generated{position:absolute;top:0;left:0}.jw-video-thumbnail-container:hover,.jw-related-item-content:hover .jw-video-thumbnail-container,.jw-related-shelf-item:hover .jw-video-thumbnail-container{cursor:pointer}.jw-video-thumbnail-container:hover .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-item-content:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-shelf-item:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail{position:absolute;top:50%;left:50%;bottom:unset;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);width:100%;height:auto;min-width:100%;min-height:100%;opacity:0;transition:opacity .3s ease;object-fit:cover;background:#000}.jw-related-item-next-up .jw-video-thumbnail-container .jw-video-thumbnail{height:100%;width:auto}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-visible:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-completed{opacity:0}.jw-video-thumbnail-container .jw-video-thumbnail~.jw-svg-icon-play{display:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-shelf-item-aspect{pointer-events:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-item-poster-content{pointer-events:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-state-idle .jw-controls{background:rgba(0,0,0,0.4)}.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay),.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay){display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon:focus{border:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon .jw-svg-icon-buffer{-webkit-animation:jw-spin 2s linear infinite;animation:jw-spin 2s linear infinite;display:block}@-webkit-keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.jwplayer.jw-state-buffering .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-pause{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-pause{display:block}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-controls-backdrop{opacity:0}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-logo-bottom-left,.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio):not(.jw-flag-autostart) .jw-logo-bottom-right{bottom:0}.jwplayer .jw-icon-playback .jw-svg-icon-stop{display:none}.jwplayer.jw-state-paused .jw-svg-icon-pause,.jwplayer.jw-state-idle .jw-svg-icon-pause,.jwplayer.jw-state-error .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-svg-icon-pause{display:none}.jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-complete .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-play{display:none}.jwplayer:not(.jw-state-buffering) .jw-svg-icon-buffer{display:none}.jwplayer:not(.jw-state-complete) .jw-svg-icon-replay{display:none}.jwplayer:not(.jw-state-error) .jw-svg-icon-error{display:none}.jwplayer.jw-state-complete .jw-display .jw-icon-display .jw-svg-icon-replay{display:block}.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-state-complete .jw-controls{background:rgba(0,0,0,0.4);height:100%}.jw-state-idle .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-state-idle .jw-display-icon-rewind,.jwplayer.jw-state-buffering .jw-display-icon-rewind,.jwplayer.jw-state-complete .jw-display-icon-rewind,body .jw-error .jw-display-icon-rewind,body .jwplayer.jw-state-error .jw-display-icon-rewind,.jw-state-idle .jw-display-icon-next,.jwplayer.jw-state-buffering .jw-display-icon-next,.jwplayer.jw-state-complete .jw-display-icon-next,body .jw-error .jw-display-icon-next,body .jwplayer.jw-state-error .jw-display-icon-next{display:none}body .jw-error .jw-icon-display,body .jwplayer.jw-state-error .jw-icon-display{cursor:default}body .jw-error .jw-icon-display .jw-svg-icon-error,body .jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-error{display:block}body .jw-error .jw-icon-container{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-preview{display:none}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title{padding-top:4px}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-primary{width:auto;display:inline-block;padding-right:.5ch}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-secondary{width:auto;display:inline-block;padding-left:0}body .jwplayer.jw-state-error .jw-controlbar,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-controlbar{display:none}body .jwplayer.jw-state-error .jw-settings-menu,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-settings-menu{height:100%;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}body .jwplayer.jw-state-error .jw-display,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-display{padding:0}body .jwplayer.jw-state-error .jw-logo-bottom-left,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-left,body .jwplayer.jw-state-error .jw-logo-bottom-right,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-right{bottom:0}.jwplayer.jw-state-playing.jw-flag-user-inactive .jw-display{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-state-playing:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display,.jwplayer.jw-state-paused:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting):not(.jw-flag-play-rejected) .jw-display{display:none}.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-rewind,.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-next{display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-text,.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-flag-casting:not(.jw-flag-audio-player) .jw-cast{display:block}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-display-icon-container{display:none}.jwplayer.jw-flag-casting .jw-icon-hd,.jwplayer.jw-flag-casting .jw-captions,.jwplayer.jw-flag-casting .jw-icon-fullscreen,.jwplayer.jw-flag-casting .jw-icon-audio-tracks{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-volume{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-airplay{color:#fff}.jw-state-playing.jw-flag-casting:not(.jw-flag-audio-player) .jw-display,.jw-state-paused.jw-flag-casting:not(.jw-flag-audio-player) .jw-display{display:table}.jwplayer.jw-flag-cast-available .jw-icon-cast,.jwplayer.jw-flag-cast-available .jw-icon-airplay{display:flex}.jwplayer.jw-flag-cardboard-available .jw-icon-cardboard{display:flex}.jwplayer.jw-flag-live .jw-display-icon-rewind{visibility:hidden}.jwplayer.jw-flag-live .jw-controlbar .jw-text-elapsed,.jwplayer.jw-flag-live .jw-controlbar .jw-text-duration,.jwplayer.jw-flag-live .jw-controlbar .jw-text-countdown,.jwplayer.jw-flag-live .jw-controlbar .jw-slider-time{display:none}.jwplayer.jw-flag-live .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-live .jw-controlbar .jw-overlay:after{display:none}.jwplayer.jw-flag-live .jw-nextup-container{bottom:44px}.jwplayer.jw-flag-live .jw-text-elapsed,.jwplayer.jw-flag-live .jw-text-duration{display:none}.jwplayer.jw-flag-live .jw-text-live{cursor:default}.jwplayer.jw-flag-live .jw-text-live:hover{color:rgba(255,255,255,0.8)}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-stop,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-stop{display:block}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-text-live{height:24px;width:auto;align-items:center;border-radius:1px;color:rgba(255,255,255,0.8);display:flex;font-size:12px;font-weight:bold;margin-right:10px;padding:0 1ch;text-rendering:geometricPrecision;text-transform:uppercase;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:box-shadow,color}.jw-text-live::before{height:8px;width:8px;background-color:currentColor;border-radius:50%;margin-right:6px;opacity:1;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-text-live.jw-dvr-live{box-shadow:inset 0 0 0 2px currentColor}.jw-text-live.jw-dvr-live::before{opacity:.5}.jw-text-live.jw-dvr-live:hover{color:#fff}.jwplayer.jw-flag-controls-hidden .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-controls-hidden:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-controls-hidden .jw-plugin{bottom:.5em}.jwplayer.jw-flag-controls-hidden .jw-nextup-container{bottom:0}.jw-flag-controls-hidden .jw-controlbar,.jw-flag-controls-hidden .jw-display{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-controls-hidden .jw-controls-backdrop{opacity:0}.jw-flag-controls-hidden .jw-logo{visibility:visible}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-plugin{bottom:.5em}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-nextup-container{bottom:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-controls-hidden) .jw-media{cursor:none;-webkit-cursor-visibility:auto-hide}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing.jw-flag-casting .jw-display{display:table}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-ads) .jw-autostart-mute{display:flex}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting .jw-nextup-container{bottom:66px}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting.jw-state-idle .jw-nextup-container{display:none}.jw-flag-media-audio .jw-preview{display:block}.jwplayer.jw-flag-ads .jw-preview,.jwplayer.jw-flag-ads .jw-logo,.jwplayer.jw-flag-ads .jw-captions.jw-captions-enabled,.jwplayer.jw-flag-ads .jw-nextup-container,.jwplayer.jw-flag-ads .jw-text-duration,.jwplayer.jw-flag-ads .jw-text-elapsed{display:none}.jwplayer.jw-flag-ads video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-rewind,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-next,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-display{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player.jw-state-buffering .jw-display-icon-display{display:inline-block}.jwplayer.jw-flag-ads .jw-controlbar{flex-wrap:wrap-reverse}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time{height:auto;padding:0;pointer-events:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-slider-container{height:5px}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-rail,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-knob,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-buffer,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-cue,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-icon-settings{display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-progress{-webkit-transform:none;transform:none;top:auto}.jwplayer.jw-flag-ads .jw-controlbar .jw-tooltip,.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-tooltip:not(.jw-icon-volume),.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-inline:not(.jw-icon-playback):not(.jw-icon-fullscreen):not(.jw-icon-volume){display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-volume-tip{padding:13px 0}.jwplayer.jw-flag-ads .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid) .jw-controls .jw-controlbar,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart .jw-controls .jw-controlbar{display:flex;pointer-events:all;visibility:visible;opacity:1}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-user-inactive .jw-controls-backdrop,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart.jw-flag-user-inactive .jw-controls-backdrop{opacity:1;background-size:100% 60px}.jwplayer.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-ads-vpaid .jw-skip,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-skip{display:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls{background:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls::after{content:none}.jwplayer.jw-flag-ads-hide-controls .jw-controls-backdrop,.jwplayer.jw-flag-ads-hide-controls .jw-controls{display:none !important}.jw-flag-overlay-open-related .jw-controls,.jw-flag-overlay-open-related .jw-title,.jw-flag-overlay-open-related .jw-logo{display:none}.jwplayer.jw-flag-rightclick-open{overflow:visible}.jwplayer.jw-flag-rightclick-open .jw-rightclick{z-index:16777215}body .jwplayer.jw-flag-flash-blocked .jw-controls,body .jwplayer.jw-flag-flash-blocked .jw-overlays,body .jwplayer.jw-flag-flash-blocked .jw-controls-backdrop,body .jwplayer.jw-flag-flash-blocked .jw-preview{display:none}body .jwplayer.jw-flag-flash-blocked .jw-error-msg{top:25%}.jw-flag-touch.jw-breakpoint-7 .jw-captions,.jw-flag-touch.jw-breakpoint-6 .jw-captions,.jw-flag-touch.jw-breakpoint-5 .jw-captions,.jw-flag-touch.jw-breakpoint-4 .jw-captions,.jw-flag-touch.jw-breakpoint-7 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-6 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-5 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-4 .jw-nextup-container{bottom:4.25em}.jw-flag-touch .jw-controlbar .jw-icon-volume{display:flex}.jw-flag-touch .jw-display,.jw-flag-touch .jw-display-container,.jw-flag-touch .jw-display-controls{pointer-events:none}.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-rewind,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-rewind{display:none}.jw-flag-touch.jw-state-paused.jw-flag-dragging .jw-display{display:none}.jw-flag-audio-player{background-color:#000}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:44px}.jw-flag-audio-player:not(.jw-flag-live) .jw-spacer{display:none}.jw-flag-audio-player .jw-preview,.jw-flag-audio-player .jw-display,.jw-flag-audio-player .jw-title,.jw-flag-audio-player .jw-nextup-container{display:none}.jw-flag-audio-player .jw-controlbar{position:relative}.jw-flag-audio-player .jw-controlbar .jw-button-container{padding-right:3px;padding-left:0}.jw-flag-audio-player .jw-controlbar .jw-icon-tooltip,.jw-flag-audio-player .jw-controlbar .jw-icon-inline{display:none}.jw-flag-audio-player .jw-controlbar .jw-icon-volume,.jw-flag-audio-player .jw-controlbar .jw-icon-playback,.jw-flag-audio-player .jw-controlbar .jw-icon-next,.jw-flag-audio-player .jw-controlbar .jw-icon-rewind,.jw-flag-audio-player .jw-controlbar .jw-icon-cast,.jw-flag-audio-player .jw-controlbar .jw-text-live,.jw-flag-audio-player .jw-controlbar .jw-icon-airplay,.jw-flag-audio-player .jw-controlbar .jw-logo-button,.jw-flag-audio-player .jw-controlbar .jw-text-elapsed,.jw-flag-audio-player .jw-controlbar .jw-text-duration{display:flex;flex:0 0 auto}.jw-flag-audio-player .jw-controlbar .jw-text-duration,.jw-flag-audio-player .jw-controlbar .jw-text-countdown{padding-right:10px}.jw-flag-audio-player .jw-controlbar .jw-slider-time{flex:0 1 auto;align-items:center;display:flex;order:1}.jw-flag-audio-player .jw-controlbar .jw-icon-volume{margin-right:0;transition:margin-right 150ms cubic-bezier(0, .25, .25, 1)}.jw-flag-audio-player .jw-controlbar .jw-icon-volume .jw-overlay{display:none}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container{transition:width 300ms cubic-bezier(0, .25, .25, 1);width:0}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open{width:140px}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open .jw-slider-volume{padding-right:24px;transition:opacity 300ms;opacity:1}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open~.jw-slider-time{flex:1 1 auto;width:auto;transition:opacity 300ms, width 300ms}.jw-flag-audio-player .jw-controlbar .jw-slider-volume{opacity:0}.jw-flag-audio-player .jw-controlbar .jw-slider-volume .jw-knob{-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.jw-flag-audio-player .jw-controlbar .jw-slider-volume~.jw-icon-volume{margin-right:140px}.jw-flag-audio-player.jw-breakpoint-1 .jw-horizontal-volume-container.jw-open~.jw-slider-time,.jw-flag-audio-player.jw-breakpoint-2 .jw-horizontal-volume-container.jw-open~.jw-slider-time{opacity:0}.jw-flag-audio-player.jw-flag-small-player .jw-text-elapsed,.jw-flag-audio-player.jw-flag-small-player .jw-text-duration{display:none}.jw-flag-audio-player.jw-flag-ads .jw-slider-time{display:none}.jw-hidden{display:none}',""])}]]); \ No newline at end of file diff --git a/ui/v2.5/public/jwplayer/jwplayer.core.controls.polyfills.html5.js b/ui/v2.5/public/jwplayer/jwplayer.core.controls.polyfills.html5.js new file mode 100644 index 000000000..c82790981 --- /dev/null +++ b/ui/v2.5/public/jwplayer/jwplayer.core.controls.polyfills.html5.js @@ -0,0 +1,95 @@ +/*! +JW Player version 8.11.5 +Copyright (c) 2019, JW Player, All Rights Reserved +https://github.com/jwplayer/jwplayer/blob/v8.11.5/README.md + +This source code and its use and distribution is subject to the terms and conditions of the applicable license agreement. +https://www.jwplayer.com/tos/ + +This product includes portions of other software. For the full text of licenses, see below: + +JW Player Third Party Software Notices and/or Additional Terms and Conditions + +************************************************************************************************** +The following software is used under Apache License 2.0 +************************************************************************************************** + +vtt.js v0.13.0 +Copyright (c) 2019 Mozilla (http://mozilla.org) +https://github.com/mozilla/vtt.js/blob/v0.13.0/LICENSE + +* * * + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. + +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. + +************************************************************************************************** +The following software is used under MIT license +************************************************************************************************** + +Underscore.js v1.6.0 +Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative +https://github.com/jashkenas/underscore/blob/1.6.0/LICENSE + +Backbone backbone.events.js v1.1.2 +Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud +https://github.com/jashkenas/backbone/blob/1.1.2/LICENSE + +Promise Polyfill v7.1.1 +Copyright (c) 2014 Taylor Hakes and Forbes Lindesay +https://github.com/taylorhakes/promise-polyfill/blob/v7.1.1/LICENSE + +can-autoplay.js v3.0.0 +Copyright (c) 2017 video-dev +https://github.com/video-dev/can-autoplay/blob/v3.0.0/LICENSE + +* * * + +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. + +************************************************************************************************** +The following software is used under W3C license +************************************************************************************************** + +Intersection Observer v0.5.0 +Copyright (c) 2016 Google Inc. (http://google.com) +https://github.com/w3c/IntersectionObserver/blob/v0.5.0/LICENSE.md + +* * * + +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. + +This work is being provided by the copyright holders under the following license. + +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. + +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. + +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. +*/ +(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[6,1,2,3,4,5,7,9],[,,,,,,,,,,,,,,,,,function(t,e,i){"use strict";i.r(e);var n,o=i(8),a=i(3),r=i(7),s=i(43),l=i(5),c=i(15),u=i(40);function d(t){return n||(n=new DOMParser),Object(l.r)(Object(l.s)(n.parseFromString(t,"image/svg+xml").documentElement))}var p=function(t,e,i,n){var o=document.createElement("div");o.className="jw-icon jw-icon-inline jw-button-color jw-reset "+t,o.setAttribute("role","button"),o.setAttribute("tabindex","0"),i&&o.setAttribute("aria-label",i),o.style.display="none";var a=new u.a(o).on("click tap enter",e||function(){});return n&&Array.prototype.forEach.call(n,(function(t){"string"==typeof t?o.appendChild(d(t)):o.appendChild(t)})),{ui:a,element:function(){return o},toggle:function(t){t?this.show():this.hide()},show:function(){o.style.display=""},hide:function(){o.style.display="none"}}},h=i(0),f=i(71),w=i.n(f),g=i(72),j=i.n(g),b=i(73),m=i.n(b),v=i(74),y=i.n(v),k=i(75),x=i.n(k),T=i(76),O=i.n(T),C=i(77),_=i.n(C),M=i(78),S=i.n(M),E=i(79),I=i.n(E),L=i(80),A=i.n(L),P=i(81),R=i.n(P),z=i(82),B=i.n(z),V=i(83),N=i.n(V),H=i(84),F=i.n(H),D=i(85),q=i.n(D),U=i(86),W=i.n(U),Q=i(62),Y=i.n(Q),X=i(87),K=i.n(X),J=i(88),Z=i.n(J),G=i(89),$=i.n(G),tt=i(90),et=i.n(tt),it=i(91),nt=i.n(it),ot=i(92),at=i.n(ot),rt=i(93),st=i.n(rt),lt=i(94),ct=i.n(lt),ut=null;function dt(t){var e=wt().querySelector(ht(t));if(e)return ft(e);throw new Error("Icon not found "+t)}function pt(t){var e=wt().querySelectorAll(t.split(",").map(ht).join(","));if(!e.length)throw new Error("Icons not found "+t);return Array.prototype.map.call(e,(function(t){return ft(t)}))}function ht(t){return".jw-svg-icon-".concat(t)}function ft(t){return t.cloneNode(!0)}function wt(){return ut||(ut=d(""+w.a+j.a+m.a+y.a+x.a+O.a+_.a+S.a+I.a+A.a+R.a+B.a+N.a+F.a+q.a+W.a+Y.a+K.a+Z.a+$.a+et.a+nt.a+at.a+st.a+ct.a+"")),ut}var gt=i(10);function jt(t,e){for(var i=0;i10&&delete bt[e[0]];var i=d(t);bt[t]=i}return bt[t].cloneNode(!0)}(e):((r=document.createElement("div")).className="jw-icon jw-button-image jw-button-color jw-reset",e&&Object(gt.d)(r,{backgroundImage:"url(".concat(e,")")})),s.appendChild(r),new u.a(s).on("click tap enter",n,this),s.addEventListener("mousedown",(function(t){t.preventDefault()})),this.id=o,this.buttonElement=s}var e,i,n;return e=t,(i=[{key:"element",value:function(){return this.buttonElement}},{key:"toggle",value:function(t){t?this.show():this.hide()}},{key:"show",value:function(){this.buttonElement.style.display=""}},{key:"hide",value:function(){this.buttonElement.style.display="none"}}])&&jt(e.prototype,i),n&&jt(e,n),t}(),vt=i(11);function yt(t,e){for(var i=0;i=0&&(e.left-=i,e.right-=i),e},xt=function(){function t(e,i){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),Object(h.g)(this,r.a),this.className=e+" jw-background-color jw-reset",this.orientation=i}var e,i,n;return e=t,(i=[{key:"setup",value:function(){this.el=Object(l.e)(function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return''}(this.className,"jw-slider-"+this.orientation)),this.elementRail=this.el.getElementsByClassName("jw-slider-container")[0],this.elementBuffer=this.el.getElementsByClassName("jw-buffer")[0],this.elementProgress=this.el.getElementsByClassName("jw-progress")[0],this.elementThumb=this.el.getElementsByClassName("jw-knob")[0],this.ui=new u.a(this.element(),{preventScrolling:!0}).on("dragStart",this.dragStart,this).on("drag",this.dragMove,this).on("dragEnd",this.dragEnd,this).on("click tap",this.tap,this)}},{key:"dragStart",value:function(){this.trigger("dragStart"),this.railBounds=kt(this.elementRail)}},{key:"dragEnd",value:function(t){this.dragMove(t),this.trigger("dragEnd")}},{key:"dragMove",value:function(t){var e,i,n=this.railBounds=this.railBounds?this.railBounds:kt(this.elementRail);return i="horizontal"===this.orientation?(e=t.pageX)n.right?100:100*Object(s.a)((e-n.left)/n.width,0,1):(e=t.pageY)>=n.bottom?0:e<=n.top?100:100*Object(s.a)((n.height-(e-n.top))/n.height,0,1),this.render(i),this.update(i),!1}},{key:"tap",value:function(t){this.railBounds=kt(this.elementRail),this.dragMove(t)}},{key:"limit",value:function(t){return t}},{key:"update",value:function(t){this.trigger("update",{percentage:t})}},{key:"render",value:function(t){t=Math.max(0,Math.min(t,100)),"horizontal"===this.orientation?(this.elementThumb.style.left=t+"%",this.elementProgress.style.width=t+"%"):(this.elementThumb.style.bottom=t+"%",this.elementProgress.style.height=t+"%")}},{key:"updateBuffer",value:function(t){this.elementBuffer.style.width=t+"%"}},{key:"element",value:function(){return this.el}}])&&yt(e.prototype,i),n&&yt(e,n),t}(),Tt=function(t,e){t&&e&&(t.setAttribute("aria-label",e),t.setAttribute("role","button"),t.setAttribute("tabindex","0"))};function Ot(t,e){for(var i=0;i0&&Array.prototype.forEach.call(o,(function(t){"string"==typeof t?a.el.appendChild(d(t)):a.el.appendChild(t)}))}var e,i,n;return e=t,(i=[{key:"addContent",value:function(t){this.content&&this.removeContent(),this.content=t,this.tooltip.appendChild(t)}},{key:"removeContent",value:function(){this.content&&(this.tooltip.removeChild(this.content),this.content=null)}},{key:"hasContent",value:function(){return!!this.content}},{key:"element",value:function(){return this.el}},{key:"openTooltip",value:function(t){this.isOpen||(this.trigger("open-"+this.componentType,t,{isOpen:!0}),this.isOpen=!0,Object(l.v)(this.el,this.openClass,this.isOpen))}},{key:"closeTooltip",value:function(t){this.isOpen&&(this.trigger("close-"+this.componentType,t,{isOpen:!1}),this.isOpen=!1,Object(l.v)(this.el,this.openClass,this.isOpen))}},{key:"toggleOpenState",value:function(t){this.isOpen?this.closeTooltip(t):this.openTooltip(t)}}])&&Ot(e.prototype,i),n&&Ot(e,n),t}(),_t=i(22),Mt=i(57);function St(t,e){for(var i=0;i=this.thumbnails.length&&(e=this.thumbnails.length-1);var i=this.thumbnails[e].img;return i.indexOf("://")<0&&(i=this.vttPath?this.vttPath+"/"+i:i),i},loadThumbnail:function(t){var e=this.chooseThumbnail(t),i={margin:"0 auto",backgroundPosition:"0 0"};if(e.indexOf("#xywh")>0)try{var n=/(.+)#xywh=(\d+),(\d+),(\d+),(\d+)/.exec(e);e=n[1],i.backgroundPosition=-1*n[2]+"px "+-1*n[3]+"px",i.width=n[4],this.timeTip.setWidth(+i.width),i.height=n[5]}catch(t){return}else this.individualImage||(this.individualImage=new Image,this.individualImage.onload=Object(h.a)((function(){this.individualImage.onload=null,this.timeTip.image({width:this.individualImage.width,height:this.individualImage.height}),this.timeTip.setWidth(this.individualImage.width)}),this),this.individualImage.src=e);return i.backgroundImage='url("'+e+'")',i},showThumbnail:function(t){this._model.get("containerWidth")<=420||this.thumbnails.length<1||this.timeTip.image(this.loadThumbnail(t))},resetThumbnails:function(){this.timeTip.image({backgroundImage:"",width:0,height:0}),this.thumbnails=[]}};function Pt(t,e,i){return(Pt="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,i){var n=function(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=Ht(t)););return t}(t,e);if(n){var o=Object.getOwnPropertyDescriptor(n,e);return o.get?o.get.call(i):o.value}})(t,e,i||t)}function Rt(t){return(Rt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function zt(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Bt(t,e){for(var i=0;i-1&&(n="Live")}var d=this.timeTip;d.update(n),this.textLength!==n.length&&(this.textLength=n.length,d.resetWidth()),this.showThumbnail(u),Object(l.a)(d.el,"jw-open");var p=d.getWidth(),h=a.width/100,f=o-a.width,w=0;p>f&&(w=(p-f)/(200*h));var g=100*Math.min(1-w,Math.max(w,c)).toFixed(3);Object(gt.d)(d.el,{left:g+"%"})}}},{key:"hideTimeTooltip",value:function(){Object(l.o)(this.timeTip.el,"jw-open")}},{key:"updateCues",value:function(t,e){var i=this;this.resetCues(),e&&e.length&&(e.forEach((function(t){i.addCue(t)})),this.drawCues())}},{key:"updateAriaText",value:function(){var t=this._model;if(!t.get("seeking")){var e=t.get("position"),i=t.get("duration"),n=Object(vt.timeFormat)(e);"DVR"!==this.streamType&&(n+=" of ".concat(Object(vt.timeFormat)(i)));var o=this.el;document.activeElement!==o&&(this.timeUpdateKeeper.textContent=n),Object(l.t)(o,"aria-valuenow",e),Object(l.t)(o,"aria-valuetext",n)}}},{key:"reset",value:function(){this.resetThumbnails(),this.timeTip.resetWidth(),this.textLength=0}}]),e}(xt);Object(h.g)(Ut.prototype,It,At);var Wt=Ut;function Qt(t,e){for(var i=0;i=75&&!t),Object(l.t)(r,"aria-valuenow",o),Object(l.t)(s,"aria-valuenow",o);var c="Volume ".concat(o,"%");Object(l.t)(r,"aria-valuetext",c),Object(l.t)(s,"aria-valuetext",c),document.activeElement!==r&&document.activeElement!==s&&(this._volumeAnnouncer.textContent=c)}}},{key:"onCastAvailable",value:function(t,e){this.elements.cast.toggle(e)}},{key:"onCastActive",value:function(t,e){this.elements.fullscreen.toggle(!e),this.elements.cast.button&&Object(l.v)(this.elements.cast.button,"jw-off",!e)}},{key:"onElapsed",value:function(t,e){var i,n,o=t.get("duration");if("DVR"===t.get("streamType")){var a=Math.ceil(e),r=this._model.get("dvrSeekLimit");i=n=a>=-r?"":"-"+Object(vt.timeFormat)(-(e+r)),t.set("dvrLive",a>=-r)}else i=Object(vt.timeFormat)(e),n=Object(vt.timeFormat)(o-e);this.elements.elapsed.textContent=i,this.elements.countdown.textContent=n}},{key:"onDuration",value:function(t,e){this.elements.duration.textContent=Object(vt.timeFormat)(Math.abs(e))}},{key:"onAudioMode",value:function(t,e){var i=this.elements.time.element();e?this.elements.buttonContainer.insertBefore(i,this.elements.elapsed):Object(l.m)(this.el,i)}},{key:"element",value:function(){return this.el}},{key:"setAltText",value:function(t,e){this.elements.alt.textContent=e}},{key:"closeMenus",value:function(t){this.menus.forEach((function(e){t&&t.target===e.el||e.closeTooltip(t)}))}},{key:"rewind",value:function(){var t,e=0,i=this._model.get("currentTime");i?t=i-10:(t=this._model.get("position")-10,"DVR"===this._model.get("streamType")&&(e=this._model.get("duration"))),this._api.seek(Math.max(t,e),{reason:"interaction"})}},{key:"onState",value:function(t,e){var i=t.get("localization"),n=i.play;this.setPlayText(n),e===a.pb&&("LIVE"!==t.get("streamType")?(n=i.pause,this.setPlayText(n)):(n=i.stop,this.setPlayText(n))),Object(l.t)(this.elements.play.element(),"aria-label",n)}},{key:"onStreamTypeChange",value:function(t,e){var i="LIVE"===e,n="DVR"===e;this.elements.rewind.toggle(!i),this.elements.live.toggle(i||n),Object(l.t)(this.elements.live.element(),"tabindex",i?"-1":"0"),this.elements.duration.style.display=n?"none":"",this.onDuration(t,t.get("duration")),this.onState(t,t.get("state"))}},{key:"addLogo",value:function(t){var e=this.elements.buttonContainer,i=new mt(t.file,this._model.get("localization").logo,(function(){t.link&&Object(l.l)(t.link,"_blank",{rel:"noreferrer"})}),"logo","jw-logo-button");t.link||Object(l.t)(i.element(),"tabindex","-1"),e.insertBefore(i.element(),e.querySelector(".jw-spacer").nextSibling)}},{key:"goToLiveEdge",value:function(){if("DVR"===this._model.get("streamType")){var t=Math.min(this._model.get("position"),-1),e=this._model.get("dvrSeekLimit");this._api.seek(Math.max(-e,t),{reason:"interaction"}),this._api.play({reason:"interaction"})}}},{key:"updateButtons",value:function(t,e,i){if(e){var n,o,a=this.elements.buttonContainer;e!==i&&i?(n=ce(e,i),o=ce(i,e),this.removeButtons(a,o)):n=e;for(var r=n.length-1;r>=0;r--){var s=n[r],l=new mt(s.img,s.tooltip,s.callback,s.id,s.btnClass);s.tooltip&&ne(l.element(),s.id,s.tooltip);var c=void 0;"related"===l.id?c=this.elements.settingsButton.element():"share"===l.id?c=a.querySelector('[button="related"]')||this.elements.settingsButton.element():(c=this.elements.spacer.nextSibling)&&"logo"===c.getAttribute("button")&&(c=c.nextSibling),a.insertBefore(l.element(),c)}}}},{key:"removeButtons",value:function(t,e){for(var i=e.length;i--;){var n=t.querySelector('[button="'.concat(e[i].id,'"]'));n&&t.removeChild(n)}}},{key:"toggleCaptionsButtonState",value:function(t){var e=this.elements.captionsButton;e&&Object(l.v)(e.element(),"jw-off",!t)}},{key:"destroy",value:function(){var t=this;this._model.off(null,null,this),Object.keys(this.elements).forEach((function(e){var i=t.elements[e];i&&"function"==typeof i.destroy&&t.elements[e].destroy()})),this.ui.forEach((function(t){t.destroy()})),this.ui=[]}}])&&ae(e.prototype,i),n&&ae(e,n),t}(),pe=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return'
    ')+'
    ')+"
    "},he=function(t){return'
    '+pe("rewind",t.rewind)+pe("display",t.playback)+pe("next",t.next)+"
    "};function fe(t,e){for(var i=0;i'.concat(a.playback,"")),Object(l.a)(o.icon,"jw-idle-label"),o.icon.appendChild(s))}return o}var i,n,o;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&ve(t,e)}(e,t),i=e,(n=[{key:"element",value:function(){return this.el}}])&&je(i.prototype,n),o&&je(i,o),e}(r.a);function ke(t,e){for(var i=0;i0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";return'
    '+'
    '.concat(t,"
    ")+'
    '.concat(e,"
    ")+'
    '.concat(i,"
    ")+"
    "+'')+"
    "}());e.querySelector(".jw-nextup-close").appendChild(dt("close")),this.addContent(e),this.closeButton=this.content.querySelector(".jw-nextup-close"),this.closeButton.setAttribute("aria-label",this.localization.close),this.tooltip=this.content.querySelector(".jw-nextup-tooltip");var i=this._model,n=i.player;this.enabled=!1,i.on("change:nextUp",this.onNextUp,this),n.change("duration",this.onDuration,this),n.change("position",this.onElapsed,this),n.change("streamType",this.onStreamType,this),n.change("state",(function(t,e){"complete"===e&&this.toggle(!1)}),this),this.closeUi=new u.a(this.closeButton,{directSelect:!0}).on("click tap enter",(function(){this.nextUpSticky=!1,this.toggle(!1)}),this),this.tooltipUi=new u.a(this.tooltip).on("click tap",this.click,this)}},{key:"loadThumbnail",value:function(t){return this.nextUpImage=new Image,this.nextUpImage.onload=function(){this.nextUpImage.onload=null}.bind(this),this.nextUpImage.src=t,{backgroundImage:'url("'+t+'")'}}},{key:"click",value:function(){var t=this.feedShownId;this.reset(),this._api.next({feedShownId:t,reason:"interaction"})}},{key:"toggle",value:function(t,e){if(this.enabled&&(Object(l.v)(this.container,"jw-nextup-sticky",!!this.nextUpSticky),this.shown!==t)){this.shown=t,Object(l.v)(this.container,"jw-nextup-container-visible",t),Object(l.v)(this._playerElement,"jw-flag-nextup",t);var i=this._model.get("nextUp");t&&i?(this.feedShownId=Object(oe.b)(oe.a),this.trigger("nextShown",{mode:i.mode,ui:"nextup",itemsShown:[i],feedData:i.feedData,reason:e,feedShownId:this.feedShownId})):this.feedShownId=""}}},{key:"setNextUpItem",value:function(t){var e=this;setTimeout((function(){if(e.thumbnail=e.content.querySelector(".jw-nextup-thumbnail"),Object(l.v)(e.content,"jw-nextup-thumbnail-visible",!!t.image),t.image){var i=e.loadThumbnail(t.image);Object(gt.d)(e.thumbnail,i)}e.header=e.content.querySelector(".jw-nextup-header"),e.header.textContent=Object(l.e)(e.localization.nextUp).textContent,e.title=e.content.querySelector(".jw-nextup-title");var n=t.title;e.title.textContent=n?Object(l.e)(n).textContent:"";var o=t.duration;o&&(e.duration=e.content.querySelector(".jw-nextup-duration"),e.duration.textContent="number"==typeof o?Object(vt.timeFormat)(o):o)}),500)}},{key:"onNextUp",value:function(t,e){this.reset(),e||(e={showNextUp:!1}),this.enabled=!(!e.title&&!e.image),this.enabled&&(e.showNextUp||(this.nextUpSticky=!1,this.toggle(!1)),this.setNextUpItem(e))}},{key:"onDuration",value:function(t,e){if(e){var i=t.get("nextupoffset"),n=-10;i&&(n=Object(_e.d)(i,e)),n<0&&(n+=e),Object(_e.c)(i)&&e-5=this.offset;n&&void 0===i?(this.nextUpSticky=n,this.toggle(n,"time")):!n&&i&&this.reset()}}},{key:"onStreamType",value:function(t,e){"VOD"!==e&&(this.nextUpSticky=!1,this.toggle(!1))}},{key:"element",value:function(){return this.container}},{key:"addContent",value:function(t){this.content&&this.removeContent(),this.content=t,this.container.appendChild(t)}},{key:"removeContent",value:function(){this.content&&(this.container.removeChild(this.content),this.content=null)}},{key:"reset",value:function(){this.nextUpSticky=void 0,this.toggle(!1)}},{key:"destroy",value:function(){this.off(),this._model.off(null,null,this),this.closeUi&&this.closeUi.destroy(),this.tooltipUi&&this.tooltipUi.destroy()}}])&&Me(e.prototype,i),n&&Me(e,n),t}(),Ee=function(t,e){var i=t.featured,n=t.showLogo,o=t.type;return t.logo=n?'':"",'
  • ').concat(Ie[o](t,e),"
  • ")},Ie={link:function(t){var e=t.link,i=t.title,n=t.logo;return'').concat(n).concat(i||"","")},info:function(t,e){return'")},share:function(t,e){return'")},keyboardShortcuts:function(t,e){return'")}},Le=i(23),Ae=i(6),Pe=i(13);function Re(t,e){for(var i=0;iJW Player '.concat(t,""),a={items:[{type:"info"},{title:Object(Pe.e)(n)?"".concat(o," ").concat(n):"".concat(n," ").concat(o),type:"link",featured:!0,showLogo:!0,link:"https://jwplayer.com/learn-more?e=".concat(ze[i])}]},r=e.get("provider"),s=a.items;if(r&&r.name.indexOf("flash")>=0){var l="Flash Version "+Object(Ae.a)();s.push({title:l,type:"link",link:"http://www.adobe.com/software/flash/about/"})}return this.shortcutsTooltip&&s.splice(s.length-1,0,{type:"keyboardShortcuts"}),a}},{key:"rightClick",value:function(t){if(this.lazySetup(),this.mouseOverContext)return!1;this.hideMenu(),this.showMenu(t),this.addHideMenuHandlers()}},{key:"getOffset",value:function(t){var e=Object(l.c)(this.wrapperElement),i=t.pageX-e.left,n=t.pageY-e.top;return this.model.get("touchMode")&&(n-=100),{x:i,y:n}}},{key:"showMenu",value:function(t){var e=this,i=this.getOffset(t);return this.el.style.left=i.x+"px",this.el.style.top=i.y+"px",this.outCount=0,Object(l.a)(this.playerContainer,"jw-flag-rightclick-open"),Object(l.a)(this.el,"jw-open"),clearTimeout(this._menuTimeout),this._menuTimeout=setTimeout((function(){return e.hideMenu()}),3e3),!1}},{key:"hideMenu",value:function(t){t&&this.el&&this.el.contains(t.target)||(Object(l.o)(this.playerContainer,"jw-flag-rightclick-open"),Object(l.o)(this.el,"jw-open"))}},{key:"lazySetup",value:function(){var t,e,i,n,o=this,a=(t=this.buildArray(),e=this.model.get("localization"),i=t.items,n=(void 0===i?[]:i).map((function(t){return Ee(t,e)})),'
    '+'
      '.concat(n.join(""),"
    ")+"
    ");if(this.el){if(this.html!==a){this.html=a;var r=Be(a);Object(l.h)(this.el);for(var s=r.childNodes.length;s--;)this.el.appendChild(r.firstChild)}}else this.html=a,this.el=Be(this.html),this.wrapperElement.appendChild(this.el),this.hideMenuHandler=function(t){return o.hideMenu(t)},this.overHandler=function(){o.mouseOverContext=!0},this.outHandler=function(t){o.mouseOverContext=!1,t.relatedTarget&&!o.el.contains(t.relatedTarget)&&++o.outCount>1&&o.hideMenu()},this.infoOverlayHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.infoOverlay.open()},this.shortcutsTooltipHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.shortcutsTooltip.open()}}},{key:"setup",value:function(t,e,i){this.wrapperElement=i,this.model=t,this.mouseOverContext=!1,this.playerContainer=e,this.ui=new u.a(i).on("longPress",this.rightClick,this)}},{key:"addHideMenuHandlers",value:function(){this.removeHideMenuHandlers(),this.wrapperElement.addEventListener("touchstart",this.hideMenuHandler),document.addEventListener("touchstart",this.hideMenuHandler),o.OS.mobile||(this.wrapperElement.addEventListener("click",this.hideMenuHandler),document.addEventListener("click",this.hideMenuHandler),this.el.addEventListener("mouseover",this.overHandler),this.el.addEventListener("mouseout",this.outHandler)),this.el.querySelector(".jw-info-overlay-item").addEventListener("click",this.infoOverlayHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").addEventListener("click",this.shortcutsTooltipHandler)}},{key:"removeHideMenuHandlers",value:function(){this.wrapperElement&&(this.wrapperElement.removeEventListener("click",this.hideMenuHandler),this.wrapperElement.removeEventListener("touchstart",this.hideMenuHandler)),this.el&&(this.el.querySelector(".jw-info-overlay-item").removeEventListener("click",this.infoOverlayHandler),this.el.removeEventListener("mouseover",this.overHandler),this.el.removeEventListener("mouseout",this.outHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").removeEventListener("click",this.shortcutsTooltipHandler)),document.removeEventListener("click",this.hideMenuHandler),document.removeEventListener("touchstart",this.hideMenuHandler)}},{key:"destroy",value:function(){clearTimeout(this._menuTimeout),this.removeHideMenuHandlers(),this.el&&(this.hideMenu(),this.hideMenuHandler=null,this.el=null),this.wrapperElement&&(this.wrapperElement.oncontextmenu=null,this.wrapperElement=null),this.model&&(this.model=null),this.ui&&(this.ui.destroy(),this.ui=null)}}])&&Re(e.prototype,i),n&&Re(e,n),t}(),Ne=function(t){return'")},He=function(t){return'"},Fe=function(t){return'"};function De(t){return(De="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function qe(t,e){return!e||"object"!==De(e)&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function Ue(t){return(Ue=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function We(t,e){return(We=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function Qe(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Ye(t,e){for(var i=0;i2&&void 0!==arguments[2]?arguments[2]:Ne;Qe(this,t),this.el=Object(l.e)(n(e)),this.ui=new u.a(this.el).on("click tap enter",i,this)}return Xe(t,[{key:"destroy",value:function(){this.ui.destroy()}}]),t}(),Ze=function(t){function e(t,i){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Fe;return Qe(this,e),qe(this,Ue(e).call(this,t,i,n))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&We(t,e)}(e,t),Xe(e,[{key:"activate",value:function(){Object(l.v)(this.el,"jw-settings-item-active",!0),this.el.setAttribute("aria-checked","true"),this.active=!0}},{key:"deactivate",value:function(){Object(l.v)(this.el,"jw-settings-item-active",!1),this.el.setAttribute("aria-checked","false"),this.active=!1}}]),e}(Je),Ge=function(t,e){return t?'':''},$e=function(t,e){var i=t.name,n={captions:"cc-off",audioTracks:"audio-tracks",quality:"quality-100",playbackRates:"playback-rate"}[i];if(n||t.icon){var o=p("jw-settings-".concat(i," jw-submenu-").concat(i),(function(e){t.open(e)}),i,[t.icon&&Object(l.e)(t.icon)||dt(n)]),a=o.element();return a.setAttribute("role","menuitemradio"),a.setAttribute("aria-checked","false"),a.setAttribute("aria-label",e),"ontouchstart"in window||(o.tooltip=ne(a,i,e)),o}};function ti(t){return(ti="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function ei(t,e){for(var i=0;i3&&void 0!==arguments[3]?arguments[3]:Ge;return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),a=this,(o=!(r=ii(e).call(this))||"object"!==ti(r)&&"function"!=typeof r?oi(a):r).open=o.open.bind(oi(oi(o))),o.close=o.close.bind(oi(oi(o))),o.toggle=o.toggle.bind(oi(oi(o))),o.onDocumentClick=o.onDocumentClick.bind(oi(oi(o))),o.name=t,o.isSubmenu=!!i,o.el=Object(l.e)(s(o.isSubmenu,t)),o.topbar=o.el.querySelector(".jw-".concat(o.name,"-topbar")),o.buttonContainer=o.el.querySelector(".jw-".concat(o.name,"-topbar-buttons")),o.children={},o.openMenus=[],o.items=[],o.visible=!1,o.parentMenu=i,o.mainMenu=o.parentMenu?o.parentMenu.mainMenu:oi(oi(o)),o.categoryButton=null,o.closeButton=o.parentMenu&&o.parentMenu.closeButton||o.createCloseButton(n),o.isSubmenu?(o.categoryButton=o.parentMenu.categoryButton||o.createCategoryButton(n),o.parentMenu.parentMenu&&!o.mainMenu.backButton&&(o.mainMenu.backButton=o.createBackButton(n)),o.itemsContainer=o.createItemsContainer(),o.parentMenu.appendMenu(oi(oi(o)))):o.ui=ri(oi(oi(o))),o}var i,n,o;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&ni(t,e)}(e,t),i=e,(n=[{key:"createItemsContainer",value:function(){var t,e,i=this,n=this.el.querySelector(".jw-settings-submenu-items"),o=new u.a(n),a=this.categoryButton&&this.categoryButton.element()||this.parentMenu.categoryButton&&this.parentMenu.categoryButton.element()||this.mainMenu.buttonContainer.firstChild;return this.parentMenu.isSubmenu&&(t=this.mainMenu.closeButton.element(),e=this.mainMenu.backButton.element()),o.on("keydown",(function(o){if(o.target.parentNode===n){var r=function(t,e){t?t.focus():void 0!==e&&n.childNodes[e].focus()},s=o.sourceEvent,c=s.target,u=n.firstChild===c,d=n.lastChild===c,p=i.topbar,h=t||Object(l.k)(a),f=e||Object(l.n)(a),w=Object(l.k)(s.target),g=Object(l.n)(s.target),j=s.key.replace(/(Arrow|ape)/,"");switch(j){case"Tab":r(s.shiftKey?f:h);break;case"Left":r(f||Object(l.n)(document.getElementsByClassName("jw-icon-settings")[0]));break;case"Up":p&&u?r(p.firstChild):r(g,n.childNodes.length-1);break;case"Right":r(h);break;case"Down":p&&d?r(p.firstChild):r(w,0)}s.preventDefault(),"Esc"!==j&&s.stopPropagation()}})),o}},{key:"createCloseButton",value:function(t){var e=p("jw-settings-close",this.close,t.close,[dt("close")]);return this.topbar.appendChild(e.element()),e.show(),e.ui.on("keydown",(function(t){var e=t.sourceEvent,i=e.key.replace(/(Arrow|ape)/,"");("Enter"===i||"Right"===i||"Tab"===i&&!e.shiftKey)&&this.close(t)}),this),this.buttonContainer.appendChild(e.element()),e}},{key:"createCategoryButton",value:function(t){var e=t[{captions:"cc",audioTracks:"audioTracks",quality:"hd",playbackRates:"playbackRates"}[this.name]];"sharing"===this.name&&(e=t.sharing.heading);var i=$e(this,e);return i.element().setAttribute("name",this.name),i}},{key:"createBackButton",value:function(t){var e=p("jw-settings-back",(function(t){Ke&&Ke.open(t)}),t.close,[dt("arrow-left")]);return Object(l.m)(this.mainMenu.topbar,e.element()),e}},{key:"createTopbar",value:function(){var t=Object(l.e)('
    ');return Object(l.m)(this.el,t),t}},{key:"createItems",value:function(t,e){var i=this,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Ze,a=this.name,r=t.map((function(t,r){var s,l;switch(a){case"quality":s="Auto"===t.label&&0===r?"".concat(n.defaultText,' '):t.label;break;case"captions":s="Off"!==t.label&&"off"!==t.id||0!==r?t.label:n.defaultText;break;case"playbackRates":l=t,s=Object(Pe.e)(n.tooltipText)?"x"+t:t+"x";break;case"audioTracks":s=t.name}s||(s=t,"object"===ti(t)&&(s.options=n));var c=new o(s,function(t){c.active||(e(l||r),c.deactivate&&(i.items.filter((function(t){return!0===t.active})).forEach((function(t){t.deactivate()})),Ke?Ke.open(t):i.mainMenu.close(t)),c.activate&&c.activate())}.bind(i));return c}));return r}},{key:"setMenuItems",value:function(t,e){var i=this;t?(this.items=[],Object(l.h)(this.itemsContainer.el),t.forEach((function(t){i.items.push(t),i.itemsContainer.el.appendChild(t.el)})),e>-1&&t[e].activate(),this.categoryButton.show()):this.removeMenu()}},{key:"appendMenu",value:function(t){if(t){var e=t.el,i=t.name,n=t.categoryButton;if(this.children[i]=t,n){var o=this.mainMenu.buttonContainer,a=o.querySelector(".jw-settings-sharing"),r="quality"===i?o.firstChild:a||this.closeButton.element();o.insertBefore(n.element(),r)}this.mainMenu.el.appendChild(e)}}},{key:"removeMenu",value:function(t){if(!t)return this.parentMenu.removeMenu(this.name);var e=this.children[t];e&&(delete this.children[t],e.destroy())}},{key:"open",value:function(t){if(!this.visible||this.openMenus){var e;if(Ke=null,this.isSubmenu){var i=this.mainMenu,n=this.parentMenu,o=this.categoryButton;if(n.openMenus.length&&n.closeChildren(),o&&o.element().setAttribute("aria-checked","true"),n.isSubmenu){n.el.classList.remove("jw-settings-submenu-active"),i.topbar.classList.add("jw-nested-menu-open");var a=i.topbar.querySelector(".jw-settings-topbar-text");a.setAttribute("name",this.name),a.innerText=this.title||this.name,i.backButton.show(),Ke=this.parentMenu,e=this.topbar?this.topbar.firstChild:t&&"enter"===t.type?this.items[0].el:a}else i.topbar.classList.remove("jw-nested-menu-open"),i.backButton&&i.backButton.hide();this.el.classList.add("jw-settings-submenu-active"),n.openMenus.push(this.name),i.visible||(i.open(t),this.items&&t&&"enter"===t.type?e=this.topbar?this.topbar.firstChild.focus():this.items[0].el:o.tooltip&&(o.tooltip.suppress=!0,e=o.element())),this.openMenus.length&&this.closeChildren(),e&&e.focus(),this.el.scrollTop=0}else this.el.parentNode.classList.add("jw-settings-open"),this.trigger("menuVisibility",{visible:!0,evt:t}),document.addEventListener("click",this.onDocumentClick);this.visible=!0,this.el.setAttribute("aria-expanded","true")}}},{key:"close",value:function(t){var e=this;this.visible&&(this.visible=!1,this.el.setAttribute("aria-expanded","false"),this.isSubmenu?(this.el.classList.remove("jw-settings-submenu-active"),this.categoryButton.element().setAttribute("aria-checked","false"),this.parentMenu.openMenus=this.parentMenu.openMenus.filter((function(t){return t!==e.name})),!this.mainMenu.openMenus.length&&this.mainMenu.visible&&this.mainMenu.close(t)):(this.el.parentNode.classList.remove("jw-settings-open"),this.trigger("menuVisibility",{visible:!1,evt:t}),document.removeEventListener("click",this.onDocumentClick)),this.openMenus.length&&this.closeChildren())}},{key:"closeChildren",value:function(){var t=this;this.openMenus.forEach((function(e){var i=t.children[e];i&&i.close()}))}},{key:"toggle",value:function(t){this.visible?this.close(t):this.open(t)}},{key:"onDocumentClick",value:function(t){/jw-(settings|video|nextup-close|sharing-link|share-item)/.test(t.target.className)||this.close()}},{key:"destroy",value:function(){var t=this;if(document.removeEventListener("click",this.onDocumentClick),Object.keys(this.children).map((function(e){t.children[e].destroy()})),this.isSubmenu){this.parentMenu.name===this.mainMenu.name&&this.categoryButton&&(this.parentMenu.buttonContainer.removeChild(this.categoryButton.element()),this.categoryButton.ui.destroy()),this.itemsContainer&&this.itemsContainer.destroy();var e=this.parentMenu.openMenus,i=e.indexOf(this.name);e.length&&i>-1&&this.openMenus.splice(i,1),delete this.parentMenu}else this.ui.destroy();this.visible=!1,this.el.parentNode&&this.el.parentNode.removeChild(this.el)}},{key:"defaultChild",get:function(){var t=this.children,e=t.quality,i=t.captions,n=t.audioTracks,o=t.sharing,a=t.playbackRates;return e||i||n||o||a}}])&&ei(i.prototype,n),o&&ei(i,o),e}(r.a),ri=function(t){var e=t.closeButton,i=t.el;return new u.a(i).on("keydown",(function(i){var n=i.sourceEvent,o=i.target,a=Object(l.k)(o),r=Object(l.n)(o),s=n.key.replace(/(Arrow|ape)/,""),c=function(e){r?e||r.focus():t.close(i)};switch(s){case"Esc":t.close(i);break;case"Left":c();break;case"Right":a&&e.element()&&o!==e.element()&&a.focus();break;case"Tab":n.shiftKey&&c(!0);break;case"Up":case"Down":!function(){var e=t.children[o.getAttribute("name")];if(!e&&Ke&&(e=Ke.children[Ke.openMenus]),e)return e.open(i),void(e.topbar?e.topbar.firstChild.focus():e.items&&e.items.length&&e.items[0].el.focus());if(i.target.parentNode.classList.contains("jw-submenu-topbar")){var n=i.target.parentNode.parentNode.querySelector(".jw-settings-submenu-items");("Down"===s?n.childNodes[0]:n.childNodes[n.childNodes.length-1]).focus()}}()}if(n.stopPropagation(),/13|32|37|38|39|40/.test(n.keyCode))return n.preventDefault(),!1}))},si=i(59),li=function(t){return hi[t]},ci=function(t){for(var e,i=Object.keys(hi),n=0;n1;i.elements.settingsButton.toggle(c)};e.change("levels",(function(t,e){r(e)}),o);var s=function(t,i,n){var o=e.get("levels");if(o&&"Auto"===o[0].label&&i&&i.items.length){var a=i.items[0].el.querySelector(".jw-auto-label"),r=o[t.index]||{label:""};a.textContent=n?"":r.label}};e.on("change:visualQuality",(function(t,i){var n=o.children.quality;i&&n&&s(i.level,n,e.get("currentLevel"))})),e.on("change:currentLevel",(function(t,i){var n=o.children.quality,a=e.get("visualQuality");a&&n&&s(a.level,n,i)}),o),e.change("captionsList",(function(i,r){var s={defaultText:n.off},l=e.get("captionsIndex");a("captions",r,(function(e){return t.setCurrentCaptions(e)}),l,s);var c=o.children.captions;if(c&&!c.children.captionsSettings){c.topbar=c.topbar||c.createTopbar();var u=new ai("captionsSettings",c,n);u.title="Subtitle Settings";var d=new Je("Settings",u.open);c.topbar.appendChild(d.el);var p=new Ze("Reset",(function(){e.set("captions",si.a),w()}));p.el.classList.add("jw-settings-reset");var f=e.get("captions"),w=function(){var t=[];pi.forEach((function(i){f&&f[i.propertyName]&&(i.defaultVal=i.getOption(f[i.propertyName]));var o=new ai(i.name,u,n),a=new Je({label:i.name,value:i.defaultVal},o.open,He),r=o.createItems(i.options,(function(t){var n=a.el.querySelector(".jw-settings-content-item-value");!function(t,i){var n=e.get("captions"),o=t.propertyName,a=t.options&&t.options[i],r=t.getTypedValue(a),s=Object(h.g)({},n);s[o]=r,e.set("captions",s)}(i,t),n.innerText=i.options[t]}),null);o.setMenuItems(r,i.options.indexOf(i.defaultVal)||0),t.push(a)})),t.push(p),u.setMenuItems(t)};w()}}));var l=function(t,e){t&&e>-1&&t.items[e].activate()};e.change("captionsIndex",(function(t,e){var n=o.children.captions;n&&l(n,e),i.toggleCaptionsButtonState(!!e)}),o);var c=function(i){if(e.get("supportsPlaybackRate")&&"LIVE"!==e.get("streamType")&&e.get("playbackRateControls")){var r=i.indexOf(e.get("playbackRate")),s={tooltipText:n.playbackRates};a("playbackRates",i,(function(e){return t.setPlaybackRate(e)}),r,s)}else o.children.playbackRates&&o.removeMenu("playbackRates")};e.on("change:playbackRates",(function(t,e){c(e)}),o);var u=function(i){a("audioTracks",i,(function(e){return t.setCurrentAudioTrack(e)}),e.get("currentAudioTrack"))};return e.on("change:audioTracks",(function(t,e){u(e)}),o),e.on("change:playbackRate",(function(t,i){var n=e.get("playbackRates"),a=-1;n&&(a=n.indexOf(i)),l(o.children.playbackRates,a)}),o),e.on("change:currentAudioTrack",(function(t,e){o.children.audioTracks.items[e].activate()}),o),e.on("change:playlistItem",(function(){o.removeMenu("captions"),i.elements.captionsButton.hide(),o.visible&&o.close()}),o),e.on("change:playbackRateControls",(function(){c(e.get("playbackRates"))})),e.on("change:castActive",(function(t,i,n){i!==n&&(i?(o.removeMenu("audioTracks"),o.removeMenu("quality"),o.removeMenu("playbackRates")):(u(e.get("audioTracks")),r(e.get("levels")),c(e.get("playbackRates"))))}),o),e.on("change:streamType",(function(){c(e.get("playbackRates"))}),o),o},wi=i(58),gi=i(35),ji=i(12),bi=function(t,e,i,n){var o=Object(l.e)('
    '),r=!1,s=null,c=!1,u=function(t){/jw-info/.test(t.target.className)||h.close()},d=function(){var n,a,s,c,u,d=p("jw-info-close",(function(){h.close()}),e.get("localization").close,[dt("close")]);d.show(),Object(l.m)(o,d.element()),a=o.querySelector(".jw-info-title"),s=o.querySelector(".jw-info-duration"),c=o.querySelector(".jw-info-description"),u=o.querySelector(".jw-info-clientid"),e.change("playlistItem",(function(t,e){var i=e.description,n=e.title;Object(l.q)(c,i||""),Object(l.q)(a,n||"Unknown Title")})),e.change("duration",(function(t,i){var n="";switch(e.get("streamType")){case"LIVE":n="Live";break;case"DVR":n="DVR";break;default:i&&(n=Object(vt.timeFormat)(i))}s.textContent=n}),h),u.textContent=(n=i.getPlugin("jwpsrv"))&&"function"==typeof n.doNotTrackUser&&n.doNotTrackUser()?"":"Client ID: ".concat(function(){try{return window.localStorage.jwplayerLocalId}catch(t){return"none"}}()),t.appendChild(o),r=!0};var h={open:function(){r||d(),document.addEventListener("click",u),c=!0;var t=e.get("state");t===a.pb&&i.pause("infoOverlayInteraction"),s=t,n(!0)},close:function(){document.removeEventListener("click",u),c=!1,e.get("state")===a.ob&&s===a.pb&&i.play("infoOverlayInteraction"),s=null,n(!1)},destroy:function(){this.close(),e.off(null,null,this)}};return Object.defineProperties(h,{visible:{enumerable:!0,get:function(){return c}}}),h};var mi=function(t,e,i){var n,o=!1,r=null,s=i.get("localization").shortcuts,c=Object(l.e)(function(t,e){var i=t.map((function(t){return'
    '+''.concat(t.description,"")+''.concat(t.key,"")+"
    "})).join("");return'
    ')+'Press shift question mark to access a list of keyboard shortcuts
    '+''.concat(e,"")+'
    '+"".concat(i)+"
    "}(function(t){var e=t.playPause,i=t.volumeToggle,n=t.fullscreenToggle,o=t.seekPercent,a=t.increaseVolume,r=t.decreaseVolume,s=t.seekForward,l=t.seekBackward;return[{key:t.spacebar,description:e},{key:"↑",description:a},{key:"↓",description:r},{key:"→",description:s},{key:"←",description:l},{key:"c",description:t.captionsToggle},{key:"f",description:n},{key:"m",description:i},{key:"0-9",description:o}]}(s),s.keyboardShortcuts)),d={reason:"settingsInteraction"},h=new u.a(c.querySelector(".jw-switch")),f=function(){h.el.setAttribute("aria-checked",i.get("enableShortcuts")),Object(l.a)(c,"jw-open"),r=i.get("state"),c.querySelector(".jw-shortcuts-close").focus(),document.addEventListener("click",g),o=!0,e.pause(d)},w=function(){Object(l.o)(c,"jw-open"),document.removeEventListener("click",g),t.focus(),o=!1,r===a.pb&&e.play(d)},g=function(t){/jw-shortcuts|jw-switch/.test(t.target.className)||w()},j=function(t){var e=t.currentTarget,n="true"!==e.getAttribute("aria-checked");e.setAttribute("aria-checked",n),i.set("enableShortcuts",n)};return n=p("jw-shortcuts-close",w,i.get("localization").close,[dt("close")]),Object(l.m)(c,n.element()),n.show(),t.appendChild(c),h.on("click tap enter",j),{el:c,open:f,close:w,destroy:function(){w(),h.destroy()},toggleVisibility:function(){o?w():f()}}},vi=function(t){return'
    ')+"
    "};function yi(t){return(yi="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function ki(t,e){for(var i=0;i16?n.activeTimeout=setTimeout(n.userInactiveTimeout,t):n.playerContainer.querySelector(".jw-tab-focus")?n.resetActiveTimeout():n.userInactive()},n}var i,n,r;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&Ii(t,e)}(e,t),i=e,(n=[{key:"resetActiveTimeout",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.inactiveTime=0}},{key:"enable",value:function(t,e){var i=this,n=this.context.createElement("div");n.className="jw-controls jw-reset",this.div=n;var r=this.context.createElement("div");r.className="jw-controls-backdrop jw-reset",this.backdrop=r,this.logo=this.playerContainer.querySelector(".jw-logo");var c=e.get("touchMode"),u=function(){(e.get("isFloating")?i.wrapperElement:i.playerContainer).focus()};if(!this.displayContainer){var d=new Oe(e,t);d.buttons.display.on("click tap enter",(function(){i.trigger(a.p),i.userActive(1e3),t.playToggle(Pi()),u()})),this.div.appendChild(d.element()),this.displayContainer=d}this.infoOverlay=new bi(n,e,t,(function(t){Object(l.v)(i.div,"jw-info-open",t),t&&i.div.querySelector(".jw-info-close").focus()})),o.OS.mobile||(this.shortcutsTooltip=new mi(this.wrapperElement,t,e)),this.rightClickMenu=new Ve(this.infoOverlay,this.shortcutsTooltip),c?(Object(l.a)(this.playerContainer,"jw-flag-touch"),this.rightClickMenu.setup(e,this.playerContainer,this.wrapperElement)):e.change("flashBlocked",(function(t,e){e?i.rightClickMenu.destroy():i.rightClickMenu.setup(t,i.playerContainer,i.wrapperElement)}),this);var h=e.get("floating");if(h){var f=new Ci(n,e.get("localization").close);f.on(a.sb,(function(){return i.trigger("dismissFloating",{doNotForward:!0})})),!1!==h.dismissible&&Object(l.a)(this.playerContainer,"jw-floating-dismissible")}var w=this.controlbar=new de(t,e,this.playerContainer.querySelector(".jw-hidden-accessibility"));if(w.on(a.sb,(function(){return i.userActive()})),w.on("nextShown",(function(t){this.trigger("nextShown",t)}),this),w.on("adjustVolume",k,this),e.get("nextUpDisplay")&&!w.nextUpToolTip){var g=new Se(e,t,this.playerContainer);g.on("all",this.trigger,this),g.setup(this.context),w.nextUpToolTip=g,this.div.appendChild(g.element())}this.div.appendChild(w.element());var j=e.get("localization"),b=this.settingsMenu=fi(t,e.player,this.controlbar,j),m=null;this.controlbar.on("menuVisibility",(function(n){var o=n.visible,r=n.evt,s=e.get("state"),l={reason:"settingsInteraction"},c=i.controlbar.elements.settingsButton,d="keydown"===(r&&r.sourceEvent||r||{}).type,p=o||d?0:Li;i.userActive(p),m=s,Object(wi.a)(e.get("containerWidth"))<2&&(o&&s===a.pb?t.pause(l):o||s!==a.ob||m!==a.pb||t.play(l)),!o&&d&&c?c.element().focus():r&&u()})),b.on("menuVisibility",(function(t){return i.controlbar.trigger("menuVisibility",t)})),this.controlbar.on("settingsInteraction",(function(t,e,i){if(e)return b.defaultChild.toggle(i);b.children[t].toggle(i)})),o.OS.mobile?this.div.appendChild(b.el):(this.playerContainer.setAttribute("aria-describedby","jw-shortcuts-tooltip-explanation"),this.div.insertBefore(b.el,w.element()));var v=function(e){if(e.get("autostartMuted")){var n=function(){return i.unmuteAutoplay(t,e)},a=function(t,e){e||n()};o.OS.mobile&&(i.mute=p("jw-autostart-mute jw-off",n,e.get("localization").unmute,[dt("volume-0")]),i.mute.show(),i.div.appendChild(i.mute.element())),w.renderVolume(!0,e.get("volume")),Object(l.a)(i.playerContainer,"jw-flag-autostart"),e.on("change:autostartFailed",n,i),e.on("change:autostartMuted change:mute",a,i),i.muteChangeCallback=a,i.unmuteCallback=n}};function y(i){var n=0,o=e.get("duration"),a=e.get("position");if("DVR"===e.get("streamType")){var r=e.get("dvrSeekLimit");n=o,o=Math.max(a,-r)}var l=Object(s.a)(a+i,n,o);t.seek(l,Pi())}function k(i){var n=Object(s.a)(e.get("volume")+i,0,100);t.setVolume(n)}e.once("change:autostartMuted",v),v(e);var x=function(n){if(n.ctrlKey||n.metaKey)return!0;var o=!i.settingsMenu.visible,a=!0===e.get("enableShortcuts"),r=i.instreamState;if(a||-1!==Ai.indexOf(n.keyCode)){switch(n.keyCode){case 27:if(e.get("fullscreen"))t.setFullscreen(!1),i.playerContainer.blur(),i.userInactive();else{var s=t.getPlugin("related");s&&s.close({type:"escape"})}i.rightClickMenu.el&&i.rightClickMenu.hideMenuHandler(),i.infoOverlay.visible&&i.infoOverlay.close(),i.shortcutsTooltip&&i.shortcutsTooltip.close();break;case 13:case 32:if(document.activeElement.classList.contains("jw-switch")&&13===n.keyCode)return!0;t.playToggle(Pi());break;case 37:!r&&o&&y(-5);break;case 39:!r&&o&&y(5);break;case 38:o&&k(10);break;case 40:o&&k(-10);break;case 67:var l=t.getCaptionsList().length;if(l){var c=(t.getCurrentCaptions()+1)%l;t.setCurrentCaptions(c)}break;case 77:t.setMute();break;case 70:t.setFullscreen();break;case 191:i.shortcutsTooltip&&i.shortcutsTooltip.toggleVisibility();break;default:if(n.keyCode>=48&&n.keyCode<=59){var u=(n.keyCode-48)/10*e.get("duration");t.seek(u,Pi())}}return/13|32|37|38|39|40/.test(n.keyCode)?(n.preventDefault(),!1):void 0}};this.playerContainer.addEventListener("keydown",x),this.keydownCallback=x;var T=function(t){switch(t.keyCode){case 9:var e=i.playerContainer.contains(t.target)?0:Li;i.userActive(e);break;case 32:t.preventDefault()}};this.playerContainer.addEventListener("keyup",T),this.keyupCallback=T;var O=function(t){var e=t.relatedTarget||document.querySelector(":focus");e&&(i.playerContainer.contains(e)||i.userInactive())};this.playerContainer.addEventListener("blur",O,!0),this.blurCallback=O;var C=function t(){"jw-shortcuts-tooltip-explanation"===i.playerContainer.getAttribute("aria-describedby")&&i.playerContainer.removeAttribute("aria-describedby"),i.playerContainer.removeEventListener("blur",t,!0)};this.shortcutsTooltip&&(this.playerContainer.addEventListener("blur",C,!0),this.onRemoveShortcutsDescription=C),this.userActive(),this.addControls(),this.addBackdrop(),e.set("controlsEnabled",!0)}},{key:"addControls",value:function(){this.wrapperElement.appendChild(this.div)}},{key:"disable",value:function(t){var e=this.nextUpToolTip,i=this.settingsMenu,n=this.infoOverlay,o=this.controlbar,a=this.rightClickMenu,r=this.shortcutsTooltip,s=this.playerContainer,c=this.div;clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.off(),t.off(null,null,this),t.set("controlsEnabled",!1),c.parentNode&&(Object(l.o)(s,"jw-flag-touch"),c.parentNode.removeChild(c)),o&&o.destroy(),a&&a.destroy(),this.keydownCallback&&s.removeEventListener("keydown",this.keydownCallback),this.keyupCallback&&s.removeEventListener("keyup",this.keyupCallback),this.blurCallback&&s.removeEventListener("blur",this.blurCallback),this.onRemoveShortcutsDescription&&s.removeEventListener("blur",this.onRemoveShortcutsDescription),this.displayContainer&&this.displayContainer.destroy(),e&&e.destroy(),i&&i.destroy(),n&&n.destroy(),r&&r.destroy(),this.removeBackdrop()}},{key:"controlbarHeight",value:function(){return this.dimensions.cbHeight||(this.dimensions.cbHeight=this.controlbar.element().clientHeight),this.dimensions.cbHeight}},{key:"element",value:function(){return this.div}},{key:"resize",value:function(){this.dimensions={}}},{key:"unmuteAutoplay",value:function(t,e){var i=!e.get("autostartFailed"),n=e.get("mute");i?n=!1:e.set("playOnViewable",!1),this.muteChangeCallback&&(e.off("change:autostartMuted change:mute",this.muteChangeCallback),this.muteChangeCallback=null),this.unmuteCallback&&(e.off("change:autostartFailed",this.unmuteCallback),this.unmuteCallback=null),e.set("autostartFailed",void 0),e.set("autostartMuted",void 0),t.setMute(n),this.controlbar.renderVolume(n,e.get("volume")),this.mute&&this.mute.hide(),Object(l.o)(this.playerContainer,"jw-flag-autostart"),this.userActive()}},{key:"mouseMove",value:function(t){var e=this.controlbar.element().contains(t.target),i=this.controlbar.nextUpToolTip&&this.controlbar.nextUpToolTip.element().contains(t.target),n=this.logo&&this.logo.contains(t.target),o=e||i||n?0:Li;this.userActive(o)}},{key:"userActive",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Li;t>0?(this.inactiveTime=Object(c.a)()+t,-1===this.activeTimeout&&(this.activeTimeout=setTimeout(this.userInactiveTimeout,t))):this.resetActiveTimeout(),this.showing||(Object(l.o)(this.playerContainer,"jw-flag-user-inactive"),this.showing=!0,this.trigger("userActive"))}},{key:"userInactive",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.settingsMenu.visible||(this.inactiveTime=0,this.showing=!1,Object(l.a)(this.playerContainer,"jw-flag-user-inactive"),this.trigger("userInactive"))}},{key:"addBackdrop",value:function(){var t=this.instreamState?this.div:this.wrapperElement.querySelector(".jw-captions");this.wrapperElement.insertBefore(this.backdrop,t)}},{key:"removeBackdrop",value:function(){var t=this.backdrop.parentNode;t&&t.removeChild(this.backdrop)}},{key:"setupInstream",value:function(){this.instreamState=!0,this.userActive(),this.addBackdrop(),this.settingsMenu&&this.settingsMenu.close(),Object(l.o)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","-1")}},{key:"destroyInstream",value:function(t){this.instreamState=null,this.addBackdrop(),t.get("autostartMuted")&&Object(l.a)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","0")}}])&&Mi(i.prototype,n),r&&Mi(i,r),e}(r.a)},function(t,e,i){"use strict";i.r(e);var n=i(0),o=i(12),a=i(50),r=i(36);var s=i(44),l=i(51),c=i(26),u=i(25),d=i(3),p=i(46),h=i(2),f=i(7),w=i(34);function g(t){var e=!1;return{async:function(){var i=this,n=arguments;return Promise.resolve().then((function(){if(!e)return t.apply(i,n)}))},cancel:function(){e=!0},cancelled:function(){return e}}}var j=i(1);function b(t){return function(e,i){var o=t.mediaModel,a=Object(n.g)({},i,{type:e});switch(e){case d.T:if(o.get(d.T)===i.mediaType)return;o.set(d.T,i.mediaType);break;case d.U:return void o.set(d.U,Object(n.g)({},i));case d.M:if(i[e]===t.model.getMute())return;break;case d.bb:i.newstate===d.mb&&(t.thenPlayPromise.cancel(),o.srcReset());var r=o.attributes.mediaState;o.attributes.mediaState=i.newstate,o.trigger("change:mediaState",o,i.newstate,r);break;case d.F:return t.beforeComplete=!0,t.trigger(d.B,a),void(t.attached&&!t.background&&t._playbackComplete());case d.G:o.get("setup")?(t.thenPlayPromise.cancel(),o.srcReset()):(e=d.tb,a.code+=1e5);break;case d.K:a.metadataType||(a.metadataType="unknown");var s=i.duration;Object(n.u)(s)&&(o.set("seekRange",i.seekRange),o.set("duration",s));break;case d.D:o.set("buffer",i.bufferPercent);case d.S:o.set("seekRange",i.seekRange),o.set("position",i.position),o.set("currentTime",i.currentTime);var l=i.duration;Object(n.u)(l)&&o.set("duration",l),e===d.S&&Object(n.r)(t.item.starttime)&&delete t.item.starttime;break;case d.R:var c=t.mediaElement;c&&c.paused&&o.set("mediaState","paused");break;case d.I:o.set(d.I,i.levels);case d.J:var u=i.currentQuality,p=i.levels;u>-1&&p.length>1&&o.set("currentLevel",parseInt(u));break;case d.f:o.set(d.f,i.tracks);case d.g:var h=i.currentTrack,f=i.tracks;h>-1&&f.length>0&&h=Math.max(l,p.a)&&(t.preloadNextItem(),v=!0)}function L(t){var e={};b.tag&&(e.tag=b.tag),this.trigger(d.F,e),A.call(this,t)}function A(t){g={},a&&w+10?t:null,f&&f.model.set("skipOffset",s)}};Object(n.g)(lt.prototype,f.a);var ct=lt,ut=i(66),dt=i(63),pt=function(t){var e=this,i=[],n={},o=0,a=0;function r(t){if(t.data=t.data||[],t.name=t.label||t.name||t.language,t._id=Object(dt.a)(t,i.length),!t.name){var e=Object(dt.b)(t,o);t.name=e.label,o=e.unknownCount}n[t._id]=t,i.push(t)}function s(){for(var t=[{id:"off",label:"Off"}],e=0;e')+'
    '},wt=i(35),gt=44,jt=function(t){var e=t.get("height");if(t.get("aspectratio"))return!1;if("string"==typeof e&&e.indexOf("%")>-1)return!1;var i=1*e||NaN;return!!(i=isNaN(i)?t.get("containerHeight"):i)&&(i&&i<=gt)},bt=i(54);function mt(t,e){if(t.get("fullscreen"))return 1;if(!t.get("activeTab"))return 0;if(t.get("isFloating"))return 1;var i=t.get("intersectionRatio");return void 0===i&&(i=function(t){var e=document.documentElement,i=document.body,n={top:0,left:0,right:e.clientWidth||i.clientWidth,width:e.clientWidth||i.clientWidth,bottom:e.clientHeight||i.clientHeight,height:e.clientHeight||i.clientHeight};if(!i.contains(t))return 0;if("none"===window.getComputedStyle(t).display)return 0;var o=vt(t);if(!o)return 0;var a=o,r=t.parentNode,s=!1;for(;!s;){var l=null;if(r===i||r===e||1!==r.nodeType?(s=!0,l=n):"visible"!==window.getComputedStyle(r).overflow&&(l=vt(r)),l&&(c=l,u=a,d=void 0,p=void 0,h=void 0,f=void 0,w=void 0,g=void 0,d=Math.max(c.top,u.top),p=Math.min(c.bottom,u.bottom),h=Math.max(c.left,u.left),f=Math.min(c.right,u.right),g=p-d,!(a=(w=f-h)>=0&&g>=0&&{top:d,bottom:p,left:h,right:f,width:w,height:g})))return 0;r=r.parentNode}var c,u,d,p,h,f,w,g;var j=o.width*o.height,b=a.width*a.height;return j?b/j:0}(e),window.top!==window.self&&i)?0:i}function vt(t){try{return t.getBoundingClientRect()}catch(t){}}var yt=i(49),kt=i(42),xt=i(58),Tt=i(10);var Ot=i(32),Ct=i(5),_t=i(6),Mt=["fullscreenchange","webkitfullscreenchange","mozfullscreenchange","MSFullscreenChange"],St=function(t,e,i){for(var n=t.requestFullscreen||t.webkitRequestFullscreen||t.webkitRequestFullScreen||t.mozRequestFullScreen||t.msRequestFullscreen,o=e.exitFullscreen||e.webkitExitFullscreen||e.webkitCancelFullScreen||e.mozCancelFullScreen||e.msExitFullscreen,a=!(!n||!o),r=Mt.length;r--;)e.addEventListener(Mt[r],i);return{events:Mt,supportsDomFullscreen:function(){return a},requestFullscreen:function(){n.call(t,{navigationUI:"hide"})},exitFullscreen:function(){null!==this.fullscreenElement()&&o.apply(e)},fullscreenElement:function(){var t=e.fullscreenElement,i=e.webkitCurrentFullScreenElement,n=e.mozFullScreenElement,o=e.msFullscreenElement;return null===t?t:t||i||n||o},destroy:function(){for(var t=Mt.length;t--;)e.removeEventListener(Mt[t],i)}}},Et=i(40);function It(t,e){for(var i=0;i')},Rt={linktarget:"_blank",margin:8,hide:!1,position:"top-right"};function zt(t){var e,i;Object(n.g)(this,f.a);var o=new Image;this.setup=function(){(i=Object(n.g)({},Rt,t.get("logo"))).position=i.position||Rt.position,i.hide="true"===i.hide.toString(),i.file&&"control-bar"!==i.position&&(e||(e=Object(Ct.e)(Pt(i.position,i.hide))),t.set("logo",i),o.onload=function(){var n=this.height,o=this.width,a={backgroundImage:'url("'+this.src+'")'};if(i.margin!==Rt.margin){var r=/(\w+)-(\w+)/.exec(i.position);3===r.length&&(a["margin-"+r[1]]=i.margin,a["margin-"+r[2]]=i.margin)}var s=.15*t.get("containerHeight"),l=.15*t.get("containerWidth");if(n>s||o>l){var c=o/n;l/s>c?(n=s,o=s*c):(o=l,n=l/c)}a.width=Math.round(o),a.height=Math.round(n),Object(Tt.d)(e,a),t.set("logoWidth",a.width)},o.src=i.file,i.link&&(e.setAttribute("tabindex","0"),e.setAttribute("aria-label",t.get("localization").logo)),this.ui=new Et.a(e).on("click tap enter",(function(t){t&&t.stopPropagation&&t.stopPropagation(),this.trigger(d.A,{link:i.link,linktarget:i.linktarget})}),this))},this.setContainer=function(t){e&&t.appendChild(e)},this.element=function(){return e},this.position=function(){return i.position},this.destroy=function(){o.onload=null,this.ui&&this.ui.destroy()}}var Bt=function(t){this.model=t,this.image=null};Object(n.g)(Bt.prototype,{setup:function(t){this.el=t},setImage:function(t){var e=this.image;e&&(e.onload=null),this.image=null;var i="";"string"==typeof t&&(i='url("'+t+'")',(e=this.image=new Image).src=t),Object(Tt.d)(this.el,{backgroundImage:i})},resize:function(t,e,i){if("uniform"===i){if(t&&(this.playerAspectRatio=t/e),!this.playerAspectRatio||!this.image||"complete"!==(s=this.model.get("state"))&&"idle"!==s&&"error"!==s&&"buffering"!==s)return;var n=this.image,o=null;if(n){if(0===n.width){var a=this;return void(n.onload=function(){a.resize(t,e,i)})}var r=n.width/n.height;Math.abs(this.playerAspectRatio-r)<.09&&(o="cover")}Object(Tt.d)(this.el,{backgroundSize:o})}var s},element:function(){return this.el}});var Vt=Bt,Nt=function(t){this.model=t.player};Object(n.g)(Nt.prototype,{hide:function(){Object(Tt.d)(this.el,{display:"none"})},show:function(){Object(Tt.d)(this.el,{display:""})},setup:function(t){this.el=t;var e=this.el.getElementsByTagName("div");this.title=e[0],this.description=e[1],this.model.on("change:logoWidth",this.update,this),this.model.change("playlistItem",this.playlistItem,this)},update:function(t){var e={},i=t.get("logo");if(i){var n=1*(""+i.margin).replace("px",""),o=t.get("logoWidth")+(isNaN(n)?0:n+10);"top-left"===i.position?e.paddingLeft=o:"top-right"===i.position&&(e.paddingRight=o)}Object(Tt.d)(this.el,e)},playlistItem:function(t,e){if(e)if(t.get("displaytitle")||t.get("displaydescription")){var i="",n="";e.title&&t.get("displaytitle")&&(i=e.title),e.description&&t.get("displaydescription")&&(n=e.description),this.updateText(i,n)}else this.hide()},updateText:function(t,e){Object(Ct.q)(this.title,t),Object(Ct.q)(this.description,e),this.title.firstChild||this.description.firstChild?this.show():this.hide()},element:function(){return this.el}});var Ht=Nt;function Ft(t,e){for(var i=0;it)}if(e.get("controls")){var r=jt(e);Object(Ct.v)(u,"jw-flag-audio-player",r),e.set("audioMode",r)}}function z(){e.set("visibility",mt(e,u))}this.updateBounds=function(){Object(kt.a)(k);var t=e.get("isFloating")?p:u,i=document.body.contains(t),n=Object(Ct.c)(t),r=Math.round(n.width),s=Math.round(n.height);if(S=Object(Ct.c)(u),r===o&&s===a)return o&&a||A(),void e.set("inDom",i);r&&s||o&&a||A(),(r||s||i)&&(e.set("containerWidth",r),e.set("containerHeight",s)),e.set("inDom",i),i&&bt.a.observe(u)},this.updateStyles=function(){var t=e.get("containerWidth"),i=e.get("containerHeight");R(t,i),I&&I.resize(t,i),$(t,i),v.resize(),T&&F()},this.checkResized=function(){var t=e.get("containerWidth"),i=e.get("containerHeight"),n=e.get("isFloating");if(t!==o||i!==a){this.resizeListener||(this.resizeListener=new Ut.a(p,this,e)),o=t,a=i,l.trigger(d.hb,{width:t,height:i});var s=Object(xt.a)(t);E!==s&&(E=s,l.trigger(d.j,{breakpoint:E}))}n!==r&&(r=n,l.trigger(d.x,{floating:n}),z())},this.responsiveListener=A,this.setup=function(){j.setup(u.querySelector(".jw-preview")),b.setup(u.querySelector(".jw-title")),(i=new zt(e)).setup(),i.setContainer(p),i.on(d.A,J),v.setup(u.id,e.get("captions")),b.element().parentNode.insertBefore(v.element(),b.element()),O=function(t,e,i){var n=new Lt(e,i),o=e.get("controls");n.on({click:function(){l.trigger(d.p),I&&(ct()?I.settingsMenu.close():ut()?I.infoOverlay.close():t.playToggle({reason:"interaction"}))},tap:function(){l.trigger(d.p),ct()&&I.settingsMenu.close(),ut()&&I.infoOverlay.close();var i=e.get("state");if(o&&(i===d.mb||i===d.kb||e.get("instream")&&i===d.ob)&&t.playToggle({reason:"interaction"}),o&&i===d.ob){if(e.get("instream")||e.get("castActive")||"audio"===e.get("mediaType"))return;Object(Ct.v)(u,"jw-flag-controls-hidden"),l.dismissible&&Object(Ct.v)(u,"jw-floating-dismissible",Object(Ct.i)(u,"jw-flag-controls-hidden")),v.renderCues(!0)}else I&&(I.showing?I.userInactive():I.userActive())},doubleClick:function(){return I&&t.setFullscreen()}}),Wt||(u.addEventListener("mousemove",W),u.addEventListener("mouseover",Q),u.addEventListener("mouseout",Y));return n}(t,e,w),_=new Et.a(u).on("click",(function(){})),C=St(u,document,et),e.on("change:hideAdsControls",(function(t,e){Object(Ct.v)(u,"jw-flag-ads-hide-controls",e)})),e.on("change:scrubbing",(function(t,e){Object(Ct.v)(u,"jw-flag-dragging",e)})),e.on("change:playRejected",(function(t,e){Object(Ct.v)(u,"jw-flag-play-rejected",e)})),e.on(d.X,tt),e.on("change:".concat(d.U),(function(){$(),v.resize()})),e.player.on("change:errorEvent",at),e.change("stretching",X);var n=e.get("width"),o=e.get("height"),a=G(n,o);Object(Tt.d)(u,a),e.change("aspectratio",K),R(n,o),e.get("controls")||(Object(Ct.a)(u,"jw-flag-controls-hidden"),Object(Ct.o)(u,"jw-floating-dismissible")),Qt&&Object(Ct.a)(u,"jw-ie");var r=e.get("skin")||{};r.name&&Object(Ct.p)(u,/jw-skin-\S+/,"jw-skin-"+r.name);var s=function(t){t||(t={});var e=t.active,i=t.inactive,n=t.background,o={};return o.controlbar=function(t){if(t||e||i||n){var o={};return t=t||{},o.iconsActive=t.iconsActive||e,o.icons=t.icons||i,o.text=t.text||i,o.background=t.background||n,o}}(t.controlbar),o.timeslider=function(t){if(t||e){var i={};return t=t||{},i.progress=t.progress||e,i.rail=t.rail,i}}(t.timeslider),o.menus=function(t){if(t||e||i||n){var o={};return t=t||{},o.text=t.text||i,o.textActive=t.textActive||e,o.background=t.background||n,o}}(t.menus),o.tooltips=function(t){if(t||i||n){var e={};return t=t||{},e.text=t.text||i,e.background=t.background||n,e}}(t.tooltips),o}(r);!function(t,e){var i;function n(e,i,n,o){if(n){e=Object(h.f)(e,"#"+t+(o?"":" "));var a={};a[i]=n,Object(Tt.b)(e.join(", "),a,t)}}e&&(e.controlbar&&function(e){n([".jw-controlbar .jw-icon-inline.jw-text",".jw-title-primary",".jw-title-secondary"],"color",e.text),e.icons&&(n([".jw-button-color:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:not(.jw-icon-cast)"],"color",e.icons),n([".jw-display-icon-container .jw-button-color"],"color",e.icons),Object(Tt.b)("#".concat(t," .jw-icon-cast google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(e.icons,"}"),t));e.iconsActive&&(n([".jw-display-icon-container .jw-button-color:hover",".jw-display-icon-container .jw-button-color:focus"],"color",e.iconsActive),n([".jw-button-color.jw-toggle:not(.jw-icon-cast)",".jw-button-color:hover:not(.jw-icon-cast)",".jw-button-color:focus:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:hover:not(.jw-icon-cast)"],"color",e.iconsActive),n([".jw-svg-icon-buffer"],"fill",e.icons),Object(Tt.b)("#".concat(t," .jw-icon-cast:hover google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(e.iconsActive,"}"),t),Object(Tt.b)("#".concat(t," .jw-icon-cast:focus google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(e.iconsActive,"}"),t),Object(Tt.b)("#".concat(t," .jw-icon-cast google-cast-launcher.jw-off:focus"),"{--disconnected-color: ".concat(e.iconsActive,"}"),t),Object(Tt.b)("#".concat(t," .jw-icon-cast google-cast-launcher"),"{--connected-color: ".concat(e.iconsActive,"}"),t),Object(Tt.b)("#".concat(t," .jw-icon-cast google-cast-launcher:focus"),"{--connected-color: ".concat(e.iconsActive,"}"),t),Object(Tt.b)("#".concat(t," .jw-icon-cast:hover google-cast-launcher"),"{--connected-color: ".concat(e.iconsActive,"}"),t),Object(Tt.b)("#".concat(t," .jw-icon-cast:focus google-cast-launcher"),"{--connected-color: ".concat(e.iconsActive,"}"),t));n([" .jw-settings-topbar",":not(.jw-state-idle) .jw-controlbar",".jw-flag-audio-player .jw-controlbar"],"background",e.background,!0)}(e.controlbar),e.timeslider&&function(t){var e=t.progress;"none"!==e&&(n([".jw-progress",".jw-knob"],"background-color",e),n([".jw-buffer"],"background-color",Object(Tt.c)(e,50)));n([".jw-rail"],"background-color",t.rail),n([".jw-background-color.jw-slider-time",".jw-slider-time .jw-cue"],"background-color",t.background)}(e.timeslider),e.menus&&(n([".jw-option",".jw-toggle.jw-off",".jw-skip .jw-skip-icon",".jw-nextup-tooltip",".jw-nextup-close",".jw-settings-content-item",".jw-related-title"],"color",(i=e.menus).text),n([".jw-option.jw-active-option",".jw-option:not(.jw-active-option):hover",".jw-option:not(.jw-active-option):focus",".jw-settings-content-item:hover",".jw-nextup-tooltip:hover",".jw-nextup-tooltip:focus",".jw-nextup-close:hover"],"color",i.textActive),n([".jw-nextup",".jw-settings-menu"],"background",i.background)),e.tooltips&&function(t){n([".jw-skip",".jw-tooltip .jw-text",".jw-time-tip .jw-text"],"background-color",t.background),n([".jw-time-tip",".jw-tooltip"],"color",t.background),n([".jw-skip"],"border","none"),n([".jw-skip .jw-text",".jw-skip .jw-icon",".jw-time-tip .jw-text",".jw-tooltip .jw-text"],"color",t.text)}(e.tooltips),e.menus&&function(e){if(e.textActive){var i={color:e.textActive,borderColor:e.textActive,stroke:e.textActive};Object(Tt.b)("#".concat(t," .jw-color-active"),i,t),Object(Tt.b)("#".concat(t," .jw-color-active-hover:hover"),i,t)}if(e.text){var n={color:e.text,borderColor:e.text,stroke:e.text};Object(Tt.b)("#".concat(t," .jw-color-inactive"),n,t),Object(Tt.b)("#".concat(t," .jw-color-inactive-hover:hover"),n,t)}}(e.menus))}(e.get("id"),s),e.set("mediaContainer",w),e.set("iFrame",m.Features.iframe),e.set("activeTab",Object(yt.a)()),e.set("touchMode",Wt&&("string"==typeof o||o>=gt)),bt.a.add(this),e.get("enableGradient")&&!Qt&&Object(Ct.a)(u,"jw-ab-drop-shadow"),this.isSetup=!0,e.trigger("viewSetup",u);var c=document.body.contains(u);c&&bt.a.observe(u),e.set("inDom",c)},this.init=function(){this.updateBounds(),e.on("change:fullscreen",Z),e.on("change:activeTab",z),e.on("change:fullscreen",z),e.on("change:intersectionRatio",z),e.on("change:visibility",U),e.on("instreamMode",(function(t){t?dt():pt()})),z(),1!==bt.a.size()||e.get("visibility")||U(e,1,0);var t=e.player;e.change("state",rt),t.change("controls",D),e.change("streamType",nt),e.change("mediaType",ot),t.change("playlistItem",(function(t,e){lt(t,e)})),o=a=null,T&&Wt&&bt.a.addScrollHandler(F),this.checkResized()};var B,V=62,N=!0;function H(){var t=e.get("isFloating"),i=S.top0&&void 0!==arguments[0])||arguments[0],e={x:0,y:0,width:o||0,height:a||0};return I&&t&&(e.height-=I.controlbarHeight()),e},this.setCaptions=function(t){v.clear(),v.setup(e.get("id"),t),v.resize()},this.setIntersection=function(t){var i=Math.round(100*t.intersectionRatio)/100;e.set("intersectionRatio",i),T&&!L()&&(M=M||i>=.5)&&ht(i)},this.stopFloating=function(t,i){if(t&&(T=null,bt.a.removeScrollHandler(F)),Yt===u){Yt=null,e.set("isFloating",!1);var n=function(){Object(Ct.o)(u,"jw-flag-floating"),K(e,e.get("aspectratio")),Object(Tt.d)(u,{backgroundImage:null}),Object(Tt.d)(p,{maxWidth:null,width:null,height:null,left:null,right:null,top:null,bottom:null,margin:null,transform:null,transition:null,"transition-timing-function":null})};i?(Object(Tt.d)(p,{transform:"translateY(-".concat(V-S.top,"px)"),"transition-timing-function":"ease-out"}),setTimeout(n,150)):n(),g.disable(),A()}},this.destroy=function(){e.destroy(),bt.a.unobserve(u),bt.a.remove(this),this.isSetup=!1,this.off(),Object(kt.a)(k),clearTimeout(y),Yt===u&&(Yt=null),_&&(_.destroy(),_=null),C&&(C.destroy(),C=null),I&&I.disable(e),O&&(O.destroy(),u.removeEventListener("mousemove",W),u.removeEventListener("mouseout",Y),u.removeEventListener("mouseover",Q),O=null),v.destroy(),i&&(i.destroy(),i=null),Object(Tt.a)(e.get("id")),this.resizeListener&&(this.resizeListener.destroy(),delete this.resizeListener),T&&Wt&&bt.a.removeScrollHandler(F)}};function Kt(t,e,i){return(Kt="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,i){var n=function(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=ee(t)););return t}(t,e);if(n){var o=Object.getOwnPropertyDescriptor(n,e);return o.get?o.get.call(i):o.value}})(t,e,i||t)}function Jt(t){return(Jt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function Zt(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Gt(t,e){for(var i=0;ie&&t(),e=n}};function Oe(t,e){e.off(d.N,t._onPlayAttempt),e.off(d.fb,t._triggerFirstFrame),e.off(d.S,t._onTime),t.off("change:activeTab",t._onTabVisible)}var Ce=function(t,e){t.change("mediaModel",(function(t,i,n){t._qoeItem&&n&&t._qoeItem.end(n.get("mediaState")),t._qoeItem=new ye.a,t._qoeItem.getFirstFrame=function(){var t=this.between(d.N,d.H),e=this.between(xe,d.H);return e>0&&e0&&rt(e,t.tracks)}),O).on(d.F,(function(){Promise.resolve().then(at)}),O).on(d.G,O.triggerError,O),Ce(C,B),C.on(d.w,O.triggerError,O),C.on("change:state",(function(t,e,i){X()||K.call(T,t,e,i)}),this),C.on("change:castState",(function(t,e){O.trigger(d.m,e)})),C.on("change:fullscreen",(function(t,e){O.trigger(d.y,{fullscreen:e}),e&&t.set("playOnViewable",!1)})),C.on("change:volume",(function(t,e){O.trigger(d.V,{volume:e})})),C.on("change:mute",(function(t){O.trigger(d.M,{mute:t.getMute()})})),C.on("change:playbackRate",(function(t,e){O.trigger(d.ab,{playbackRate:e,position:t.get("position")})}));var V=function t(e,i){"clickthrough"!==i&&"interaction"!==i&&"external"!==i||(C.set("playOnViewable",!1),C.off("change:playReason change:pauseReason",t))};function N(t,e){Object(n.t)(e)||C.set("viewable",Math.round(e))}function H(){dt&&(!0!==C.get("autostart")||C.get("playOnViewable")||$("autostart"),dt.flush())}function F(t,e){O.trigger("viewable",{viewable:e}),D()}function D(){if((o.a[0]===e||1===C.get("viewable"))&&"idle"===C.get("state")&&!1===C.get("autostart"))if(!b.primed()&&m.OS.android){var t=b.getTestElement(),i=O.getMute();Promise.resolve().then((function(){return fe(t,{muted:i})})).then((function(){"idle"===C.get("state")&&B.preloadVideo()})).catch(Se)}else B.preloadVideo()}function q(t){O._instreamAdapter.noResume=!t,t||et({reason:"viewable"})}function U(t){t||(O.pause({reason:"viewable"}),C.set("playOnViewable",!t))}function W(t,e){var i=X();if(t.get("playOnViewable")){if(e){var n=t.get("autoPause").pauseAds,o=t.get("pauseReason");J()===d.mb?$("viewable"):i&&!n||"interaction"===o||Z({reason:"viewable"})}else m.OS.mobile&&!i&&(O.pause({reason:"autostart"}),C.set("playOnViewable",!0));m.OS.mobile&&i&&q(e)}}function Q(t,e){var i=t.get("state"),n=X(),o=t.get("playReason");n?t.get("autoPause").pauseAds?U(e):q(e):i===d.pb||i===d.jb?U(e):i===d.mb&&"playlist"===o&&t.once("change:state",(function(){U(e)}))}function X(){var t=O._instreamAdapter;return!!t&&t.getState()}function J(){var t=X();return t||C.get("state")}function Z(t){if(E.cancel(),M=!1,C.get("state")===d.lb)return Promise.resolve();var i=G(t);return C.set("playReason",i),X()?(e.pauseAd(!1,t),Promise.resolve()):(C.get("state")===d.kb&&(tt(!0),O.setItemIndex(0)),!_&&(_=!0,O.trigger(d.C,{playReason:i,startTime:t&&t.startTime?t.startTime:C.get("playlistItem").starttime}),_=!1,ve()&&!b.primed()&&b.prime(),"playlist"===i&&C.get("autoPause").viewability&&Q(C,C.get("viewable")),x)?(ve()&&!R&&C.get("mediaElement").load(),x=!1,k=null,Promise.resolve()):B.playVideo(i).then(b.played))}function G(t){return t&&t.reason?t.reason:"unknown"}function $(t){if(J()===d.mb){E=g(H);var e=C.get("advertising");(function(t,e){var i=e.cancelable,n=e.muted,o=void 0!==n&&n,a=e.allowMuted,r=void 0!==a&&a,s=e.timeout,l=void 0===s?1e4:s,c=t.getTestElement(),u=o?"muted":"".concat(r);be[u]||(be[u]=fe(c,{muted:o}).catch((function(t){if(!i.cancelled()&&!1===o&&r)return fe(c,{muted:o=!0});throw t})).then((function(){return o?(be[u]=null,ge):we})).catch((function(t){throw clearTimeout(d),be[u]=null,t.reason=je,t})));var d,p=be[u].then((function(t){if(clearTimeout(d),i.cancelled()){var e=new Error("Autoplay test was cancelled");throw e.reason="cancelled",e}return t})),h=new Promise((function(t,e){d=setTimeout((function(){be[u]=null;var t=new Error("Autoplay test timed out");t.reason="timeout",e(t)}),l)}));return Promise.race([p,h])})(b,{cancelable:E,muted:O.getMute(),allowMuted:!e||e.autoplayadsmuted}).then((function(e){return C.set("canAutoplay",e),e!==ge||O.getMute()||(C.set("autostartMuted",!0),ut(),C.once("change:autostartMuted",(function(t){t.off("change:viewable",W),O.trigger(d.M,{mute:C.getMute()})}))),O.getMute()&&C.get("enableDefaultCaptions")&&y.selectDefaultIndex(1),Z({reason:t}).catch((function(){O._instreamAdapter||C.set("autostartFailed",!0),k=null}))})).catch((function(t){if(C.set("canAutoplay",je),C.set("autostart",!1),!E.cancelled()){var e=Object(j.w)(t);O.trigger(d.h,{reason:t.reason,code:e,error:t})}}))}}function tt(t){if(E.cancel(),dt.empty(),X()){var e=O._instreamAdapter;return e&&(e.noResume=!0),void(k=function(){return B.stopVideo()})}k=null,!t&&(M=!0),_&&(x=!0),C.set("errorEvent",void 0),B.stopVideo()}function et(t){var e=G(t);C.set("pauseReason",e),C.set("playOnViewable","viewable"===e)}function it(t){k=null,E.cancel();var i=X();if(i&&i!==d.ob)return et(t),void e.pauseAd(!0,t);switch(C.get("state")){case d.lb:return;case d.pb:case d.jb:et(t),B.pause();break;default:_&&(x=!0)}}function nt(t,e){tt(!0),O.setItemIndex(t),O.play(e)}function ot(t){nt(C.get("item")+1,t)}function at(){O.completeCancelled()||(k=O.completeHandler,O.shouldAutoAdvance()?O.nextItem():C.get("repeat")?ot({reason:"repeat"}):(m.OS.iOS&<(!1),C.set("playOnViewable",!1),C.set("state",d.kb),O.trigger(d.cb,{})))}function rt(t,e){t=parseInt(t,10)||0,C.persistVideoSubtitleTrack(t,e),B.subtitles=t,O.trigger(d.k,{tracks:st(),track:t})}function st(){return y.getCaptionsList()}function lt(t){Object(n.n)(t)||(t=!C.get("fullscreen")),C.set("fullscreen",t),O._instreamAdapter&&O._instreamAdapter._adModel&&O._instreamAdapter._adModel.set("fullscreen",t)}function ut(){B.mute=C.getMute(),B.volume=C.get("volume")}C.on("change:playReason change:pauseReason",V),O.on(d.c,(function(t){return V(0,t.playReason)})),O.on(d.b,(function(t){return V(0,t.pauseReason)})),C.on("change:scrubbing",(function(t,e){e?(S=C.get("state")!==d.ob,it()):S&&Z({reason:"interaction"})})),C.on("change:captionsList",(function(t,e){O.trigger(d.l,{tracks:e,track:C.get("captionsIndex")||0})})),C.on("change:mediaModel",(function(t,e){var i=this;t.set("errorEvent",void 0),e.change("mediaState",(function(e,i){var n;t.get("errorEvent")||t.set(d.bb,(n=i)===d.nb||n===d.qb?d.jb:n)}),this),e.change("duration",(function(e,i){if(0!==i){var n=t.get("minDvrWindow"),o=Object(me.b)(i,n);t.setStreamType(o)}}),this);var n=t.get("item")+1,o="autoplay"===(t.get("related")||{}).oncomplete,a=t.get("playlist")[n];if((a||o)&&R){e.on("change:position",(function t(n,r){var s=a&&!a.daiSetting,l=e.get("duration");s&&r&&l>0&&r>=l-p.b?(e.off("change:position",t,i),B.backgroundLoad(a)):o&&(a=C.get("nextUp"))}),this)}})),(y=new ht(C)).on("all",P,O),z.on("viewSetup",(function(t){Object(a.b)(T,t)})),this.playerReady=function(){v.once(d.hb,(function(){try{!function(){C.change("visibility",N),L.off(),O.trigger(d.gb,{setupTime:0}),C.change("playlist",(function(t,e){if(e.length){var i={playlist:e},o=C.get("feedData");o&&(i.feedData=Object(n.g)({},o)),O.trigger(d.eb,i)}})),C.change("playlistItem",(function(t,e){if(e){var i=e.title,n=e.image;if("mediaSession"in navigator&&window.MediaMetadata&&(i||n))try{navigator.mediaSession.metadata=new window.MediaMetadata({title:i,artist:window.location.hostname,artwork:[{src:n||""}]})}catch(t){}t.set("cues",[]),O.trigger(d.db,{index:C.get("item"),item:e})}})),L.flush(),L.destroy(),L=null,C.change("viewable",F),C.change("viewable",W),C.get("autoPause").viewability?C.change("viewable",Q):C.once("change:autostartFailed change:mute",(function(t){t.off("change:viewable",W)}));H(),C.on("change:itemReady",(function(t,e){e&&dt.flush()}))}()}catch(t){O.triggerError(Object(j.v)(j.m,j.a,t))}})),v.init()},this.preload=D,this.load=function(t,e){var i,n=O._instreamAdapter;switch(n&&(n.noResume=!0),O.trigger("destroyPlugin",{}),tt(!0),E.cancel(),E=g(H),I.cancel(),ve()&&b.prime(),_e(t)){case"string":C.attributes.item=0,C.attributes.itemReady=!1,I=g((function(t){if(t)return O.updatePlaylist(Object(c.a)(t.playlist),t)})),i=function(t){var e=this;return new Promise((function(i,n){var o=new l.a;o.on(d.eb,(function(t){i(t)})),o.on(d.w,n,e),o.load(t)}))}(t).then(I.async);break;case"object":C.attributes.item=0,i=O.updatePlaylist(Object(c.a)(t),e||{});break;case"number":i=O.setItemIndex(t);break;default:return}i.catch((function(t){O.triggerError(Object(j.u)(t,j.c))})),i.then(E.async).catch(Se)},this.play=function(t){return Z(t).catch(Se)},this.pause=it,this.seek=function(t,e){var i=C.get("state");if(i!==d.lb){B.position=t;var n=i===d.mb;C.get("scrubbing")||!n&&i!==d.kb||(n&&((e=e||{}).startTime=t),this.play(e))}},this.stop=tt,this.playlistItem=nt,this.playlistNext=ot,this.playlistPrev=function(t){nt(C.get("item")-1,t)},this.setCurrentCaptions=rt,this.setCurrentQuality=function(t){B.quality=t},this.setFullscreen=lt,this.getCurrentQuality=function(){return B.quality},this.getQualityLevels=function(){return B.qualities},this.setCurrentAudioTrack=function(t){B.audioTrack=t},this.getCurrentAudioTrack=function(){return B.audioTrack},this.getAudioTracks=function(){return B.audioTracks},this.getCurrentCaptions=function(){return y.getCurrentIndex()},this.getCaptionsList=st,this.getVisualQuality=function(){var t=this._model.get("mediaModel");return t?t.get(d.U):null},this.getConfig=function(){return this._model?this._model.getConfiguration():void 0},this.getState=J,this.next=Se,this.completeHandler=at,this.completeCancelled=function(){return(t=C.get("state"))!==d.mb&&t!==d.kb&&t!==d.lb||!!M&&(M=!1,!0);var t},this.shouldAutoAdvance=function(){return C.get("item")!==C.get("playlist").length-1},this.nextItem=function(){ot({reason:"playlist"})},this.setConfig=function(t){!function(t,e){var i=t._model,n=i.attributes;e.height&&(e.height=Object(r.b)(e.height),e.width=e.width||n.width),e.width&&(e.width=Object(r.b)(e.width),e.aspectratio?(n.width=e.width,delete e.width):e.height=n.height),e.width&&e.height&&!e.aspectratio&&t._view.resize(e.width,e.height),Object.keys(e).forEach((function(o){var a=e[o];if(void 0!==a)switch(o){case"aspectratio":i.set(o,Object(r.a)(a,n.width));break;case"autostart":!function(t,e,i){t.setAutoStart(i),"idle"===t.get("state")&&!0===i&&e.play({reason:"autostart"})}(i,t,a);break;case"mute":t.setMute(a);break;case"volume":t.setVolume(a);break;case"playbackRateControls":case"playbackRates":case"repeat":case"stretching":i.set(o,a)}}))}(O,t)},this.setItemIndex=function(t){B.stopVideo();var e=C.get("playlist").length;return(t=(parseInt(t,10)||0)%e)<0&&(t+=e),B.setActiveItem(t).catch((function(t){t.code>=151&&t.code<=162&&(t=Object(j.u)(t,j.e)),T.triggerError(Object(j.v)(j.k,j.d,t))}))},this.detachMedia=function(){if(_&&(x=!0),C.get("autoPause").viewability&&Q(C,C.get("viewable")),!R)return B.setAttached(!1);B.backgroundActiveMedia()},this.attachMedia=function(){R?B.restoreBackgroundMedia():B.setAttached(!0),"function"==typeof k&&k()},this.routeEvents=function(t){return B.routeEvents(t)},this.forwardEvents=function(){return B.forwardEvents()},this.playVideo=function(t){return B.playVideo(t)},this.stopVideo=function(){return B.stopVideo()},this.castVideo=function(t,e){return B.castVideo(t,e)},this.stopCast=function(){return B.stopCast()},this.backgroundActiveMedia=function(){return B.backgroundActiveMedia()},this.restoreBackgroundMedia=function(){return B.restoreBackgroundMedia()},this.preloadNextItem=function(){B.background.currentMedia&&B.preloadVideo()},this.isBeforeComplete=function(){return B.beforeComplete},this.setVolume=function(t){C.setVolume(t),ut()},this.setMute=function(t){C.setMute(t),ut()},this.setPlaybackRate=function(t){C.setPlaybackRate(t)},this.getProvider=function(){return C.get("provider")},this.getWidth=function(){return C.get("containerWidth")},this.getHeight=function(){return C.get("containerHeight")},this.getItemQoe=function(){return C._qoeItem},this.addButton=function(t,e,i,n,o){var a=C.get("customButtons")||[],r=!1,s={img:t,tooltip:e,callback:i,id:n,btnClass:o};a=a.reduce((function(t,e){return e.id===n?(r=!0,t.push(s)):t.push(e),t}),[]),r||a.unshift(s),C.set("customButtons",a)},this.removeButton=function(t){var e=C.get("customButtons")||[];e=e.filter((function(e){return e.id!==t})),C.set("customButtons",e)},this.resize=v.resize,this.getSafeRegion=v.getSafeRegion,this.setCaptions=v.setCaptions,this.checkBeforePlay=function(){return _},this.setControls=function(t){Object(n.n)(t)||(t=!C.get("controls")),C.set("controls",t),B.controls=t},this.addCues=function(t){this.setCues(C.get("cues").concat(t))},this.setCues=function(t){C.set("cues",t)},this.updatePlaylist=function(t,e){try{var i=Object(c.b)(t,C,e);Object(c.e)(i);var o=Object(n.g)({},e);delete o.playlist,C.set("feedData",o),C.set("playlist",i)}catch(t){return Promise.reject(t)}return this.setItemIndex(C.get("item"))},this.setPlaylistItem=function(t,e){(e=Object(c.d)(C,new u.a(e),e.feedData||{}))&&(C.get("playlist")[t]=e,t===C.get("item")&&"idle"===C.get("state")&&this.setItemIndex(t))},this.playerDestroy=function(){this.off(),this.stop(),Object(a.b)(this,this.originalContainer),v&&v.destroy(),C&&C.destroy(),dt&&dt.destroy(),y&&y.destroy(),B&&B.destroy(),this.instreamDestroy()},this.isBeforePlay=this.checkBeforePlay,this.createInstream=function(){return this.instreamDestroy(),this._instreamAdapter=new ct(this,C,v,b),this._instreamAdapter},this.instreamDestroy=function(){O._instreamAdapter&&(O._instreamAdapter.destroy(),O._instreamAdapter=null)};var dt=new s.a(this,["play","pause","setCurrentAudioTrack","setCurrentCaptions","setCurrentQuality","setFullscreen"],(function(){return!T._model.get("itemReady")||L}));dt.queue.push.apply(dt.queue,w),v.setup()},get:function(t){if(t in y.a){var e=this._model.get("mediaModel");return e?e.get(t):y.a[t]}return this._model.get(t)},getContainer:function(){return this.currentContainer||this.originalContainer},getMute:function(){return this._model.getMute()},triggerError:function(t){var e=this._model;t.message=e.get("localization").errors[t.key],delete t.key,e.set("errorEvent",t),e.set("state",d.lb),e.once("change:state",(function(){this.set("errorEvent",void 0)}),e),this.trigger(d.w,t)}});e.default=Me},,,,,,,,,,,,function(t,e){!function(t,e){"use strict";if("IntersectionObserver"in t&&"IntersectionObserverEntry"in t&&"intersectionRatio"in t.IntersectionObserverEntry.prototype)"isIntersecting"in t.IntersectionObserverEntry.prototype||Object.defineProperty(t.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}});else{var i=[];o.prototype.THROTTLE_TIMEOUT=100,o.prototype.POLL_INTERVAL=null,o.prototype.USE_MUTATION_OBSERVER=!0,o.prototype.observe=function(t){if(!this._observationTargets.some((function(e){return e.element==t}))){if(!t||1!=t.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:t,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},o.prototype.unobserve=function(t){this._observationTargets=this._observationTargets.filter((function(e){return e.element!=t})),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},o.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},o.prototype.takeRecords=function(){var t=this._queuedEntries.slice();return this._queuedEntries=[],t},o.prototype._initThresholds=function(t){var e=t||[0];return Array.isArray(e)||(e=[e]),e.sort().filter((function(t,e,i){if("number"!=typeof t||isNaN(t)||t<0||t>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return t!==i[e-1]}))},o.prototype._parseRootMargin=function(t){var e=(t||"0px").split(/\s+/).map((function(t){var e=/^(-?\d*\.?\d+)(px|%)$/.exec(t);if(!e)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(e[1]),unit:e[2]}}));return e[1]=e[1]||e[0],e[2]=e[2]||e[0],e[3]=e[3]||e[1],e},o.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(a(t,"resize",this._checkForIntersections,!0),a(e,"scroll",this._checkForIntersections,!0),this.USE_MUTATION_OBSERVER&&"MutationObserver"in t&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(e,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},o.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,r(t,"resize",this._checkForIntersections,!0),r(e,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},o.prototype._checkForIntersections=function(){var e=this._rootIsInDom(),i=e?this._getRootRect():{top:0,bottom:0,left:0,right:0,width:0,height:0};this._observationTargets.forEach((function(o){var a=o.element,r=s(a),l=this._rootContainsTarget(a),c=o.entry,u=e&&l&&this._computeTargetAndRootIntersection(a,i),d=o.entry=new n({time:t.performance&&performance.now&&performance.now(),target:a,boundingClientRect:r,rootBounds:i,intersectionRect:u});c?e&&l?this._hasCrossedThreshold(c,d)&&this._queuedEntries.push(d):c&&c.isIntersecting&&this._queuedEntries.push(d):this._queuedEntries.push(d)}),this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},o.prototype._computeTargetAndRootIntersection=function(i,n){if("none"!=t.getComputedStyle(i).display){for(var o,a,r,l,u,d,p,h,f=s(i),w=c(i),g=!1;!g;){var j=null,b=1==w.nodeType?t.getComputedStyle(w):{};if("none"==b.display)return;if(w==this.root||w==e?(g=!0,j=n):w!=e.body&&w!=e.documentElement&&"visible"!=b.overflow&&(j=s(w)),j&&(o=j,a=f,r=void 0,l=void 0,u=void 0,d=void 0,p=void 0,h=void 0,r=Math.max(o.top,a.top),l=Math.min(o.bottom,a.bottom),u=Math.max(o.left,a.left),d=Math.min(o.right,a.right),h=l-r,!(f=(p=d-u)>=0&&h>=0&&{top:r,bottom:l,left:u,right:d,width:p,height:h})))break;w=c(w)}return f}},o.prototype._getRootRect=function(){var t;if(this.root)t=s(this.root);else{var i=e.documentElement,n=e.body;t={top:0,left:0,right:i.clientWidth||n.clientWidth,width:i.clientWidth||n.clientWidth,bottom:i.clientHeight||n.clientHeight,height:i.clientHeight||n.clientHeight}}return this._expandRectByRootMargin(t)},o.prototype._expandRectByRootMargin=function(t){var e=this._rootMarginValues.map((function(e,i){return"px"==e.unit?e.value:e.value*(i%2?t.width:t.height)/100})),i={top:t.top-e[0],right:t.right+e[1],bottom:t.bottom+e[2],left:t.left-e[3]};return i.width=i.right-i.left,i.height=i.bottom-i.top,i},o.prototype._hasCrossedThreshold=function(t,e){var i=t&&t.isIntersecting?t.intersectionRatio||0:-1,n=e.isIntersecting?e.intersectionRatio||0:-1;if(i!==n)for(var o=0;o=0&&(n.metadata.mpegts=o+e)}var a=this.getLiveLatency();null!==a&&(n.latency=a),(this.state===r.pb||this.seeking)&&this.trigger(r.S,n)}},click:function(t){this.trigger(r.n,t)},volumechange:function(){var t=this.video;this.trigger(r.V,{volume:Math.round(100*t.volume)}),this.trigger(r.M,{mute:t.muted})},seeked:function(){this.seeking&&(this.seeking=!1,this.trigger(r.R))},playing:function(){-1===this.stallTime&&this.setState(r.pb),this.trigger(r.fb)},pause:function(){this.state!==r.kb&&(this.video.ended||this.video.error||this.getVideoCurrentTime()!==this.getDuration()&&this.setState(r.ob))},progress:function(){var t=this.getDuration();if(!(t<=0||t===1/0)){var e=this.video.buffered;if(e&&0!==e.length){var i=Object(s.a)(e.end(e.length-1)/t,0,1);this.trigger(r.D,{bufferPercent:100*i,position:this.getCurrentTime(),duration:t,currentTime:this.getVideoCurrentTime(),seekRange:this.getSeekRange()})}}},ratechange:function(){this.trigger(r.P,{playbackRate:this.video.playbackRate})},ended:function(){this.videoHeight=0,this.streamBitrate=-1,this.state!==r.mb&&this.state!==r.kb&&this.trigger(r.F)},loadeddata:function(){this.renderNatively&&this.setTextTracks(this.video.textTracks)}},c=i(10);function u(t){return t&&t.length?t.end(t.length-1):0}var d={container:null,volume:function(t){this.video.volume=Math.min(Math.max(0,t/100),1)},mute:function(t){this.video.muted=!!t,this.video.muted||this.video.removeAttribute("muted")},resize:function(t,e,i){var n=this.video,a=n.videoWidth,r=n.videoHeight;if(t&&e&&a&&r){var s={objectFit:"",width:"",height:""};if("uniform"===i){var l=t/e,u=a/r,d=Math.abs(l-u);d<.09&&d>.0025&&(s.objectFit="fill",i="exactfit")}if(o.Browser.ie||o.OS.iOS&&o.OS.version.major<9||o.Browser.androidNative)if("uniform"!==i){s.objectFit="contain";var p=t/e,h=a/r,f=1,w=1;"none"===i?f=w=p>h?Math.ceil(100*r/e)/100:Math.ceil(100*a/t)/100:"fill"===i?f=w=p>h?p/h:h/p:"exactfit"===i&&(p>h?(f=p/h,w=1):(f=1,w=h/p)),Object(c.e)(n,"matrix(".concat(f.toFixed(2),", 0, 0, ").concat(w.toFixed(2),", 0, 0)"))}else s.top=s.left=s.margin="",Object(c.e)(n,"");Object(c.d)(n,s)}},getContainer:function(){return this.container},setContainer:function(t){this.container=t,this.video.parentNode!==t&&t.appendChild(this.video)},remove:function(){this.stop(),this.destroy();var t=this.container;t&&t===this.video.parentNode&&t.removeChild(this.video)},atEdgeOfLiveStream:function(){if(!this.isLive())return!1;return u(this.video.buffered)-this.video.currentTime<=2}},p={eventsOn_:function(){},eventsOff_:function(){},attachMedia:function(){this.eventsOn_()},detachMedia:function(){return this.eventsOff_()}},h=i(65),f=i(5),w=i(53),g=i(7),j=i(66),b=i(63),m={TIT2:"title",TT2:"title",WXXX:"url",TPE1:"artist",TP1:"artist",TALB:"album",TAL:"album"};function v(t,e){for(var i,n,o,a=t.length,r="",s=e||0;s>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:r+=String.fromCharCode(i);break;case 12:case 13:n=t[s++],r+=String.fromCharCode((31&i)<<6|63&n);break;case 14:n=t[s++],o=t[s++],r+=String.fromCharCode((15&i)<<12|(63&n)<<6|(63&o)<<0)}return r}function y(t){var e=function(t){for(var e="0x",i=0;i>1|(8323072&e)>>2|(2130706432&e)>>3}function k(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:[]).reduce((function(t,e){if(!("value"in e)&&"data"in e&&e.data instanceof ArrayBuffer){var i=new Uint8Array(e.data),n=i.length;e={value:{key:"",data:""}};for(var o=10;o<14&&o0){var c=v(i.subarray(a,a+=s),0);if("PRIV"===e.value.key){if("com.apple.streaming.transportStreamTimestamp"===c){var u=1&y(i.subarray(a,a+=4)),d=y(i.subarray(a,a+=4))+(u?4294967296:0);e.value.data=d}else e.value.data=v(i,a+1);e.value.info=c}else e.value.info=c,e.value.data=v(i,a+1)}else{var p=i[a];e.value.data=1===p||2===p?function(t,e){for(var i=t.length-1,n="",o=e||0;o=0&&o[a].startTime>e.startTime;a--)i.unshift(o[a]),t.removeCue(o[a]);try{t.addCue(e),i.forEach((function(e){return t.addCue(e)}))}catch(t){console.error(t)}t.mode=n}(e,n)}else try{e.addCue(i)}catch(t){console.error(t)}}function M(t,e){e&&e.length&&Object(n.f)(e,(function(e){if(!(o.Browser.ie&&t&&/^(native|subtitle|cc)/.test(e._id))){o.Browser.ie&&"disabled"===e.mode||(e.mode="disabled",e.mode="hidden");for(var i=e.cues.length;i--;)e.removeCue(e.cues[i]);e.embedded||(e.mode="disabled"),e.inuse=!1}}))}function S(t){return"subtitles"===t||"captions"===t}function E(t){var e,i=Object(b.b)(t,this._unknownCount),o=i.label;if(this._unknownCount=i.unknownCount,this.renderNatively||"metadata"===t.kind){var a=this.video.textTracks;(e=Object(n.j)(a,{label:o}))||(e=this.video.addTextTrack(t.kind,o,t.language||"")),e.default=t.default,e.mode="disabled",e.inuse=!0}else(e=t).data=e.data||[];return e._id||(e._id=Object(b.a)(t,this._textTracks.length)),e}function I(t){this._textTracks.push(t),this._tracksById[t._id]=t}function L(){if(this._textTracks){var t=this._textTracks.filter((function(t){return t.embedded||"subs"===t.groupid}));this._initTextTracks(),t.forEach((function(t){this._tracksById[t._id]=t})),this._textTracks=t}}function A(t){this.triggerActiveCues(t.currentTarget.activeCues)}function P(t,e,i){var n=t.kind;this._cachedVTTCues[t._id]||(this._cachedVTTCues[t._id]={});var o,a=this._cachedVTTCues[t._id];switch(n){case"captions":case"subtitles":o=i||Math.floor(20*e.startTime);var r="_"+e.line,s=Math.floor(20*e.endTime),l=a[o+r]||a[o+1+r]||a[o-1+r];return!(l&&Math.abs(l-s)<=1)&&(a[o+r]=s,!0);case"metadata":var c=e.data?new Uint8Array(e.data).join(""):e.text;return!a[o=i||e.startTime+c]&&(a[o]=e.endTime,!0);default:return!1}}function R(t){if(t.length>this._textTracks.length)return!0;for(var e=0;e=0&&(w.retries=0);var t=w.getVideoCurrentTime();w.currentTime=t,M&&C!==t&&$(t),l.timeupdate.call(w),ft(),o.Browser.ie&&G()},resize:G,ended:function(){_=-1,wt(),l.ended.call(w)},loadedmetadata:function(){var t=w.getDuration();R&&t===1/0&&(t=0);var e={metadataType:"media",duration:t,height:v.videoHeight,width:v.videoWidth,seekRange:w.getSeekRange()};w.trigger(r.K,e),G()},durationchange:function(){R||l.progress.call(w)},loadeddata:function(){var t;!function(){if(v.getStartDate){var t=v.getStartDate(),e=t.getTime?t.getTime():NaN;if(e!==w.startDateTime&&!isNaN(e)){w.startDateTime=e;var i=t.toISOString(),n=w.getSeekRange(),o=n.start,a=n.end,s={metadataType:"program-date-time",programDateTime:i,start:o,end:a},l=w.createCue(o,a,JSON.stringify(s));w.addVTTCue({type:"metadata",cue:l}),delete s.metadataType,w.trigger(r.L,{metadataType:"program-date-time",metadata:s})}}}(),l.loadeddata.call(w),function(t){if(E=null,!t)return;if(t.length){for(var e=0;e0&&(e=t.map((function(t,e){return{label:t.label||e}}))),e}function it(t){w.currentTime=-1,j=t.minDvrWindow,m=t.sources,_=function(t){var i=Math.max(0,_),n=e.qualityLabel;if(t)for(var o=0;o0&&(T=-1,w.seek(t)),t>0&&w.getVideoCurrentTime()!==t&&w.seek(t);var n=et(m);n&&w.trigger(r.I,{levels:n,currentQuality:_}),m.length&&"hls"!==m[0].type&&ht()}function at(t){E=null,I=-1,y.reason||(y.reason="initial choice",y.level={}),x=!1;var e=document.createElement("source");e.src=t.file,v.src!==e.src&&(v.src=t.file)}function rt(){v&&(w.disableTextTrack(),v.removeAttribute("preload"),v.removeAttribute("src"),Object(f.h)(v),Object(c.d)(v,{objectFit:""}),_=-1,!o.Browser.msie&&"load"in v&&v.load())}function st(){var t=1/0;return["buffered","seekable"].forEach((function(e){for(var i=v[e],o=i?i.length:0;o--;){var a=Math.min(t,i.start(o));Object(n.o)(a)&&(t=a)}})),t}function lt(){var t=0;return["buffered","seekable"].forEach((function(e){for(var i=v[e],o=i?i.length:0;o--;){var a=Math.max(t,i.end(o));Object(n.o)(a)&&(t=a)}})),t}function ct(){for(var t=-1,e=0;e-1&&t1)&&function(t){X=t.end,J=Math.min(0,w.getVideoCurrentTime()-X),Z=Object(V.a)()}(e),Object(h.a)(e.end-e.start,j))return J}return t}(w.getVideoCurrentTime())},w.getDuration=function(){if(e.getDurationHook)return e.getDurationHook();var t=v.duration;if(R&&t===1/0&&0===w.getVideoCurrentTime()||isNaN(t))return 0;var i=lt();if(v.duration===1/0&&i){var n=i-st();Object(h.a)(n,j)&&(t=-n)}return t},w.getSeekRange=function(){var t={start:0,end:w.getDuration()};return v.seekable.length&&(t.end=lt(),t.start=st()),t},w.getLiveLatency=function(){var t=null,e=lt();return w.isLive()&&e&&(t=e+(Object(V.a)()-Z)/1e3-w.getVideoCurrentTime()),t},this.stop=function(){wt(),rt(),this.clearTracks(),o.Browser.ie&&v.pause(),this.setState(r.mb)},this.destroy=function(){S=Q,Y(b,v),this.removeTracksListener(v.audioTracks,"change",ct),this.removeTracksListener(v.textTracks,"change",w.textTrackChangeHandler),this.off()},this.init=function(t){w.retries=0,w.maxRetries=t.adType?0:3,it(t);var e=m[_];(R=Object(a.a)(e))&&(w.supportsPlaybackRate=!1,b.waiting=Q),w.eventsOn_(),m.length&&"hls"!==m[0].type&&this.sendMediaType(m),y.reason=""},this.preload=function(t){it(t);var e=m[_],i=e.preload||"metadata";"none"!==i&&(v.setAttribute("preload",i),at(e))},this.load=function(t){it(t),ot(t.starttime),this.setupSideloadedTracks(t.tracks)},this.play=function(){return S(),nt()},this.pause=function(){wt(),S=function(){if(v.paused&&w.getVideoCurrentTime()&&w.isLive()){var t=lt(),e=t-st(),i=!Object(h.a)(e,j),o=t-w.getVideoCurrentTime();if(i&&t&&(o>15||o<0)){if(O=Math.max(t-10,t-e),!Object(n.o)(O))return;$(w.getVideoCurrentTime()),v.currentTime=O}}},v.pause()},this.seek=function(t){if(e.seekHook)return e.seekHook(t,v);var i=w.getSeekRange(),n=t;if(t<0&&(n+=i.end),x||(x=!!lt()),x){T=0;try{if(w.seeking=!0,w.isLive()&&Object(h.a)(i.end-i.start,j))if(J=Math.min(0,n-X),t<0)n+=Math.min(12,(Object(V.a)()-Z)/1e3);O=n,$(w.getVideoCurrentTime()),v.currentTime=n}catch(t){w.seeking=!1,T=n}}else T=n,o.Browser.firefox&&v.paused&&nt()},this.setVisibility=function(t){(t=!!t)||o.OS.android?Object(c.d)(w.container,{visibility:"visible",opacity:1}):Object(c.d)(w.container,{visibility:"",opacity:0})},this.setFullscreen=function(t){if(t=!!t){try{var e=v.webkitEnterFullscreen||v.webkitEnterFullScreen;e&&e.apply(v)}catch(t){return!1}return w.getFullScreen()}var i=v.webkitExitFullscreen||v.webkitExitFullScreen;return i&&i.apply(v),t},w.getFullScreen=function(){return M||!!v.webkitDisplayingFullscreen},this.setCurrentQuality=function(t){_!==t&&t>=0&&m&&m.length>t&&(_=t,y.reason="api",y.level={},this.trigger(r.J,{currentQuality:t,levels:et(m)}),e.qualityLabel=m[t].label,ot(w.getVideoCurrentTime()||0),nt())},this.setPlaybackRate=function(t){v.playbackRate=v.defaultPlaybackRate=t},this.getPlaybackRate=function(){return v.playbackRate},this.getCurrentQuality=function(){return _},this.getQualityLevels=function(){return Array.isArray(m)?m.map((function(t){return function(t){return{bitrate:t.bitrate,label:t.label,width:t.width,height:t.height}}(t)})):[]},this.getName=function(){return{name:W}},this.setCurrentAudioTrack=dt,this.getAudioTracks=function(){return E||[]},this.getCurrentAudioTrack=function(){return I}}Object(n.g)(X.prototype,w.a),X.getName=function(){return{name:"html5"}};e.default=X;var K=220001},,,,,,,,,,,,,,,,,,,,,,,,,,function(t,e,i){"use strict";i.d(e,"a",(function(){return o}));var n=i(2);function o(t){var e=[],i=(t=Object(n.i)(t)).split("\r\n\r\n");1===i.length&&(i=t.split("\n\n"));for(var o=0;o0&&(o=0),i.length>o+1&&i[o+1]){var a=i[o],r=a.indexOf(" --\x3e ");r>0&&(e.begin=Object(n.g)(a.substr(0,r)),e.end=Object(n.g)(a.substr(r+5)),e.text=i.slice(o+1).join("\r\n"))}return e}},function(t,e,i){"use strict";i.d(e,"a",(function(){return o})),i.d(e,"b",(function(){return a}));var n=i(5);function o(t){var e=-1;return t>=1280?e=7:t>=960?e=6:t>=800?e=5:t>=640?e=4:t>=540?e=3:t>=420?e=2:t>=320?e=1:t>=250&&(e=0),e}function a(t,e){var i="jw-breakpoint-"+e;Object(n.p)(t,/jw-breakpoint--?\d+/,i)}},function(t,e,i){"use strict";i.d(e,"a",(function(){return d}));var n,o=i(0),a=i(8),r=i(16),s=i(7),l=i(3),c=i(10),u=i(5),d={back:!0,backgroundOpacity:50,edgeStyle:null,fontSize:14,fontOpacity:100,fontScale:.05,preprocessor:o.k,windowOpacity:0},p=function(t){var e,s,p,h,f,w,g,j,b,m=this,v=t.player;function y(){Object(o.o)(e.fontSize)&&(v.get("containerHeight")?j=d.fontScale*(e.userFontScale||1)*e.fontSize/d.fontSize:v.once("change:containerHeight",y,this))}function k(){var t=v.get("containerHeight");if(t){var e;if(v.get("fullscreen")&&a.OS.iOS)e=null;else{var i=t*j;e=Math.round(10*function(t){var e=v.get("mediaElement");if(e&&e.videoHeight){var i=e.videoWidth,n=e.videoHeight,o=i/n,r=v.get("containerHeight"),s=v.get("containerWidth");if(v.get("fullscreen")&&a.OS.mobile){var l=window.screen;l.orientation&&(r=l.availHeight,s=l.availWidth)}if(s&&r&&i&&n)return(s/r>o?r:n*s/i)*j}return t}(i))/10}v.get("renderCaptionsNatively")?function(t,e){var i="#".concat(t," .jw-video::-webkit-media-text-track-display");e&&(e+="px",a.OS.iOS&&Object(c.b)(i,{fontSize:"inherit"},t,!0));b.fontSize=e,Object(c.b)(i,b,t,!0)}(v.get("id"),e):Object(c.d)(f,{fontSize:e})}}function x(t,e,i){var n=Object(c.c)("#000000",i);"dropshadow"===t?e.textShadow="0 2px 1px "+n:"raised"===t?e.textShadow="0 0 5px "+n+", 0 1px 5px "+n+", 0 2px 5px "+n:"depressed"===t?e.textShadow="0 -2px 1px "+n:"uniform"===t&&(e.textShadow="-2px 0 1px "+n+",2px 0 1px "+n+",0 -2px 1px "+n+",0 2px 1px "+n+",-1px 1px 1px "+n+",1px 1px 1px "+n+",1px -1px 1px "+n+",1px 1px 1px "+n)}(f=document.createElement("div")).className="jw-captions jw-reset",this.show=function(){Object(u.a)(f,"jw-captions-enabled")},this.hide=function(){Object(u.o)(f,"jw-captions-enabled")},this.populate=function(t){v.get("renderCaptionsNatively")||(p=[],s=t,t?this.selectCues(t,h):this.renderCues())},this.resize=function(){k(),this.renderCues(!0)},this.renderCues=function(t){t=!!t,n&&n.processCues(window,p,f,t)},this.selectCues=function(t,e){if(t&&t.data&&e&&!v.get("renderCaptionsNatively")){var i=this.getAlignmentPosition(t,e);!1!==i&&(p=this.getCurrentCues(t.data,i),this.renderCues(!0))}},this.getCurrentCues=function(t,e){return Object(o.h)(t,(function(t){return e>=t.startTime&&(!t.endTime||e<=t.endTime)}))},this.getAlignmentPosition=function(t,e){var i=t.source,n=e.metadata,a=e.currentTime;return i&&n&&Object(o.r)(n[i])&&(a=n[i]),a},this.clear=function(){Object(u.g)(f)},this.setup=function(t,i){w=document.createElement("div"),g=document.createElement("span"),w.className="jw-captions-window jw-reset",g.className="jw-captions-text jw-reset",e=Object(o.g)({},d,i),j=d.fontScale;var n=function(){if(!v.get("renderCaptionsNatively")){y(e.fontSize);var i=e.windowColor,n=e.windowOpacity,o=e.edgeStyle;b={};var r={};!function(t,e){var i=e.color,n=e.fontOpacity;(i||n!==d.fontOpacity)&&(t.color=Object(c.c)(i||"#ffffff",n));if(e.back){var o=e.backgroundColor,a=e.backgroundOpacity;o===d.backgroundColor&&a===d.backgroundOpacity||(t.backgroundColor=Object(c.c)(o,a))}else t.background="transparent";e.fontFamily&&(t.fontFamily=e.fontFamily);e.fontStyle&&(t.fontStyle=e.fontStyle);e.fontWeight&&(t.fontWeight=e.fontWeight);e.textDecoration&&(t.textDecoration=e.textDecoration)}(r,e),(i||n!==d.windowOpacity)&&(b.backgroundColor=Object(c.c)(i||"#000000",n)),x(o,r,e.fontOpacity),e.back||null!==o||x("uniform",r),Object(c.d)(w,b),Object(c.d)(g,r),function(t,e){k(),function(t,e){a.Browser.safari&&Object(c.b)("#"+t+" .jw-video::-webkit-media-text-track-display-backdrop",{backgroundColor:e.backgroundColor},t,!0);Object(c.b)("#"+t+" .jw-video::-webkit-media-text-track-display",b,t,!0),Object(c.b)("#"+t+" .jw-video::cue",e,t,!0)}(t,e),function(t,e){Object(c.b)("#"+t+" .jw-text-track-display",b,t),Object(c.b)("#"+t+" .jw-text-track-cue",e,t)}(t,e)}(t,r)}};n(),w.appendChild(g),f.appendChild(w),v.change("captionsTrack",(function(t,e){this.populate(e)}),this),v.set("captions",e),v.on("change:captions",(function(t,i){e=i,n()}))},this.element=function(){return f},this.destroy=function(){v.off(null,null,this),this.off()};var T=function(t){h=t,m.selectCues(s,h)};v.on("change:playlistItem",(function(){h=null,p=[]}),this),v.on(l.Q,(function(t){p=[],T(t)}),this),v.on(l.S,T,this),v.on("subtitlesTrackData",(function(){this.selectCues(s,h)}),this),v.on("change:captionsList",(function t(e,o){var a=this;1!==o.length&&(e.get("renderCaptionsNatively")||n||(i.e(8).then(function(t){n=i(68).default}.bind(null,i)).catch(Object(r.c)(301121)).catch((function(t){a.trigger(l.tb,t)})),e.off("change:captionsList",t,this)))}),this)};Object(o.g)(p.prototype,s.a),e.b=p},function(t,e,i){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var i=function(t,e){var i=t[1]||"",n=t[3];if(!n)return i;if(e&&"function"==typeof btoa){var o=(r=n,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */"),a=n.sources.map((function(t){return"/*# sourceURL="+n.sourceRoot+t+" */"}));return[i].concat(a).concat([o]).join("\n")}var r;return[i].join("\n")}(e,t);return e[2]?"@media "+e[2]+"{"+i+"}":i})).join("")},e.i=function(t,i){"string"==typeof t&&(t=[[null,t,""]]);for(var n={},o=0;o'},function(t,e,i){"use strict";function n(t,e){var i=t.kind||"cc";return t.default||t.defaulttrack?"default":t._id||t.file||i+e}function o(t,e){var i=t.label||t.name||t.language;return i||(i="Unknown CC",(e+=1)>1&&(i+=" ["+e+"]")),{label:i,unknownCount:e}}i.d(e,"a",(function(){return n})),i.d(e,"b",(function(){return o}))},function(t,e,i){"use strict";function n(t){return new Promise((function(e,i){if(t.paused)return i(o("NotAllowedError",0,"play() failed."));var n=function(){t.removeEventListener("play",a),t.removeEventListener("playing",r),t.removeEventListener("pause",r),t.removeEventListener("abort",r),t.removeEventListener("error",r)},a=function(){t.addEventListener("playing",r),t.addEventListener("abort",r),t.addEventListener("error",r),t.addEventListener("pause",r)},r=function(t){if(n(),"playing"===t.type)e();else{var a='The play() request was interrupted by a "'.concat(t.type,'" event.');"error"===t.type?i(o("NotSupportedError",9,a)):i(o("AbortError",20,a))}};t.addEventListener("play",a)}))}function o(t,e,i){var n=new Error(i);return n.name=t,n.code=e,n}i.d(e,"a",(function(){return n}))},function(t,e,i){"use strict";function n(t,e){return t!==1/0&&Math.abs(t)>=Math.max(a(e),0)}function o(t,e){var i="VOD";return t===1/0?i="LIVE":t<0&&(i=n(t,a(e))?"DVR":"LIVE"),i}function a(t){return void 0===t?120:Math.max(t,0)}i.d(e,"a",(function(){return n})),i.d(e,"b",(function(){return o}))},function(t,e,i){"use strict";var n=i(67),o=i(16),a=i(22),r=i(4),s=i(57),l=i(2),c=i(1);function u(t){throw new c.n(null,t)}function d(t,e,n){t.xhr=Object(a.a)(t.file,(function(a){!function(t,e,n,a){var d,p,f=t.responseXML?t.responseXML.firstChild:null;if(f)for("xml"===Object(r.b)(f)&&(f=f.nextSibling);f.nodeType===f.COMMENT_NODE;)f=f.nextSibling;try{if(f&&"tt"===Object(r.b)(f))d=function(t){t||u(306007);var e=[],i=t.getElementsByTagName("p"),n=30,o=t.getElementsByTagName("tt");if(o&&o[0]){var a=parseFloat(o[0].getAttribute("ttp:frameRate"));isNaN(a)||(n=a)}i||u(306005),i.length||(i=t.getElementsByTagName("tt:p")).length||(i=t.getElementsByTagName("tts:p"));for(var r=0;r\s+<").replace(/(<\/?)tts?:/g,"$1").replace(//g,"\r\n");if(f){var w=s.getAttribute("begin"),g=s.getAttribute("dur"),j=s.getAttribute("end"),b={begin:Object(l.g)(w,n),text:f};j?b.end=Object(l.g)(j,n):g&&(b.end=b.begin+Object(l.g)(g,n)),e.push(b)}}return e.length||u(306005),e}(t.responseXML),p=h(d),delete e.xhr,n(p);else{var w=t.responseText;w.indexOf("WEBVTT")>=0?i.e(10).then(function(t){return i(97).default}.bind(null,i)).catch(Object(o.c)(301131)).then((function(t){var i=new t(window);p=[],i.oncue=function(t){p.push(t)},i.onflush=function(){delete e.xhr,n(p)},i.parse(w)})).catch((function(t){delete e.xhr,a(Object(c.v)(null,c.b,t))})):(d=Object(s.a)(w),p=h(d),delete e.xhr,n(p))}}catch(t){delete e.xhr,a(Object(c.v)(null,c.b,t))}}(a,t,e,n)}),(function(t,e,i,o){n(Object(c.u)(o,c.b))}))}function p(t){t&&t.forEach((function(t){var e=t.xhr;e&&(e.onload=null,e.onreadystatechange=null,e.onerror=null,"abort"in e&&e.abort()),delete t.xhr}))}function h(t){return t.map((function(t){return new n.a(t.begin,t.end,t.text)}))}i.d(e,"c",(function(){return d})),i.d(e,"a",(function(){return p})),i.d(e,"b",(function(){return h}))},function(t,e,i){"use strict";var n=window.VTTCue;function o(t){if("string"!=typeof t)return!1;return!!{start:!0,middle:!0,end:!0,left:!0,right:!0}[t.toLowerCase()]&&t.toLowerCase()}if(!n){(n=function(t,e,i){var n=this;n.hasBeenReset=!1;var a="",r=!1,s=t,l=e,c=i,u=null,d="",p=!0,h="auto",f="start",w="auto",g=100,j="middle";Object.defineProperty(n,"id",{enumerable:!0,get:function(){return a},set:function(t){a=""+t}}),Object.defineProperty(n,"pauseOnExit",{enumerable:!0,get:function(){return r},set:function(t){r=!!t}}),Object.defineProperty(n,"startTime",{enumerable:!0,get:function(){return s},set:function(t){if("number"!=typeof t)throw new TypeError("Start time must be set to a number.");s=t,this.hasBeenReset=!0}}),Object.defineProperty(n,"endTime",{enumerable:!0,get:function(){return l},set:function(t){if("number"!=typeof t)throw new TypeError("End time must be set to a number.");l=t,this.hasBeenReset=!0}}),Object.defineProperty(n,"text",{enumerable:!0,get:function(){return c},set:function(t){c=""+t,this.hasBeenReset=!0}}),Object.defineProperty(n,"region",{enumerable:!0,get:function(){return u},set:function(t){u=t,this.hasBeenReset=!0}}),Object.defineProperty(n,"vertical",{enumerable:!0,get:function(){return d},set:function(t){var e=function(t){return"string"==typeof t&&(!!{"":!0,lr:!0,rl:!0}[t.toLowerCase()]&&t.toLowerCase())}(t);if(!1===e)throw new SyntaxError("An invalid or illegal string was specified.");d=e,this.hasBeenReset=!0}}),Object.defineProperty(n,"snapToLines",{enumerable:!0,get:function(){return p},set:function(t){p=!!t,this.hasBeenReset=!0}}),Object.defineProperty(n,"line",{enumerable:!0,get:function(){return h},set:function(t){if("number"!=typeof t&&"auto"!==t)throw new SyntaxError("An invalid number or illegal string was specified.");h=t,this.hasBeenReset=!0}}),Object.defineProperty(n,"lineAlign",{enumerable:!0,get:function(){return f},set:function(t){var e=o(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");f=e,this.hasBeenReset=!0}}),Object.defineProperty(n,"position",{enumerable:!0,get:function(){return w},set:function(t){if(t<0||t>100)throw new Error("Position must be between 0 and 100.");w=t,this.hasBeenReset=!0}}),Object.defineProperty(n,"size",{enumerable:!0,get:function(){return g},set:function(t){if(t<0||t>100)throw new Error("Size must be between 0 and 100.");g=t,this.hasBeenReset=!0}}),Object.defineProperty(n,"align",{enumerable:!0,get:function(){return j},set:function(t){var e=o(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");j=e,this.hasBeenReset=!0}}),n.displayState=void 0}).prototype.getCueAsHTML=function(){return window.WebVTT.convertCueToDOMTree(window,this.text)}}e.a=n},,function(t,e,i){var n=i(70);"string"==typeof n&&(n=[["all-players",n,""]]),i(61).style(n,"all-players"),n.locals&&(t.exports=n.locals)},function(t,e,i){(t.exports=i(60)(!1)).push([t.i,'.jw-reset{text-align:left;direction:ltr}.jw-reset-text,.jw-reset{color:inherit;background-color:transparent;padding:0;margin:0;float:none;font-family:Arial,Helvetica,sans-serif;font-size:1em;line-height:1em;list-style:none;text-transform:none;vertical-align:baseline;border:0;font-variant:inherit;font-stretch:inherit;-webkit-tap-highlight-color:rgba(255,255,255,0)}body .jw-error,body .jwplayer.jw-state-error{height:100%;width:100%}.jw-title{position:absolute;top:0}.jw-background-color{background:rgba(0,0,0,0.4)}.jw-text{color:rgba(255,255,255,0.8)}.jw-knob{color:rgba(255,255,255,0.8);background-color:#fff}.jw-button-color{color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):focus,:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):hover{color:#fff}.jw-toggle{color:#fff}.jw-toggle.jw-off{color:rgba(255,255,255,0.8)}.jw-toggle.jw-off:focus{color:#fff}.jw-toggle:focus{outline:none}:not(.jw-flag-touch) .jw-toggle.jw-off:hover{color:#fff}.jw-rail{background:rgba(255,255,255,0.3)}.jw-buffer{background:rgba(255,255,255,0.3)}.jw-progress{background:#f2f2f2}.jw-time-tip,.jw-volume-tip{border:0}.jw-slider-volume.jw-volume-tip.jw-background-color.jw-slider-vertical{background:none}.jw-skip{padding:.5em;outline:none}.jw-skip .jw-skiptext,.jw-skip .jw-skip-icon{color:rgba(255,255,255,0.8)}.jw-skip.jw-skippable:hover .jw-skip-icon,.jw-skip.jw-skippable:focus .jw-skip-icon{color:#fff}.jw-icon-cast google-cast-launcher{--connected-color:#fff;--disconnected-color:rgba(255,255,255,0.8)}.jw-icon-cast google-cast-launcher:focus{outline:none}.jw-icon-cast google-cast-launcher.jw-off{--connected-color:rgba(255,255,255,0.8)}.jw-icon-cast:focus google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-icon-cast:hover google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-nextup-container{bottom:2.5em;padding:5px .5em}.jw-nextup{border-radius:0}.jw-color-active{color:#fff;stroke:#fff;border-color:#fff}:not(.jw-flag-touch) .jw-color-active-hover:hover,:not(.jw-flag-touch) .jw-color-active-hover:focus{color:#fff;stroke:#fff;border-color:#fff}.jw-color-inactive{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-color-inactive-hover:hover{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}.jw-option{color:rgba(255,255,255,0.8)}.jw-option.jw-active-option{color:#fff;background-color:rgba(255,255,255,0.1)}:not(.jw-flag-touch) .jw-option:hover{color:#fff}.jwplayer{width:100%;font-size:16px;position:relative;display:block;min-height:0;overflow:hidden;box-sizing:border-box;font-family:Arial,Helvetica,sans-serif;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:none}.jwplayer *{box-sizing:inherit}.jwplayer.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jwplayer.jw-flag-aspect-mode{height:auto !important}.jwplayer.jw-flag-aspect-mode .jw-aspect{display:block}.jwplayer .jw-aspect{display:none}.jwplayer .jw-swf{outline:none}.jw-media,.jw-preview{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}.jw-media{overflow:hidden;cursor:pointer}.jw-plugin{position:absolute;bottom:66px}.jw-breakpoint-7 .jw-plugin{bottom:132px}.jw-plugin .jw-banner{max-width:100%;opacity:0;cursor:pointer;position:absolute;margin:auto auto 0;left:0;right:0;bottom:0;display:block}.jw-preview,.jw-captions,.jw-title{pointer-events:none}.jw-media,.jw-logo{pointer-events:all}.jw-wrapper{background-color:#000;position:absolute;top:0;left:0;right:0;bottom:0}.jw-hidden-accessibility{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.jw-contract-trigger::before{content:"";overflow:hidden;width:200%;height:200%;display:block;position:absolute;top:0;left:0}.jwplayer .jw-media video{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;margin:auto;background:transparent}.jwplayer .jw-media video::-webkit-media-controls-start-playback-button{display:none}.jwplayer.jw-stretch-uniform .jw-media video{object-fit:contain}.jwplayer.jw-stretch-none .jw-media video{object-fit:none}.jwplayer.jw-stretch-fill .jw-media video{object-fit:cover}.jwplayer.jw-stretch-exactfit .jw-media video{object-fit:fill}.jw-preview{position:absolute;display:none;opacity:1;visibility:visible;width:100%;height:100%;background:#000 no-repeat 50% 50%}.jwplayer .jw-preview,.jw-error .jw-preview{background-size:contain}.jw-stretch-none .jw-preview{background-size:auto auto}.jw-stretch-fill .jw-preview{background-size:cover}.jw-stretch-exactfit .jw-preview{background-size:100% 100%}.jw-title{display:none;padding-top:20px;width:100%;z-index:1}.jw-title-primary,.jw-title-secondary{color:#fff;padding-left:20px;padding-right:20px;padding-bottom:.5em;overflow:hidden;text-overflow:ellipsis;direction:unset;white-space:nowrap;width:100%}.jw-title-primary{font-size:1.625em}.jw-breakpoint-2 .jw-title-primary,.jw-breakpoint-3 .jw-title-primary{font-size:1.5em}.jw-flag-small-player .jw-title-primary{font-size:1.25em}.jw-flag-small-player .jw-title-secondary,.jw-title-secondary:empty{display:none}.jw-captions{position:absolute;width:100%;height:100%;text-align:center;display:none;letter-spacing:normal;word-spacing:normal;text-transform:none;text-indent:0;text-decoration:none;pointer-events:none;overflow:hidden;top:0}.jw-captions.jw-captions-enabled{display:block}.jw-captions-window{display:none;padding:.25em;border-radius:.25em}.jw-captions-window.jw-captions-window-active{display:inline-block}.jw-captions-text{display:inline-block;color:#fff;background-color:#000;word-wrap:normal;word-break:normal;white-space:pre-line;font-style:normal;font-weight:normal;text-align:center;text-decoration:none}.jw-text-track-display{font-size:inherit;line-height:1.5}.jw-text-track-cue{background-color:rgba(0,0,0,0.5);color:#fff;padding:.1em .3em}.jwplayer video::-webkit-media-controls{display:none;justify-content:flex-start}.jwplayer video::-webkit-media-text-track-display{min-width:-webkit-min-content}.jwplayer video::cue{background-color:rgba(0,0,0,0.5)}.jwplayer video::-webkit-media-controls-panel-container{display:none}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing) .jw-captions,.jwplayer.jw-flag-media-audio.jw-state-playing .jw-captions,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden) .jw-captions{max-height:calc(100% - 60px)}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-flag-media-audio.jw-state-playing:not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container{max-height:calc(100% - 60px)}.jw-logo{position:absolute;margin:20px;cursor:pointer;pointer-events:all;background-repeat:no-repeat;background-size:contain;top:auto;right:auto;left:auto;bottom:auto;outline:none}.jw-logo.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-flag-audio-player .jw-logo{display:none}.jw-logo-top-right{top:0;right:0}.jw-logo-top-left{top:0;left:0}.jw-logo-bottom-left{left:0}.jw-logo-bottom-right{right:0}.jw-logo-bottom-left,.jw-logo-bottom-right{bottom:44px;transition:bottom 150ms cubic-bezier(0, .25, .25, 1)}.jw-state-idle .jw-logo{z-index:1}.jw-state-setup .jw-wrapper{background-color:inherit}.jw-state-setup .jw-logo,.jw-state-setup .jw-controls,.jw-state-setup .jw-controls-backdrop{visibility:hidden}span.jw-break{display:block}body .jw-error,body .jwplayer.jw-state-error{background-color:#333;color:#fff;font-size:16px;display:table;opacity:1;position:relative}body .jw-error .jw-display,body .jwplayer.jw-state-error .jw-display{display:none}body .jw-error .jw-media,body .jwplayer.jw-state-error .jw-media{cursor:default}body .jw-error .jw-preview,body .jwplayer.jw-state-error .jw-preview{background-color:#333}body .jw-error .jw-error-msg,body .jwplayer.jw-state-error .jw-error-msg{background-color:#000;border-radius:2px;display:flex;flex-direction:row;align-items:stretch;padding:20px}body .jw-error .jw-error-msg .jw-icon,body .jwplayer.jw-state-error .jw-error-msg .jw-icon{height:30px;width:30px;margin-right:20px;flex:0 0 auto;align-self:center}body .jw-error .jw-error-msg .jw-icon:empty,body .jwplayer.jw-state-error .jw-error-msg .jw-icon:empty{display:none}body .jw-error .jw-error-msg .jw-info-container,body .jwplayer.jw-state-error .jw-error-msg .jw-info-container{margin:0;padding:0}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg{flex-direction:column}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text{text-align:center}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon{flex:.5 0 auto;margin-right:0;margin-bottom:20px}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break{display:inline}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break:before{content:" "}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg{height:100%;width:100%;top:0;position:absolute;left:0;background:#000;-webkit-transform:none;transform:none;padding:4px 16px;z-index:1}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg.jw-info-overlay{max-width:none;max-height:none}body .jwplayer.jw-state-error .jw-title,.jw-state-idle .jw-title,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-title{display:block}body .jwplayer.jw-state-error .jw-preview,.jw-state-idle .jw-preview,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-preview{display:block}.jw-state-idle .jw-captions,.jwplayer.jw-state-complete .jw-captions,body .jwplayer.jw-state-error .jw-captions{display:none}.jw-state-idle video::-webkit-media-text-track-container,.jwplayer.jw-state-complete video::-webkit-media-text-track-container,body .jwplayer.jw-state-error video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-fullscreen{width:100% !important;height:100% !important;top:0;right:0;bottom:0;left:0;z-index:1000;margin:0;position:fixed}body .jwplayer.jw-flag-flash-blocked .jw-title{display:block}.jwplayer.jw-flag-controls-hidden .jw-media{cursor:default}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:45px}.jw-flag-floating{background-size:cover;background-color:#000}.jw-flag-floating .jw-wrapper{position:fixed;z-index:2147483647;-webkit-animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;top:auto;bottom:1rem;left:auto;right:1rem;max-width:400px;max-height:400px;margin:0 auto}@media screen and (max-width:480px){.jw-flag-floating .jw-wrapper{width:100%;left:0;right:0}}.jw-flag-floating .jw-wrapper .jw-media{touch-action:none}@media screen and (max-device-width:480px) and (orientation:portrait){.jw-flag-touch.jw-flag-floating .jw-wrapper{-webkit-animation:none;animation:none;top:62px;bottom:auto;left:0;right:0;max-width:none;max-height:none}}.jw-flag-floating .jw-float-icon{pointer-events:all;cursor:pointer;display:none}.jw-flag-floating .jw-float-icon .jw-svg-icon{-webkit-filter:drop-shadow(0 0 1px #000);filter:drop-shadow(0 0 1px #000)}.jw-flag-floating.jw-floating-dismissible .jw-dismiss-icon{display:none}.jw-flag-floating.jw-floating-dismissible.jw-flag-ads .jw-float-icon{display:flex}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-logo,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-logo{display:none}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-float-icon,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-float-icon{display:flex}.jw-float-icon{display:none;position:absolute;top:3px;right:5px;align-items:center;justify-content:center}@-webkit-keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}.jw-flag-top{margin-top:2em;overflow:visible}.jw-top{height:2em;line-height:2;pointer-events:none;text-align:center;opacity:.8;position:absolute;top:-2em;width:100%}.jw-top .jw-icon{cursor:pointer;pointer-events:all;height:auto;width:auto}.jw-top .jw-text{color:#555}',""])},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e,i){var n=i(96);"string"==typeof n&&(n=[["all-players",n,""]]),i(61).style(n,"all-players"),n.locals&&(t.exports=n.locals)},function(t,e,i){(t.exports=i(60)(!1)).push([t.i,'.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-flag-small-player .jw-settings-menu,.jw-settings-submenu{height:100%;width:100%}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;right:0}.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-settings-item-active::before{top:0;position:absolute;left:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;bottom:0;left:0}.jw-nextup-close{position:absolute;top:0;right:0}.jw-overlays,.jw-controls,.jw-flag-small-player .jw-settings-menu{position:absolute;bottom:0;right:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-time-tip::after,.jw-settings-menu .jw-icon.jw-button-color::after,.jw-text-live::before,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{content:"";display:block}.jw-svg-icon{height:24px;width:24px;fill:currentColor;pointer-events:none}.jw-icon{height:44px;width:44px;background-color:transparent;outline:none}.jw-icon.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-icon-airplay .jw-svg-icon-airplay-off{display:none}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-off{display:block}.jw-icon-airplay .jw-svg-icon-airplay-on{display:block}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-on{display:none}.jw-icon-cc .jw-svg-icon-cc-off{display:none}.jw-off.jw-icon-cc .jw-svg-icon-cc-off{display:block}.jw-icon-cc .jw-svg-icon-cc-on{display:block}.jw-off.jw-icon-cc .jw-svg-icon-cc-on{display:none}.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:none}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:block}.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:block}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:none}.jw-icon-volume .jw-svg-icon-volume-0{display:none}.jw-off.jw-icon-volume .jw-svg-icon-volume-0{display:block}.jw-icon-volume .jw-svg-icon-volume-100{display:none}.jw-full.jw-icon-volume .jw-svg-icon-volume-100{display:block}.jw-icon-volume .jw-svg-icon-volume-50{display:block}.jw-off.jw-icon-volume .jw-svg-icon-volume-50,.jw-full.jw-icon-volume .jw-svg-icon-volume-50{display:none}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon[aria-checked="true"]::after,.jw-settings-open .jw-icon-settings::after,.jw-icon-volume.jw-open::after{opacity:1}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-cc,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-settings,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-audio-tracks,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-hd,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-settings-sharing,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-fullscreen,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-airplay,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-cast{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-text-live{bottom:6px}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume::after{display:none}.jw-overlays,.jw-controls{pointer-events:none}.jw-controls-backdrop{display:block;background:linear-gradient(to bottom, transparent, rgba(0,0,0,0.4) 77%, rgba(0,0,0,0.4) 100%) 100% 100% / 100% 240px no-repeat transparent;transition:opacity 250ms cubic-bezier(0, .25, .25, 1),background-size 250ms cubic-bezier(0, .25, .25, 1);pointer-events:none}.jw-overlays{cursor:auto}.jw-controls{overflow:hidden}.jw-flag-small-player .jw-controls{text-align:center}.jw-text{height:1em;font-family:Arial,Helvetica,sans-serif;font-size:.75em;font-style:normal;font-weight:normal;color:#fff;text-align:center;font-variant:normal;font-stretch:normal}.jw-controlbar,.jw-skip,.jw-display-icon-container .jw-icon,.jw-nextup-container,.jw-autostart-mute,.jw-overlays .jw-plugin{pointer-events:all}.jwplayer .jw-display-icon-container,.jw-error .jw-display-icon-container{width:auto;height:auto;box-sizing:content-box}.jw-display{display:table;height:100%;padding:57px 0;position:relative;width:100%}.jw-flag-dragging .jw-display{display:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-display-container{display:table-cell;height:100%;text-align:center;vertical-align:middle}.jw-display-controls{display:inline-block}.jwplayer .jw-display-icon-container{float:left}.jw-display-icon-container{display:inline-block;padding:5.5px;margin:0 22px}.jw-display-icon-container .jw-icon{height:75px;width:75px;cursor:pointer;display:flex;justify-content:center;align-items:center}.jw-display-icon-container .jw-icon .jw-svg-icon{height:33px;width:33px;padding:0;position:relative}.jw-display-icon-container .jw-icon .jw-svg-icon-rewind{padding:.2em .05em}.jw-breakpoint--1 .jw-nextup-container{display:none}.jw-breakpoint-0 .jw-display-icon-next,.jw-breakpoint--1 .jw-display-icon-next,.jw-breakpoint-0 .jw-display-icon-rewind,.jw-breakpoint--1 .jw-display-icon-rewind{display:none}.jw-breakpoint-0 .jw-display .jw-icon,.jw-breakpoint--1 .jw-display .jw-icon,.jw-breakpoint-0 .jw-display .jw-svg-icon,.jw-breakpoint--1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-0 .jw-display .jw-icon:before,.jw-breakpoint--1 .jw-display .jw-icon:before,.jw-breakpoint-0 .jw-display .jw-svg-icon:before,.jw-breakpoint--1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon,.jw-breakpoint-1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-1 .jw-display .jw-icon:before,.jw-breakpoint-1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon.jw-icon-rewind:before{width:33px;height:33px}.jw-breakpoint-2 .jw-display .jw-icon,.jw-breakpoint-3 .jw-display .jw-icon,.jw-breakpoint-2 .jw-display .jw-svg-icon,.jw-breakpoint-3 .jw-display .jw-svg-icon{width:77px;height:77px;line-height:77px}.jw-breakpoint-2 .jw-display .jw-icon:before,.jw-breakpoint-3 .jw-display .jw-icon:before,.jw-breakpoint-2 .jw-display .jw-svg-icon:before,.jw-breakpoint-3 .jw-display .jw-svg-icon:before{width:38.5px;height:38.5px}.jw-breakpoint-4 .jw-display .jw-icon,.jw-breakpoint-5 .jw-display .jw-icon,.jw-breakpoint-6 .jw-display .jw-icon,.jw-breakpoint-7 .jw-display .jw-icon,.jw-breakpoint-4 .jw-display .jw-svg-icon,.jw-breakpoint-5 .jw-display .jw-svg-icon,.jw-breakpoint-6 .jw-display .jw-svg-icon,.jw-breakpoint-7 .jw-display .jw-svg-icon{width:88px;height:88px;line-height:88px}.jw-breakpoint-4 .jw-display .jw-icon:before,.jw-breakpoint-5 .jw-display .jw-icon:before,.jw-breakpoint-6 .jw-display .jw-icon:before,.jw-breakpoint-7 .jw-display .jw-icon:before,.jw-breakpoint-4 .jw-display .jw-svg-icon:before,.jw-breakpoint-5 .jw-display .jw-svg-icon:before,.jw-breakpoint-6 .jw-display .jw-svg-icon:before,.jw-breakpoint-7 .jw-display .jw-svg-icon:before{width:44px;height:44px}.jw-controlbar{display:flex;flex-flow:row wrap;align-items:center;justify-content:center;position:absolute;left:0;bottom:0;width:100%;border:none;border-radius:0;background-size:auto;box-shadow:none;max-height:72px;transition:250ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s}.jw-breakpoint-7 .jw-controlbar{max-height:140px}.jw-breakpoint-7 .jw-controlbar .jw-button-container{padding:0 48px 20px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-tooltip{margin-bottom:-7px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-overlay{padding-bottom:40%}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text{font-size:1em}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text.jw-text-elapsed{justify-content:flex-end}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume{height:60px;width:60px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline .jw-svg-icon,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time{padding:0 60px;height:34px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time .jw-slider-container{height:10px}.jw-controlbar .jw-button-image{background:no-repeat 50% 50%;background-size:contain;max-height:24px}.jw-controlbar .jw-spacer{flex:1 1 auto;align-self:stretch}.jw-controlbar .jw-icon.jw-button-color:hover{color:#fff}.jw-button-container{display:flex;flex-flow:row nowrap;flex:1 1 auto;align-items:center;justify-content:center;width:100%;padding:0 12px}.jw-slider-horizontal{background-color:transparent}.jw-icon-inline{position:relative}.jw-icon-inline,.jw-icon-tooltip{height:44px;width:44px;align-items:center;display:flex;justify-content:center}.jw-icon-inline:not(.jw-text),.jw-icon-tooltip,.jw-slider-horizontal{cursor:pointer}.jw-text-elapsed,.jw-text-duration{justify-content:flex-start;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.jw-icon-tooltip{position:relative}.jw-knob:hover,.jw-icon-inline:hover,.jw-icon-tooltip:hover,.jw-icon-display:hover,.jw-option:before:hover{color:#fff}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{pointer-events:none}.jw-icon-cast{display:none;margin:0;padding:0}.jw-icon-cast google-cast-launcher{background-color:transparent;border:none;padding:0;width:24px;height:24px;cursor:pointer}.jw-icon-inline.jw-icon-volume{display:none}.jwplayer .jw-text-countdown{display:none}.jw-flag-small-player .jw-display{padding-top:0;padding-bottom:0}.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-rewind,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-next,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-playback{display:none}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop{opacity:0}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-countdown{display:flex}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-duration,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-duration{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-text-countdown,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-related-btn,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-slider-volume{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-controlbar{flex-direction:column-reverse}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-button-container{height:30px}.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-volume,.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-fullscreen{display:none}.jwplayer:not(.jw-breakpoint-0) .jw-text-duration:before,.jwplayer:not(.jw-breakpoint--1) .jw-text-duration:before{content:"/";padding-right:1ch;padding-left:1ch}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar{will-change:transform}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar .jw-text{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.jw-slider-container{display:flex;align-items:center;position:relative;touch-action:none}.jw-rail,.jw-buffer,.jw-progress{position:absolute;cursor:pointer}.jw-progress{background-color:#f2f2f2}.jw-rail{background-color:rgba(255,255,255,0.3)}.jw-buffer{background-color:rgba(255,255,255,0.3)}.jw-knob{height:13px;width:13px;background-color:#fff;border-radius:50%;box-shadow:0 0 10px rgba(0,0,0,0.4);opacity:1;pointer-events:none;position:absolute;-webkit-transform:translate(-50%, -50%) scale(0);transform:translate(-50%, -50%) scale(0);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform}.jw-flag-dragging .jw-slider-time .jw-knob,.jw-icon-volume:active .jw-slider-volume .jw-knob{box-shadow:0 0 26px rgba(0,0,0,0.2),0 0 10px rgba(0,0,0,0.4),0 0 0 6px rgba(255,255,255,0.2)}.jw-slider-horizontal,.jw-slider-vertical{display:flex}.jw-slider-horizontal .jw-slider-container{height:5px;width:100%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue,.jw-slider-horizontal .jw-knob{top:50%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue{-webkit-transform:translate(0, -50%);transform:translate(0, -50%)}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress{height:5px}.jw-slider-horizontal .jw-rail{width:100%}.jw-slider-vertical{align-items:center;flex-direction:column}.jw-slider-vertical .jw-slider-container{height:88px;width:5px}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress,.jw-slider-vertical .jw-knob{left:50%}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress{height:100%;width:5px;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out;bottom:0}.jw-slider-vertical .jw-knob{-webkit-transform:translate(-50%, 50%);transform:translate(-50%, 50%)}.jw-slider-time.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-slider-time,.jw-flag-audio-player .jw-slider-volume{height:17px;width:100%;align-items:center;background:transparent none;padding:0 12px}.jw-slider-time .jw-cue{background-color:rgba(33,33,33,0.8);cursor:pointer;position:absolute;width:6px}.jw-slider-time,.jw-horizontal-volume-container{z-index:1;outline:none}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail,.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer,.jw-slider-time .jw-progress,.jw-horizontal-volume-container .jw-progress,.jw-slider-time .jw-cue,.jw-horizontal-volume-container .jw-cue{-webkit-backface-visibility:hidden;backface-visibility:hidden;height:100%;-webkit-transform:translate(0, -50%) scale(1, .6);transform:translate(0, -50%) scale(1, .6);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out}.jw-slider-time:hover .jw-rail,.jw-horizontal-volume-container:hover .jw-rail,.jw-slider-time:focus .jw-rail,.jw-horizontal-volume-container:focus .jw-rail,.jw-flag-dragging .jw-slider-time .jw-rail,.jw-flag-dragging .jw-horizontal-volume-container .jw-rail,.jw-flag-touch .jw-slider-time .jw-rail,.jw-flag-touch .jw-horizontal-volume-container .jw-rail,.jw-slider-time:hover .jw-buffer,.jw-horizontal-volume-container:hover .jw-buffer,.jw-slider-time:focus .jw-buffer,.jw-horizontal-volume-container:focus .jw-buffer,.jw-flag-dragging .jw-slider-time .jw-buffer,.jw-flag-dragging .jw-horizontal-volume-container .jw-buffer,.jw-flag-touch .jw-slider-time .jw-buffer,.jw-flag-touch .jw-horizontal-volume-container .jw-buffer,.jw-slider-time:hover .jw-progress,.jw-horizontal-volume-container:hover .jw-progress,.jw-slider-time:focus .jw-progress,.jw-horizontal-volume-container:focus .jw-progress,.jw-flag-dragging .jw-slider-time .jw-progress,.jw-flag-dragging .jw-horizontal-volume-container .jw-progress,.jw-flag-touch .jw-slider-time .jw-progress,.jw-flag-touch .jw-horizontal-volume-container .jw-progress,.jw-slider-time:hover .jw-cue,.jw-horizontal-volume-container:hover .jw-cue,.jw-slider-time:focus .jw-cue,.jw-horizontal-volume-container:focus .jw-cue,.jw-flag-dragging .jw-slider-time .jw-cue,.jw-flag-dragging .jw-horizontal-volume-container .jw-cue,.jw-flag-touch .jw-slider-time .jw-cue,.jw-flag-touch .jw-horizontal-volume-container .jw-cue{-webkit-transform:translate(0, -50%) scale(1, 1);transform:translate(0, -50%) scale(1, 1)}.jw-slider-time:hover .jw-knob,.jw-horizontal-volume-container:hover .jw-knob,.jw-slider-time:focus .jw-knob,.jw-horizontal-volume-container:focus .jw-knob{-webkit-transform:translate(-50%, -50%) scale(1);transform:translate(-50%, -50%) scale(1)}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail{background-color:rgba(255,255,255,0.2)}.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer{background-color:rgba(255,255,255,0.4)}.jw-flag-touch .jw-slider-time::before,.jw-flag-touch .jw-horizontal-volume-container::before{height:44px;width:100%;content:"";position:absolute;display:block;bottom:calc(100% - 17px);left:0}.jw-slider-time.jw-tab-focus:focus .jw-rail,.jw-horizontal-volume-container.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time{height:17px;padding:0}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-slider-container{height:10px}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-knob{border-radius:0;border:1px solid rgba(0,0,0,0.75);height:12px;width:10px}.jw-modal{width:284px}.jw-breakpoint-7 .jw-modal,.jw-breakpoint-6 .jw-modal,.jw-breakpoint-5 .jw-modal{height:232px}.jw-breakpoint-4 .jw-modal,.jw-breakpoint-3 .jw-modal{height:192px}.jw-breakpoint-2 .jw-modal,.jw-flag-small-player .jw-modal{bottom:0;right:0;height:100%;width:100%;max-height:none;max-width:none;z-index:2}.jwplayer .jw-rightclick{display:none;position:absolute;white-space:nowrap}.jwplayer .jw-rightclick.jw-open{display:block}.jwplayer .jw-rightclick .jw-rightclick-list{border-radius:1px;list-style:none;margin:0;padding:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item{background-color:rgba(0,0,0,0.8);border-bottom:1px solid #444;margin:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo{color:#fff;display:inline-flex;padding:0 10px 0 0;vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo .jw-svg-icon{height:20px;width:20px}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-link{border:none;color:#fff;display:block;font-size:11px;line-height:1em;padding:15px 23px;text-align:start;text-decoration:none;width:100%}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:last-child{border-bottom:none}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:hover{cursor:pointer}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured{vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link{color:#fff}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link span{color:#fff}.jwplayer .jw-rightclick .jw-info-overlay-item,.jwplayer .jw-rightclick .jw-share-item,.jwplayer .jw-rightclick .jw-shortcuts-item{border:none;background-color:transparent;outline:none;cursor:pointer}.jw-icon-tooltip.jw-open .jw-overlay{opacity:1;pointer-events:auto;transition-delay:0s}.jw-icon-tooltip.jw-open .jw-overlay:focus{outline:none}.jw-icon-tooltip.jw-open .jw-overlay:focus.jw-tab-focus{outline:solid 2px #4d90fe}.jw-slider-time .jw-overlay:before{height:1em;top:auto}.jw-slider-time .jw-icon-tooltip.jw-open .jw-overlay{pointer-events:none}.jw-volume-tip{padding:13px 0 26px}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{height:auto;width:100%;box-shadow:0 0 10px rgba(0,0,0,0.4);color:#fff;display:block;margin:0 0 14px;pointer-events:none;position:relative;z-index:0}.jw-time-tip::after,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{top:100%;position:absolute;left:50%;height:14px;width:14px;border-radius:1px;background-color:currentColor;-webkit-transform-origin:75% 50%;transform-origin:75% 50%;-webkit-transform:translate(-50%, -50%) rotate(45deg);transform:translate(-50%, -50%) rotate(45deg);z-index:-1}.jw-time-tip .jw-text,.jw-controlbar .jw-tooltip .jw-text,.jw-settings-menu .jw-tooltip .jw-text{background-color:#fff;border-radius:1px;color:#000;font-size:10px;height:auto;line-height:1;padding:7px 10px;display:inline-block;min-width:100%;vertical-align:middle}.jw-controlbar .jw-overlay{position:absolute;bottom:100%;left:50%;margin:0;min-height:44px;min-width:44px;opacity:0;pointer-events:none;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s, 150ms;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);width:100%;z-index:1}.jw-controlbar .jw-overlay .jw-contents{position:relative}.jw-controlbar .jw-option{position:relative;white-space:nowrap;cursor:pointer;list-style:none;height:1.5em;font-family:inherit;line-height:1.5em;padding:0 .5em;font-size:.8em;margin:0}.jw-controlbar .jw-option::before{padding-right:.125em}.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{position:absolute;bottom:100%;left:50%;opacity:0;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:100ms 0s cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility, -webkit-transform;transition-property:opacity, transform, visibility;transition-property:opacity, transform, visibility, -webkit-transform;visibility:hidden;white-space:nowrap;width:auto;z-index:1}.jw-controlbar .jw-tooltip.jw-open,.jw-settings-menu .jw-tooltip.jw-open{opacity:1;-webkit-transform:translate(-50%, -10px);transform:translate(-50%, -10px);transition-duration:150ms;transition-delay:500ms,0s,500ms;visibility:visible}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen{left:auto;right:0;-webkit-transform:translate(0, 0);transform:translate(0, 0)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen.jw-open,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen.jw-open{-webkit-transform:translate(0, -10px);transform:translate(0, -10px)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen::after,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen::after{left:auto;right:9px}.jw-tooltip-time{height:auto;width:0;bottom:100%;line-height:normal;padding:0;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.jw-tooltip-time .jw-overlay{bottom:0;min-height:0;width:auto}.jw-tooltip{bottom:57px;display:none;position:absolute}.jw-tooltip .jw-text{height:100%;white-space:nowrap;text-overflow:ellipsis;direction:unset;max-width:246px;overflow:hidden}.jw-flag-audio-player .jw-tooltip{display:none}.jw-flag-small-player .jw-time-thumb{display:none}.jwplayer .jw-shortcuts-tooltip{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column;z-index:1}.jwplayer .jw-shortcuts-tooltip.jw-open{display:flex}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-close{flex:0 0 auto;margin:5px 5px 5px auto}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container{display:flex;flex:1 1 auto;flex-flow:column;font-size:12px;margin:0 20px 20px;overflow-y:auto;padding:5px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar{background-color:transparent;width:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-title{font-weight:bold}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list{display:flex;max-width:340px;margin:0 10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-tooltip-descriptions{width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row{display:flex;align-items:center;justify-content:space-between;margin:10px 0;width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-description{margin-right:10px;max-width:70%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-key{background:#fefefe;color:#333;overflow:hidden;padding:7px 10px;text-overflow:ellipsis;white-space:nowrap}.jw-skip{color:rgba(255,255,255,0.8);cursor:default;position:absolute;display:flex;right:.75em;bottom:56px;padding:.5em;border:1px solid #333;background-color:#000;align-items:center;height:2em}.jw-skip.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-skip.jw-skippable{cursor:pointer;padding:.25em .75em}.jw-skip.jw-skippable:hover{cursor:pointer;color:#fff}.jw-skip.jw-skippable .jw-skip-icon{display:inline;height:24px;width:24px;margin:0}.jw-breakpoint-7 .jw-skip{padding:1.35em 1em;bottom:130px}.jw-breakpoint-7 .jw-skip .jw-text{font-size:1em;font-weight:normal}.jw-breakpoint-7 .jw-skip .jw-icon-inline{height:30px;width:30px}.jw-breakpoint-7 .jw-skip .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-skip .jw-skip-icon{display:none;margin-left:-0.75em;padding:0 .5em;pointer-events:none}.jw-skip .jw-skip-icon .jw-svg-icon-next{display:block;padding:0}.jw-skip .jw-text,.jw-skip .jw-skip-icon{vertical-align:middle;font-size:.7em}.jw-skip .jw-text{font-weight:bold}.jw-cast{background-size:cover;display:none;height:100%;position:relative;width:100%}.jw-cast-container{background:linear-gradient(180deg, rgba(25,25,25,0.75), rgba(25,25,25,0.25), rgba(25,25,25,0));left:0;padding:20px 20px 80px;position:absolute;top:0;width:100%}.jw-cast-text{color:#fff;font-size:1.6em}.jw-breakpoint--1 .jw-cast-text,.jw-breakpoint-0 .jw-cast-text{font-size:1.15em}.jw-breakpoint-1 .jw-cast-text,.jw-breakpoint-2 .jw-cast-text,.jw-breakpoint-3 .jw-cast-text{font-size:1.3em}.jw-nextup-container{position:absolute;bottom:66px;left:0;background-color:transparent;cursor:pointer;margin:0 auto;padding:12px;pointer-events:none;right:0;text-align:right;visibility:hidden;width:100%}.jw-settings-open .jw-nextup-container,.jw-info-open .jw-nextup-container{display:none}.jw-breakpoint-7 .jw-nextup-container{padding:60px}.jw-flag-small-player .jw-nextup-container{padding:0 12px 0 0}.jw-flag-small-player .jw-nextup-container .jw-nextup-title,.jw-flag-small-player .jw-nextup-container .jw-nextup-duration,.jw-flag-small-player .jw-nextup-container .jw-nextup-close{display:none}.jw-flag-small-player .jw-nextup-container .jw-nextup-tooltip{height:30px}.jw-flag-small-player .jw-nextup-container .jw-nextup-header{font-size:12px}.jw-flag-small-player .jw-nextup-container .jw-nextup-body{justify-content:center;align-items:center;padding:.75em .3em}.jw-flag-small-player .jw-nextup-container .jw-nextup-thumbnail{width:50%}.jw-flag-small-player .jw-nextup-container .jw-nextup{max-width:65px}.jw-flag-small-player .jw-nextup-container .jw-nextup.jw-nextup-thumbnail-visible{max-width:120px}.jw-nextup{background:#333;border-radius:0;box-shadow:0 0 10px rgba(0,0,0,0.5);color:rgba(255,255,255,0.8);display:inline-block;max-width:280px;overflow:hidden;opacity:0;position:relative;width:64%;pointer-events:all;-webkit-transform:translate(0, -5px);transform:translate(0, -5px);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform;transition-delay:0s}.jw-nextup:hover .jw-nextup-tooltip{color:#fff}.jw-nextup.jw-nextup-thumbnail-visible{max-width:400px}.jw-nextup.jw-nextup-thumbnail-visible .jw-nextup-thumbnail{display:block}.jw-nextup-container-visible{visibility:visible}.jw-nextup-container-visible .jw-nextup{opacity:1;-webkit-transform:translate(0, 0);transform:translate(0, 0);transition-delay:0s, 0s, 150ms}.jw-nextup-tooltip{display:flex;height:80px}.jw-nextup-thumbnail{width:120px;background-position:center;background-size:cover;flex:0 0 auto;display:none}.jw-nextup-body{flex:1 1 auto;overflow:hidden;padding:.75em .875em;display:flex;flex-flow:column wrap;justify-content:space-between}.jw-nextup-header,.jw-nextup-title{font-size:14px;line-height:1.35}.jw-nextup-header{font-weight:bold}.jw-nextup-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.jw-nextup-duration{align-self:flex-end;text-align:right;font-size:12px}.jw-nextup-close{height:24px;width:24px;border:none;color:rgba(255,255,255,0.8);cursor:pointer;margin:6px;visibility:hidden}.jw-nextup-close:hover{color:#fff}.jw-nextup-sticky .jw-nextup-close{visibility:visible}.jw-autostart-mute{position:absolute;bottom:0;right:12px;height:44px;width:44px;background-color:rgba(33,33,33,0.4);padding:5px 4px 5px 6px;display:none}.jwplayer.jw-flag-autostart:not(.jw-flag-media-audio) .jw-nextup{display:none}.jw-settings-menu{position:absolute;bottom:57px;right:12px;align-items:flex-start;background-color:#333;display:none;flex-flow:column nowrap;max-width:284px;pointer-events:auto}.jw-settings-open .jw-settings-menu{display:flex}.jw-breakpoint-7 .jw-settings-menu{bottom:130px;right:60px;max-height:none;max-width:none;height:35%;width:25%}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline{height:60px;width:60px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-tooltip .jw-text{font-size:1em}.jw-breakpoint-7 .jw-settings-menu .jw-settings-back{min-width:60px}.jw-breakpoint-6 .jw-settings-menu,.jw-breakpoint-5 .jw-settings-menu{height:232px;width:284px;max-height:232px}.jw-breakpoint-4 .jw-settings-menu,.jw-breakpoint-3 .jw-settings-menu{height:192px;width:284px;max-height:192px}.jw-breakpoint-2 .jw-settings-menu{height:179px;width:284px;max-height:179px}.jw-flag-small-player .jw-settings-menu{max-width:none}.jw-settings-menu .jw-icon.jw-button-color::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon.jw-button-color[aria-checked="true"]::after{opacity:1}.jw-settings-menu .jw-settings-reset{text-decoration:underline}.jw-settings-topbar{align-items:center;background-color:rgba(0,0,0,0.4);display:flex;flex:0 0 auto;padding:3px 5px 0;width:100%}.jw-settings-topbar.jw-nested-menu-open{padding:0}.jw-settings-topbar.jw-nested-menu-open .jw-icon:not(.jw-settings-close):not(.jw-settings-back){display:none}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-close{width:20px}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-arrow-left{height:12px}.jw-settings-topbar.jw-nested-menu-open .jw-settings-topbar-text{display:block;outline:none}.jw-settings-topbar .jw-settings-back{min-width:44px}.jw-settings-topbar .jw-settings-topbar-buttons{display:inherit;width:100%;height:100%}.jw-settings-topbar .jw-settings-topbar-text{display:none;color:#fff;font-size:13px;width:100%}.jw-settings-topbar .jw-settings-close{margin-left:auto}.jw-settings-submenu{display:none;flex:1 1 auto;overflow-y:auto;padding:8px 20px 0 5px}.jw-settings-submenu::-webkit-scrollbar{background-color:transparent;width:6px}.jw-settings-submenu::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-settings-submenu.jw-settings-submenu-active{display:block}.jw-settings-submenu .jw-submenu-topbar{box-shadow:0 2px 9px 0 #1d1d1d;background-color:#2f2d2d;margin:-8px -20px 0 -5px}.jw-settings-submenu .jw-submenu-topbar .jw-settings-content-item{cursor:pointer;text-align:right;padding-right:15px;text-decoration:underline}.jw-settings-submenu .jw-settings-value-wrapper{float:right;display:flex;align-items:center}.jw-settings-submenu .jw-settings-value-wrapper .jw-settings-content-item-arrow{display:flex}.jw-settings-submenu .jw-settings-value-wrapper .jw-svg-icon-arrow-right{width:8px;margin-left:5px;height:12px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item{font-size:1em;padding:11px 15px 11px 30px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-settings-item-active::before{justify-content:flex-end}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-auto-label{font-size:.85em;padding-left:10px}.jw-flag-touch .jw-settings-submenu{overflow-y:scroll;-webkit-overflow-scrolling:touch}.jw-auto-label{font-size:10px;font-weight:initial;opacity:.75;padding-left:5px}.jw-settings-content-item{position:relative;color:rgba(255,255,255,0.8);cursor:pointer;font-size:12px;line-height:1;padding:7px 0 7px 15px;width:100%;text-align:left;outline:none}.jw-settings-content-item:hover{color:#fff}.jw-settings-content-item:focus{font-weight:bold}.jw-flag-small-player .jw-settings-content-item{line-height:1.75}.jw-settings-content-item.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-settings-item-active{font-weight:bold;position:relative}.jw-settings-item-active::before{height:100%;width:1em;align-items:center;content:"\\2022";display:inline-flex;justify-content:center}.jw-breakpoint-2 .jw-settings-open .jw-display-container,.jw-flag-small-player .jw-settings-open .jw-display-container,.jw-flag-touch .jw-settings-open .jw-display-container{display:none}.jw-breakpoint-2 .jw-settings-open.jw-controls,.jw-flag-small-player .jw-settings-open.jw-controls,.jw-flag-touch .jw-settings-open.jw-controls{z-index:1}.jw-flag-small-player .jw-settings-open .jw-controlbar{display:none}.jw-settings-open .jw-icon-settings::after{opacity:1}.jw-settings-open .jw-tooltip-settings{display:none}.jw-sharing-link{cursor:pointer}.jw-shortcuts-container .jw-switch{position:relative;display:inline-block;transition:ease-out .15s;transition-property:opacity, background;border-radius:18px;width:80px;height:20px;padding:10px;background:rgba(80,80,80,0.8);cursor:pointer;font-size:inherit;vertical-align:middle}.jw-shortcuts-container .jw-switch.jw-tab-focus{outline:solid 2px #4d90fe}.jw-shortcuts-container .jw-switch .jw-switch-knob{position:absolute;top:2px;left:1px;transition:ease-out .15s;box-shadow:0 0 10px rgba(0,0,0,0.4);border-radius:13px;width:15px;height:15px;background:#fefefe}.jw-shortcuts-container .jw-switch:before,.jw-shortcuts-container .jw-switch:after{position:absolute;top:3px;transition:inherit;color:#fefefe}.jw-shortcuts-container .jw-switch:before{content:attr(data-jw-switch-disabled);right:8px}.jw-shortcuts-container .jw-switch:after{content:attr(data-jw-switch-enabled);left:8px;opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]{background:#475470}.jw-shortcuts-container .jw-switch[aria-checked="true"]:before{opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]:after{opacity:1}.jw-shortcuts-container .jw-switch[aria-checked="true"] .jw-switch-knob{left:60px}.jw-idle-icon-text{display:none;line-height:1;position:absolute;text-align:center;text-indent:.35em;top:100%;white-space:nowrap;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.jw-idle-label{border-radius:50%;color:#fff;-webkit-filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));font:normal 16px/1 Arial,Helvetica,sans-serif;position:relative;transition:background-color 150ms cubic-bezier(0, .25, .25, 1);transition-property:background-color,-webkit-filter;transition-property:background-color,filter;transition-property:background-color,filter,-webkit-filter;-webkit-font-smoothing:antialiased}.jw-state-idle .jw-icon-display.jw-idle-label .jw-idle-icon-text{display:block}.jw-state-idle .jw-icon-display.jw-idle-label .jw-svg-icon-play{-webkit-transform:scale(.7, .7);transform:scale(.7, .7)}.jw-breakpoint-0.jw-state-idle .jw-icon-display.jw-idle-label,.jw-breakpoint--1.jw-state-idle .jw-icon-display.jw-idle-label{font-size:12px}.jw-info-overlay{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column}.jw-info-overlay .jw-info-close{flex:0 0 auto;margin:5px 5px 5px auto}.jw-info-open .jw-info-overlay{display:flex}.jw-info-container{display:flex;flex:1 1 auto;flex-flow:column;margin:0 20px 20px;overflow-y:auto;padding:5px}.jw-info-container [class*="jw-info"]:not(:first-of-type){color:rgba(255,255,255,0.8);padding-top:10px;font-size:12px}.jw-info-container .jw-info-description{margin-bottom:30px;text-align:start}.jw-info-container .jw-info-description:empty{display:none}.jw-info-container .jw-info-duration{text-align:start}.jw-info-container .jw-info-title{text-align:start;font-size:12px;font-weight:bold}.jw-info-container::-webkit-scrollbar{background-color:transparent;width:6px}.jw-info-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-info-clientid{align-self:flex-end;font-size:12px;color:rgba(255,255,255,0.8);margin:0 20px 20px 44px;text-align:right}.jw-flag-touch .jw-info-open .jw-display-container{display:none}@supports ((-webkit-filter: drop-shadow(0 0 3px #000)) or (filter: drop-shadow(0 0 3px #000))){.jwplayer.jw-ab-drop-shadow .jw-controls .jw-svg-icon,.jwplayer.jw-ab-drop-shadow .jw-controls .jw-icon.jw-text,.jwplayer.jw-ab-drop-shadow .jw-slider-container .jw-rail,.jwplayer.jw-ab-drop-shadow .jw-title{text-shadow:none;box-shadow:none;-webkit-filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3));filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3))}.jwplayer.jw-ab-drop-shadow .jw-button-color{opacity:.8;transition-property:color, opacity}.jwplayer.jw-ab-drop-shadow .jw-button-color:not(:hover){color:#fff;opacity:.8}.jwplayer.jw-ab-drop-shadow .jw-button-color:hover{opacity:1}.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0), hsla(0, 0%, 0%, 0.00787) 10.79%, hsla(0, 0%, 0%, 0.02963) 21.99%, hsla(0, 0%, 0%, 0.0625) 33.34%, hsla(0, 0%, 0%, 0.1037) 44.59%, hsla(0, 0%, 0%, 0.15046) 55.48%, hsla(0, 0%, 0%, 0.2) 65.75%, hsla(0, 0%, 0%, 0.24954) 75.14%, hsla(0, 0%, 0%, 0.2963) 83.41%, hsla(0, 0%, 0%, 0.3375) 90.28%, hsla(0, 0%, 0%, 0.37037) 95.51%, hsla(0, 0%, 0%, 0.39213) 98.83%, hsla(0, 0%, 0%, 0.4));mix-blend-mode:multiply;transition-property:opacity}.jw-state-idle.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0.2), hsla(0, 0%, 0%, 0.19606) 1.17%, hsla(0, 0%, 0%, 0.18519) 4.49%, hsla(0, 0%, 0%, 0.16875) 9.72%, hsla(0, 0%, 0%, 0.14815) 16.59%, hsla(0, 0%, 0%, 0.12477) 24.86%, hsla(0, 0%, 0%, 0.1) 34.25%, hsla(0, 0%, 0%, 0.07523) 44.52%, hsla(0, 0%, 0%, 0.05185) 55.41%, hsla(0, 0%, 0%, 0.03125) 66.66%, hsla(0, 0%, 0%, 0.01481) 78.01%, hsla(0, 0%, 0%, 0.00394) 89.21%, hsla(0, 0%, 0%, 0));background-size:100% 7rem;background-position:50% 0}.jwplayer.jw-ab-drop-shadow.jw-state-idle .jw-controls{background-color:transparent}}.jw-video-thumbnail-container{position:relative;overflow:hidden}.jw-video-thumbnail-container:not(.jw-related-shelf-item-image){height:100%;width:100%}.jw-video-thumbnail-container.jw-video-thumbnail-generated{position:absolute;top:0;left:0}.jw-video-thumbnail-container:hover,.jw-related-item-content:hover .jw-video-thumbnail-container,.jw-related-shelf-item:hover .jw-video-thumbnail-container{cursor:pointer}.jw-video-thumbnail-container:hover .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-item-content:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-shelf-item:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail{position:absolute;top:50%;left:50%;bottom:unset;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);width:100%;height:auto;min-width:100%;min-height:100%;opacity:0;transition:opacity .3s ease;object-fit:cover;background:#000}.jw-related-item-next-up .jw-video-thumbnail-container .jw-video-thumbnail{height:100%;width:auto}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-visible:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-completed{opacity:0}.jw-video-thumbnail-container .jw-video-thumbnail~.jw-svg-icon-play{display:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-shelf-item-aspect{pointer-events:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-item-poster-content{pointer-events:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-state-idle .jw-controls{background:rgba(0,0,0,0.4)}.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay),.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay){display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon:focus{border:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon .jw-svg-icon-buffer{-webkit-animation:jw-spin 2s linear infinite;animation:jw-spin 2s linear infinite;display:block}@-webkit-keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.jwplayer.jw-state-buffering .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-pause{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-pause{display:block}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-controls-backdrop{opacity:0}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-logo-bottom-left,.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio):not(.jw-flag-autostart) .jw-logo-bottom-right{bottom:0}.jwplayer .jw-icon-playback .jw-svg-icon-stop{display:none}.jwplayer.jw-state-paused .jw-svg-icon-pause,.jwplayer.jw-state-idle .jw-svg-icon-pause,.jwplayer.jw-state-error .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-svg-icon-pause{display:none}.jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-complete .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-play{display:none}.jwplayer:not(.jw-state-buffering) .jw-svg-icon-buffer{display:none}.jwplayer:not(.jw-state-complete) .jw-svg-icon-replay{display:none}.jwplayer:not(.jw-state-error) .jw-svg-icon-error{display:none}.jwplayer.jw-state-complete .jw-display .jw-icon-display .jw-svg-icon-replay{display:block}.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-state-complete .jw-controls{background:rgba(0,0,0,0.4);height:100%}.jw-state-idle .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-state-idle .jw-display-icon-rewind,.jwplayer.jw-state-buffering .jw-display-icon-rewind,.jwplayer.jw-state-complete .jw-display-icon-rewind,body .jw-error .jw-display-icon-rewind,body .jwplayer.jw-state-error .jw-display-icon-rewind,.jw-state-idle .jw-display-icon-next,.jwplayer.jw-state-buffering .jw-display-icon-next,.jwplayer.jw-state-complete .jw-display-icon-next,body .jw-error .jw-display-icon-next,body .jwplayer.jw-state-error .jw-display-icon-next{display:none}body .jw-error .jw-icon-display,body .jwplayer.jw-state-error .jw-icon-display{cursor:default}body .jw-error .jw-icon-display .jw-svg-icon-error,body .jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-error{display:block}body .jw-error .jw-icon-container{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-preview{display:none}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title{padding-top:4px}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-primary{width:auto;display:inline-block;padding-right:.5ch}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-secondary{width:auto;display:inline-block;padding-left:0}body .jwplayer.jw-state-error .jw-controlbar,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-controlbar{display:none}body .jwplayer.jw-state-error .jw-settings-menu,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-settings-menu{height:100%;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}body .jwplayer.jw-state-error .jw-display,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-display{padding:0}body .jwplayer.jw-state-error .jw-logo-bottom-left,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-left,body .jwplayer.jw-state-error .jw-logo-bottom-right,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-right{bottom:0}.jwplayer.jw-state-playing.jw-flag-user-inactive .jw-display{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-state-playing:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display,.jwplayer.jw-state-paused:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting):not(.jw-flag-play-rejected) .jw-display{display:none}.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-rewind,.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-next{display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-text,.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-flag-casting:not(.jw-flag-audio-player) .jw-cast{display:block}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-display-icon-container{display:none}.jwplayer.jw-flag-casting .jw-icon-hd,.jwplayer.jw-flag-casting .jw-captions,.jwplayer.jw-flag-casting .jw-icon-fullscreen,.jwplayer.jw-flag-casting .jw-icon-audio-tracks{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-volume{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-airplay{color:#fff}.jw-state-playing.jw-flag-casting:not(.jw-flag-audio-player) .jw-display,.jw-state-paused.jw-flag-casting:not(.jw-flag-audio-player) .jw-display{display:table}.jwplayer.jw-flag-cast-available .jw-icon-cast,.jwplayer.jw-flag-cast-available .jw-icon-airplay{display:flex}.jwplayer.jw-flag-cardboard-available .jw-icon-cardboard{display:flex}.jwplayer.jw-flag-live .jw-display-icon-rewind{visibility:hidden}.jwplayer.jw-flag-live .jw-controlbar .jw-text-elapsed,.jwplayer.jw-flag-live .jw-controlbar .jw-text-duration,.jwplayer.jw-flag-live .jw-controlbar .jw-text-countdown,.jwplayer.jw-flag-live .jw-controlbar .jw-slider-time{display:none}.jwplayer.jw-flag-live .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-live .jw-controlbar .jw-overlay:after{display:none}.jwplayer.jw-flag-live .jw-nextup-container{bottom:44px}.jwplayer.jw-flag-live .jw-text-elapsed,.jwplayer.jw-flag-live .jw-text-duration{display:none}.jwplayer.jw-flag-live .jw-text-live{cursor:default}.jwplayer.jw-flag-live .jw-text-live:hover{color:rgba(255,255,255,0.8)}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-stop,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-stop{display:block}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-text-live{height:24px;width:auto;align-items:center;border-radius:1px;color:rgba(255,255,255,0.8);display:flex;font-size:12px;font-weight:bold;margin-right:10px;padding:0 1ch;text-rendering:geometricPrecision;text-transform:uppercase;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:box-shadow,color}.jw-text-live::before{height:8px;width:8px;background-color:currentColor;border-radius:50%;margin-right:6px;opacity:1;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-text-live.jw-dvr-live{box-shadow:inset 0 0 0 2px currentColor}.jw-text-live.jw-dvr-live::before{opacity:.5}.jw-text-live.jw-dvr-live:hover{color:#fff}.jwplayer.jw-flag-controls-hidden .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-controls-hidden:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-controls-hidden .jw-plugin{bottom:.5em}.jwplayer.jw-flag-controls-hidden .jw-nextup-container{bottom:0}.jw-flag-controls-hidden .jw-controlbar,.jw-flag-controls-hidden .jw-display{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-controls-hidden .jw-controls-backdrop{opacity:0}.jw-flag-controls-hidden .jw-logo{visibility:visible}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-plugin{bottom:.5em}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-nextup-container{bottom:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-controls-hidden) .jw-media{cursor:none;-webkit-cursor-visibility:auto-hide}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing.jw-flag-casting .jw-display{display:table}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-ads) .jw-autostart-mute{display:flex}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting .jw-nextup-container{bottom:66px}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting.jw-state-idle .jw-nextup-container{display:none}.jw-flag-media-audio .jw-preview{display:block}.jwplayer.jw-flag-ads .jw-preview,.jwplayer.jw-flag-ads .jw-logo,.jwplayer.jw-flag-ads .jw-captions.jw-captions-enabled,.jwplayer.jw-flag-ads .jw-nextup-container,.jwplayer.jw-flag-ads .jw-text-duration,.jwplayer.jw-flag-ads .jw-text-elapsed{display:none}.jwplayer.jw-flag-ads video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-rewind,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-next,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-display{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player.jw-state-buffering .jw-display-icon-display{display:inline-block}.jwplayer.jw-flag-ads .jw-controlbar{flex-wrap:wrap-reverse}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time{height:auto;padding:0;pointer-events:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-slider-container{height:5px}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-rail,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-knob,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-buffer,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-cue,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-icon-settings{display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-progress{-webkit-transform:none;transform:none;top:auto}.jwplayer.jw-flag-ads .jw-controlbar .jw-tooltip,.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-tooltip:not(.jw-icon-volume),.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-inline:not(.jw-icon-playback):not(.jw-icon-fullscreen):not(.jw-icon-volume){display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-volume-tip{padding:13px 0}.jwplayer.jw-flag-ads .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid) .jw-controls .jw-controlbar,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart .jw-controls .jw-controlbar{display:flex;pointer-events:all;visibility:visible;opacity:1}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-user-inactive .jw-controls-backdrop,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart.jw-flag-user-inactive .jw-controls-backdrop{opacity:1;background-size:100% 60px}.jwplayer.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-ads-vpaid .jw-skip,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-skip{display:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls{background:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls::after{content:none}.jwplayer.jw-flag-ads-hide-controls .jw-controls-backdrop,.jwplayer.jw-flag-ads-hide-controls .jw-controls{display:none !important}.jw-flag-overlay-open-related .jw-controls,.jw-flag-overlay-open-related .jw-title,.jw-flag-overlay-open-related .jw-logo{display:none}.jwplayer.jw-flag-rightclick-open{overflow:visible}.jwplayer.jw-flag-rightclick-open .jw-rightclick{z-index:16777215}body .jwplayer.jw-flag-flash-blocked .jw-controls,body .jwplayer.jw-flag-flash-blocked .jw-overlays,body .jwplayer.jw-flag-flash-blocked .jw-controls-backdrop,body .jwplayer.jw-flag-flash-blocked .jw-preview{display:none}body .jwplayer.jw-flag-flash-blocked .jw-error-msg{top:25%}.jw-flag-touch.jw-breakpoint-7 .jw-captions,.jw-flag-touch.jw-breakpoint-6 .jw-captions,.jw-flag-touch.jw-breakpoint-5 .jw-captions,.jw-flag-touch.jw-breakpoint-4 .jw-captions,.jw-flag-touch.jw-breakpoint-7 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-6 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-5 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-4 .jw-nextup-container{bottom:4.25em}.jw-flag-touch .jw-controlbar .jw-icon-volume{display:flex}.jw-flag-touch .jw-display,.jw-flag-touch .jw-display-container,.jw-flag-touch .jw-display-controls{pointer-events:none}.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-rewind,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-rewind{display:none}.jw-flag-touch.jw-state-paused.jw-flag-dragging .jw-display{display:none}.jw-flag-audio-player{background-color:#000}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:44px}.jw-flag-audio-player:not(.jw-flag-live) .jw-spacer{display:none}.jw-flag-audio-player .jw-preview,.jw-flag-audio-player .jw-display,.jw-flag-audio-player .jw-title,.jw-flag-audio-player .jw-nextup-container{display:none}.jw-flag-audio-player .jw-controlbar{position:relative}.jw-flag-audio-player .jw-controlbar .jw-button-container{padding-right:3px;padding-left:0}.jw-flag-audio-player .jw-controlbar .jw-icon-tooltip,.jw-flag-audio-player .jw-controlbar .jw-icon-inline{display:none}.jw-flag-audio-player .jw-controlbar .jw-icon-volume,.jw-flag-audio-player .jw-controlbar .jw-icon-playback,.jw-flag-audio-player .jw-controlbar .jw-icon-next,.jw-flag-audio-player .jw-controlbar .jw-icon-rewind,.jw-flag-audio-player .jw-controlbar .jw-icon-cast,.jw-flag-audio-player .jw-controlbar .jw-text-live,.jw-flag-audio-player .jw-controlbar .jw-icon-airplay,.jw-flag-audio-player .jw-controlbar .jw-logo-button,.jw-flag-audio-player .jw-controlbar .jw-text-elapsed,.jw-flag-audio-player .jw-controlbar .jw-text-duration{display:flex;flex:0 0 auto}.jw-flag-audio-player .jw-controlbar .jw-text-duration,.jw-flag-audio-player .jw-controlbar .jw-text-countdown{padding-right:10px}.jw-flag-audio-player .jw-controlbar .jw-slider-time{flex:0 1 auto;align-items:center;display:flex;order:1}.jw-flag-audio-player .jw-controlbar .jw-icon-volume{margin-right:0;transition:margin-right 150ms cubic-bezier(0, .25, .25, 1)}.jw-flag-audio-player .jw-controlbar .jw-icon-volume .jw-overlay{display:none}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container{transition:width 300ms cubic-bezier(0, .25, .25, 1);width:0}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open{width:140px}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open .jw-slider-volume{padding-right:24px;transition:opacity 300ms;opacity:1}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open~.jw-slider-time{flex:1 1 auto;width:auto;transition:opacity 300ms, width 300ms}.jw-flag-audio-player .jw-controlbar .jw-slider-volume{opacity:0}.jw-flag-audio-player .jw-controlbar .jw-slider-volume .jw-knob{-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.jw-flag-audio-player .jw-controlbar .jw-slider-volume~.jw-icon-volume{margin-right:140px}.jw-flag-audio-player.jw-breakpoint-1 .jw-horizontal-volume-container.jw-open~.jw-slider-time,.jw-flag-audio-player.jw-breakpoint-2 .jw-horizontal-volume-container.jw-open~.jw-slider-time{opacity:0}.jw-flag-audio-player.jw-flag-small-player .jw-text-elapsed,.jw-flag-audio-player.jw-flag-small-player .jw-text-duration{display:none}.jw-flag-audio-player.jw-flag-ads .jw-slider-time{display:none}.jw-hidden{display:none}',""])}]]); \ No newline at end of file diff --git a/ui/v2.5/public/jwplayer/jwplayer.core.controls.polyfills.js b/ui/v2.5/public/jwplayer/jwplayer.core.controls.polyfills.js new file mode 100644 index 000000000..0ad8f2471 --- /dev/null +++ b/ui/v2.5/public/jwplayer/jwplayer.core.controls.polyfills.js @@ -0,0 +1,95 @@ +/*! +JW Player version 8.11.5 +Copyright (c) 2019, JW Player, All Rights Reserved +https://github.com/jwplayer/jwplayer/blob/v8.11.5/README.md + +This source code and its use and distribution is subject to the terms and conditions of the applicable license agreement. +https://www.jwplayer.com/tos/ + +This product includes portions of other software. For the full text of licenses, see below: + +JW Player Third Party Software Notices and/or Additional Terms and Conditions + +************************************************************************************************** +The following software is used under Apache License 2.0 +************************************************************************************************** + +vtt.js v0.13.0 +Copyright (c) 2019 Mozilla (http://mozilla.org) +https://github.com/mozilla/vtt.js/blob/v0.13.0/LICENSE + +* * * + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. + +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. + +************************************************************************************************** +The following software is used under MIT license +************************************************************************************************** + +Underscore.js v1.6.0 +Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative +https://github.com/jashkenas/underscore/blob/1.6.0/LICENSE + +Backbone backbone.events.js v1.1.2 +Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud +https://github.com/jashkenas/backbone/blob/1.1.2/LICENSE + +Promise Polyfill v7.1.1 +Copyright (c) 2014 Taylor Hakes and Forbes Lindesay +https://github.com/taylorhakes/promise-polyfill/blob/v7.1.1/LICENSE + +can-autoplay.js v3.0.0 +Copyright (c) 2017 video-dev +https://github.com/video-dev/can-autoplay/blob/v3.0.0/LICENSE + +* * * + +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. + +************************************************************************************************** +The following software is used under W3C license +************************************************************************************************** + +Intersection Observer v0.5.0 +Copyright (c) 2016 Google Inc. (http://google.com) +https://github.com/w3c/IntersectionObserver/blob/v0.5.0/LICENSE.md + +* * * + +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. + +This work is being provided by the copyright holders under the following license. + +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. + +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. + +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. +*/ +(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[5,1,2,3,7],[,,,,,,,,,,,,,,,,,function(t,e,n){"use strict";n.r(e);var i,o=n(8),a=n(3),r=n(7),s=n(43),l=n(5),c=n(15),u=n(40);function d(t){return i||(i=new DOMParser),Object(l.r)(Object(l.s)(i.parseFromString(t,"image/svg+xml").documentElement))}var p=function(t,e,n,i){var o=document.createElement("div");o.className="jw-icon jw-icon-inline jw-button-color jw-reset "+t,o.setAttribute("role","button"),o.setAttribute("tabindex","0"),n&&o.setAttribute("aria-label",n),o.style.display="none";var a=new u.a(o).on("click tap enter",e||function(){});return i&&Array.prototype.forEach.call(i,(function(t){"string"==typeof t?o.appendChild(d(t)):o.appendChild(t)})),{ui:a,element:function(){return o},toggle:function(t){t?this.show():this.hide()},show:function(){o.style.display=""},hide:function(){o.style.display="none"}}},w=n(0),h=n(71),f=n.n(h),j=n(72),g=n.n(j),b=n(73),m=n.n(b),v=n(74),y=n.n(v),k=n(75),x=n.n(k),O=n(76),C=n.n(O),M=n(77),T=n.n(M),S=n(78),_=n.n(S),E=n(79),z=n.n(E),P=n(80),A=n.n(P),I=n(81),R=n.n(I),L=n(82),B=n.n(L),V=n(83),N=n.n(V),H=n(84),F=n.n(H),q=n(85),D=n.n(q),U=n(86),W=n.n(U),Q=n(62),Y=n.n(Q),X=n(87),Z=n.n(X),K=n(88),J=n.n(K),G=n(89),$=n.n(G),tt=n(90),et=n.n(tt),nt=n(91),it=n.n(nt),ot=n(92),at=n.n(ot),rt=n(93),st=n.n(rt),lt=n(94),ct=n.n(lt),ut=null;function dt(t){var e=ft().querySelector(wt(t));if(e)return ht(e);throw new Error("Icon not found "+t)}function pt(t){var e=ft().querySelectorAll(t.split(",").map(wt).join(","));if(!e.length)throw new Error("Icons not found "+t);return Array.prototype.map.call(e,(function(t){return ht(t)}))}function wt(t){return".jw-svg-icon-".concat(t)}function ht(t){return t.cloneNode(!0)}function ft(){return ut||(ut=d(""+f.a+g.a+m.a+y.a+x.a+C.a+T.a+_.a+z.a+A.a+R.a+B.a+N.a+F.a+D.a+W.a+Y.a+Z.a+J.a+$.a+et.a+it.a+at.a+st.a+ct.a+"")),ut}var jt=n(10);function gt(t,e){for(var n=0;n10&&delete bt[e[0]];var n=d(t);bt[t]=n}return bt[t].cloneNode(!0)}(e):((r=document.createElement("div")).className="jw-icon jw-button-image jw-button-color jw-reset",e&&Object(jt.d)(r,{backgroundImage:"url(".concat(e,")")})),s.appendChild(r),new u.a(s).on("click tap enter",i,this),s.addEventListener("mousedown",(function(t){t.preventDefault()})),this.id=o,this.buttonElement=s}var e,n,i;return e=t,(n=[{key:"element",value:function(){return this.buttonElement}},{key:"toggle",value:function(t){t?this.show():this.hide()}},{key:"show",value:function(){this.buttonElement.style.display=""}},{key:"hide",value:function(){this.buttonElement.style.display="none"}}])&>(e.prototype,n),i&>(e,i),t}(),vt=n(11);function yt(t,e){for(var n=0;n=0&&(e.left-=n,e.right-=n),e},xt=function(){function t(e,n){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),Object(w.g)(this,r.a),this.className=e+" jw-background-color jw-reset",this.orientation=n}var e,n,i;return e=t,(n=[{key:"setup",value:function(){this.el=Object(l.e)(function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return''}(this.className,"jw-slider-"+this.orientation)),this.elementRail=this.el.getElementsByClassName("jw-slider-container")[0],this.elementBuffer=this.el.getElementsByClassName("jw-buffer")[0],this.elementProgress=this.el.getElementsByClassName("jw-progress")[0],this.elementThumb=this.el.getElementsByClassName("jw-knob")[0],this.ui=new u.a(this.element(),{preventScrolling:!0}).on("dragStart",this.dragStart,this).on("drag",this.dragMove,this).on("dragEnd",this.dragEnd,this).on("click tap",this.tap,this)}},{key:"dragStart",value:function(){this.trigger("dragStart"),this.railBounds=kt(this.elementRail)}},{key:"dragEnd",value:function(t){this.dragMove(t),this.trigger("dragEnd")}},{key:"dragMove",value:function(t){var e,n,i=this.railBounds=this.railBounds?this.railBounds:kt(this.elementRail);return n="horizontal"===this.orientation?(e=t.pageX)i.right?100:100*Object(s.a)((e-i.left)/i.width,0,1):(e=t.pageY)>=i.bottom?0:e<=i.top?100:100*Object(s.a)((i.height-(e-i.top))/i.height,0,1),this.render(n),this.update(n),!1}},{key:"tap",value:function(t){this.railBounds=kt(this.elementRail),this.dragMove(t)}},{key:"limit",value:function(t){return t}},{key:"update",value:function(t){this.trigger("update",{percentage:t})}},{key:"render",value:function(t){t=Math.max(0,Math.min(t,100)),"horizontal"===this.orientation?(this.elementThumb.style.left=t+"%",this.elementProgress.style.width=t+"%"):(this.elementThumb.style.bottom=t+"%",this.elementProgress.style.height=t+"%")}},{key:"updateBuffer",value:function(t){this.elementBuffer.style.width=t+"%"}},{key:"element",value:function(){return this.el}}])&&yt(e.prototype,n),i&&yt(e,i),t}(),Ot=function(t,e){t&&e&&(t.setAttribute("aria-label",e),t.setAttribute("role","button"),t.setAttribute("tabindex","0"))};function Ct(t,e){for(var n=0;n0&&Array.prototype.forEach.call(o,(function(t){"string"==typeof t?a.el.appendChild(d(t)):a.el.appendChild(t)}))}var e,n,i;return e=t,(n=[{key:"addContent",value:function(t){this.content&&this.removeContent(),this.content=t,this.tooltip.appendChild(t)}},{key:"removeContent",value:function(){this.content&&(this.tooltip.removeChild(this.content),this.content=null)}},{key:"hasContent",value:function(){return!!this.content}},{key:"element",value:function(){return this.el}},{key:"openTooltip",value:function(t){this.isOpen||(this.trigger("open-"+this.componentType,t,{isOpen:!0}),this.isOpen=!0,Object(l.v)(this.el,this.openClass,this.isOpen))}},{key:"closeTooltip",value:function(t){this.isOpen&&(this.trigger("close-"+this.componentType,t,{isOpen:!1}),this.isOpen=!1,Object(l.v)(this.el,this.openClass,this.isOpen))}},{key:"toggleOpenState",value:function(t){this.isOpen?this.closeTooltip(t):this.openTooltip(t)}}])&&Ct(e.prototype,n),i&&Ct(e,i),t}(),Tt=n(22),St=n(57);function _t(t,e){for(var n=0;n=this.thumbnails.length&&(e=this.thumbnails.length-1);var n=this.thumbnails[e].img;return n.indexOf("://")<0&&(n=this.vttPath?this.vttPath+"/"+n:n),n},loadThumbnail:function(t){var e=this.chooseThumbnail(t),n={margin:"0 auto",backgroundPosition:"0 0"};if(e.indexOf("#xywh")>0)try{var i=/(.+)#xywh=(\d+),(\d+),(\d+),(\d+)/.exec(e);e=i[1],n.backgroundPosition=-1*i[2]+"px "+-1*i[3]+"px",n.width=i[4],this.timeTip.setWidth(+n.width),n.height=i[5]}catch(t){return}else this.individualImage||(this.individualImage=new Image,this.individualImage.onload=Object(w.a)((function(){this.individualImage.onload=null,this.timeTip.image({width:this.individualImage.width,height:this.individualImage.height}),this.timeTip.setWidth(this.individualImage.width)}),this),this.individualImage.src=e);return n.backgroundImage='url("'+e+'")',n},showThumbnail:function(t){this._model.get("containerWidth")<=420||this.thumbnails.length<1||this.timeTip.image(this.loadThumbnail(t))},resetThumbnails:function(){this.timeTip.image({backgroundImage:"",width:0,height:0}),this.thumbnails=[]}};function It(t,e,n){return(It="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,n){var i=function(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=Ht(t)););return t}(t,e);if(i){var o=Object.getOwnPropertyDescriptor(i,e);return o.get?o.get.call(n):o.value}})(t,e,n||t)}function Rt(t){return(Rt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function Lt(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Bt(t,e){for(var n=0;n-1&&(i="Live")}var d=this.timeTip;d.update(i),this.textLength!==i.length&&(this.textLength=i.length,d.resetWidth()),this.showThumbnail(u),Object(l.a)(d.el,"jw-open");var p=d.getWidth(),w=a.width/100,h=o-a.width,f=0;p>h&&(f=(p-h)/(200*w));var j=100*Math.min(1-f,Math.max(f,c)).toFixed(3);Object(jt.d)(d.el,{left:j+"%"})}}},{key:"hideTimeTooltip",value:function(){Object(l.o)(this.timeTip.el,"jw-open")}},{key:"updateCues",value:function(t,e){var n=this;this.resetCues(),e&&e.length&&(e.forEach((function(t){n.addCue(t)})),this.drawCues())}},{key:"updateAriaText",value:function(){var t=this._model;if(!t.get("seeking")){var e=t.get("position"),n=t.get("duration"),i=Object(vt.timeFormat)(e);"DVR"!==this.streamType&&(i+=" of ".concat(Object(vt.timeFormat)(n)));var o=this.el;document.activeElement!==o&&(this.timeUpdateKeeper.textContent=i),Object(l.t)(o,"aria-valuenow",e),Object(l.t)(o,"aria-valuetext",i)}}},{key:"reset",value:function(){this.resetThumbnails(),this.timeTip.resetWidth(),this.textLength=0}}]),e}(xt);Object(w.g)(Ut.prototype,zt,At);var Wt=Ut;function Qt(t,e){for(var n=0;n=75&&!t),Object(l.t)(r,"aria-valuenow",o),Object(l.t)(s,"aria-valuenow",o);var c="Volume ".concat(o,"%");Object(l.t)(r,"aria-valuetext",c),Object(l.t)(s,"aria-valuetext",c),document.activeElement!==r&&document.activeElement!==s&&(this._volumeAnnouncer.textContent=c)}}},{key:"onCastAvailable",value:function(t,e){this.elements.cast.toggle(e)}},{key:"onCastActive",value:function(t,e){this.elements.fullscreen.toggle(!e),this.elements.cast.button&&Object(l.v)(this.elements.cast.button,"jw-off",!e)}},{key:"onElapsed",value:function(t,e){var n,i,o=t.get("duration");if("DVR"===t.get("streamType")){var a=Math.ceil(e),r=this._model.get("dvrSeekLimit");n=i=a>=-r?"":"-"+Object(vt.timeFormat)(-(e+r)),t.set("dvrLive",a>=-r)}else n=Object(vt.timeFormat)(e),i=Object(vt.timeFormat)(o-e);this.elements.elapsed.textContent=n,this.elements.countdown.textContent=i}},{key:"onDuration",value:function(t,e){this.elements.duration.textContent=Object(vt.timeFormat)(Math.abs(e))}},{key:"onAudioMode",value:function(t,e){var n=this.elements.time.element();e?this.elements.buttonContainer.insertBefore(n,this.elements.elapsed):Object(l.m)(this.el,n)}},{key:"element",value:function(){return this.el}},{key:"setAltText",value:function(t,e){this.elements.alt.textContent=e}},{key:"closeMenus",value:function(t){this.menus.forEach((function(e){t&&t.target===e.el||e.closeTooltip(t)}))}},{key:"rewind",value:function(){var t,e=0,n=this._model.get("currentTime");n?t=n-10:(t=this._model.get("position")-10,"DVR"===this._model.get("streamType")&&(e=this._model.get("duration"))),this._api.seek(Math.max(t,e),{reason:"interaction"})}},{key:"onState",value:function(t,e){var n=t.get("localization"),i=n.play;this.setPlayText(i),e===a.pb&&("LIVE"!==t.get("streamType")?(i=n.pause,this.setPlayText(i)):(i=n.stop,this.setPlayText(i))),Object(l.t)(this.elements.play.element(),"aria-label",i)}},{key:"onStreamTypeChange",value:function(t,e){var n="LIVE"===e,i="DVR"===e;this.elements.rewind.toggle(!n),this.elements.live.toggle(n||i),Object(l.t)(this.elements.live.element(),"tabindex",n?"-1":"0"),this.elements.duration.style.display=i?"none":"",this.onDuration(t,t.get("duration")),this.onState(t,t.get("state"))}},{key:"addLogo",value:function(t){var e=this.elements.buttonContainer,n=new mt(t.file,this._model.get("localization").logo,(function(){t.link&&Object(l.l)(t.link,"_blank",{rel:"noreferrer"})}),"logo","jw-logo-button");t.link||Object(l.t)(n.element(),"tabindex","-1"),e.insertBefore(n.element(),e.querySelector(".jw-spacer").nextSibling)}},{key:"goToLiveEdge",value:function(){if("DVR"===this._model.get("streamType")){var t=Math.min(this._model.get("position"),-1),e=this._model.get("dvrSeekLimit");this._api.seek(Math.max(-e,t),{reason:"interaction"}),this._api.play({reason:"interaction"})}}},{key:"updateButtons",value:function(t,e,n){if(e){var i,o,a=this.elements.buttonContainer;e!==n&&n?(i=ce(e,n),o=ce(n,e),this.removeButtons(a,o)):i=e;for(var r=i.length-1;r>=0;r--){var s=i[r],l=new mt(s.img,s.tooltip,s.callback,s.id,s.btnClass);s.tooltip&&ie(l.element(),s.id,s.tooltip);var c=void 0;"related"===l.id?c=this.elements.settingsButton.element():"share"===l.id?c=a.querySelector('[button="related"]')||this.elements.settingsButton.element():(c=this.elements.spacer.nextSibling)&&"logo"===c.getAttribute("button")&&(c=c.nextSibling),a.insertBefore(l.element(),c)}}}},{key:"removeButtons",value:function(t,e){for(var n=e.length;n--;){var i=t.querySelector('[button="'.concat(e[n].id,'"]'));i&&t.removeChild(i)}}},{key:"toggleCaptionsButtonState",value:function(t){var e=this.elements.captionsButton;e&&Object(l.v)(e.element(),"jw-off",!t)}},{key:"destroy",value:function(){var t=this;this._model.off(null,null,this),Object.keys(this.elements).forEach((function(e){var n=t.elements[e];n&&"function"==typeof n.destroy&&t.elements[e].destroy()})),this.ui.forEach((function(t){t.destroy()})),this.ui=[]}}])&&ae(e.prototype,n),i&&ae(e,i),t}(),pe=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return'
    ')+'
    ')+"
    "},we=function(t){return'
    '+pe("rewind",t.rewind)+pe("display",t.playback)+pe("next",t.next)+"
    "};function he(t,e){for(var n=0;n'.concat(a.playback,"")),Object(l.a)(o.icon,"jw-idle-label"),o.icon.appendChild(s))}return o}var n,i,o;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&ve(t,e)}(e,t),n=e,(i=[{key:"element",value:function(){return this.el}}])&&ge(n.prototype,i),o&&ge(n,o),e}(r.a);function ke(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"";return'
    '+'
    '.concat(t,"
    ")+'
    '.concat(e,"
    ")+'
    '.concat(n,"
    ")+"
    "+'')+"
    "}());e.querySelector(".jw-nextup-close").appendChild(dt("close")),this.addContent(e),this.closeButton=this.content.querySelector(".jw-nextup-close"),this.closeButton.setAttribute("aria-label",this.localization.close),this.tooltip=this.content.querySelector(".jw-nextup-tooltip");var n=this._model,i=n.player;this.enabled=!1,n.on("change:nextUp",this.onNextUp,this),i.change("duration",this.onDuration,this),i.change("position",this.onElapsed,this),i.change("streamType",this.onStreamType,this),i.change("state",(function(t,e){"complete"===e&&this.toggle(!1)}),this),this.closeUi=new u.a(this.closeButton,{directSelect:!0}).on("click tap enter",(function(){this.nextUpSticky=!1,this.toggle(!1)}),this),this.tooltipUi=new u.a(this.tooltip).on("click tap",this.click,this)}},{key:"loadThumbnail",value:function(t){return this.nextUpImage=new Image,this.nextUpImage.onload=function(){this.nextUpImage.onload=null}.bind(this),this.nextUpImage.src=t,{backgroundImage:'url("'+t+'")'}}},{key:"click",value:function(){var t=this.feedShownId;this.reset(),this._api.next({feedShownId:t,reason:"interaction"})}},{key:"toggle",value:function(t,e){if(this.enabled&&(Object(l.v)(this.container,"jw-nextup-sticky",!!this.nextUpSticky),this.shown!==t)){this.shown=t,Object(l.v)(this.container,"jw-nextup-container-visible",t),Object(l.v)(this._playerElement,"jw-flag-nextup",t);var n=this._model.get("nextUp");t&&n?(this.feedShownId=Object(oe.b)(oe.a),this.trigger("nextShown",{mode:n.mode,ui:"nextup",itemsShown:[n],feedData:n.feedData,reason:e,feedShownId:this.feedShownId})):this.feedShownId=""}}},{key:"setNextUpItem",value:function(t){var e=this;setTimeout((function(){if(e.thumbnail=e.content.querySelector(".jw-nextup-thumbnail"),Object(l.v)(e.content,"jw-nextup-thumbnail-visible",!!t.image),t.image){var n=e.loadThumbnail(t.image);Object(jt.d)(e.thumbnail,n)}e.header=e.content.querySelector(".jw-nextup-header"),e.header.textContent=Object(l.e)(e.localization.nextUp).textContent,e.title=e.content.querySelector(".jw-nextup-title");var i=t.title;e.title.textContent=i?Object(l.e)(i).textContent:"";var o=t.duration;o&&(e.duration=e.content.querySelector(".jw-nextup-duration"),e.duration.textContent="number"==typeof o?Object(vt.timeFormat)(o):o)}),500)}},{key:"onNextUp",value:function(t,e){this.reset(),e||(e={showNextUp:!1}),this.enabled=!(!e.title&&!e.image),this.enabled&&(e.showNextUp||(this.nextUpSticky=!1,this.toggle(!1)),this.setNextUpItem(e))}},{key:"onDuration",value:function(t,e){if(e){var n=t.get("nextupoffset"),i=-10;n&&(i=Object(Te.d)(n,e)),i<0&&(i+=e),Object(Te.c)(n)&&e-5=this.offset;i&&void 0===n?(this.nextUpSticky=i,this.toggle(i,"time")):!i&&n&&this.reset()}}},{key:"onStreamType",value:function(t,e){"VOD"!==e&&(this.nextUpSticky=!1,this.toggle(!1))}},{key:"element",value:function(){return this.container}},{key:"addContent",value:function(t){this.content&&this.removeContent(),this.content=t,this.container.appendChild(t)}},{key:"removeContent",value:function(){this.content&&(this.container.removeChild(this.content),this.content=null)}},{key:"reset",value:function(){this.nextUpSticky=void 0,this.toggle(!1)}},{key:"destroy",value:function(){this.off(),this._model.off(null,null,this),this.closeUi&&this.closeUi.destroy(),this.tooltipUi&&this.tooltipUi.destroy()}}])&&Se(e.prototype,n),i&&Se(e,i),t}(),Ee=function(t,e){var n=t.featured,i=t.showLogo,o=t.type;return t.logo=i?'':"",'
  • ').concat(ze[o](t,e),"
  • ")},ze={link:function(t){var e=t.link,n=t.title,i=t.logo;return'').concat(i).concat(n||"","")},info:function(t,e){return'")},share:function(t,e){return'")},keyboardShortcuts:function(t,e){return'")}},Pe=n(23),Ae=n(6),Ie=n(13);function Re(t,e){for(var n=0;nJW Player '.concat(t,""),a={items:[{type:"info"},{title:Object(Ie.e)(i)?"".concat(o," ").concat(i):"".concat(i," ").concat(o),type:"link",featured:!0,showLogo:!0,link:"https://jwplayer.com/learn-more?e=".concat(Le[n])}]},r=e.get("provider"),s=a.items;if(r&&r.name.indexOf("flash")>=0){var l="Flash Version "+Object(Ae.a)();s.push({title:l,type:"link",link:"http://www.adobe.com/software/flash/about/"})}return this.shortcutsTooltip&&s.splice(s.length-1,0,{type:"keyboardShortcuts"}),a}},{key:"rightClick",value:function(t){if(this.lazySetup(),this.mouseOverContext)return!1;this.hideMenu(),this.showMenu(t),this.addHideMenuHandlers()}},{key:"getOffset",value:function(t){var e=Object(l.c)(this.wrapperElement),n=t.pageX-e.left,i=t.pageY-e.top;return this.model.get("touchMode")&&(i-=100),{x:n,y:i}}},{key:"showMenu",value:function(t){var e=this,n=this.getOffset(t);return this.el.style.left=n.x+"px",this.el.style.top=n.y+"px",this.outCount=0,Object(l.a)(this.playerContainer,"jw-flag-rightclick-open"),Object(l.a)(this.el,"jw-open"),clearTimeout(this._menuTimeout),this._menuTimeout=setTimeout((function(){return e.hideMenu()}),3e3),!1}},{key:"hideMenu",value:function(t){t&&this.el&&this.el.contains(t.target)||(Object(l.o)(this.playerContainer,"jw-flag-rightclick-open"),Object(l.o)(this.el,"jw-open"))}},{key:"lazySetup",value:function(){var t,e,n,i,o=this,a=(t=this.buildArray(),e=this.model.get("localization"),n=t.items,i=(void 0===n?[]:n).map((function(t){return Ee(t,e)})),'
    '+'
      '.concat(i.join(""),"
    ")+"
    ");if(this.el){if(this.html!==a){this.html=a;var r=Be(a);Object(l.h)(this.el);for(var s=r.childNodes.length;s--;)this.el.appendChild(r.firstChild)}}else this.html=a,this.el=Be(this.html),this.wrapperElement.appendChild(this.el),this.hideMenuHandler=function(t){return o.hideMenu(t)},this.overHandler=function(){o.mouseOverContext=!0},this.outHandler=function(t){o.mouseOverContext=!1,t.relatedTarget&&!o.el.contains(t.relatedTarget)&&++o.outCount>1&&o.hideMenu()},this.infoOverlayHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.infoOverlay.open()},this.shortcutsTooltipHandler=function(){o.mouseOverContext=!1,o.hideMenu(),o.shortcutsTooltip.open()}}},{key:"setup",value:function(t,e,n){this.wrapperElement=n,this.model=t,this.mouseOverContext=!1,this.playerContainer=e,this.ui=new u.a(n).on("longPress",this.rightClick,this)}},{key:"addHideMenuHandlers",value:function(){this.removeHideMenuHandlers(),this.wrapperElement.addEventListener("touchstart",this.hideMenuHandler),document.addEventListener("touchstart",this.hideMenuHandler),o.OS.mobile||(this.wrapperElement.addEventListener("click",this.hideMenuHandler),document.addEventListener("click",this.hideMenuHandler),this.el.addEventListener("mouseover",this.overHandler),this.el.addEventListener("mouseout",this.outHandler)),this.el.querySelector(".jw-info-overlay-item").addEventListener("click",this.infoOverlayHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").addEventListener("click",this.shortcutsTooltipHandler)}},{key:"removeHideMenuHandlers",value:function(){this.wrapperElement&&(this.wrapperElement.removeEventListener("click",this.hideMenuHandler),this.wrapperElement.removeEventListener("touchstart",this.hideMenuHandler)),this.el&&(this.el.querySelector(".jw-info-overlay-item").removeEventListener("click",this.infoOverlayHandler),this.el.removeEventListener("mouseover",this.overHandler),this.el.removeEventListener("mouseout",this.outHandler),this.shortcutsTooltip&&this.el.querySelector(".jw-shortcuts-item").removeEventListener("click",this.shortcutsTooltipHandler)),document.removeEventListener("click",this.hideMenuHandler),document.removeEventListener("touchstart",this.hideMenuHandler)}},{key:"destroy",value:function(){clearTimeout(this._menuTimeout),this.removeHideMenuHandlers(),this.el&&(this.hideMenu(),this.hideMenuHandler=null,this.el=null),this.wrapperElement&&(this.wrapperElement.oncontextmenu=null,this.wrapperElement=null),this.model&&(this.model=null),this.ui&&(this.ui.destroy(),this.ui=null)}}])&&Re(e.prototype,n),i&&Re(e,i),t}(),Ne=function(t){return'")},He=function(t){return'"},Fe=function(t){return'"};function qe(t){return(qe="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function De(t,e){return!e||"object"!==qe(e)&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function Ue(t){return(Ue=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function We(t,e){return(We=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function Qe(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Ye(t,e){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:Ne;Qe(this,t),this.el=Object(l.e)(i(e)),this.ui=new u.a(this.el).on("click tap enter",n,this)}return Xe(t,[{key:"destroy",value:function(){this.ui.destroy()}}]),t}(),Je=function(t){function e(t,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Fe;return Qe(this,e),De(this,Ue(e).call(this,t,n,i))}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&We(t,e)}(e,t),Xe(e,[{key:"activate",value:function(){Object(l.v)(this.el,"jw-settings-item-active",!0),this.el.setAttribute("aria-checked","true"),this.active=!0}},{key:"deactivate",value:function(){Object(l.v)(this.el,"jw-settings-item-active",!1),this.el.setAttribute("aria-checked","false"),this.active=!1}}]),e}(Ke),Ge=function(t,e){return t?'':''},$e=function(t,e){var n=t.name,i={captions:"cc-off",audioTracks:"audio-tracks",quality:"quality-100",playbackRates:"playback-rate"}[n];if(i||t.icon){var o=p("jw-settings-".concat(n," jw-submenu-").concat(n),(function(e){t.open(e)}),n,[t.icon&&Object(l.e)(t.icon)||dt(i)]),a=o.element();return a.setAttribute("role","menuitemradio"),a.setAttribute("aria-checked","false"),a.setAttribute("aria-label",e),"ontouchstart"in window||(o.tooltip=ie(a,n,e)),o}};function tn(t){return(tn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function en(t,e){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:Ge;return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),a=this,(o=!(r=nn(e).call(this))||"object"!==tn(r)&&"function"!=typeof r?an(a):r).open=o.open.bind(an(an(o))),o.close=o.close.bind(an(an(o))),o.toggle=o.toggle.bind(an(an(o))),o.onDocumentClick=o.onDocumentClick.bind(an(an(o))),o.name=t,o.isSubmenu=!!n,o.el=Object(l.e)(s(o.isSubmenu,t)),o.topbar=o.el.querySelector(".jw-".concat(o.name,"-topbar")),o.buttonContainer=o.el.querySelector(".jw-".concat(o.name,"-topbar-buttons")),o.children={},o.openMenus=[],o.items=[],o.visible=!1,o.parentMenu=n,o.mainMenu=o.parentMenu?o.parentMenu.mainMenu:an(an(o)),o.categoryButton=null,o.closeButton=o.parentMenu&&o.parentMenu.closeButton||o.createCloseButton(i),o.isSubmenu?(o.categoryButton=o.parentMenu.categoryButton||o.createCategoryButton(i),o.parentMenu.parentMenu&&!o.mainMenu.backButton&&(o.mainMenu.backButton=o.createBackButton(i)),o.itemsContainer=o.createItemsContainer(),o.parentMenu.appendMenu(an(an(o)))):o.ui=sn(an(an(o))),o}var n,i,o;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&on(t,e)}(e,t),n=e,(i=[{key:"createItemsContainer",value:function(){var t,e,n=this,i=this.el.querySelector(".jw-settings-submenu-items"),o=new u.a(i),a=this.categoryButton&&this.categoryButton.element()||this.parentMenu.categoryButton&&this.parentMenu.categoryButton.element()||this.mainMenu.buttonContainer.firstChild;return this.parentMenu.isSubmenu&&(t=this.mainMenu.closeButton.element(),e=this.mainMenu.backButton.element()),o.on("keydown",(function(o){if(o.target.parentNode===i){var r=function(t,e){t?t.focus():void 0!==e&&i.childNodes[e].focus()},s=o.sourceEvent,c=s.target,u=i.firstChild===c,d=i.lastChild===c,p=n.topbar,w=t||Object(l.k)(a),h=e||Object(l.n)(a),f=Object(l.k)(s.target),j=Object(l.n)(s.target),g=s.key.replace(/(Arrow|ape)/,"");switch(g){case"Tab":r(s.shiftKey?h:w);break;case"Left":r(h||Object(l.n)(document.getElementsByClassName("jw-icon-settings")[0]));break;case"Up":p&&u?r(p.firstChild):r(j,i.childNodes.length-1);break;case"Right":r(w);break;case"Down":p&&d?r(p.firstChild):r(f,0)}s.preventDefault(),"Esc"!==g&&s.stopPropagation()}})),o}},{key:"createCloseButton",value:function(t){var e=p("jw-settings-close",this.close,t.close,[dt("close")]);return this.topbar.appendChild(e.element()),e.show(),e.ui.on("keydown",(function(t){var e=t.sourceEvent,n=e.key.replace(/(Arrow|ape)/,"");("Enter"===n||"Right"===n||"Tab"===n&&!e.shiftKey)&&this.close(t)}),this),this.buttonContainer.appendChild(e.element()),e}},{key:"createCategoryButton",value:function(t){var e=t[{captions:"cc",audioTracks:"audioTracks",quality:"hd",playbackRates:"playbackRates"}[this.name]];"sharing"===this.name&&(e=t.sharing.heading);var n=$e(this,e);return n.element().setAttribute("name",this.name),n}},{key:"createBackButton",value:function(t){var e=p("jw-settings-back",(function(t){Ze&&Ze.open(t)}),t.close,[dt("arrow-left")]);return Object(l.m)(this.mainMenu.topbar,e.element()),e}},{key:"createTopbar",value:function(){var t=Object(l.e)('
    ');return Object(l.m)(this.el,t),t}},{key:"createItems",value:function(t,e){var n=this,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Je,a=this.name,r=t.map((function(t,r){var s,l;switch(a){case"quality":s="Auto"===t.label&&0===r?"".concat(i.defaultText,' '):t.label;break;case"captions":s="Off"!==t.label&&"off"!==t.id||0!==r?t.label:i.defaultText;break;case"playbackRates":l=t,s=Object(Ie.e)(i.tooltipText)?"x"+t:t+"x";break;case"audioTracks":s=t.name}s||(s=t,"object"===tn(t)&&(s.options=i));var c=new o(s,function(t){c.active||(e(l||r),c.deactivate&&(n.items.filter((function(t){return!0===t.active})).forEach((function(t){t.deactivate()})),Ze?Ze.open(t):n.mainMenu.close(t)),c.activate&&c.activate())}.bind(n));return c}));return r}},{key:"setMenuItems",value:function(t,e){var n=this;t?(this.items=[],Object(l.h)(this.itemsContainer.el),t.forEach((function(t){n.items.push(t),n.itemsContainer.el.appendChild(t.el)})),e>-1&&t[e].activate(),this.categoryButton.show()):this.removeMenu()}},{key:"appendMenu",value:function(t){if(t){var e=t.el,n=t.name,i=t.categoryButton;if(this.children[n]=t,i){var o=this.mainMenu.buttonContainer,a=o.querySelector(".jw-settings-sharing"),r="quality"===n?o.firstChild:a||this.closeButton.element();o.insertBefore(i.element(),r)}this.mainMenu.el.appendChild(e)}}},{key:"removeMenu",value:function(t){if(!t)return this.parentMenu.removeMenu(this.name);var e=this.children[t];e&&(delete this.children[t],e.destroy())}},{key:"open",value:function(t){if(!this.visible||this.openMenus){var e;if(Ze=null,this.isSubmenu){var n=this.mainMenu,i=this.parentMenu,o=this.categoryButton;if(i.openMenus.length&&i.closeChildren(),o&&o.element().setAttribute("aria-checked","true"),i.isSubmenu){i.el.classList.remove("jw-settings-submenu-active"),n.topbar.classList.add("jw-nested-menu-open");var a=n.topbar.querySelector(".jw-settings-topbar-text");a.setAttribute("name",this.name),a.innerText=this.title||this.name,n.backButton.show(),Ze=this.parentMenu,e=this.topbar?this.topbar.firstChild:t&&"enter"===t.type?this.items[0].el:a}else n.topbar.classList.remove("jw-nested-menu-open"),n.backButton&&n.backButton.hide();this.el.classList.add("jw-settings-submenu-active"),i.openMenus.push(this.name),n.visible||(n.open(t),this.items&&t&&"enter"===t.type?e=this.topbar?this.topbar.firstChild.focus():this.items[0].el:o.tooltip&&(o.tooltip.suppress=!0,e=o.element())),this.openMenus.length&&this.closeChildren(),e&&e.focus(),this.el.scrollTop=0}else this.el.parentNode.classList.add("jw-settings-open"),this.trigger("menuVisibility",{visible:!0,evt:t}),document.addEventListener("click",this.onDocumentClick);this.visible=!0,this.el.setAttribute("aria-expanded","true")}}},{key:"close",value:function(t){var e=this;this.visible&&(this.visible=!1,this.el.setAttribute("aria-expanded","false"),this.isSubmenu?(this.el.classList.remove("jw-settings-submenu-active"),this.categoryButton.element().setAttribute("aria-checked","false"),this.parentMenu.openMenus=this.parentMenu.openMenus.filter((function(t){return t!==e.name})),!this.mainMenu.openMenus.length&&this.mainMenu.visible&&this.mainMenu.close(t)):(this.el.parentNode.classList.remove("jw-settings-open"),this.trigger("menuVisibility",{visible:!1,evt:t}),document.removeEventListener("click",this.onDocumentClick)),this.openMenus.length&&this.closeChildren())}},{key:"closeChildren",value:function(){var t=this;this.openMenus.forEach((function(e){var n=t.children[e];n&&n.close()}))}},{key:"toggle",value:function(t){this.visible?this.close(t):this.open(t)}},{key:"onDocumentClick",value:function(t){/jw-(settings|video|nextup-close|sharing-link|share-item)/.test(t.target.className)||this.close()}},{key:"destroy",value:function(){var t=this;if(document.removeEventListener("click",this.onDocumentClick),Object.keys(this.children).map((function(e){t.children[e].destroy()})),this.isSubmenu){this.parentMenu.name===this.mainMenu.name&&this.categoryButton&&(this.parentMenu.buttonContainer.removeChild(this.categoryButton.element()),this.categoryButton.ui.destroy()),this.itemsContainer&&this.itemsContainer.destroy();var e=this.parentMenu.openMenus,n=e.indexOf(this.name);e.length&&n>-1&&this.openMenus.splice(n,1),delete this.parentMenu}else this.ui.destroy();this.visible=!1,this.el.parentNode&&this.el.parentNode.removeChild(this.el)}},{key:"defaultChild",get:function(){var t=this.children,e=t.quality,n=t.captions,i=t.audioTracks,o=t.sharing,a=t.playbackRates;return e||n||i||o||a}}])&&en(n.prototype,i),o&&en(n,o),e}(r.a),sn=function(t){var e=t.closeButton,n=t.el;return new u.a(n).on("keydown",(function(n){var i=n.sourceEvent,o=n.target,a=Object(l.k)(o),r=Object(l.n)(o),s=i.key.replace(/(Arrow|ape)/,""),c=function(e){r?e||r.focus():t.close(n)};switch(s){case"Esc":t.close(n);break;case"Left":c();break;case"Right":a&&e.element()&&o!==e.element()&&a.focus();break;case"Tab":i.shiftKey&&c(!0);break;case"Up":case"Down":!function(){var e=t.children[o.getAttribute("name")];if(!e&&Ze&&(e=Ze.children[Ze.openMenus]),e)return e.open(n),void(e.topbar?e.topbar.firstChild.focus():e.items&&e.items.length&&e.items[0].el.focus());if(n.target.parentNode.classList.contains("jw-submenu-topbar")){var i=n.target.parentNode.parentNode.querySelector(".jw-settings-submenu-items");("Down"===s?i.childNodes[0]:i.childNodes[i.childNodes.length-1]).focus()}}()}if(i.stopPropagation(),/13|32|37|38|39|40/.test(i.keyCode))return i.preventDefault(),!1}))},ln=n(59),cn=function(t){return hn[t]},un=function(t){for(var e,n=Object.keys(hn),i=0;i1;n.elements.settingsButton.toggle(c)};e.change("levels",(function(t,e){r(e)}),o);var s=function(t,n,i){var o=e.get("levels");if(o&&"Auto"===o[0].label&&n&&n.items.length){var a=n.items[0].el.querySelector(".jw-auto-label"),r=o[t.index]||{label:""};a.textContent=i?"":r.label}};e.on("change:visualQuality",(function(t,n){var i=o.children.quality;n&&i&&s(n.level,i,e.get("currentLevel"))})),e.on("change:currentLevel",(function(t,n){var i=o.children.quality,a=e.get("visualQuality");a&&i&&s(a.level,i,n)}),o),e.change("captionsList",(function(n,r){var s={defaultText:i.off},l=e.get("captionsIndex");a("captions",r,(function(e){return t.setCurrentCaptions(e)}),l,s);var c=o.children.captions;if(c&&!c.children.captionsSettings){c.topbar=c.topbar||c.createTopbar();var u=new rn("captionsSettings",c,i);u.title="Subtitle Settings";var d=new Ke("Settings",u.open);c.topbar.appendChild(d.el);var p=new Je("Reset",(function(){e.set("captions",ln.a),f()}));p.el.classList.add("jw-settings-reset");var h=e.get("captions"),f=function(){var t=[];wn.forEach((function(n){h&&h[n.propertyName]&&(n.defaultVal=n.getOption(h[n.propertyName]));var o=new rn(n.name,u,i),a=new Ke({label:n.name,value:n.defaultVal},o.open,He),r=o.createItems(n.options,(function(t){var i=a.el.querySelector(".jw-settings-content-item-value");!function(t,n){var i=e.get("captions"),o=t.propertyName,a=t.options&&t.options[n],r=t.getTypedValue(a),s=Object(w.g)({},i);s[o]=r,e.set("captions",s)}(n,t),i.innerText=n.options[t]}),null);o.setMenuItems(r,n.options.indexOf(n.defaultVal)||0),t.push(a)})),t.push(p),u.setMenuItems(t)};f()}}));var l=function(t,e){t&&e>-1&&t.items[e].activate()};e.change("captionsIndex",(function(t,e){var i=o.children.captions;i&&l(i,e),n.toggleCaptionsButtonState(!!e)}),o);var c=function(n){if(e.get("supportsPlaybackRate")&&"LIVE"!==e.get("streamType")&&e.get("playbackRateControls")){var r=n.indexOf(e.get("playbackRate")),s={tooltipText:i.playbackRates};a("playbackRates",n,(function(e){return t.setPlaybackRate(e)}),r,s)}else o.children.playbackRates&&o.removeMenu("playbackRates")};e.on("change:playbackRates",(function(t,e){c(e)}),o);var u=function(n){a("audioTracks",n,(function(e){return t.setCurrentAudioTrack(e)}),e.get("currentAudioTrack"))};return e.on("change:audioTracks",(function(t,e){u(e)}),o),e.on("change:playbackRate",(function(t,n){var i=e.get("playbackRates"),a=-1;i&&(a=i.indexOf(n)),l(o.children.playbackRates,a)}),o),e.on("change:currentAudioTrack",(function(t,e){o.children.audioTracks.items[e].activate()}),o),e.on("change:playlistItem",(function(){o.removeMenu("captions"),n.elements.captionsButton.hide(),o.visible&&o.close()}),o),e.on("change:playbackRateControls",(function(){c(e.get("playbackRates"))})),e.on("change:castActive",(function(t,n,i){n!==i&&(n?(o.removeMenu("audioTracks"),o.removeMenu("quality"),o.removeMenu("playbackRates")):(u(e.get("audioTracks")),r(e.get("levels")),c(e.get("playbackRates"))))}),o),e.on("change:streamType",(function(){c(e.get("playbackRates"))}),o),o},jn=n(58),gn=n(35),bn=n(12),mn=function(t,e,n,i){var o=Object(l.e)('
    '),r=!1,s=null,c=!1,u=function(t){/jw-info/.test(t.target.className)||w.close()},d=function(){var i,a,s,c,u,d=p("jw-info-close",(function(){w.close()}),e.get("localization").close,[dt("close")]);d.show(),Object(l.m)(o,d.element()),a=o.querySelector(".jw-info-title"),s=o.querySelector(".jw-info-duration"),c=o.querySelector(".jw-info-description"),u=o.querySelector(".jw-info-clientid"),e.change("playlistItem",(function(t,e){var n=e.description,i=e.title;Object(l.q)(c,n||""),Object(l.q)(a,i||"Unknown Title")})),e.change("duration",(function(t,n){var i="";switch(e.get("streamType")){case"LIVE":i="Live";break;case"DVR":i="DVR";break;default:n&&(i=Object(vt.timeFormat)(n))}s.textContent=i}),w),u.textContent=(i=n.getPlugin("jwpsrv"))&&"function"==typeof i.doNotTrackUser&&i.doNotTrackUser()?"":"Client ID: ".concat(function(){try{return window.localStorage.jwplayerLocalId}catch(t){return"none"}}()),t.appendChild(o),r=!0};var w={open:function(){r||d(),document.addEventListener("click",u),c=!0;var t=e.get("state");t===a.pb&&n.pause("infoOverlayInteraction"),s=t,i(!0)},close:function(){document.removeEventListener("click",u),c=!1,e.get("state")===a.ob&&s===a.pb&&n.play("infoOverlayInteraction"),s=null,i(!1)},destroy:function(){this.close(),e.off(null,null,this)}};return Object.defineProperties(w,{visible:{enumerable:!0,get:function(){return c}}}),w};var vn=function(t,e,n){var i,o=!1,r=null,s=n.get("localization").shortcuts,c=Object(l.e)(function(t,e){var n=t.map((function(t){return'
    '+''.concat(t.description,"")+''.concat(t.key,"")+"
    "})).join("");return'
    ')+'Press shift question mark to access a list of keyboard shortcuts
    '+''.concat(e,"")+'
    '+"".concat(n)+"
    "}(function(t){var e=t.playPause,n=t.volumeToggle,i=t.fullscreenToggle,o=t.seekPercent,a=t.increaseVolume,r=t.decreaseVolume,s=t.seekForward,l=t.seekBackward;return[{key:t.spacebar,description:e},{key:"↑",description:a},{key:"↓",description:r},{key:"→",description:s},{key:"←",description:l},{key:"c",description:t.captionsToggle},{key:"f",description:i},{key:"m",description:n},{key:"0-9",description:o}]}(s),s.keyboardShortcuts)),d={reason:"settingsInteraction"},w=new u.a(c.querySelector(".jw-switch")),h=function(){w.el.setAttribute("aria-checked",n.get("enableShortcuts")),Object(l.a)(c,"jw-open"),r=n.get("state"),c.querySelector(".jw-shortcuts-close").focus(),document.addEventListener("click",j),o=!0,e.pause(d)},f=function(){Object(l.o)(c,"jw-open"),document.removeEventListener("click",j),t.focus(),o=!1,r===a.pb&&e.play(d)},j=function(t){/jw-shortcuts|jw-switch/.test(t.target.className)||f()},g=function(t){var e=t.currentTarget,i="true"!==e.getAttribute("aria-checked");e.setAttribute("aria-checked",i),n.set("enableShortcuts",i)};return i=p("jw-shortcuts-close",f,n.get("localization").close,[dt("close")]),Object(l.m)(c,i.element()),i.show(),t.appendChild(c),w.on("click tap enter",g),{el:c,open:h,close:f,destroy:function(){f(),w.destroy()},toggleVisibility:function(){o?f():h()}}},yn=function(t){return'
    ')+"
    "};function kn(t){return(kn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function xn(t,e){for(var n=0;n16?i.activeTimeout=setTimeout(i.userInactiveTimeout,t):i.playerContainer.querySelector(".jw-tab-focus")?i.resetActiveTimeout():i.userInactive()},i}var n,i,r;return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&Pn(t,e)}(e,t),n=e,(i=[{key:"resetActiveTimeout",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.inactiveTime=0}},{key:"enable",value:function(t,e){var n=this,i=this.context.createElement("div");i.className="jw-controls jw-reset",this.div=i;var r=this.context.createElement("div");r.className="jw-controls-backdrop jw-reset",this.backdrop=r,this.logo=this.playerContainer.querySelector(".jw-logo");var c=e.get("touchMode"),u=function(){(e.get("isFloating")?n.wrapperElement:n.playerContainer).focus()};if(!this.displayContainer){var d=new Ce(e,t);d.buttons.display.on("click tap enter",(function(){n.trigger(a.p),n.userActive(1e3),t.playToggle(Rn()),u()})),this.div.appendChild(d.element()),this.displayContainer=d}this.infoOverlay=new mn(i,e,t,(function(t){Object(l.v)(n.div,"jw-info-open",t),t&&n.div.querySelector(".jw-info-close").focus()})),o.OS.mobile||(this.shortcutsTooltip=new vn(this.wrapperElement,t,e)),this.rightClickMenu=new Ve(this.infoOverlay,this.shortcutsTooltip),c?(Object(l.a)(this.playerContainer,"jw-flag-touch"),this.rightClickMenu.setup(e,this.playerContainer,this.wrapperElement)):e.change("flashBlocked",(function(t,e){e?n.rightClickMenu.destroy():n.rightClickMenu.setup(t,n.playerContainer,n.wrapperElement)}),this);var w=e.get("floating");if(w){var h=new Tn(i,e.get("localization").close);h.on(a.sb,(function(){return n.trigger("dismissFloating",{doNotForward:!0})})),!1!==w.dismissible&&Object(l.a)(this.playerContainer,"jw-floating-dismissible")}var f=this.controlbar=new de(t,e,this.playerContainer.querySelector(".jw-hidden-accessibility"));if(f.on(a.sb,(function(){return n.userActive()})),f.on("nextShown",(function(t){this.trigger("nextShown",t)}),this),f.on("adjustVolume",k,this),e.get("nextUpDisplay")&&!f.nextUpToolTip){var j=new _e(e,t,this.playerContainer);j.on("all",this.trigger,this),j.setup(this.context),f.nextUpToolTip=j,this.div.appendChild(j.element())}this.div.appendChild(f.element());var g=e.get("localization"),b=this.settingsMenu=fn(t,e.player,this.controlbar,g),m=null;this.controlbar.on("menuVisibility",(function(i){var o=i.visible,r=i.evt,s=e.get("state"),l={reason:"settingsInteraction"},c=n.controlbar.elements.settingsButton,d="keydown"===(r&&r.sourceEvent||r||{}).type,p=o||d?0:An;n.userActive(p),m=s,Object(jn.a)(e.get("containerWidth"))<2&&(o&&s===a.pb?t.pause(l):o||s!==a.ob||m!==a.pb||t.play(l)),!o&&d&&c?c.element().focus():r&&u()})),b.on("menuVisibility",(function(t){return n.controlbar.trigger("menuVisibility",t)})),this.controlbar.on("settingsInteraction",(function(t,e,n){if(e)return b.defaultChild.toggle(n);b.children[t].toggle(n)})),o.OS.mobile?this.div.appendChild(b.el):(this.playerContainer.setAttribute("aria-describedby","jw-shortcuts-tooltip-explanation"),this.div.insertBefore(b.el,f.element()));var v=function(e){if(e.get("autostartMuted")){var i=function(){return n.unmuteAutoplay(t,e)},a=function(t,e){e||i()};o.OS.mobile&&(n.mute=p("jw-autostart-mute jw-off",i,e.get("localization").unmute,[dt("volume-0")]),n.mute.show(),n.div.appendChild(n.mute.element())),f.renderVolume(!0,e.get("volume")),Object(l.a)(n.playerContainer,"jw-flag-autostart"),e.on("change:autostartFailed",i,n),e.on("change:autostartMuted change:mute",a,n),n.muteChangeCallback=a,n.unmuteCallback=i}};function y(n){var i=0,o=e.get("duration"),a=e.get("position");if("DVR"===e.get("streamType")){var r=e.get("dvrSeekLimit");i=o,o=Math.max(a,-r)}var l=Object(s.a)(a+n,i,o);t.seek(l,Rn())}function k(n){var i=Object(s.a)(e.get("volume")+n,0,100);t.setVolume(i)}e.once("change:autostartMuted",v),v(e);var x=function(i){if(i.ctrlKey||i.metaKey)return!0;var o=!n.settingsMenu.visible,a=!0===e.get("enableShortcuts"),r=n.instreamState;if(a||-1!==In.indexOf(i.keyCode)){switch(i.keyCode){case 27:if(e.get("fullscreen"))t.setFullscreen(!1),n.playerContainer.blur(),n.userInactive();else{var s=t.getPlugin("related");s&&s.close({type:"escape"})}n.rightClickMenu.el&&n.rightClickMenu.hideMenuHandler(),n.infoOverlay.visible&&n.infoOverlay.close(),n.shortcutsTooltip&&n.shortcutsTooltip.close();break;case 13:case 32:if(document.activeElement.classList.contains("jw-switch")&&13===i.keyCode)return!0;t.playToggle(Rn());break;case 37:!r&&o&&y(-5);break;case 39:!r&&o&&y(5);break;case 38:o&&k(10);break;case 40:o&&k(-10);break;case 67:var l=t.getCaptionsList().length;if(l){var c=(t.getCurrentCaptions()+1)%l;t.setCurrentCaptions(c)}break;case 77:t.setMute();break;case 70:t.setFullscreen();break;case 191:n.shortcutsTooltip&&n.shortcutsTooltip.toggleVisibility();break;default:if(i.keyCode>=48&&i.keyCode<=59){var u=(i.keyCode-48)/10*e.get("duration");t.seek(u,Rn())}}return/13|32|37|38|39|40/.test(i.keyCode)?(i.preventDefault(),!1):void 0}};this.playerContainer.addEventListener("keydown",x),this.keydownCallback=x;var O=function(t){switch(t.keyCode){case 9:var e=n.playerContainer.contains(t.target)?0:An;n.userActive(e);break;case 32:t.preventDefault()}};this.playerContainer.addEventListener("keyup",O),this.keyupCallback=O;var C=function(t){var e=t.relatedTarget||document.querySelector(":focus");e&&(n.playerContainer.contains(e)||n.userInactive())};this.playerContainer.addEventListener("blur",C,!0),this.blurCallback=C;var M=function t(){"jw-shortcuts-tooltip-explanation"===n.playerContainer.getAttribute("aria-describedby")&&n.playerContainer.removeAttribute("aria-describedby"),n.playerContainer.removeEventListener("blur",t,!0)};this.shortcutsTooltip&&(this.playerContainer.addEventListener("blur",M,!0),this.onRemoveShortcutsDescription=M),this.userActive(),this.addControls(),this.addBackdrop(),e.set("controlsEnabled",!0)}},{key:"addControls",value:function(){this.wrapperElement.appendChild(this.div)}},{key:"disable",value:function(t){var e=this.nextUpToolTip,n=this.settingsMenu,i=this.infoOverlay,o=this.controlbar,a=this.rightClickMenu,r=this.shortcutsTooltip,s=this.playerContainer,c=this.div;clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.off(),t.off(null,null,this),t.set("controlsEnabled",!1),c.parentNode&&(Object(l.o)(s,"jw-flag-touch"),c.parentNode.removeChild(c)),o&&o.destroy(),a&&a.destroy(),this.keydownCallback&&s.removeEventListener("keydown",this.keydownCallback),this.keyupCallback&&s.removeEventListener("keyup",this.keyupCallback),this.blurCallback&&s.removeEventListener("blur",this.blurCallback),this.onRemoveShortcutsDescription&&s.removeEventListener("blur",this.onRemoveShortcutsDescription),this.displayContainer&&this.displayContainer.destroy(),e&&e.destroy(),n&&n.destroy(),i&&i.destroy(),r&&r.destroy(),this.removeBackdrop()}},{key:"controlbarHeight",value:function(){return this.dimensions.cbHeight||(this.dimensions.cbHeight=this.controlbar.element().clientHeight),this.dimensions.cbHeight}},{key:"element",value:function(){return this.div}},{key:"resize",value:function(){this.dimensions={}}},{key:"unmuteAutoplay",value:function(t,e){var n=!e.get("autostartFailed"),i=e.get("mute");n?i=!1:e.set("playOnViewable",!1),this.muteChangeCallback&&(e.off("change:autostartMuted change:mute",this.muteChangeCallback),this.muteChangeCallback=null),this.unmuteCallback&&(e.off("change:autostartFailed",this.unmuteCallback),this.unmuteCallback=null),e.set("autostartFailed",void 0),e.set("autostartMuted",void 0),t.setMute(i),this.controlbar.renderVolume(i,e.get("volume")),this.mute&&this.mute.hide(),Object(l.o)(this.playerContainer,"jw-flag-autostart"),this.userActive()}},{key:"mouseMove",value:function(t){var e=this.controlbar.element().contains(t.target),n=this.controlbar.nextUpToolTip&&this.controlbar.nextUpToolTip.element().contains(t.target),i=this.logo&&this.logo.contains(t.target),o=e||n||i?0:An;this.userActive(o)}},{key:"userActive",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:An;t>0?(this.inactiveTime=Object(c.a)()+t,-1===this.activeTimeout&&(this.activeTimeout=setTimeout(this.userInactiveTimeout,t))):this.resetActiveTimeout(),this.showing||(Object(l.o)(this.playerContainer,"jw-flag-user-inactive"),this.showing=!0,this.trigger("userActive"))}},{key:"userInactive",value:function(){clearTimeout(this.activeTimeout),this.activeTimeout=-1,this.settingsMenu.visible||(this.inactiveTime=0,this.showing=!1,Object(l.a)(this.playerContainer,"jw-flag-user-inactive"),this.trigger("userInactive"))}},{key:"addBackdrop",value:function(){var t=this.instreamState?this.div:this.wrapperElement.querySelector(".jw-captions");this.wrapperElement.insertBefore(this.backdrop,t)}},{key:"removeBackdrop",value:function(){var t=this.backdrop.parentNode;t&&t.removeChild(this.backdrop)}},{key:"setupInstream",value:function(){this.instreamState=!0,this.userActive(),this.addBackdrop(),this.settingsMenu&&this.settingsMenu.close(),Object(l.o)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","-1")}},{key:"destroyInstream",value:function(t){this.instreamState=null,this.addBackdrop(),t.get("autostartMuted")&&Object(l.a)(this.playerContainer,"jw-flag-autostart"),this.controlbar.elements.time.element().setAttribute("tabindex","0")}}])&&_n(n.prototype,i),r&&_n(n,r),e}(r.a)},function(t,e,n){"use strict";n.r(e);var i=n(0),o=n(12),a=n(50),r=n(36);var s=n(44),l=n(51),c=n(26),u=n(25),d=n(3),p=n(46),w=n(2),h=n(7),f=n(34);function j(t){var e=!1;return{async:function(){var n=this,i=arguments;return Promise.resolve().then((function(){if(!e)return t.apply(n,i)}))},cancel:function(){e=!0},cancelled:function(){return e}}}var g=n(1);function b(t){return function(e,n){var o=t.mediaModel,a=Object(i.g)({},n,{type:e});switch(e){case d.T:if(o.get(d.T)===n.mediaType)return;o.set(d.T,n.mediaType);break;case d.U:return void o.set(d.U,Object(i.g)({},n));case d.M:if(n[e]===t.model.getMute())return;break;case d.bb:n.newstate===d.mb&&(t.thenPlayPromise.cancel(),o.srcReset());var r=o.attributes.mediaState;o.attributes.mediaState=n.newstate,o.trigger("change:mediaState",o,n.newstate,r);break;case d.F:return t.beforeComplete=!0,t.trigger(d.B,a),void(t.attached&&!t.background&&t._playbackComplete());case d.G:o.get("setup")?(t.thenPlayPromise.cancel(),o.srcReset()):(e=d.tb,a.code+=1e5);break;case d.K:a.metadataType||(a.metadataType="unknown");var s=n.duration;Object(i.u)(s)&&(o.set("seekRange",n.seekRange),o.set("duration",s));break;case d.D:o.set("buffer",n.bufferPercent);case d.S:o.set("seekRange",n.seekRange),o.set("position",n.position),o.set("currentTime",n.currentTime);var l=n.duration;Object(i.u)(l)&&o.set("duration",l),e===d.S&&Object(i.r)(t.item.starttime)&&delete t.item.starttime;break;case d.R:var c=t.mediaElement;c&&c.paused&&o.set("mediaState","paused");break;case d.I:o.set(d.I,n.levels);case d.J:var u=n.currentQuality,p=n.levels;u>-1&&p.length>1&&o.set("currentLevel",parseInt(u));break;case d.f:o.set(d.f,n.tracks);case d.g:var w=n.currentTrack,h=n.tracks;w>-1&&h.length>0&&w=Math.max(l,p.a)&&(t.preloadNextItem(),v=!0)}function P(t){var e={};b.tag&&(e.tag=b.tag),this.trigger(d.F,e),A.call(this,t)}function A(t){j={},a&&f+10?t:null,h&&h.model.set("skipOffset",s)}};Object(i.g)(lt.prototype,h.a);var ct=lt,ut=n(66),dt=n(63),pt=function(t){var e=this,n=[],i={},o=0,a=0;function r(t){if(t.data=t.data||[],t.name=t.label||t.name||t.language,t._id=Object(dt.a)(t,n.length),!t.name){var e=Object(dt.b)(t,o);t.name=e.label,o=e.unknownCount}i[t._id]=t,n.push(t)}function s(){for(var t=[{id:"off",label:"Off"}],e=0;e')+'
    '},ft=n(35),jt=44,gt=function(t){var e=t.get("height");if(t.get("aspectratio"))return!1;if("string"==typeof e&&e.indexOf("%")>-1)return!1;var n=1*e||NaN;return!!(n=isNaN(n)?t.get("containerHeight"):n)&&(n&&n<=jt)},bt=n(54);function mt(t,e){if(t.get("fullscreen"))return 1;if(!t.get("activeTab"))return 0;if(t.get("isFloating"))return 1;var n=t.get("intersectionRatio");return void 0===n&&(n=function(t){var e=document.documentElement,n=document.body,i={top:0,left:0,right:e.clientWidth||n.clientWidth,width:e.clientWidth||n.clientWidth,bottom:e.clientHeight||n.clientHeight,height:e.clientHeight||n.clientHeight};if(!n.contains(t))return 0;if("none"===window.getComputedStyle(t).display)return 0;var o=vt(t);if(!o)return 0;var a=o,r=t.parentNode,s=!1;for(;!s;){var l=null;if(r===n||r===e||1!==r.nodeType?(s=!0,l=i):"visible"!==window.getComputedStyle(r).overflow&&(l=vt(r)),l&&(c=l,u=a,d=void 0,p=void 0,w=void 0,h=void 0,f=void 0,j=void 0,d=Math.max(c.top,u.top),p=Math.min(c.bottom,u.bottom),w=Math.max(c.left,u.left),h=Math.min(c.right,u.right),j=p-d,!(a=(f=h-w)>=0&&j>=0&&{top:d,bottom:p,left:w,right:h,width:f,height:j})))return 0;r=r.parentNode}var c,u,d,p,w,h,f,j;var g=o.width*o.height,b=a.width*a.height;return g?b/g:0}(e),window.top!==window.self&&n)?0:n}function vt(t){try{return t.getBoundingClientRect()}catch(t){}}var yt=n(49),kt=n(42),xt=n(58),Ot=n(10);var Ct=n(32),Mt=n(5),Tt=n(6),St=["fullscreenchange","webkitfullscreenchange","mozfullscreenchange","MSFullscreenChange"],_t=function(t,e,n){for(var i=t.requestFullscreen||t.webkitRequestFullscreen||t.webkitRequestFullScreen||t.mozRequestFullScreen||t.msRequestFullscreen,o=e.exitFullscreen||e.webkitExitFullscreen||e.webkitCancelFullScreen||e.mozCancelFullScreen||e.msExitFullscreen,a=!(!i||!o),r=St.length;r--;)e.addEventListener(St[r],n);return{events:St,supportsDomFullscreen:function(){return a},requestFullscreen:function(){i.call(t,{navigationUI:"hide"})},exitFullscreen:function(){null!==this.fullscreenElement()&&o.apply(e)},fullscreenElement:function(){var t=e.fullscreenElement,n=e.webkitCurrentFullScreenElement,i=e.mozFullScreenElement,o=e.msFullscreenElement;return null===t?t:t||n||i||o},destroy:function(){for(var t=St.length;t--;)e.removeEventListener(St[t],n)}}},Et=n(40);function zt(t,e){for(var n=0;n')},Rt={linktarget:"_blank",margin:8,hide:!1,position:"top-right"};function Lt(t){var e,n;Object(i.g)(this,h.a);var o=new Image;this.setup=function(){(n=Object(i.g)({},Rt,t.get("logo"))).position=n.position||Rt.position,n.hide="true"===n.hide.toString(),n.file&&"control-bar"!==n.position&&(e||(e=Object(Mt.e)(It(n.position,n.hide))),t.set("logo",n),o.onload=function(){var i=this.height,o=this.width,a={backgroundImage:'url("'+this.src+'")'};if(n.margin!==Rt.margin){var r=/(\w+)-(\w+)/.exec(n.position);3===r.length&&(a["margin-"+r[1]]=n.margin,a["margin-"+r[2]]=n.margin)}var s=.15*t.get("containerHeight"),l=.15*t.get("containerWidth");if(i>s||o>l){var c=o/i;l/s>c?(i=s,o=s*c):(o=l,i=l/c)}a.width=Math.round(o),a.height=Math.round(i),Object(Ot.d)(e,a),t.set("logoWidth",a.width)},o.src=n.file,n.link&&(e.setAttribute("tabindex","0"),e.setAttribute("aria-label",t.get("localization").logo)),this.ui=new Et.a(e).on("click tap enter",(function(t){t&&t.stopPropagation&&t.stopPropagation(),this.trigger(d.A,{link:n.link,linktarget:n.linktarget})}),this))},this.setContainer=function(t){e&&t.appendChild(e)},this.element=function(){return e},this.position=function(){return n.position},this.destroy=function(){o.onload=null,this.ui&&this.ui.destroy()}}var Bt=function(t){this.model=t,this.image=null};Object(i.g)(Bt.prototype,{setup:function(t){this.el=t},setImage:function(t){var e=this.image;e&&(e.onload=null),this.image=null;var n="";"string"==typeof t&&(n='url("'+t+'")',(e=this.image=new Image).src=t),Object(Ot.d)(this.el,{backgroundImage:n})},resize:function(t,e,n){if("uniform"===n){if(t&&(this.playerAspectRatio=t/e),!this.playerAspectRatio||!this.image||"complete"!==(s=this.model.get("state"))&&"idle"!==s&&"error"!==s&&"buffering"!==s)return;var i=this.image,o=null;if(i){if(0===i.width){var a=this;return void(i.onload=function(){a.resize(t,e,n)})}var r=i.width/i.height;Math.abs(this.playerAspectRatio-r)<.09&&(o="cover")}Object(Ot.d)(this.el,{backgroundSize:o})}var s},element:function(){return this.el}});var Vt=Bt,Nt=function(t){this.model=t.player};Object(i.g)(Nt.prototype,{hide:function(){Object(Ot.d)(this.el,{display:"none"})},show:function(){Object(Ot.d)(this.el,{display:""})},setup:function(t){this.el=t;var e=this.el.getElementsByTagName("div");this.title=e[0],this.description=e[1],this.model.on("change:logoWidth",this.update,this),this.model.change("playlistItem",this.playlistItem,this)},update:function(t){var e={},n=t.get("logo");if(n){var i=1*(""+n.margin).replace("px",""),o=t.get("logoWidth")+(isNaN(i)?0:i+10);"top-left"===n.position?e.paddingLeft=o:"top-right"===n.position&&(e.paddingRight=o)}Object(Ot.d)(this.el,e)},playlistItem:function(t,e){if(e)if(t.get("displaytitle")||t.get("displaydescription")){var n="",i="";e.title&&t.get("displaytitle")&&(n=e.title),e.description&&t.get("displaydescription")&&(i=e.description),this.updateText(n,i)}else this.hide()},updateText:function(t,e){Object(Mt.q)(this.title,t),Object(Mt.q)(this.description,e),this.title.firstChild||this.description.firstChild?this.show():this.hide()},element:function(){return this.el}});var Ht=Nt;function Ft(t,e){for(var n=0;nt)}if(e.get("controls")){var r=gt(e);Object(Mt.v)(u,"jw-flag-audio-player",r),e.set("audioMode",r)}}function L(){e.set("visibility",mt(e,u))}this.updateBounds=function(){Object(kt.a)(k);var t=e.get("isFloating")?p:u,n=document.body.contains(t),i=Object(Mt.c)(t),r=Math.round(i.width),s=Math.round(i.height);if(_=Object(Mt.c)(u),r===o&&s===a)return o&&a||A(),void e.set("inDom",n);r&&s||o&&a||A(),(r||s||n)&&(e.set("containerWidth",r),e.set("containerHeight",s)),e.set("inDom",n),n&&bt.a.observe(u)},this.updateStyles=function(){var t=e.get("containerWidth"),n=e.get("containerHeight");R(t,n),z&&z.resize(t,n),$(t,n),v.resize(),O&&F()},this.checkResized=function(){var t=e.get("containerWidth"),n=e.get("containerHeight"),i=e.get("isFloating");if(t!==o||n!==a){this.resizeListener||(this.resizeListener=new Ut.a(p,this,e)),o=t,a=n,l.trigger(d.hb,{width:t,height:n});var s=Object(xt.a)(t);E!==s&&(E=s,l.trigger(d.j,{breakpoint:E}))}i!==r&&(r=i,l.trigger(d.x,{floating:i}),L())},this.responsiveListener=A,this.setup=function(){g.setup(u.querySelector(".jw-preview")),b.setup(u.querySelector(".jw-title")),(n=new Lt(e)).setup(),n.setContainer(p),n.on(d.A,K),v.setup(u.id,e.get("captions")),b.element().parentNode.insertBefore(v.element(),b.element()),C=function(t,e,n){var i=new Pt(e,n),o=e.get("controls");i.on({click:function(){l.trigger(d.p),z&&(ct()?z.settingsMenu.close():ut()?z.infoOverlay.close():t.playToggle({reason:"interaction"}))},tap:function(){l.trigger(d.p),ct()&&z.settingsMenu.close(),ut()&&z.infoOverlay.close();var n=e.get("state");if(o&&(n===d.mb||n===d.kb||e.get("instream")&&n===d.ob)&&t.playToggle({reason:"interaction"}),o&&n===d.ob){if(e.get("instream")||e.get("castActive")||"audio"===e.get("mediaType"))return;Object(Mt.v)(u,"jw-flag-controls-hidden"),l.dismissible&&Object(Mt.v)(u,"jw-floating-dismissible",Object(Mt.i)(u,"jw-flag-controls-hidden")),v.renderCues(!0)}else z&&(z.showing?z.userInactive():z.userActive())},doubleClick:function(){return z&&t.setFullscreen()}}),Wt||(u.addEventListener("mousemove",W),u.addEventListener("mouseover",Q),u.addEventListener("mouseout",Y));return i}(t,e,f),T=new Et.a(u).on("click",(function(){})),M=_t(u,document,et),e.on("change:hideAdsControls",(function(t,e){Object(Mt.v)(u,"jw-flag-ads-hide-controls",e)})),e.on("change:scrubbing",(function(t,e){Object(Mt.v)(u,"jw-flag-dragging",e)})),e.on("change:playRejected",(function(t,e){Object(Mt.v)(u,"jw-flag-play-rejected",e)})),e.on(d.X,tt),e.on("change:".concat(d.U),(function(){$(),v.resize()})),e.player.on("change:errorEvent",at),e.change("stretching",X);var i=e.get("width"),o=e.get("height"),a=G(i,o);Object(Ot.d)(u,a),e.change("aspectratio",Z),R(i,o),e.get("controls")||(Object(Mt.a)(u,"jw-flag-controls-hidden"),Object(Mt.o)(u,"jw-floating-dismissible")),Qt&&Object(Mt.a)(u,"jw-ie");var r=e.get("skin")||{};r.name&&Object(Mt.p)(u,/jw-skin-\S+/,"jw-skin-"+r.name);var s=function(t){t||(t={});var e=t.active,n=t.inactive,i=t.background,o={};return o.controlbar=function(t){if(t||e||n||i){var o={};return t=t||{},o.iconsActive=t.iconsActive||e,o.icons=t.icons||n,o.text=t.text||n,o.background=t.background||i,o}}(t.controlbar),o.timeslider=function(t){if(t||e){var n={};return t=t||{},n.progress=t.progress||e,n.rail=t.rail,n}}(t.timeslider),o.menus=function(t){if(t||e||n||i){var o={};return t=t||{},o.text=t.text||n,o.textActive=t.textActive||e,o.background=t.background||i,o}}(t.menus),o.tooltips=function(t){if(t||n||i){var e={};return t=t||{},e.text=t.text||n,e.background=t.background||i,e}}(t.tooltips),o}(r);!function(t,e){var n;function i(e,n,i,o){if(i){e=Object(w.f)(e,"#"+t+(o?"":" "));var a={};a[n]=i,Object(Ot.b)(e.join(", "),a,t)}}e&&(e.controlbar&&function(e){i([".jw-controlbar .jw-icon-inline.jw-text",".jw-title-primary",".jw-title-secondary"],"color",e.text),e.icons&&(i([".jw-button-color:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:not(.jw-icon-cast)"],"color",e.icons),i([".jw-display-icon-container .jw-button-color"],"color",e.icons),Object(Ot.b)("#".concat(t," .jw-icon-cast google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(e.icons,"}"),t));e.iconsActive&&(i([".jw-display-icon-container .jw-button-color:hover",".jw-display-icon-container .jw-button-color:focus"],"color",e.iconsActive),i([".jw-button-color.jw-toggle:not(.jw-icon-cast)",".jw-button-color:hover:not(.jw-icon-cast)",".jw-button-color:focus:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:hover:not(.jw-icon-cast)"],"color",e.iconsActive),i([".jw-svg-icon-buffer"],"fill",e.icons),Object(Ot.b)("#".concat(t," .jw-icon-cast:hover google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(e.iconsActive,"}"),t),Object(Ot.b)("#".concat(t," .jw-icon-cast:focus google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(e.iconsActive,"}"),t),Object(Ot.b)("#".concat(t," .jw-icon-cast google-cast-launcher.jw-off:focus"),"{--disconnected-color: ".concat(e.iconsActive,"}"),t),Object(Ot.b)("#".concat(t," .jw-icon-cast google-cast-launcher"),"{--connected-color: ".concat(e.iconsActive,"}"),t),Object(Ot.b)("#".concat(t," .jw-icon-cast google-cast-launcher:focus"),"{--connected-color: ".concat(e.iconsActive,"}"),t),Object(Ot.b)("#".concat(t," .jw-icon-cast:hover google-cast-launcher"),"{--connected-color: ".concat(e.iconsActive,"}"),t),Object(Ot.b)("#".concat(t," .jw-icon-cast:focus google-cast-launcher"),"{--connected-color: ".concat(e.iconsActive,"}"),t));i([" .jw-settings-topbar",":not(.jw-state-idle) .jw-controlbar",".jw-flag-audio-player .jw-controlbar"],"background",e.background,!0)}(e.controlbar),e.timeslider&&function(t){var e=t.progress;"none"!==e&&(i([".jw-progress",".jw-knob"],"background-color",e),i([".jw-buffer"],"background-color",Object(Ot.c)(e,50)));i([".jw-rail"],"background-color",t.rail),i([".jw-background-color.jw-slider-time",".jw-slider-time .jw-cue"],"background-color",t.background)}(e.timeslider),e.menus&&(i([".jw-option",".jw-toggle.jw-off",".jw-skip .jw-skip-icon",".jw-nextup-tooltip",".jw-nextup-close",".jw-settings-content-item",".jw-related-title"],"color",(n=e.menus).text),i([".jw-option.jw-active-option",".jw-option:not(.jw-active-option):hover",".jw-option:not(.jw-active-option):focus",".jw-settings-content-item:hover",".jw-nextup-tooltip:hover",".jw-nextup-tooltip:focus",".jw-nextup-close:hover"],"color",n.textActive),i([".jw-nextup",".jw-settings-menu"],"background",n.background)),e.tooltips&&function(t){i([".jw-skip",".jw-tooltip .jw-text",".jw-time-tip .jw-text"],"background-color",t.background),i([".jw-time-tip",".jw-tooltip"],"color",t.background),i([".jw-skip"],"border","none"),i([".jw-skip .jw-text",".jw-skip .jw-icon",".jw-time-tip .jw-text",".jw-tooltip .jw-text"],"color",t.text)}(e.tooltips),e.menus&&function(e){if(e.textActive){var n={color:e.textActive,borderColor:e.textActive,stroke:e.textActive};Object(Ot.b)("#".concat(t," .jw-color-active"),n,t),Object(Ot.b)("#".concat(t," .jw-color-active-hover:hover"),n,t)}if(e.text){var i={color:e.text,borderColor:e.text,stroke:e.text};Object(Ot.b)("#".concat(t," .jw-color-inactive"),i,t),Object(Ot.b)("#".concat(t," .jw-color-inactive-hover:hover"),i,t)}}(e.menus))}(e.get("id"),s),e.set("mediaContainer",f),e.set("iFrame",m.Features.iframe),e.set("activeTab",Object(yt.a)()),e.set("touchMode",Wt&&("string"==typeof o||o>=jt)),bt.a.add(this),e.get("enableGradient")&&!Qt&&Object(Mt.a)(u,"jw-ab-drop-shadow"),this.isSetup=!0,e.trigger("viewSetup",u);var c=document.body.contains(u);c&&bt.a.observe(u),e.set("inDom",c)},this.init=function(){this.updateBounds(),e.on("change:fullscreen",J),e.on("change:activeTab",L),e.on("change:fullscreen",L),e.on("change:intersectionRatio",L),e.on("change:visibility",U),e.on("instreamMode",(function(t){t?dt():pt()})),L(),1!==bt.a.size()||e.get("visibility")||U(e,1,0);var t=e.player;e.change("state",rt),t.change("controls",q),e.change("streamType",it),e.change("mediaType",ot),t.change("playlistItem",(function(t,e){lt(t,e)})),o=a=null,O&&Wt&&bt.a.addScrollHandler(F),this.checkResized()};var B,V=62,N=!0;function H(){var t=e.get("isFloating"),n=_.top0&&void 0!==arguments[0])||arguments[0],e={x:0,y:0,width:o||0,height:a||0};return z&&t&&(e.height-=z.controlbarHeight()),e},this.setCaptions=function(t){v.clear(),v.setup(e.get("id"),t),v.resize()},this.setIntersection=function(t){var n=Math.round(100*t.intersectionRatio)/100;e.set("intersectionRatio",n),O&&!P()&&(S=S||n>=.5)&&wt(n)},this.stopFloating=function(t,n){if(t&&(O=null,bt.a.removeScrollHandler(F)),Yt===u){Yt=null,e.set("isFloating",!1);var i=function(){Object(Mt.o)(u,"jw-flag-floating"),Z(e,e.get("aspectratio")),Object(Ot.d)(u,{backgroundImage:null}),Object(Ot.d)(p,{maxWidth:null,width:null,height:null,left:null,right:null,top:null,bottom:null,margin:null,transform:null,transition:null,"transition-timing-function":null})};n?(Object(Ot.d)(p,{transform:"translateY(-".concat(V-_.top,"px)"),"transition-timing-function":"ease-out"}),setTimeout(i,150)):i(),j.disable(),A()}},this.destroy=function(){e.destroy(),bt.a.unobserve(u),bt.a.remove(this),this.isSetup=!1,this.off(),Object(kt.a)(k),clearTimeout(y),Yt===u&&(Yt=null),T&&(T.destroy(),T=null),M&&(M.destroy(),M=null),z&&z.disable(e),C&&(C.destroy(),u.removeEventListener("mousemove",W),u.removeEventListener("mouseout",Y),u.removeEventListener("mouseover",Q),C=null),v.destroy(),n&&(n.destroy(),n=null),Object(Ot.a)(e.get("id")),this.resizeListener&&(this.resizeListener.destroy(),delete this.resizeListener),O&&Wt&&bt.a.removeScrollHandler(F)}};function Zt(t,e,n){return(Zt="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,n){var i=function(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=ee(t)););return t}(t,e);if(i){var o=Object.getOwnPropertyDescriptor(i,e);return o.get?o.get.call(n):o.value}})(t,e,n||t)}function Kt(t){return(Kt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function Jt(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Gt(t,e){for(var n=0;ne&&t(),e=i}};function Ce(t,e){e.off(d.N,t._onPlayAttempt),e.off(d.fb,t._triggerFirstFrame),e.off(d.S,t._onTime),t.off("change:activeTab",t._onTabVisible)}var Me=function(t,e){t.change("mediaModel",(function(t,n,i){t._qoeItem&&i&&t._qoeItem.end(i.get("mediaState")),t._qoeItem=new ye.a,t._qoeItem.getFirstFrame=function(){var t=this.between(d.N,d.H),e=this.between(xe,d.H);return e>0&&e0&&rt(e,t.tracks)}),C).on(d.F,(function(){Promise.resolve().then(at)}),C).on(d.G,C.triggerError,C),Me(M,B),M.on(d.w,C.triggerError,C),M.on("change:state",(function(t,e,n){X()||Z.call(O,t,e,n)}),this),M.on("change:castState",(function(t,e){C.trigger(d.m,e)})),M.on("change:fullscreen",(function(t,e){C.trigger(d.y,{fullscreen:e}),e&&t.set("playOnViewable",!1)})),M.on("change:volume",(function(t,e){C.trigger(d.V,{volume:e})})),M.on("change:mute",(function(t){C.trigger(d.M,{mute:t.getMute()})})),M.on("change:playbackRate",(function(t,e){C.trigger(d.ab,{playbackRate:e,position:t.get("position")})}));var V=function t(e,n){"clickthrough"!==n&&"interaction"!==n&&"external"!==n||(M.set("playOnViewable",!1),M.off("change:playReason change:pauseReason",t))};function N(t,e){Object(i.t)(e)||M.set("viewable",Math.round(e))}function H(){dt&&(!0!==M.get("autostart")||M.get("playOnViewable")||$("autostart"),dt.flush())}function F(t,e){C.trigger("viewable",{viewable:e}),q()}function q(){if((o.a[0]===e||1===M.get("viewable"))&&"idle"===M.get("state")&&!1===M.get("autostart"))if(!b.primed()&&m.OS.android){var t=b.getTestElement(),n=C.getMute();Promise.resolve().then((function(){return he(t,{muted:n})})).then((function(){"idle"===M.get("state")&&B.preloadVideo()})).catch(_e)}else B.preloadVideo()}function D(t){C._instreamAdapter.noResume=!t,t||et({reason:"viewable"})}function U(t){t||(C.pause({reason:"viewable"}),M.set("playOnViewable",!t))}function W(t,e){var n=X();if(t.get("playOnViewable")){if(e){var i=t.get("autoPause").pauseAds,o=t.get("pauseReason");K()===d.mb?$("viewable"):n&&!i||"interaction"===o||J({reason:"viewable"})}else m.OS.mobile&&!n&&(C.pause({reason:"autostart"}),M.set("playOnViewable",!0));m.OS.mobile&&n&&D(e)}}function Q(t,e){var n=t.get("state"),i=X(),o=t.get("playReason");i?t.get("autoPause").pauseAds?U(e):D(e):n===d.pb||n===d.jb?U(e):n===d.mb&&"playlist"===o&&t.once("change:state",(function(){U(e)}))}function X(){var t=C._instreamAdapter;return!!t&&t.getState()}function K(){var t=X();return t||M.get("state")}function J(t){if(E.cancel(),S=!1,M.get("state")===d.lb)return Promise.resolve();var n=G(t);return M.set("playReason",n),X()?(e.pauseAd(!1,t),Promise.resolve()):(M.get("state")===d.kb&&(tt(!0),C.setItemIndex(0)),!T&&(T=!0,C.trigger(d.C,{playReason:n,startTime:t&&t.startTime?t.startTime:M.get("playlistItem").starttime}),T=!1,ve()&&!b.primed()&&b.prime(),"playlist"===n&&M.get("autoPause").viewability&&Q(M,M.get("viewable")),x)?(ve()&&!R&&M.get("mediaElement").load(),x=!1,k=null,Promise.resolve()):B.playVideo(n).then(b.played))}function G(t){return t&&t.reason?t.reason:"unknown"}function $(t){if(K()===d.mb){E=j(H);var e=M.get("advertising");(function(t,e){var n=e.cancelable,i=e.muted,o=void 0!==i&&i,a=e.allowMuted,r=void 0!==a&&a,s=e.timeout,l=void 0===s?1e4:s,c=t.getTestElement(),u=o?"muted":"".concat(r);be[u]||(be[u]=he(c,{muted:o}).catch((function(t){if(!n.cancelled()&&!1===o&&r)return he(c,{muted:o=!0});throw t})).then((function(){return o?(be[u]=null,je):fe})).catch((function(t){throw clearTimeout(d),be[u]=null,t.reason=ge,t})));var d,p=be[u].then((function(t){if(clearTimeout(d),n.cancelled()){var e=new Error("Autoplay test was cancelled");throw e.reason="cancelled",e}return t})),w=new Promise((function(t,e){d=setTimeout((function(){be[u]=null;var t=new Error("Autoplay test timed out");t.reason="timeout",e(t)}),l)}));return Promise.race([p,w])})(b,{cancelable:E,muted:C.getMute(),allowMuted:!e||e.autoplayadsmuted}).then((function(e){return M.set("canAutoplay",e),e!==je||C.getMute()||(M.set("autostartMuted",!0),ut(),M.once("change:autostartMuted",(function(t){t.off("change:viewable",W),C.trigger(d.M,{mute:M.getMute()})}))),C.getMute()&&M.get("enableDefaultCaptions")&&y.selectDefaultIndex(1),J({reason:t}).catch((function(){C._instreamAdapter||M.set("autostartFailed",!0),k=null}))})).catch((function(t){if(M.set("canAutoplay",ge),M.set("autostart",!1),!E.cancelled()){var e=Object(g.w)(t);C.trigger(d.h,{reason:t.reason,code:e,error:t})}}))}}function tt(t){if(E.cancel(),dt.empty(),X()){var e=C._instreamAdapter;return e&&(e.noResume=!0),void(k=function(){return B.stopVideo()})}k=null,!t&&(S=!0),T&&(x=!0),M.set("errorEvent",void 0),B.stopVideo()}function et(t){var e=G(t);M.set("pauseReason",e),M.set("playOnViewable","viewable"===e)}function nt(t){k=null,E.cancel();var n=X();if(n&&n!==d.ob)return et(t),void e.pauseAd(!0,t);switch(M.get("state")){case d.lb:return;case d.pb:case d.jb:et(t),B.pause();break;default:T&&(x=!0)}}function it(t,e){tt(!0),C.setItemIndex(t),C.play(e)}function ot(t){it(M.get("item")+1,t)}function at(){C.completeCancelled()||(k=C.completeHandler,C.shouldAutoAdvance()?C.nextItem():M.get("repeat")?ot({reason:"repeat"}):(m.OS.iOS&<(!1),M.set("playOnViewable",!1),M.set("state",d.kb),C.trigger(d.cb,{})))}function rt(t,e){t=parseInt(t,10)||0,M.persistVideoSubtitleTrack(t,e),B.subtitles=t,C.trigger(d.k,{tracks:st(),track:t})}function st(){return y.getCaptionsList()}function lt(t){Object(i.n)(t)||(t=!M.get("fullscreen")),M.set("fullscreen",t),C._instreamAdapter&&C._instreamAdapter._adModel&&C._instreamAdapter._adModel.set("fullscreen",t)}function ut(){B.mute=M.getMute(),B.volume=M.get("volume")}M.on("change:playReason change:pauseReason",V),C.on(d.c,(function(t){return V(0,t.playReason)})),C.on(d.b,(function(t){return V(0,t.pauseReason)})),M.on("change:scrubbing",(function(t,e){e?(_=M.get("state")!==d.ob,nt()):_&&J({reason:"interaction"})})),M.on("change:captionsList",(function(t,e){C.trigger(d.l,{tracks:e,track:M.get("captionsIndex")||0})})),M.on("change:mediaModel",(function(t,e){var n=this;t.set("errorEvent",void 0),e.change("mediaState",(function(e,n){var i;t.get("errorEvent")||t.set(d.bb,(i=n)===d.nb||i===d.qb?d.jb:i)}),this),e.change("duration",(function(e,n){if(0!==n){var i=t.get("minDvrWindow"),o=Object(me.b)(n,i);t.setStreamType(o)}}),this);var i=t.get("item")+1,o="autoplay"===(t.get("related")||{}).oncomplete,a=t.get("playlist")[i];if((a||o)&&R){e.on("change:position",(function t(i,r){var s=a&&!a.daiSetting,l=e.get("duration");s&&r&&l>0&&r>=l-p.b?(e.off("change:position",t,n),B.backgroundLoad(a)):o&&(a=M.get("nextUp"))}),this)}})),(y=new wt(M)).on("all",I,C),L.on("viewSetup",(function(t){Object(a.b)(O,t)})),this.playerReady=function(){v.once(d.hb,(function(){try{!function(){M.change("visibility",N),P.off(),C.trigger(d.gb,{setupTime:0}),M.change("playlist",(function(t,e){if(e.length){var n={playlist:e},o=M.get("feedData");o&&(n.feedData=Object(i.g)({},o)),C.trigger(d.eb,n)}})),M.change("playlistItem",(function(t,e){if(e){var n=e.title,i=e.image;if("mediaSession"in navigator&&window.MediaMetadata&&(n||i))try{navigator.mediaSession.metadata=new window.MediaMetadata({title:n,artist:window.location.hostname,artwork:[{src:i||""}]})}catch(t){}t.set("cues",[]),C.trigger(d.db,{index:M.get("item"),item:e})}})),P.flush(),P.destroy(),P=null,M.change("viewable",F),M.change("viewable",W),M.get("autoPause").viewability?M.change("viewable",Q):M.once("change:autostartFailed change:mute",(function(t){t.off("change:viewable",W)}));H(),M.on("change:itemReady",(function(t,e){e&&dt.flush()}))}()}catch(t){C.triggerError(Object(g.v)(g.m,g.a,t))}})),v.init()},this.preload=q,this.load=function(t,e){var n,i=C._instreamAdapter;switch(i&&(i.noResume=!0),C.trigger("destroyPlugin",{}),tt(!0),E.cancel(),E=j(H),z.cancel(),ve()&&b.prime(),Te(t)){case"string":M.attributes.item=0,M.attributes.itemReady=!1,z=j((function(t){if(t)return C.updatePlaylist(Object(c.a)(t.playlist),t)})),n=function(t){var e=this;return new Promise((function(n,i){var o=new l.a;o.on(d.eb,(function(t){n(t)})),o.on(d.w,i,e),o.load(t)}))}(t).then(z.async);break;case"object":M.attributes.item=0,n=C.updatePlaylist(Object(c.a)(t),e||{});break;case"number":n=C.setItemIndex(t);break;default:return}n.catch((function(t){C.triggerError(Object(g.u)(t,g.c))})),n.then(E.async).catch(_e)},this.play=function(t){return J(t).catch(_e)},this.pause=nt,this.seek=function(t,e){var n=M.get("state");if(n!==d.lb){B.position=t;var i=n===d.mb;M.get("scrubbing")||!i&&n!==d.kb||(i&&((e=e||{}).startTime=t),this.play(e))}},this.stop=tt,this.playlistItem=it,this.playlistNext=ot,this.playlistPrev=function(t){it(M.get("item")-1,t)},this.setCurrentCaptions=rt,this.setCurrentQuality=function(t){B.quality=t},this.setFullscreen=lt,this.getCurrentQuality=function(){return B.quality},this.getQualityLevels=function(){return B.qualities},this.setCurrentAudioTrack=function(t){B.audioTrack=t},this.getCurrentAudioTrack=function(){return B.audioTrack},this.getAudioTracks=function(){return B.audioTracks},this.getCurrentCaptions=function(){return y.getCurrentIndex()},this.getCaptionsList=st,this.getVisualQuality=function(){var t=this._model.get("mediaModel");return t?t.get(d.U):null},this.getConfig=function(){return this._model?this._model.getConfiguration():void 0},this.getState=K,this.next=_e,this.completeHandler=at,this.completeCancelled=function(){return(t=M.get("state"))!==d.mb&&t!==d.kb&&t!==d.lb||!!S&&(S=!1,!0);var t},this.shouldAutoAdvance=function(){return M.get("item")!==M.get("playlist").length-1},this.nextItem=function(){ot({reason:"playlist"})},this.setConfig=function(t){!function(t,e){var n=t._model,i=n.attributes;e.height&&(e.height=Object(r.b)(e.height),e.width=e.width||i.width),e.width&&(e.width=Object(r.b)(e.width),e.aspectratio?(i.width=e.width,delete e.width):e.height=i.height),e.width&&e.height&&!e.aspectratio&&t._view.resize(e.width,e.height),Object.keys(e).forEach((function(o){var a=e[o];if(void 0!==a)switch(o){case"aspectratio":n.set(o,Object(r.a)(a,i.width));break;case"autostart":!function(t,e,n){t.setAutoStart(n),"idle"===t.get("state")&&!0===n&&e.play({reason:"autostart"})}(n,t,a);break;case"mute":t.setMute(a);break;case"volume":t.setVolume(a);break;case"playbackRateControls":case"playbackRates":case"repeat":case"stretching":n.set(o,a)}}))}(C,t)},this.setItemIndex=function(t){B.stopVideo();var e=M.get("playlist").length;return(t=(parseInt(t,10)||0)%e)<0&&(t+=e),B.setActiveItem(t).catch((function(t){t.code>=151&&t.code<=162&&(t=Object(g.u)(t,g.e)),O.triggerError(Object(g.v)(g.k,g.d,t))}))},this.detachMedia=function(){if(T&&(x=!0),M.get("autoPause").viewability&&Q(M,M.get("viewable")),!R)return B.setAttached(!1);B.backgroundActiveMedia()},this.attachMedia=function(){R?B.restoreBackgroundMedia():B.setAttached(!0),"function"==typeof k&&k()},this.routeEvents=function(t){return B.routeEvents(t)},this.forwardEvents=function(){return B.forwardEvents()},this.playVideo=function(t){return B.playVideo(t)},this.stopVideo=function(){return B.stopVideo()},this.castVideo=function(t,e){return B.castVideo(t,e)},this.stopCast=function(){return B.stopCast()},this.backgroundActiveMedia=function(){return B.backgroundActiveMedia()},this.restoreBackgroundMedia=function(){return B.restoreBackgroundMedia()},this.preloadNextItem=function(){B.background.currentMedia&&B.preloadVideo()},this.isBeforeComplete=function(){return B.beforeComplete},this.setVolume=function(t){M.setVolume(t),ut()},this.setMute=function(t){M.setMute(t),ut()},this.setPlaybackRate=function(t){M.setPlaybackRate(t)},this.getProvider=function(){return M.get("provider")},this.getWidth=function(){return M.get("containerWidth")},this.getHeight=function(){return M.get("containerHeight")},this.getItemQoe=function(){return M._qoeItem},this.addButton=function(t,e,n,i,o){var a=M.get("customButtons")||[],r=!1,s={img:t,tooltip:e,callback:n,id:i,btnClass:o};a=a.reduce((function(t,e){return e.id===i?(r=!0,t.push(s)):t.push(e),t}),[]),r||a.unshift(s),M.set("customButtons",a)},this.removeButton=function(t){var e=M.get("customButtons")||[];e=e.filter((function(e){return e.id!==t})),M.set("customButtons",e)},this.resize=v.resize,this.getSafeRegion=v.getSafeRegion,this.setCaptions=v.setCaptions,this.checkBeforePlay=function(){return T},this.setControls=function(t){Object(i.n)(t)||(t=!M.get("controls")),M.set("controls",t),B.controls=t},this.addCues=function(t){this.setCues(M.get("cues").concat(t))},this.setCues=function(t){M.set("cues",t)},this.updatePlaylist=function(t,e){try{var n=Object(c.b)(t,M,e);Object(c.e)(n);var o=Object(i.g)({},e);delete o.playlist,M.set("feedData",o),M.set("playlist",n)}catch(t){return Promise.reject(t)}return this.setItemIndex(M.get("item"))},this.setPlaylistItem=function(t,e){(e=Object(c.d)(M,new u.a(e),e.feedData||{}))&&(M.get("playlist")[t]=e,t===M.get("item")&&"idle"===M.get("state")&&this.setItemIndex(t))},this.playerDestroy=function(){this.off(),this.stop(),Object(a.b)(this,this.originalContainer),v&&v.destroy(),M&&M.destroy(),dt&&dt.destroy(),y&&y.destroy(),B&&B.destroy(),this.instreamDestroy()},this.isBeforePlay=this.checkBeforePlay,this.createInstream=function(){return this.instreamDestroy(),this._instreamAdapter=new ct(this,M,v,b),this._instreamAdapter},this.instreamDestroy=function(){C._instreamAdapter&&(C._instreamAdapter.destroy(),C._instreamAdapter=null)};var dt=new s.a(this,["play","pause","setCurrentAudioTrack","setCurrentCaptions","setCurrentQuality","setFullscreen"],(function(){return!O._model.get("itemReady")||P}));dt.queue.push.apply(dt.queue,f),v.setup()},get:function(t){if(t in y.a){var e=this._model.get("mediaModel");return e?e.get(t):y.a[t]}return this._model.get(t)},getContainer:function(){return this.currentContainer||this.originalContainer},getMute:function(){return this._model.getMute()},triggerError:function(t){var e=this._model;t.message=e.get("localization").errors[t.key],delete t.key,e.set("errorEvent",t),e.set("state",d.lb),e.once("change:state",(function(){this.set("errorEvent",void 0)}),e),this.trigger(d.w,t)}});e.default=Se},,,,,,,,,,,,function(t,e){!function(t,e){"use strict";if("IntersectionObserver"in t&&"IntersectionObserverEntry"in t&&"intersectionRatio"in t.IntersectionObserverEntry.prototype)"isIntersecting"in t.IntersectionObserverEntry.prototype||Object.defineProperty(t.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}});else{var n=[];o.prototype.THROTTLE_TIMEOUT=100,o.prototype.POLL_INTERVAL=null,o.prototype.USE_MUTATION_OBSERVER=!0,o.prototype.observe=function(t){if(!this._observationTargets.some((function(e){return e.element==t}))){if(!t||1!=t.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:t,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},o.prototype.unobserve=function(t){this._observationTargets=this._observationTargets.filter((function(e){return e.element!=t})),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},o.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},o.prototype.takeRecords=function(){var t=this._queuedEntries.slice();return this._queuedEntries=[],t},o.prototype._initThresholds=function(t){var e=t||[0];return Array.isArray(e)||(e=[e]),e.sort().filter((function(t,e,n){if("number"!=typeof t||isNaN(t)||t<0||t>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return t!==n[e-1]}))},o.prototype._parseRootMargin=function(t){var e=(t||"0px").split(/\s+/).map((function(t){var e=/^(-?\d*\.?\d+)(px|%)$/.exec(t);if(!e)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(e[1]),unit:e[2]}}));return e[1]=e[1]||e[0],e[2]=e[2]||e[0],e[3]=e[3]||e[1],e},o.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(a(t,"resize",this._checkForIntersections,!0),a(e,"scroll",this._checkForIntersections,!0),this.USE_MUTATION_OBSERVER&&"MutationObserver"in t&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(e,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},o.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,r(t,"resize",this._checkForIntersections,!0),r(e,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},o.prototype._checkForIntersections=function(){var e=this._rootIsInDom(),n=e?this._getRootRect():{top:0,bottom:0,left:0,right:0,width:0,height:0};this._observationTargets.forEach((function(o){var a=o.element,r=s(a),l=this._rootContainsTarget(a),c=o.entry,u=e&&l&&this._computeTargetAndRootIntersection(a,n),d=o.entry=new i({time:t.performance&&performance.now&&performance.now(),target:a,boundingClientRect:r,rootBounds:n,intersectionRect:u});c?e&&l?this._hasCrossedThreshold(c,d)&&this._queuedEntries.push(d):c&&c.isIntersecting&&this._queuedEntries.push(d):this._queuedEntries.push(d)}),this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},o.prototype._computeTargetAndRootIntersection=function(n,i){if("none"!=t.getComputedStyle(n).display){for(var o,a,r,l,u,d,p,w,h=s(n),f=c(n),j=!1;!j;){var g=null,b=1==f.nodeType?t.getComputedStyle(f):{};if("none"==b.display)return;if(f==this.root||f==e?(j=!0,g=i):f!=e.body&&f!=e.documentElement&&"visible"!=b.overflow&&(g=s(f)),g&&(o=g,a=h,r=void 0,l=void 0,u=void 0,d=void 0,p=void 0,w=void 0,r=Math.max(o.top,a.top),l=Math.min(o.bottom,a.bottom),u=Math.max(o.left,a.left),d=Math.min(o.right,a.right),w=l-r,!(h=(p=d-u)>=0&&w>=0&&{top:r,bottom:l,left:u,right:d,width:p,height:w})))break;f=c(f)}return h}},o.prototype._getRootRect=function(){var t;if(this.root)t=s(this.root);else{var n=e.documentElement,i=e.body;t={top:0,left:0,right:n.clientWidth||i.clientWidth,width:n.clientWidth||i.clientWidth,bottom:n.clientHeight||i.clientHeight,height:n.clientHeight||i.clientHeight}}return this._expandRectByRootMargin(t)},o.prototype._expandRectByRootMargin=function(t){var e=this._rootMarginValues.map((function(e,n){return"px"==e.unit?e.value:e.value*(n%2?t.width:t.height)/100})),n={top:t.top-e[0],right:t.right+e[1],bottom:t.bottom+e[2],left:t.left-e[3]};return n.width=n.right-n.left,n.height=n.bottom-n.top,n},o.prototype._hasCrossedThreshold=function(t,e){var n=t&&t.isIntersecting?t.intersectionRatio||0:-1,i=e.isIntersecting?e.intersectionRatio||0:-1;if(n!==i)for(var o=0;o0&&(o=0),n.length>o+1&&n[o+1]){var a=n[o],r=a.indexOf(" --\x3e ");r>0&&(e.begin=Object(i.g)(a.substr(0,r)),e.end=Object(i.g)(a.substr(r+5)),e.text=n.slice(o+1).join("\r\n"))}return e}},function(t,e,n){"use strict";n.d(e,"a",(function(){return o})),n.d(e,"b",(function(){return a}));var i=n(5);function o(t){var e=-1;return t>=1280?e=7:t>=960?e=6:t>=800?e=5:t>=640?e=4:t>=540?e=3:t>=420?e=2:t>=320?e=1:t>=250&&(e=0),e}function a(t,e){var n="jw-breakpoint-"+e;Object(i.p)(t,/jw-breakpoint--?\d+/,n)}},function(t,e,n){"use strict";n.d(e,"a",(function(){return d}));var i,o=n(0),a=n(8),r=n(16),s=n(7),l=n(3),c=n(10),u=n(5),d={back:!0,backgroundOpacity:50,edgeStyle:null,fontSize:14,fontOpacity:100,fontScale:.05,preprocessor:o.k,windowOpacity:0},p=function(t){var e,s,p,w,h,f,j,g,b,m=this,v=t.player;function y(){Object(o.o)(e.fontSize)&&(v.get("containerHeight")?g=d.fontScale*(e.userFontScale||1)*e.fontSize/d.fontSize:v.once("change:containerHeight",y,this))}function k(){var t=v.get("containerHeight");if(t){var e;if(v.get("fullscreen")&&a.OS.iOS)e=null;else{var n=t*g;e=Math.round(10*function(t){var e=v.get("mediaElement");if(e&&e.videoHeight){var n=e.videoWidth,i=e.videoHeight,o=n/i,r=v.get("containerHeight"),s=v.get("containerWidth");if(v.get("fullscreen")&&a.OS.mobile){var l=window.screen;l.orientation&&(r=l.availHeight,s=l.availWidth)}if(s&&r&&n&&i)return(s/r>o?r:i*s/n)*g}return t}(n))/10}v.get("renderCaptionsNatively")?function(t,e){var n="#".concat(t," .jw-video::-webkit-media-text-track-display");e&&(e+="px",a.OS.iOS&&Object(c.b)(n,{fontSize:"inherit"},t,!0));b.fontSize=e,Object(c.b)(n,b,t,!0)}(v.get("id"),e):Object(c.d)(h,{fontSize:e})}}function x(t,e,n){var i=Object(c.c)("#000000",n);"dropshadow"===t?e.textShadow="0 2px 1px "+i:"raised"===t?e.textShadow="0 0 5px "+i+", 0 1px 5px "+i+", 0 2px 5px "+i:"depressed"===t?e.textShadow="0 -2px 1px "+i:"uniform"===t&&(e.textShadow="-2px 0 1px "+i+",2px 0 1px "+i+",0 -2px 1px "+i+",0 2px 1px "+i+",-1px 1px 1px "+i+",1px 1px 1px "+i+",1px -1px 1px "+i+",1px 1px 1px "+i)}(h=document.createElement("div")).className="jw-captions jw-reset",this.show=function(){Object(u.a)(h,"jw-captions-enabled")},this.hide=function(){Object(u.o)(h,"jw-captions-enabled")},this.populate=function(t){v.get("renderCaptionsNatively")||(p=[],s=t,t?this.selectCues(t,w):this.renderCues())},this.resize=function(){k(),this.renderCues(!0)},this.renderCues=function(t){t=!!t,i&&i.processCues(window,p,h,t)},this.selectCues=function(t,e){if(t&&t.data&&e&&!v.get("renderCaptionsNatively")){var n=this.getAlignmentPosition(t,e);!1!==n&&(p=this.getCurrentCues(t.data,n),this.renderCues(!0))}},this.getCurrentCues=function(t,e){return Object(o.h)(t,(function(t){return e>=t.startTime&&(!t.endTime||e<=t.endTime)}))},this.getAlignmentPosition=function(t,e){var n=t.source,i=e.metadata,a=e.currentTime;return n&&i&&Object(o.r)(i[n])&&(a=i[n]),a},this.clear=function(){Object(u.g)(h)},this.setup=function(t,n){f=document.createElement("div"),j=document.createElement("span"),f.className="jw-captions-window jw-reset",j.className="jw-captions-text jw-reset",e=Object(o.g)({},d,n),g=d.fontScale;var i=function(){if(!v.get("renderCaptionsNatively")){y(e.fontSize);var n=e.windowColor,i=e.windowOpacity,o=e.edgeStyle;b={};var r={};!function(t,e){var n=e.color,i=e.fontOpacity;(n||i!==d.fontOpacity)&&(t.color=Object(c.c)(n||"#ffffff",i));if(e.back){var o=e.backgroundColor,a=e.backgroundOpacity;o===d.backgroundColor&&a===d.backgroundOpacity||(t.backgroundColor=Object(c.c)(o,a))}else t.background="transparent";e.fontFamily&&(t.fontFamily=e.fontFamily);e.fontStyle&&(t.fontStyle=e.fontStyle);e.fontWeight&&(t.fontWeight=e.fontWeight);e.textDecoration&&(t.textDecoration=e.textDecoration)}(r,e),(n||i!==d.windowOpacity)&&(b.backgroundColor=Object(c.c)(n||"#000000",i)),x(o,r,e.fontOpacity),e.back||null!==o||x("uniform",r),Object(c.d)(f,b),Object(c.d)(j,r),function(t,e){k(),function(t,e){a.Browser.safari&&Object(c.b)("#"+t+" .jw-video::-webkit-media-text-track-display-backdrop",{backgroundColor:e.backgroundColor},t,!0);Object(c.b)("#"+t+" .jw-video::-webkit-media-text-track-display",b,t,!0),Object(c.b)("#"+t+" .jw-video::cue",e,t,!0)}(t,e),function(t,e){Object(c.b)("#"+t+" .jw-text-track-display",b,t),Object(c.b)("#"+t+" .jw-text-track-cue",e,t)}(t,e)}(t,r)}};i(),f.appendChild(j),h.appendChild(f),v.change("captionsTrack",(function(t,e){this.populate(e)}),this),v.set("captions",e),v.on("change:captions",(function(t,n){e=n,i()}))},this.element=function(){return h},this.destroy=function(){v.off(null,null,this),this.off()};var O=function(t){w=t,m.selectCues(s,w)};v.on("change:playlistItem",(function(){w=null,p=[]}),this),v.on(l.Q,(function(t){p=[],O(t)}),this),v.on(l.S,O,this),v.on("subtitlesTrackData",(function(){this.selectCues(s,w)}),this),v.on("change:captionsList",(function t(e,o){var a=this;1!==o.length&&(e.get("renderCaptionsNatively")||i||(n.e(8).then(function(t){i=n(68).default}.bind(null,n)).catch(Object(r.c)(301121)).catch((function(t){a.trigger(l.tb,t)})),e.off("change:captionsList",t,this)))}),this)};Object(o.g)(p.prototype,s.a),e.b=p},function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var n=function(t,e){var n=t[1]||"",i=t[3];if(!i)return n;if(e&&"function"==typeof btoa){var o=(r=i,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */"),a=i.sources.map((function(t){return"/*# sourceURL="+i.sourceRoot+t+" */"}));return[n].concat(a).concat([o]).join("\n")}var r;return[n].join("\n")}(e,t);return e[2]?"@media "+e[2]+"{"+n+"}":n})).join("")},e.i=function(t,n){"string"==typeof t&&(t=[[null,t,""]]);for(var i={},o=0;o'},function(t,e,n){"use strict";function i(t,e){var n=t.kind||"cc";return t.default||t.defaulttrack?"default":t._id||t.file||n+e}function o(t,e){var n=t.label||t.name||t.language;return n||(n="Unknown CC",(e+=1)>1&&(n+=" ["+e+"]")),{label:n,unknownCount:e}}n.d(e,"a",(function(){return i})),n.d(e,"b",(function(){return o}))},function(t,e,n){"use strict";function i(t){return new Promise((function(e,n){if(t.paused)return n(o("NotAllowedError",0,"play() failed."));var i=function(){t.removeEventListener("play",a),t.removeEventListener("playing",r),t.removeEventListener("pause",r),t.removeEventListener("abort",r),t.removeEventListener("error",r)},a=function(){t.addEventListener("playing",r),t.addEventListener("abort",r),t.addEventListener("error",r),t.addEventListener("pause",r)},r=function(t){if(i(),"playing"===t.type)e();else{var a='The play() request was interrupted by a "'.concat(t.type,'" event.');"error"===t.type?n(o("NotSupportedError",9,a)):n(o("AbortError",20,a))}};t.addEventListener("play",a)}))}function o(t,e,n){var i=new Error(n);return i.name=t,i.code=e,i}n.d(e,"a",(function(){return i}))},function(t,e,n){"use strict";function i(t,e){return t!==1/0&&Math.abs(t)>=Math.max(a(e),0)}function o(t,e){var n="VOD";return t===1/0?n="LIVE":t<0&&(n=i(t,a(e))?"DVR":"LIVE"),n}function a(t){return void 0===t?120:Math.max(t,0)}n.d(e,"a",(function(){return i})),n.d(e,"b",(function(){return o}))},function(t,e,n){"use strict";var i=n(67),o=n(16),a=n(22),r=n(4),s=n(57),l=n(2),c=n(1);function u(t){throw new c.n(null,t)}function d(t,e,i){t.xhr=Object(a.a)(t.file,(function(a){!function(t,e,i,a){var d,p,h=t.responseXML?t.responseXML.firstChild:null;if(h)for("xml"===Object(r.b)(h)&&(h=h.nextSibling);h.nodeType===h.COMMENT_NODE;)h=h.nextSibling;try{if(h&&"tt"===Object(r.b)(h))d=function(t){t||u(306007);var e=[],n=t.getElementsByTagName("p"),i=30,o=t.getElementsByTagName("tt");if(o&&o[0]){var a=parseFloat(o[0].getAttribute("ttp:frameRate"));isNaN(a)||(i=a)}n||u(306005),n.length||(n=t.getElementsByTagName("tt:p")).length||(n=t.getElementsByTagName("tts:p"));for(var r=0;r\s+<").replace(/(<\/?)tts?:/g,"$1").replace(//g,"\r\n");if(h){var f=s.getAttribute("begin"),j=s.getAttribute("dur"),g=s.getAttribute("end"),b={begin:Object(l.g)(f,i),text:h};g?b.end=Object(l.g)(g,i):j&&(b.end=b.begin+Object(l.g)(j,i)),e.push(b)}}return e.length||u(306005),e}(t.responseXML),p=w(d),delete e.xhr,i(p);else{var f=t.responseText;f.indexOf("WEBVTT")>=0?n.e(10).then(function(t){return n(97).default}.bind(null,n)).catch(Object(o.c)(301131)).then((function(t){var n=new t(window);p=[],n.oncue=function(t){p.push(t)},n.onflush=function(){delete e.xhr,i(p)},n.parse(f)})).catch((function(t){delete e.xhr,a(Object(c.v)(null,c.b,t))})):(d=Object(s.a)(f),p=w(d),delete e.xhr,i(p))}}catch(t){delete e.xhr,a(Object(c.v)(null,c.b,t))}}(a,t,e,i)}),(function(t,e,n,o){i(Object(c.u)(o,c.b))}))}function p(t){t&&t.forEach((function(t){var e=t.xhr;e&&(e.onload=null,e.onreadystatechange=null,e.onerror=null,"abort"in e&&e.abort()),delete t.xhr}))}function w(t){return t.map((function(t){return new i.a(t.begin,t.end,t.text)}))}n.d(e,"c",(function(){return d})),n.d(e,"a",(function(){return p})),n.d(e,"b",(function(){return w}))},function(t,e,n){"use strict";var i=window.VTTCue;function o(t){if("string"!=typeof t)return!1;return!!{start:!0,middle:!0,end:!0,left:!0,right:!0}[t.toLowerCase()]&&t.toLowerCase()}if(!i){(i=function(t,e,n){var i=this;i.hasBeenReset=!1;var a="",r=!1,s=t,l=e,c=n,u=null,d="",p=!0,w="auto",h="start",f="auto",j=100,g="middle";Object.defineProperty(i,"id",{enumerable:!0,get:function(){return a},set:function(t){a=""+t}}),Object.defineProperty(i,"pauseOnExit",{enumerable:!0,get:function(){return r},set:function(t){r=!!t}}),Object.defineProperty(i,"startTime",{enumerable:!0,get:function(){return s},set:function(t){if("number"!=typeof t)throw new TypeError("Start time must be set to a number.");s=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"endTime",{enumerable:!0,get:function(){return l},set:function(t){if("number"!=typeof t)throw new TypeError("End time must be set to a number.");l=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"text",{enumerable:!0,get:function(){return c},set:function(t){c=""+t,this.hasBeenReset=!0}}),Object.defineProperty(i,"region",{enumerable:!0,get:function(){return u},set:function(t){u=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"vertical",{enumerable:!0,get:function(){return d},set:function(t){var e=function(t){return"string"==typeof t&&(!!{"":!0,lr:!0,rl:!0}[t.toLowerCase()]&&t.toLowerCase())}(t);if(!1===e)throw new SyntaxError("An invalid or illegal string was specified.");d=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"snapToLines",{enumerable:!0,get:function(){return p},set:function(t){p=!!t,this.hasBeenReset=!0}}),Object.defineProperty(i,"line",{enumerable:!0,get:function(){return w},set:function(t){if("number"!=typeof t&&"auto"!==t)throw new SyntaxError("An invalid number or illegal string was specified.");w=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"lineAlign",{enumerable:!0,get:function(){return h},set:function(t){var e=o(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");h=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"position",{enumerable:!0,get:function(){return f},set:function(t){if(t<0||t>100)throw new Error("Position must be between 0 and 100.");f=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"size",{enumerable:!0,get:function(){return j},set:function(t){if(t<0||t>100)throw new Error("Size must be between 0 and 100.");j=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"align",{enumerable:!0,get:function(){return g},set:function(t){var e=o(t);if(!e)throw new SyntaxError("An invalid or illegal string was specified.");g=e,this.hasBeenReset=!0}}),i.displayState=void 0}).prototype.getCueAsHTML=function(){return window.WebVTT.convertCueToDOMTree(window,this.text)}}e.a=i},,function(t,e,n){var i=n(70);"string"==typeof i&&(i=[["all-players",i,""]]),n(61).style(i,"all-players"),i.locals&&(t.exports=i.locals)},function(t,e,n){(t.exports=n(60)(!1)).push([t.i,'.jw-reset{text-align:left;direction:ltr}.jw-reset-text,.jw-reset{color:inherit;background-color:transparent;padding:0;margin:0;float:none;font-family:Arial,Helvetica,sans-serif;font-size:1em;line-height:1em;list-style:none;text-transform:none;vertical-align:baseline;border:0;font-variant:inherit;font-stretch:inherit;-webkit-tap-highlight-color:rgba(255,255,255,0)}body .jw-error,body .jwplayer.jw-state-error{height:100%;width:100%}.jw-title{position:absolute;top:0}.jw-background-color{background:rgba(0,0,0,0.4)}.jw-text{color:rgba(255,255,255,0.8)}.jw-knob{color:rgba(255,255,255,0.8);background-color:#fff}.jw-button-color{color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):focus,:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):hover{color:#fff}.jw-toggle{color:#fff}.jw-toggle.jw-off{color:rgba(255,255,255,0.8)}.jw-toggle.jw-off:focus{color:#fff}.jw-toggle:focus{outline:none}:not(.jw-flag-touch) .jw-toggle.jw-off:hover{color:#fff}.jw-rail{background:rgba(255,255,255,0.3)}.jw-buffer{background:rgba(255,255,255,0.3)}.jw-progress{background:#f2f2f2}.jw-time-tip,.jw-volume-tip{border:0}.jw-slider-volume.jw-volume-tip.jw-background-color.jw-slider-vertical{background:none}.jw-skip{padding:.5em;outline:none}.jw-skip .jw-skiptext,.jw-skip .jw-skip-icon{color:rgba(255,255,255,0.8)}.jw-skip.jw-skippable:hover .jw-skip-icon,.jw-skip.jw-skippable:focus .jw-skip-icon{color:#fff}.jw-icon-cast google-cast-launcher{--connected-color:#fff;--disconnected-color:rgba(255,255,255,0.8)}.jw-icon-cast google-cast-launcher:focus{outline:none}.jw-icon-cast google-cast-launcher.jw-off{--connected-color:rgba(255,255,255,0.8)}.jw-icon-cast:focus google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-icon-cast:hover google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-nextup-container{bottom:2.5em;padding:5px .5em}.jw-nextup{border-radius:0}.jw-color-active{color:#fff;stroke:#fff;border-color:#fff}:not(.jw-flag-touch) .jw-color-active-hover:hover,:not(.jw-flag-touch) .jw-color-active-hover:focus{color:#fff;stroke:#fff;border-color:#fff}.jw-color-inactive{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-color-inactive-hover:hover{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}.jw-option{color:rgba(255,255,255,0.8)}.jw-option.jw-active-option{color:#fff;background-color:rgba(255,255,255,0.1)}:not(.jw-flag-touch) .jw-option:hover{color:#fff}.jwplayer{width:100%;font-size:16px;position:relative;display:block;min-height:0;overflow:hidden;box-sizing:border-box;font-family:Arial,Helvetica,sans-serif;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:none}.jwplayer *{box-sizing:inherit}.jwplayer.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jwplayer.jw-flag-aspect-mode{height:auto !important}.jwplayer.jw-flag-aspect-mode .jw-aspect{display:block}.jwplayer .jw-aspect{display:none}.jwplayer .jw-swf{outline:none}.jw-media,.jw-preview{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}.jw-media{overflow:hidden;cursor:pointer}.jw-plugin{position:absolute;bottom:66px}.jw-breakpoint-7 .jw-plugin{bottom:132px}.jw-plugin .jw-banner{max-width:100%;opacity:0;cursor:pointer;position:absolute;margin:auto auto 0;left:0;right:0;bottom:0;display:block}.jw-preview,.jw-captions,.jw-title{pointer-events:none}.jw-media,.jw-logo{pointer-events:all}.jw-wrapper{background-color:#000;position:absolute;top:0;left:0;right:0;bottom:0}.jw-hidden-accessibility{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.jw-contract-trigger::before{content:"";overflow:hidden;width:200%;height:200%;display:block;position:absolute;top:0;left:0}.jwplayer .jw-media video{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;margin:auto;background:transparent}.jwplayer .jw-media video::-webkit-media-controls-start-playback-button{display:none}.jwplayer.jw-stretch-uniform .jw-media video{object-fit:contain}.jwplayer.jw-stretch-none .jw-media video{object-fit:none}.jwplayer.jw-stretch-fill .jw-media video{object-fit:cover}.jwplayer.jw-stretch-exactfit .jw-media video{object-fit:fill}.jw-preview{position:absolute;display:none;opacity:1;visibility:visible;width:100%;height:100%;background:#000 no-repeat 50% 50%}.jwplayer .jw-preview,.jw-error .jw-preview{background-size:contain}.jw-stretch-none .jw-preview{background-size:auto auto}.jw-stretch-fill .jw-preview{background-size:cover}.jw-stretch-exactfit .jw-preview{background-size:100% 100%}.jw-title{display:none;padding-top:20px;width:100%;z-index:1}.jw-title-primary,.jw-title-secondary{color:#fff;padding-left:20px;padding-right:20px;padding-bottom:.5em;overflow:hidden;text-overflow:ellipsis;direction:unset;white-space:nowrap;width:100%}.jw-title-primary{font-size:1.625em}.jw-breakpoint-2 .jw-title-primary,.jw-breakpoint-3 .jw-title-primary{font-size:1.5em}.jw-flag-small-player .jw-title-primary{font-size:1.25em}.jw-flag-small-player .jw-title-secondary,.jw-title-secondary:empty{display:none}.jw-captions{position:absolute;width:100%;height:100%;text-align:center;display:none;letter-spacing:normal;word-spacing:normal;text-transform:none;text-indent:0;text-decoration:none;pointer-events:none;overflow:hidden;top:0}.jw-captions.jw-captions-enabled{display:block}.jw-captions-window{display:none;padding:.25em;border-radius:.25em}.jw-captions-window.jw-captions-window-active{display:inline-block}.jw-captions-text{display:inline-block;color:#fff;background-color:#000;word-wrap:normal;word-break:normal;white-space:pre-line;font-style:normal;font-weight:normal;text-align:center;text-decoration:none}.jw-text-track-display{font-size:inherit;line-height:1.5}.jw-text-track-cue{background-color:rgba(0,0,0,0.5);color:#fff;padding:.1em .3em}.jwplayer video::-webkit-media-controls{display:none;justify-content:flex-start}.jwplayer video::-webkit-media-text-track-display{min-width:-webkit-min-content}.jwplayer video::cue{background-color:rgba(0,0,0,0.5)}.jwplayer video::-webkit-media-controls-panel-container{display:none}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing) .jw-captions,.jwplayer.jw-flag-media-audio.jw-state-playing .jw-captions,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden) .jw-captions{max-height:calc(100% - 60px)}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-flag-media-audio.jw-state-playing:not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container{max-height:calc(100% - 60px)}.jw-logo{position:absolute;margin:20px;cursor:pointer;pointer-events:all;background-repeat:no-repeat;background-size:contain;top:auto;right:auto;left:auto;bottom:auto;outline:none}.jw-logo.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-flag-audio-player .jw-logo{display:none}.jw-logo-top-right{top:0;right:0}.jw-logo-top-left{top:0;left:0}.jw-logo-bottom-left{left:0}.jw-logo-bottom-right{right:0}.jw-logo-bottom-left,.jw-logo-bottom-right{bottom:44px;transition:bottom 150ms cubic-bezier(0, .25, .25, 1)}.jw-state-idle .jw-logo{z-index:1}.jw-state-setup .jw-wrapper{background-color:inherit}.jw-state-setup .jw-logo,.jw-state-setup .jw-controls,.jw-state-setup .jw-controls-backdrop{visibility:hidden}span.jw-break{display:block}body .jw-error,body .jwplayer.jw-state-error{background-color:#333;color:#fff;font-size:16px;display:table;opacity:1;position:relative}body .jw-error .jw-display,body .jwplayer.jw-state-error .jw-display{display:none}body .jw-error .jw-media,body .jwplayer.jw-state-error .jw-media{cursor:default}body .jw-error .jw-preview,body .jwplayer.jw-state-error .jw-preview{background-color:#333}body .jw-error .jw-error-msg,body .jwplayer.jw-state-error .jw-error-msg{background-color:#000;border-radius:2px;display:flex;flex-direction:row;align-items:stretch;padding:20px}body .jw-error .jw-error-msg .jw-icon,body .jwplayer.jw-state-error .jw-error-msg .jw-icon{height:30px;width:30px;margin-right:20px;flex:0 0 auto;align-self:center}body .jw-error .jw-error-msg .jw-icon:empty,body .jwplayer.jw-state-error .jw-error-msg .jw-icon:empty{display:none}body .jw-error .jw-error-msg .jw-info-container,body .jwplayer.jw-state-error .jw-error-msg .jw-info-container{margin:0;padding:0}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg{flex-direction:column}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text{text-align:center}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon{flex:.5 0 auto;margin-right:0;margin-bottom:20px}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break{display:inline}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break:before{content:" "}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg{height:100%;width:100%;top:0;position:absolute;left:0;background:#000;-webkit-transform:none;transform:none;padding:4px 16px;z-index:1}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg.jw-info-overlay{max-width:none;max-height:none}body .jwplayer.jw-state-error .jw-title,.jw-state-idle .jw-title,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-title{display:block}body .jwplayer.jw-state-error .jw-preview,.jw-state-idle .jw-preview,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-preview{display:block}.jw-state-idle .jw-captions,.jwplayer.jw-state-complete .jw-captions,body .jwplayer.jw-state-error .jw-captions{display:none}.jw-state-idle video::-webkit-media-text-track-container,.jwplayer.jw-state-complete video::-webkit-media-text-track-container,body .jwplayer.jw-state-error video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-fullscreen{width:100% !important;height:100% !important;top:0;right:0;bottom:0;left:0;z-index:1000;margin:0;position:fixed}body .jwplayer.jw-flag-flash-blocked .jw-title{display:block}.jwplayer.jw-flag-controls-hidden .jw-media{cursor:default}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:45px}.jw-flag-floating{background-size:cover;background-color:#000}.jw-flag-floating .jw-wrapper{position:fixed;z-index:2147483647;-webkit-animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;top:auto;bottom:1rem;left:auto;right:1rem;max-width:400px;max-height:400px;margin:0 auto}@media screen and (max-width:480px){.jw-flag-floating .jw-wrapper{width:100%;left:0;right:0}}.jw-flag-floating .jw-wrapper .jw-media{touch-action:none}@media screen and (max-device-width:480px) and (orientation:portrait){.jw-flag-touch.jw-flag-floating .jw-wrapper{-webkit-animation:none;animation:none;top:62px;bottom:auto;left:0;right:0;max-width:none;max-height:none}}.jw-flag-floating .jw-float-icon{pointer-events:all;cursor:pointer;display:none}.jw-flag-floating .jw-float-icon .jw-svg-icon{-webkit-filter:drop-shadow(0 0 1px #000);filter:drop-shadow(0 0 1px #000)}.jw-flag-floating.jw-floating-dismissible .jw-dismiss-icon{display:none}.jw-flag-floating.jw-floating-dismissible.jw-flag-ads .jw-float-icon{display:flex}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-logo,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-logo{display:none}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-float-icon,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-float-icon{display:flex}.jw-float-icon{display:none;position:absolute;top:3px;right:5px;align-items:center;justify-content:center}@-webkit-keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}.jw-flag-top{margin-top:2em;overflow:visible}.jw-top{height:2em;line-height:2;pointer-events:none;text-align:center;opacity:.8;position:absolute;top:-2em;width:100%}.jw-top .jw-icon{cursor:pointer;pointer-events:all;height:auto;width:auto}.jw-top .jw-text{color:#555}',""])},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e){t.exports=''},function(t,e,n){var i=n(96);"string"==typeof i&&(i=[["all-players",i,""]]),n(61).style(i,"all-players"),i.locals&&(t.exports=i.locals)},function(t,e,n){(t.exports=n(60)(!1)).push([t.i,'.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-flag-small-player .jw-settings-menu,.jw-settings-submenu{height:100%;width:100%}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;right:0}.jw-overlays,.jw-controls,.jw-controls-backdrop,.jw-settings-item-active::before{top:0;position:absolute;left:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-settings-menu .jw-icon.jw-button-color::after{position:absolute;bottom:0;left:0}.jw-nextup-close{position:absolute;top:0;right:0}.jw-overlays,.jw-controls,.jw-flag-small-player .jw-settings-menu{position:absolute;bottom:0;right:0}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after,.jw-time-tip::after,.jw-settings-menu .jw-icon.jw-button-color::after,.jw-text-live::before,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{content:"";display:block}.jw-svg-icon{height:24px;width:24px;fill:currentColor;pointer-events:none}.jw-icon{height:44px;width:44px;background-color:transparent;outline:none}.jw-icon.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-icon-airplay .jw-svg-icon-airplay-off{display:none}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-off{display:block}.jw-icon-airplay .jw-svg-icon-airplay-on{display:block}.jw-off.jw-icon-airplay .jw-svg-icon-airplay-on{display:none}.jw-icon-cc .jw-svg-icon-cc-off{display:none}.jw-off.jw-icon-cc .jw-svg-icon-cc-off{display:block}.jw-icon-cc .jw-svg-icon-cc-on{display:block}.jw-off.jw-icon-cc .jw-svg-icon-cc-on{display:none}.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:none}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-off{display:block}.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:block}.jw-off.jw-icon-fullscreen .jw-svg-icon-fullscreen-on{display:none}.jw-icon-volume .jw-svg-icon-volume-0{display:none}.jw-off.jw-icon-volume .jw-svg-icon-volume-0{display:block}.jw-icon-volume .jw-svg-icon-volume-100{display:none}.jw-full.jw-icon-volume .jw-svg-icon-volume-100{display:block}.jw-icon-volume .jw-svg-icon-volume-50{display:block}.jw-off.jw-icon-volume .jw-svg-icon-volume-50,.jw-full.jw-icon-volume .jw-svg-icon-volume-50{display:none}.jw-settings-menu .jw-icon::after,.jw-icon-settings::after,.jw-icon-volume::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon[aria-checked="true"]::after,.jw-settings-open .jw-icon-settings::after,.jw-icon-volume.jw-open::after{opacity:1}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-cc,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-settings,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-audio-tracks,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-hd,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-settings-sharing,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-fullscreen,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-airplay,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player).jw-flag-cast-available .jw-icon-cast{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume,.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-text-live{bottom:6px}.jwplayer.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-icon-volume::after{display:none}.jw-overlays,.jw-controls{pointer-events:none}.jw-controls-backdrop{display:block;background:linear-gradient(to bottom, transparent, rgba(0,0,0,0.4) 77%, rgba(0,0,0,0.4) 100%) 100% 100% / 100% 240px no-repeat transparent;transition:opacity 250ms cubic-bezier(0, .25, .25, 1),background-size 250ms cubic-bezier(0, .25, .25, 1);pointer-events:none}.jw-overlays{cursor:auto}.jw-controls{overflow:hidden}.jw-flag-small-player .jw-controls{text-align:center}.jw-text{height:1em;font-family:Arial,Helvetica,sans-serif;font-size:.75em;font-style:normal;font-weight:normal;color:#fff;text-align:center;font-variant:normal;font-stretch:normal}.jw-controlbar,.jw-skip,.jw-display-icon-container .jw-icon,.jw-nextup-container,.jw-autostart-mute,.jw-overlays .jw-plugin{pointer-events:all}.jwplayer .jw-display-icon-container,.jw-error .jw-display-icon-container{width:auto;height:auto;box-sizing:content-box}.jw-display{display:table;height:100%;padding:57px 0;position:relative;width:100%}.jw-flag-dragging .jw-display{display:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-display-container{display:table-cell;height:100%;text-align:center;vertical-align:middle}.jw-display-controls{display:inline-block}.jwplayer .jw-display-icon-container{float:left}.jw-display-icon-container{display:inline-block;padding:5.5px;margin:0 22px}.jw-display-icon-container .jw-icon{height:75px;width:75px;cursor:pointer;display:flex;justify-content:center;align-items:center}.jw-display-icon-container .jw-icon .jw-svg-icon{height:33px;width:33px;padding:0;position:relative}.jw-display-icon-container .jw-icon .jw-svg-icon-rewind{padding:.2em .05em}.jw-breakpoint--1 .jw-nextup-container{display:none}.jw-breakpoint-0 .jw-display-icon-next,.jw-breakpoint--1 .jw-display-icon-next,.jw-breakpoint-0 .jw-display-icon-rewind,.jw-breakpoint--1 .jw-display-icon-rewind{display:none}.jw-breakpoint-0 .jw-display .jw-icon,.jw-breakpoint--1 .jw-display .jw-icon,.jw-breakpoint-0 .jw-display .jw-svg-icon,.jw-breakpoint--1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-0 .jw-display .jw-icon:before,.jw-breakpoint--1 .jw-display .jw-icon:before,.jw-breakpoint-0 .jw-display .jw-svg-icon:before,.jw-breakpoint--1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon,.jw-breakpoint-1 .jw-display .jw-svg-icon{width:44px;height:44px;line-height:44px}.jw-breakpoint-1 .jw-display .jw-icon:before,.jw-breakpoint-1 .jw-display .jw-svg-icon:before{width:22px;height:22px}.jw-breakpoint-1 .jw-display .jw-icon.jw-icon-rewind:before{width:33px;height:33px}.jw-breakpoint-2 .jw-display .jw-icon,.jw-breakpoint-3 .jw-display .jw-icon,.jw-breakpoint-2 .jw-display .jw-svg-icon,.jw-breakpoint-3 .jw-display .jw-svg-icon{width:77px;height:77px;line-height:77px}.jw-breakpoint-2 .jw-display .jw-icon:before,.jw-breakpoint-3 .jw-display .jw-icon:before,.jw-breakpoint-2 .jw-display .jw-svg-icon:before,.jw-breakpoint-3 .jw-display .jw-svg-icon:before{width:38.5px;height:38.5px}.jw-breakpoint-4 .jw-display .jw-icon,.jw-breakpoint-5 .jw-display .jw-icon,.jw-breakpoint-6 .jw-display .jw-icon,.jw-breakpoint-7 .jw-display .jw-icon,.jw-breakpoint-4 .jw-display .jw-svg-icon,.jw-breakpoint-5 .jw-display .jw-svg-icon,.jw-breakpoint-6 .jw-display .jw-svg-icon,.jw-breakpoint-7 .jw-display .jw-svg-icon{width:88px;height:88px;line-height:88px}.jw-breakpoint-4 .jw-display .jw-icon:before,.jw-breakpoint-5 .jw-display .jw-icon:before,.jw-breakpoint-6 .jw-display .jw-icon:before,.jw-breakpoint-7 .jw-display .jw-icon:before,.jw-breakpoint-4 .jw-display .jw-svg-icon:before,.jw-breakpoint-5 .jw-display .jw-svg-icon:before,.jw-breakpoint-6 .jw-display .jw-svg-icon:before,.jw-breakpoint-7 .jw-display .jw-svg-icon:before{width:44px;height:44px}.jw-controlbar{display:flex;flex-flow:row wrap;align-items:center;justify-content:center;position:absolute;left:0;bottom:0;width:100%;border:none;border-radius:0;background-size:auto;box-shadow:none;max-height:72px;transition:250ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s}.jw-breakpoint-7 .jw-controlbar{max-height:140px}.jw-breakpoint-7 .jw-controlbar .jw-button-container{padding:0 48px 20px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-tooltip{margin-bottom:-7px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-overlay{padding-bottom:40%}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text{font-size:1em}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-text.jw-text-elapsed{justify-content:flex-end}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume{height:60px;width:60px}.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-inline .jw-svg-icon,.jw-breakpoint-7 .jw-controlbar .jw-button-container .jw-icon-volume .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time{padding:0 60px;height:34px}.jw-breakpoint-7 .jw-controlbar .jw-slider-time .jw-slider-container{height:10px}.jw-controlbar .jw-button-image{background:no-repeat 50% 50%;background-size:contain;max-height:24px}.jw-controlbar .jw-spacer{flex:1 1 auto;align-self:stretch}.jw-controlbar .jw-icon.jw-button-color:hover{color:#fff}.jw-button-container{display:flex;flex-flow:row nowrap;flex:1 1 auto;align-items:center;justify-content:center;width:100%;padding:0 12px}.jw-slider-horizontal{background-color:transparent}.jw-icon-inline{position:relative}.jw-icon-inline,.jw-icon-tooltip{height:44px;width:44px;align-items:center;display:flex;justify-content:center}.jw-icon-inline:not(.jw-text),.jw-icon-tooltip,.jw-slider-horizontal{cursor:pointer}.jw-text-elapsed,.jw-text-duration{justify-content:flex-start;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.jw-icon-tooltip{position:relative}.jw-knob:hover,.jw-icon-inline:hover,.jw-icon-tooltip:hover,.jw-icon-display:hover,.jw-option:before:hover{color:#fff}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{pointer-events:none}.jw-icon-cast{display:none;margin:0;padding:0}.jw-icon-cast google-cast-launcher{background-color:transparent;border:none;padding:0;width:24px;height:24px;cursor:pointer}.jw-icon-inline.jw-icon-volume{display:none}.jwplayer .jw-text-countdown{display:none}.jw-flag-small-player .jw-display{padding-top:0;padding-bottom:0}.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-rewind,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-next,.jw-flag-small-player:not(.jw-flag-audio-player):not(.jw-flag-ads) .jw-controlbar .jw-button-container>.jw-icon-playback{display:none}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controlbar{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-ads-vpaid:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-playing:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop,.jw-flag-user-inactive.jw-state-buffering:not(.jw-flag-media-audio):not(.jw-flag-audio-player):not(.jw-flag-ads-vpaid-controls):not(.jw-flag-casting) .jw-controls-backdrop{opacity:0}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-countdown{display:flex}.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-elapsed,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint--1 .jw-text-duration,.jwplayer:not(.jw-flag-ads):not(.jw-flag-live).jw-breakpoint-0 .jw-text-duration{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-text-countdown,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-related-btn,.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-slider-volume{display:none}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-controlbar{flex-direction:column-reverse}.jwplayer.jw-breakpoint--1:not(.jw-flag-ads):not(.jw-flag-audio-player) .jw-button-container{height:30px}.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-volume,.jw-breakpoint--1.jw-flag-ads:not(.jw-flag-audio-player) .jw-icon-fullscreen{display:none}.jwplayer:not(.jw-breakpoint-0) .jw-text-duration:before,.jwplayer:not(.jw-breakpoint--1) .jw-text-duration:before{content:"/";padding-right:1ch;padding-left:1ch}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar{will-change:transform}.jwplayer:not(.jw-flag-user-inactive) .jw-controlbar .jw-text{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.jw-slider-container{display:flex;align-items:center;position:relative;touch-action:none}.jw-rail,.jw-buffer,.jw-progress{position:absolute;cursor:pointer}.jw-progress{background-color:#f2f2f2}.jw-rail{background-color:rgba(255,255,255,0.3)}.jw-buffer{background-color:rgba(255,255,255,0.3)}.jw-knob{height:13px;width:13px;background-color:#fff;border-radius:50%;box-shadow:0 0 10px rgba(0,0,0,0.4);opacity:1;pointer-events:none;position:absolute;-webkit-transform:translate(-50%, -50%) scale(0);transform:translate(-50%, -50%) scale(0);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform}.jw-flag-dragging .jw-slider-time .jw-knob,.jw-icon-volume:active .jw-slider-volume .jw-knob{box-shadow:0 0 26px rgba(0,0,0,0.2),0 0 10px rgba(0,0,0,0.4),0 0 0 6px rgba(255,255,255,0.2)}.jw-slider-horizontal,.jw-slider-vertical{display:flex}.jw-slider-horizontal .jw-slider-container{height:5px;width:100%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue,.jw-slider-horizontal .jw-knob{top:50%}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress,.jw-slider-horizontal .jw-cue{-webkit-transform:translate(0, -50%);transform:translate(0, -50%)}.jw-slider-horizontal .jw-rail,.jw-slider-horizontal .jw-buffer,.jw-slider-horizontal .jw-progress{height:5px}.jw-slider-horizontal .jw-rail{width:100%}.jw-slider-vertical{align-items:center;flex-direction:column}.jw-slider-vertical .jw-slider-container{height:88px;width:5px}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress,.jw-slider-vertical .jw-knob{left:50%}.jw-slider-vertical .jw-rail,.jw-slider-vertical .jw-buffer,.jw-slider-vertical .jw-progress{height:100%;width:5px;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out;bottom:0}.jw-slider-vertical .jw-knob{-webkit-transform:translate(-50%, 50%);transform:translate(-50%, 50%)}.jw-slider-time.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-slider-time,.jw-flag-audio-player .jw-slider-volume{height:17px;width:100%;align-items:center;background:transparent none;padding:0 12px}.jw-slider-time .jw-cue{background-color:rgba(33,33,33,0.8);cursor:pointer;position:absolute;width:6px}.jw-slider-time,.jw-horizontal-volume-container{z-index:1;outline:none}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail,.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer,.jw-slider-time .jw-progress,.jw-horizontal-volume-container .jw-progress,.jw-slider-time .jw-cue,.jw-horizontal-volume-container .jw-cue{-webkit-backface-visibility:hidden;backface-visibility:hidden;height:100%;-webkit-transform:translate(0, -50%) scale(1, .6);transform:translate(0, -50%) scale(1, .6);transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out}.jw-slider-time:hover .jw-rail,.jw-horizontal-volume-container:hover .jw-rail,.jw-slider-time:focus .jw-rail,.jw-horizontal-volume-container:focus .jw-rail,.jw-flag-dragging .jw-slider-time .jw-rail,.jw-flag-dragging .jw-horizontal-volume-container .jw-rail,.jw-flag-touch .jw-slider-time .jw-rail,.jw-flag-touch .jw-horizontal-volume-container .jw-rail,.jw-slider-time:hover .jw-buffer,.jw-horizontal-volume-container:hover .jw-buffer,.jw-slider-time:focus .jw-buffer,.jw-horizontal-volume-container:focus .jw-buffer,.jw-flag-dragging .jw-slider-time .jw-buffer,.jw-flag-dragging .jw-horizontal-volume-container .jw-buffer,.jw-flag-touch .jw-slider-time .jw-buffer,.jw-flag-touch .jw-horizontal-volume-container .jw-buffer,.jw-slider-time:hover .jw-progress,.jw-horizontal-volume-container:hover .jw-progress,.jw-slider-time:focus .jw-progress,.jw-horizontal-volume-container:focus .jw-progress,.jw-flag-dragging .jw-slider-time .jw-progress,.jw-flag-dragging .jw-horizontal-volume-container .jw-progress,.jw-flag-touch .jw-slider-time .jw-progress,.jw-flag-touch .jw-horizontal-volume-container .jw-progress,.jw-slider-time:hover .jw-cue,.jw-horizontal-volume-container:hover .jw-cue,.jw-slider-time:focus .jw-cue,.jw-horizontal-volume-container:focus .jw-cue,.jw-flag-dragging .jw-slider-time .jw-cue,.jw-flag-dragging .jw-horizontal-volume-container .jw-cue,.jw-flag-touch .jw-slider-time .jw-cue,.jw-flag-touch .jw-horizontal-volume-container .jw-cue{-webkit-transform:translate(0, -50%) scale(1, 1);transform:translate(0, -50%) scale(1, 1)}.jw-slider-time:hover .jw-knob,.jw-horizontal-volume-container:hover .jw-knob,.jw-slider-time:focus .jw-knob,.jw-horizontal-volume-container:focus .jw-knob{-webkit-transform:translate(-50%, -50%) scale(1);transform:translate(-50%, -50%) scale(1)}.jw-slider-time .jw-rail,.jw-horizontal-volume-container .jw-rail{background-color:rgba(255,255,255,0.2)}.jw-slider-time .jw-buffer,.jw-horizontal-volume-container .jw-buffer{background-color:rgba(255,255,255,0.4)}.jw-flag-touch .jw-slider-time::before,.jw-flag-touch .jw-horizontal-volume-container::before{height:44px;width:100%;content:"";position:absolute;display:block;bottom:calc(100% - 17px);left:0}.jw-slider-time.jw-tab-focus:focus .jw-rail,.jw-horizontal-volume-container.jw-tab-focus:focus .jw-rail{outline:solid 2px #4d90fe}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time{height:17px;padding:0}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-slider-container{height:10px}.jw-breakpoint--1:not(.jw-flag-audio-player) .jw-slider-time .jw-knob{border-radius:0;border:1px solid rgba(0,0,0,0.75);height:12px;width:10px}.jw-modal{width:284px}.jw-breakpoint-7 .jw-modal,.jw-breakpoint-6 .jw-modal,.jw-breakpoint-5 .jw-modal{height:232px}.jw-breakpoint-4 .jw-modal,.jw-breakpoint-3 .jw-modal{height:192px}.jw-breakpoint-2 .jw-modal,.jw-flag-small-player .jw-modal{bottom:0;right:0;height:100%;width:100%;max-height:none;max-width:none;z-index:2}.jwplayer .jw-rightclick{display:none;position:absolute;white-space:nowrap}.jwplayer .jw-rightclick.jw-open{display:block}.jwplayer .jw-rightclick .jw-rightclick-list{border-radius:1px;list-style:none;margin:0;padding:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item{background-color:rgba(0,0,0,0.8);border-bottom:1px solid #444;margin:0}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo{color:#fff;display:inline-flex;padding:0 10px 0 0;vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-logo .jw-svg-icon{height:20px;width:20px}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item .jw-rightclick-link{border:none;color:#fff;display:block;font-size:11px;line-height:1em;padding:15px 23px;text-align:start;text-decoration:none;width:100%}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:last-child{border-bottom:none}.jwplayer .jw-rightclick .jw-rightclick-list .jw-rightclick-item:hover{cursor:pointer}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured{vertical-align:middle}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link{color:#fff}.jwplayer .jw-rightclick .jw-rightclick-list .jw-featured .jw-rightclick-link span{color:#fff}.jwplayer .jw-rightclick .jw-info-overlay-item,.jwplayer .jw-rightclick .jw-share-item,.jwplayer .jw-rightclick .jw-shortcuts-item{border:none;background-color:transparent;outline:none;cursor:pointer}.jw-icon-tooltip.jw-open .jw-overlay{opacity:1;pointer-events:auto;transition-delay:0s}.jw-icon-tooltip.jw-open .jw-overlay:focus{outline:none}.jw-icon-tooltip.jw-open .jw-overlay:focus.jw-tab-focus{outline:solid 2px #4d90fe}.jw-slider-time .jw-overlay:before{height:1em;top:auto}.jw-slider-time .jw-icon-tooltip.jw-open .jw-overlay{pointer-events:none}.jw-volume-tip{padding:13px 0 26px}.jw-time-tip,.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{height:auto;width:100%;box-shadow:0 0 10px rgba(0,0,0,0.4);color:#fff;display:block;margin:0 0 14px;pointer-events:none;position:relative;z-index:0}.jw-time-tip::after,.jw-controlbar .jw-tooltip::after,.jw-settings-menu .jw-tooltip::after{top:100%;position:absolute;left:50%;height:14px;width:14px;border-radius:1px;background-color:currentColor;-webkit-transform-origin:75% 50%;transform-origin:75% 50%;-webkit-transform:translate(-50%, -50%) rotate(45deg);transform:translate(-50%, -50%) rotate(45deg);z-index:-1}.jw-time-tip .jw-text,.jw-controlbar .jw-tooltip .jw-text,.jw-settings-menu .jw-tooltip .jw-text{background-color:#fff;border-radius:1px;color:#000;font-size:10px;height:auto;line-height:1;padding:7px 10px;display:inline-block;min-width:100%;vertical-align:middle}.jw-controlbar .jw-overlay{position:absolute;bottom:100%;left:50%;margin:0;min-height:44px;min-width:44px;opacity:0;pointer-events:none;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility;transition-delay:0s, 150ms;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);width:100%;z-index:1}.jw-controlbar .jw-overlay .jw-contents{position:relative}.jw-controlbar .jw-option{position:relative;white-space:nowrap;cursor:pointer;list-style:none;height:1.5em;font-family:inherit;line-height:1.5em;padding:0 .5em;font-size:.8em;margin:0}.jw-controlbar .jw-option::before{padding-right:.125em}.jw-controlbar .jw-tooltip,.jw-settings-menu .jw-tooltip{position:absolute;bottom:100%;left:50%;opacity:0;-webkit-transform:translate(-50%, 0);transform:translate(-50%, 0);transition:100ms 0s cubic-bezier(0, .25, .25, 1);transition-property:opacity, visibility, -webkit-transform;transition-property:opacity, transform, visibility;transition-property:opacity, transform, visibility, -webkit-transform;visibility:hidden;white-space:nowrap;width:auto;z-index:1}.jw-controlbar .jw-tooltip.jw-open,.jw-settings-menu .jw-tooltip.jw-open{opacity:1;-webkit-transform:translate(-50%, -10px);transform:translate(-50%, -10px);transition-duration:150ms;transition-delay:500ms,0s,500ms;visibility:visible}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen{left:auto;right:0;-webkit-transform:translate(0, 0);transform:translate(0, 0)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen.jw-open,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen.jw-open{-webkit-transform:translate(0, -10px);transform:translate(0, -10px)}.jw-controlbar .jw-tooltip.jw-tooltip-fullscreen::after,.jw-settings-menu .jw-tooltip.jw-tooltip-fullscreen::after{left:auto;right:9px}.jw-tooltip-time{height:auto;width:0;bottom:100%;line-height:normal;padding:0;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.jw-tooltip-time .jw-overlay{bottom:0;min-height:0;width:auto}.jw-tooltip{bottom:57px;display:none;position:absolute}.jw-tooltip .jw-text{height:100%;white-space:nowrap;text-overflow:ellipsis;direction:unset;max-width:246px;overflow:hidden}.jw-flag-audio-player .jw-tooltip{display:none}.jw-flag-small-player .jw-time-thumb{display:none}.jwplayer .jw-shortcuts-tooltip{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column;z-index:1}.jwplayer .jw-shortcuts-tooltip.jw-open{display:flex}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-close{flex:0 0 auto;margin:5px 5px 5px auto}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container{display:flex;flex:1 1 auto;flex-flow:column;font-size:12px;margin:0 20px 20px;overflow-y:auto;padding:5px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar{background-color:transparent;width:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-title{font-weight:bold}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list{display:flex;max-width:340px;margin:0 10px}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-tooltip-descriptions{width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row{display:flex;align-items:center;justify-content:space-between;margin:10px 0;width:100%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-description{margin-right:10px;max-width:70%}.jwplayer .jw-shortcuts-tooltip .jw-shortcuts-container .jw-shortcuts-tooltip-list .jw-shortcuts-row .jw-shortcuts-key{background:#fefefe;color:#333;overflow:hidden;padding:7px 10px;text-overflow:ellipsis;white-space:nowrap}.jw-skip{color:rgba(255,255,255,0.8);cursor:default;position:absolute;display:flex;right:.75em;bottom:56px;padding:.5em;border:1px solid #333;background-color:#000;align-items:center;height:2em}.jw-skip.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-skip.jw-skippable{cursor:pointer;padding:.25em .75em}.jw-skip.jw-skippable:hover{cursor:pointer;color:#fff}.jw-skip.jw-skippable .jw-skip-icon{display:inline;height:24px;width:24px;margin:0}.jw-breakpoint-7 .jw-skip{padding:1.35em 1em;bottom:130px}.jw-breakpoint-7 .jw-skip .jw-text{font-size:1em;font-weight:normal}.jw-breakpoint-7 .jw-skip .jw-icon-inline{height:30px;width:30px}.jw-breakpoint-7 .jw-skip .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-skip .jw-skip-icon{display:none;margin-left:-0.75em;padding:0 .5em;pointer-events:none}.jw-skip .jw-skip-icon .jw-svg-icon-next{display:block;padding:0}.jw-skip .jw-text,.jw-skip .jw-skip-icon{vertical-align:middle;font-size:.7em}.jw-skip .jw-text{font-weight:bold}.jw-cast{background-size:cover;display:none;height:100%;position:relative;width:100%}.jw-cast-container{background:linear-gradient(180deg, rgba(25,25,25,0.75), rgba(25,25,25,0.25), rgba(25,25,25,0));left:0;padding:20px 20px 80px;position:absolute;top:0;width:100%}.jw-cast-text{color:#fff;font-size:1.6em}.jw-breakpoint--1 .jw-cast-text,.jw-breakpoint-0 .jw-cast-text{font-size:1.15em}.jw-breakpoint-1 .jw-cast-text,.jw-breakpoint-2 .jw-cast-text,.jw-breakpoint-3 .jw-cast-text{font-size:1.3em}.jw-nextup-container{position:absolute;bottom:66px;left:0;background-color:transparent;cursor:pointer;margin:0 auto;padding:12px;pointer-events:none;right:0;text-align:right;visibility:hidden;width:100%}.jw-settings-open .jw-nextup-container,.jw-info-open .jw-nextup-container{display:none}.jw-breakpoint-7 .jw-nextup-container{padding:60px}.jw-flag-small-player .jw-nextup-container{padding:0 12px 0 0}.jw-flag-small-player .jw-nextup-container .jw-nextup-title,.jw-flag-small-player .jw-nextup-container .jw-nextup-duration,.jw-flag-small-player .jw-nextup-container .jw-nextup-close{display:none}.jw-flag-small-player .jw-nextup-container .jw-nextup-tooltip{height:30px}.jw-flag-small-player .jw-nextup-container .jw-nextup-header{font-size:12px}.jw-flag-small-player .jw-nextup-container .jw-nextup-body{justify-content:center;align-items:center;padding:.75em .3em}.jw-flag-small-player .jw-nextup-container .jw-nextup-thumbnail{width:50%}.jw-flag-small-player .jw-nextup-container .jw-nextup{max-width:65px}.jw-flag-small-player .jw-nextup-container .jw-nextup.jw-nextup-thumbnail-visible{max-width:120px}.jw-nextup{background:#333;border-radius:0;box-shadow:0 0 10px rgba(0,0,0,0.5);color:rgba(255,255,255,0.8);display:inline-block;max-width:280px;overflow:hidden;opacity:0;position:relative;width:64%;pointer-events:all;-webkit-transform:translate(0, -5px);transform:translate(0, -5px);transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:opacity, -webkit-transform;transition-property:opacity, transform;transition-property:opacity, transform, -webkit-transform;transition-delay:0s}.jw-nextup:hover .jw-nextup-tooltip{color:#fff}.jw-nextup.jw-nextup-thumbnail-visible{max-width:400px}.jw-nextup.jw-nextup-thumbnail-visible .jw-nextup-thumbnail{display:block}.jw-nextup-container-visible{visibility:visible}.jw-nextup-container-visible .jw-nextup{opacity:1;-webkit-transform:translate(0, 0);transform:translate(0, 0);transition-delay:0s, 0s, 150ms}.jw-nextup-tooltip{display:flex;height:80px}.jw-nextup-thumbnail{width:120px;background-position:center;background-size:cover;flex:0 0 auto;display:none}.jw-nextup-body{flex:1 1 auto;overflow:hidden;padding:.75em .875em;display:flex;flex-flow:column wrap;justify-content:space-between}.jw-nextup-header,.jw-nextup-title{font-size:14px;line-height:1.35}.jw-nextup-header{font-weight:bold}.jw-nextup-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.jw-nextup-duration{align-self:flex-end;text-align:right;font-size:12px}.jw-nextup-close{height:24px;width:24px;border:none;color:rgba(255,255,255,0.8);cursor:pointer;margin:6px;visibility:hidden}.jw-nextup-close:hover{color:#fff}.jw-nextup-sticky .jw-nextup-close{visibility:visible}.jw-autostart-mute{position:absolute;bottom:0;right:12px;height:44px;width:44px;background-color:rgba(33,33,33,0.4);padding:5px 4px 5px 6px;display:none}.jwplayer.jw-flag-autostart:not(.jw-flag-media-audio) .jw-nextup{display:none}.jw-settings-menu{position:absolute;bottom:57px;right:12px;align-items:flex-start;background-color:#333;display:none;flex-flow:column nowrap;max-width:284px;pointer-events:auto}.jw-settings-open .jw-settings-menu{display:flex}.jw-breakpoint-7 .jw-settings-menu{bottom:130px;right:60px;max-height:none;max-width:none;height:35%;width:25%}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline{height:60px;width:60px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-svg-icon{height:30px;width:30px}.jw-breakpoint-7 .jw-settings-menu .jw-settings-topbar:not(.jw-nested-menu-open) .jw-icon-inline .jw-tooltip .jw-text{font-size:1em}.jw-breakpoint-7 .jw-settings-menu .jw-settings-back{min-width:60px}.jw-breakpoint-6 .jw-settings-menu,.jw-breakpoint-5 .jw-settings-menu{height:232px;width:284px;max-height:232px}.jw-breakpoint-4 .jw-settings-menu,.jw-breakpoint-3 .jw-settings-menu{height:192px;width:284px;max-height:192px}.jw-breakpoint-2 .jw-settings-menu{height:179px;width:284px;max-height:179px}.jw-flag-small-player .jw-settings-menu{max-width:none}.jw-settings-menu .jw-icon.jw-button-color::after{height:100%;width:24px;box-shadow:inset 0 -3px 0 -1px currentColor;margin:auto;opacity:0;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-settings-menu .jw-icon.jw-button-color[aria-checked="true"]::after{opacity:1}.jw-settings-menu .jw-settings-reset{text-decoration:underline}.jw-settings-topbar{align-items:center;background-color:rgba(0,0,0,0.4);display:flex;flex:0 0 auto;padding:3px 5px 0;width:100%}.jw-settings-topbar.jw-nested-menu-open{padding:0}.jw-settings-topbar.jw-nested-menu-open .jw-icon:not(.jw-settings-close):not(.jw-settings-back){display:none}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-close{width:20px}.jw-settings-topbar.jw-nested-menu-open .jw-svg-icon-arrow-left{height:12px}.jw-settings-topbar.jw-nested-menu-open .jw-settings-topbar-text{display:block;outline:none}.jw-settings-topbar .jw-settings-back{min-width:44px}.jw-settings-topbar .jw-settings-topbar-buttons{display:inherit;width:100%;height:100%}.jw-settings-topbar .jw-settings-topbar-text{display:none;color:#fff;font-size:13px;width:100%}.jw-settings-topbar .jw-settings-close{margin-left:auto}.jw-settings-submenu{display:none;flex:1 1 auto;overflow-y:auto;padding:8px 20px 0 5px}.jw-settings-submenu::-webkit-scrollbar{background-color:transparent;width:6px}.jw-settings-submenu::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-settings-submenu.jw-settings-submenu-active{display:block}.jw-settings-submenu .jw-submenu-topbar{box-shadow:0 2px 9px 0 #1d1d1d;background-color:#2f2d2d;margin:-8px -20px 0 -5px}.jw-settings-submenu .jw-submenu-topbar .jw-settings-content-item{cursor:pointer;text-align:right;padding-right:15px;text-decoration:underline}.jw-settings-submenu .jw-settings-value-wrapper{float:right;display:flex;align-items:center}.jw-settings-submenu .jw-settings-value-wrapper .jw-settings-content-item-arrow{display:flex}.jw-settings-submenu .jw-settings-value-wrapper .jw-svg-icon-arrow-right{width:8px;margin-left:5px;height:12px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item{font-size:1em;padding:11px 15px 11px 30px}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-settings-item-active::before{justify-content:flex-end}.jw-breakpoint-7 .jw-settings-submenu .jw-settings-content-item .jw-auto-label{font-size:.85em;padding-left:10px}.jw-flag-touch .jw-settings-submenu{overflow-y:scroll;-webkit-overflow-scrolling:touch}.jw-auto-label{font-size:10px;font-weight:initial;opacity:.75;padding-left:5px}.jw-settings-content-item{position:relative;color:rgba(255,255,255,0.8);cursor:pointer;font-size:12px;line-height:1;padding:7px 0 7px 15px;width:100%;text-align:left;outline:none}.jw-settings-content-item:hover{color:#fff}.jw-settings-content-item:focus{font-weight:bold}.jw-flag-small-player .jw-settings-content-item{line-height:1.75}.jw-settings-content-item.jw-tab-focus:focus{border:solid 2px #4d90fe}.jw-settings-item-active{font-weight:bold;position:relative}.jw-settings-item-active::before{height:100%;width:1em;align-items:center;content:"\\2022";display:inline-flex;justify-content:center}.jw-breakpoint-2 .jw-settings-open .jw-display-container,.jw-flag-small-player .jw-settings-open .jw-display-container,.jw-flag-touch .jw-settings-open .jw-display-container{display:none}.jw-breakpoint-2 .jw-settings-open.jw-controls,.jw-flag-small-player .jw-settings-open.jw-controls,.jw-flag-touch .jw-settings-open.jw-controls{z-index:1}.jw-flag-small-player .jw-settings-open .jw-controlbar{display:none}.jw-settings-open .jw-icon-settings::after{opacity:1}.jw-settings-open .jw-tooltip-settings{display:none}.jw-sharing-link{cursor:pointer}.jw-shortcuts-container .jw-switch{position:relative;display:inline-block;transition:ease-out .15s;transition-property:opacity, background;border-radius:18px;width:80px;height:20px;padding:10px;background:rgba(80,80,80,0.8);cursor:pointer;font-size:inherit;vertical-align:middle}.jw-shortcuts-container .jw-switch.jw-tab-focus{outline:solid 2px #4d90fe}.jw-shortcuts-container .jw-switch .jw-switch-knob{position:absolute;top:2px;left:1px;transition:ease-out .15s;box-shadow:0 0 10px rgba(0,0,0,0.4);border-radius:13px;width:15px;height:15px;background:#fefefe}.jw-shortcuts-container .jw-switch:before,.jw-shortcuts-container .jw-switch:after{position:absolute;top:3px;transition:inherit;color:#fefefe}.jw-shortcuts-container .jw-switch:before{content:attr(data-jw-switch-disabled);right:8px}.jw-shortcuts-container .jw-switch:after{content:attr(data-jw-switch-enabled);left:8px;opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]{background:#475470}.jw-shortcuts-container .jw-switch[aria-checked="true"]:before{opacity:0}.jw-shortcuts-container .jw-switch[aria-checked="true"]:after{opacity:1}.jw-shortcuts-container .jw-switch[aria-checked="true"] .jw-switch-knob{left:60px}.jw-idle-icon-text{display:none;line-height:1;position:absolute;text-align:center;text-indent:.35em;top:100%;white-space:nowrap;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.jw-idle-label{border-radius:50%;color:#fff;-webkit-filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));filter:drop-shadow(1px 1px 5px rgba(12,26,71,0.25));font:normal 16px/1 Arial,Helvetica,sans-serif;position:relative;transition:background-color 150ms cubic-bezier(0, .25, .25, 1);transition-property:background-color,-webkit-filter;transition-property:background-color,filter;transition-property:background-color,filter,-webkit-filter;-webkit-font-smoothing:antialiased}.jw-state-idle .jw-icon-display.jw-idle-label .jw-idle-icon-text{display:block}.jw-state-idle .jw-icon-display.jw-idle-label .jw-svg-icon-play{-webkit-transform:scale(.7, .7);transform:scale(.7, .7)}.jw-breakpoint-0.jw-state-idle .jw-icon-display.jw-idle-label,.jw-breakpoint--1.jw-state-idle .jw-icon-display.jw-idle-label{font-size:12px}.jw-info-overlay{top:50%;position:absolute;left:50%;background:#333;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);display:none;color:#fff;pointer-events:all;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;overflow:hidden;flex-direction:column}.jw-info-overlay .jw-info-close{flex:0 0 auto;margin:5px 5px 5px auto}.jw-info-open .jw-info-overlay{display:flex}.jw-info-container{display:flex;flex:1 1 auto;flex-flow:column;margin:0 20px 20px;overflow-y:auto;padding:5px}.jw-info-container [class*="jw-info"]:not(:first-of-type){color:rgba(255,255,255,0.8);padding-top:10px;font-size:12px}.jw-info-container .jw-info-description{margin-bottom:30px;text-align:start}.jw-info-container .jw-info-description:empty{display:none}.jw-info-container .jw-info-duration{text-align:start}.jw-info-container .jw-info-title{text-align:start;font-size:12px;font-weight:bold}.jw-info-container::-webkit-scrollbar{background-color:transparent;width:6px}.jw-info-container::-webkit-scrollbar-thumb{background-color:#fff;border:1px solid #333;border-radius:6px}.jw-info-clientid{align-self:flex-end;font-size:12px;color:rgba(255,255,255,0.8);margin:0 20px 20px 44px;text-align:right}.jw-flag-touch .jw-info-open .jw-display-container{display:none}@supports ((-webkit-filter: drop-shadow(0 0 3px #000)) or (filter: drop-shadow(0 0 3px #000))){.jwplayer.jw-ab-drop-shadow .jw-controls .jw-svg-icon,.jwplayer.jw-ab-drop-shadow .jw-controls .jw-icon.jw-text,.jwplayer.jw-ab-drop-shadow .jw-slider-container .jw-rail,.jwplayer.jw-ab-drop-shadow .jw-title{text-shadow:none;box-shadow:none;-webkit-filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3));filter:drop-shadow(0 2px 3px rgba(0,0,0,0.3))}.jwplayer.jw-ab-drop-shadow .jw-button-color{opacity:.8;transition-property:color, opacity}.jwplayer.jw-ab-drop-shadow .jw-button-color:not(:hover){color:#fff;opacity:.8}.jwplayer.jw-ab-drop-shadow .jw-button-color:hover{opacity:1}.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0), hsla(0, 0%, 0%, 0.00787) 10.79%, hsla(0, 0%, 0%, 0.02963) 21.99%, hsla(0, 0%, 0%, 0.0625) 33.34%, hsla(0, 0%, 0%, 0.1037) 44.59%, hsla(0, 0%, 0%, 0.15046) 55.48%, hsla(0, 0%, 0%, 0.2) 65.75%, hsla(0, 0%, 0%, 0.24954) 75.14%, hsla(0, 0%, 0%, 0.2963) 83.41%, hsla(0, 0%, 0%, 0.3375) 90.28%, hsla(0, 0%, 0%, 0.37037) 95.51%, hsla(0, 0%, 0%, 0.39213) 98.83%, hsla(0, 0%, 0%, 0.4));mix-blend-mode:multiply;transition-property:opacity}.jw-state-idle.jwplayer.jw-ab-drop-shadow .jw-controls-backdrop{background-image:linear-gradient(to bottom, hsla(0, 0%, 0%, 0.2), hsla(0, 0%, 0%, 0.19606) 1.17%, hsla(0, 0%, 0%, 0.18519) 4.49%, hsla(0, 0%, 0%, 0.16875) 9.72%, hsla(0, 0%, 0%, 0.14815) 16.59%, hsla(0, 0%, 0%, 0.12477) 24.86%, hsla(0, 0%, 0%, 0.1) 34.25%, hsla(0, 0%, 0%, 0.07523) 44.52%, hsla(0, 0%, 0%, 0.05185) 55.41%, hsla(0, 0%, 0%, 0.03125) 66.66%, hsla(0, 0%, 0%, 0.01481) 78.01%, hsla(0, 0%, 0%, 0.00394) 89.21%, hsla(0, 0%, 0%, 0));background-size:100% 7rem;background-position:50% 0}.jwplayer.jw-ab-drop-shadow.jw-state-idle .jw-controls{background-color:transparent}}.jw-video-thumbnail-container{position:relative;overflow:hidden}.jw-video-thumbnail-container:not(.jw-related-shelf-item-image){height:100%;width:100%}.jw-video-thumbnail-container.jw-video-thumbnail-generated{position:absolute;top:0;left:0}.jw-video-thumbnail-container:hover,.jw-related-item-content:hover .jw-video-thumbnail-container,.jw-related-shelf-item:hover .jw-video-thumbnail-container{cursor:pointer}.jw-video-thumbnail-container:hover .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-item-content:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed),.jw-related-shelf-item:hover .jw-video-thumbnail-container .jw-video-thumbnail:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail{position:absolute;top:50%;left:50%;bottom:unset;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);width:100%;height:auto;min-width:100%;min-height:100%;opacity:0;transition:opacity .3s ease;object-fit:cover;background:#000}.jw-related-item-next-up .jw-video-thumbnail-container .jw-video-thumbnail{height:100%;width:auto}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-visible:not(.jw-video-thumbnail-completed){opacity:1}.jw-video-thumbnail-container .jw-video-thumbnail.jw-video-thumbnail-completed{opacity:0}.jw-video-thumbnail-container .jw-video-thumbnail~.jw-svg-icon-play{display:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-shelf-item-aspect{pointer-events:none}.jw-video-thumbnail-container .jw-video-thumbnail+.jw-related-item-poster-content{pointer-events:none}.jw-state-idle:not(.jw-flag-cast-available) .jw-display{padding:0}.jw-state-idle .jw-controls{background:rgba(0,0,0,0.4)}.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-slider-time,.jw-state-idle.jw-flag-cast-available:not(.jw-flag-audio-player) .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay),.jw-state-idle.jw-flag-cardboard-available .jw-controlbar .jw-icon:not(.jw-icon-cardboard):not(.jw-icon-cast):not(.jw-icon-airplay){display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon:focus{border:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-icon .jw-svg-icon-buffer{-webkit-animation:jw-spin 2s linear infinite;animation:jw-spin 2s linear infinite;display:block}@-webkit-keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes jw-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.jwplayer.jw-state-buffering .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-pause{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-play{display:none}.jwplayer.jw-state-playing .jw-display .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-playing .jw-icon-playback .jw-svg-icon-pause{display:block}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-controls-backdrop{opacity:0}.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio) .jw-logo-bottom-left,.jwplayer.jw-state-playing.jw-flag-user-inactive:not(.jw-flag-audio-player):not(.jw-flag-casting):not(.jw-flag-media-audio):not(.jw-flag-autostart) .jw-logo-bottom-right{bottom:0}.jwplayer .jw-icon-playback .jw-svg-icon-stop{display:none}.jwplayer.jw-state-paused .jw-svg-icon-pause,.jwplayer.jw-state-idle .jw-svg-icon-pause,.jwplayer.jw-state-error .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-svg-icon-pause{display:none}.jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-complete .jw-icon-display .jw-svg-icon-play,.jwplayer.jw-state-buffering .jw-icon-display .jw-svg-icon-play{display:none}.jwplayer:not(.jw-state-buffering) .jw-svg-icon-buffer{display:none}.jwplayer:not(.jw-state-complete) .jw-svg-icon-replay{display:none}.jwplayer:not(.jw-state-error) .jw-svg-icon-error{display:none}.jwplayer.jw-state-complete .jw-display .jw-icon-display .jw-svg-icon-replay{display:block}.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-state-complete .jw-controls{background:rgba(0,0,0,0.4);height:100%}.jw-state-idle .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-state-paused .jw-icon-display .jw-svg-icon-pause,.jwplayer.jw-state-complete .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-state-idle .jw-display-icon-rewind,.jwplayer.jw-state-buffering .jw-display-icon-rewind,.jwplayer.jw-state-complete .jw-display-icon-rewind,body .jw-error .jw-display-icon-rewind,body .jwplayer.jw-state-error .jw-display-icon-rewind,.jw-state-idle .jw-display-icon-next,.jwplayer.jw-state-buffering .jw-display-icon-next,.jwplayer.jw-state-complete .jw-display-icon-next,body .jw-error .jw-display-icon-next,body .jwplayer.jw-state-error .jw-display-icon-next{display:none}body .jw-error .jw-icon-display,body .jwplayer.jw-state-error .jw-icon-display{cursor:default}body .jw-error .jw-icon-display .jw-svg-icon-error,body .jwplayer.jw-state-error .jw-icon-display .jw-svg-icon-error{display:block}body .jw-error .jw-icon-container{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-preview{display:none}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title{padding-top:4px}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-primary{width:auto;display:inline-block;padding-right:.5ch}body .jwplayer.jw-state-error.jw-flag-audio-player .jw-title-secondary{width:auto;display:inline-block;padding-left:0}body .jwplayer.jw-state-error .jw-controlbar,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-controlbar{display:none}body .jwplayer.jw-state-error .jw-settings-menu,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-settings-menu{height:100%;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}body .jwplayer.jw-state-error .jw-display,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-display{padding:0}body .jwplayer.jw-state-error .jw-logo-bottom-left,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-left,body .jwplayer.jw-state-error .jw-logo-bottom-right,.jwplayer.jw-state-idle:not(.jw-flag-audio-player):not(.jw-flag-cast-available):not(.jw-flag-cardboard-available) .jw-logo-bottom-right{bottom:0}.jwplayer.jw-state-playing.jw-flag-user-inactive .jw-display{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-state-playing:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display,.jwplayer.jw-state-paused:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting):not(.jw-flag-play-rejected) .jw-display{display:none}.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-rewind,.jwplayer.jw-state-paused.jw-flag-play-rejected:not(.jw-flag-touch):not(.jw-flag-small-player):not(.jw-flag-casting) .jw-display-icon-next{display:none}.jwplayer.jw-state-buffering .jw-display-icon-display .jw-text,.jwplayer.jw-state-complete .jw-display .jw-text{display:none}.jwplayer.jw-flag-casting:not(.jw-flag-audio-player) .jw-cast{display:block}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-display-icon-container{display:none}.jwplayer.jw-flag-casting .jw-icon-hd,.jwplayer.jw-flag-casting .jw-captions,.jwplayer.jw-flag-casting .jw-icon-fullscreen,.jwplayer.jw-flag-casting .jw-icon-audio-tracks{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-volume{display:none}.jwplayer.jw-flag-casting.jw-flag-airplay-casting .jw-icon-airplay{color:#fff}.jw-state-playing.jw-flag-casting:not(.jw-flag-audio-player) .jw-display,.jw-state-paused.jw-flag-casting:not(.jw-flag-audio-player) .jw-display{display:table}.jwplayer.jw-flag-cast-available .jw-icon-cast,.jwplayer.jw-flag-cast-available .jw-icon-airplay{display:flex}.jwplayer.jw-flag-cardboard-available .jw-icon-cardboard{display:flex}.jwplayer.jw-flag-live .jw-display-icon-rewind{visibility:hidden}.jwplayer.jw-flag-live .jw-controlbar .jw-text-elapsed,.jwplayer.jw-flag-live .jw-controlbar .jw-text-duration,.jwplayer.jw-flag-live .jw-controlbar .jw-text-countdown,.jwplayer.jw-flag-live .jw-controlbar .jw-slider-time{display:none}.jwplayer.jw-flag-live .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-live .jw-controlbar .jw-overlay:after{display:none}.jwplayer.jw-flag-live .jw-nextup-container{bottom:44px}.jwplayer.jw-flag-live .jw-text-elapsed,.jwplayer.jw-flag-live .jw-text-duration{display:none}.jwplayer.jw-flag-live .jw-text-live{cursor:default}.jwplayer.jw-flag-live .jw-text-live:hover{color:rgba(255,255,255,0.8)}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-stop,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-stop{display:block}.jwplayer.jw-flag-live.jw-state-playing .jw-icon-playback .jw-svg-icon-pause,.jwplayer.jw-flag-live.jw-state-buffering .jw-icon-playback .jw-svg-icon-pause{display:none}.jw-text-live{height:24px;width:auto;align-items:center;border-radius:1px;color:rgba(255,255,255,0.8);display:flex;font-size:12px;font-weight:bold;margin-right:10px;padding:0 1ch;text-rendering:geometricPrecision;text-transform:uppercase;transition:150ms cubic-bezier(0, .25, .25, 1);transition-property:box-shadow,color}.jw-text-live::before{height:8px;width:8px;background-color:currentColor;border-radius:50%;margin-right:6px;opacity:1;transition:opacity 150ms cubic-bezier(0, .25, .25, 1)}.jw-text-live.jw-dvr-live{box-shadow:inset 0 0 0 2px currentColor}.jw-text-live.jw-dvr-live::before{opacity:.5}.jw-text-live.jw-dvr-live:hover{color:#fff}.jwplayer.jw-flag-controls-hidden .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-controls-hidden:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-controls-hidden .jw-plugin{bottom:.5em}.jwplayer.jw-flag-controls-hidden .jw-nextup-container{bottom:0}.jw-flag-controls-hidden .jw-controlbar,.jw-flag-controls-hidden .jw-display{visibility:hidden;pointer-events:none;opacity:0;transition-delay:0s, 250ms}.jw-flag-controls-hidden .jw-controls-backdrop{opacity:0}.jw-flag-controls-hidden .jw-logo{visibility:visible}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-logo.jw-hide{visibility:hidden;pointer-events:none;opacity:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-casting) .jw-logo-top-right{top:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-plugin{bottom:.5em}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing .jw-nextup-container{bottom:0}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-controls-hidden) .jw-media{cursor:none;-webkit-cursor-visibility:auto-hide}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing.jw-flag-casting .jw-display{display:table}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-state-playing:not(.jw-flag-ads) .jw-autostart-mute{display:flex}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting .jw-nextup-container{bottom:66px}.jwplayer.jw-flag-user-inactive:not(.jw-flag-media-audio).jw-flag-casting.jw-state-idle .jw-nextup-container{display:none}.jw-flag-media-audio .jw-preview{display:block}.jwplayer.jw-flag-ads .jw-preview,.jwplayer.jw-flag-ads .jw-logo,.jwplayer.jw-flag-ads .jw-captions.jw-captions-enabled,.jwplayer.jw-flag-ads .jw-nextup-container,.jwplayer.jw-flag-ads .jw-text-duration,.jwplayer.jw-flag-ads .jw-text-elapsed{display:none}.jwplayer.jw-flag-ads video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-rewind,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-next,.jwplayer.jw-flag-ads.jw-flag-small-player .jw-display-icon-display{display:none}.jwplayer.jw-flag-ads.jw-flag-small-player.jw-state-buffering .jw-display-icon-display{display:inline-block}.jwplayer.jw-flag-ads .jw-controlbar{flex-wrap:wrap-reverse}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time{height:auto;padding:0;pointer-events:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-slider-container{height:5px}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-rail,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-knob,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-buffer,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-cue,.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-icon-settings{display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-slider-time .jw-progress{-webkit-transform:none;transform:none;top:auto}.jwplayer.jw-flag-ads .jw-controlbar .jw-tooltip,.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-tooltip:not(.jw-icon-volume),.jwplayer.jw-flag-ads .jw-controlbar .jw-icon-inline:not(.jw-icon-playback):not(.jw-icon-fullscreen):not(.jw-icon-volume){display:none}.jwplayer.jw-flag-ads .jw-controlbar .jw-volume-tip{padding:13px 0}.jwplayer.jw-flag-ads .jw-controlbar .jw-text-alt{display:flex}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid) .jw-controls .jw-controlbar,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart .jw-controls .jw-controlbar{display:flex;pointer-events:all;visibility:visible;opacity:1}.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-user-inactive .jw-controls-backdrop,.jwplayer.jw-flag-ads.jw-flag-ads.jw-state-playing.jw-flag-touch:not(.jw-flag-ads-vpaid).jw-flag-autostart.jw-flag-user-inactive .jw-controls-backdrop{opacity:1;background-size:100% 60px}.jwplayer.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-display-container,.jwplayer.jw-flag-ads-vpaid .jw-skip,.jwplayer.jw-flag-touch.jw-flag-ads-vpaid .jw-skip{display:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls{background:none}.jwplayer.jw-flag-ads-vpaid.jw-flag-small-player .jw-controls::after{content:none}.jwplayer.jw-flag-ads-hide-controls .jw-controls-backdrop,.jwplayer.jw-flag-ads-hide-controls .jw-controls{display:none !important}.jw-flag-overlay-open-related .jw-controls,.jw-flag-overlay-open-related .jw-title,.jw-flag-overlay-open-related .jw-logo{display:none}.jwplayer.jw-flag-rightclick-open{overflow:visible}.jwplayer.jw-flag-rightclick-open .jw-rightclick{z-index:16777215}body .jwplayer.jw-flag-flash-blocked .jw-controls,body .jwplayer.jw-flag-flash-blocked .jw-overlays,body .jwplayer.jw-flag-flash-blocked .jw-controls-backdrop,body .jwplayer.jw-flag-flash-blocked .jw-preview{display:none}body .jwplayer.jw-flag-flash-blocked .jw-error-msg{top:25%}.jw-flag-touch.jw-breakpoint-7 .jw-captions,.jw-flag-touch.jw-breakpoint-6 .jw-captions,.jw-flag-touch.jw-breakpoint-5 .jw-captions,.jw-flag-touch.jw-breakpoint-4 .jw-captions,.jw-flag-touch.jw-breakpoint-7 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-6 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-5 .jw-nextup-container,.jw-flag-touch.jw-breakpoint-4 .jw-nextup-container{bottom:4.25em}.jw-flag-touch .jw-controlbar .jw-icon-volume{display:flex}.jw-flag-touch .jw-display,.jw-flag-touch .jw-display-container,.jw-flag-touch .jw-display-controls{pointer-events:none}.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-next,.jw-flag-touch.jw-state-paused:not(.jw-breakpoint-1) .jw-display-icon-rewind,.jw-flag-touch.jw-state-playing:not(.jw-breakpoint-1) .jw-display-icon-rewind{display:none}.jw-flag-touch.jw-state-paused.jw-flag-dragging .jw-display{display:none}.jw-flag-audio-player{background-color:#000}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:44px}.jw-flag-audio-player:not(.jw-flag-live) .jw-spacer{display:none}.jw-flag-audio-player .jw-preview,.jw-flag-audio-player .jw-display,.jw-flag-audio-player .jw-title,.jw-flag-audio-player .jw-nextup-container{display:none}.jw-flag-audio-player .jw-controlbar{position:relative}.jw-flag-audio-player .jw-controlbar .jw-button-container{padding-right:3px;padding-left:0}.jw-flag-audio-player .jw-controlbar .jw-icon-tooltip,.jw-flag-audio-player .jw-controlbar .jw-icon-inline{display:none}.jw-flag-audio-player .jw-controlbar .jw-icon-volume,.jw-flag-audio-player .jw-controlbar .jw-icon-playback,.jw-flag-audio-player .jw-controlbar .jw-icon-next,.jw-flag-audio-player .jw-controlbar .jw-icon-rewind,.jw-flag-audio-player .jw-controlbar .jw-icon-cast,.jw-flag-audio-player .jw-controlbar .jw-text-live,.jw-flag-audio-player .jw-controlbar .jw-icon-airplay,.jw-flag-audio-player .jw-controlbar .jw-logo-button,.jw-flag-audio-player .jw-controlbar .jw-text-elapsed,.jw-flag-audio-player .jw-controlbar .jw-text-duration{display:flex;flex:0 0 auto}.jw-flag-audio-player .jw-controlbar .jw-text-duration,.jw-flag-audio-player .jw-controlbar .jw-text-countdown{padding-right:10px}.jw-flag-audio-player .jw-controlbar .jw-slider-time{flex:0 1 auto;align-items:center;display:flex;order:1}.jw-flag-audio-player .jw-controlbar .jw-icon-volume{margin-right:0;transition:margin-right 150ms cubic-bezier(0, .25, .25, 1)}.jw-flag-audio-player .jw-controlbar .jw-icon-volume .jw-overlay{display:none}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container{transition:width 300ms cubic-bezier(0, .25, .25, 1);width:0}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open{width:140px}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open .jw-slider-volume{padding-right:24px;transition:opacity 300ms;opacity:1}.jw-flag-audio-player .jw-controlbar .jw-horizontal-volume-container.jw-open~.jw-slider-time{flex:1 1 auto;width:auto;transition:opacity 300ms, width 300ms}.jw-flag-audio-player .jw-controlbar .jw-slider-volume{opacity:0}.jw-flag-audio-player .jw-controlbar .jw-slider-volume .jw-knob{-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%)}.jw-flag-audio-player .jw-controlbar .jw-slider-volume~.jw-icon-volume{margin-right:140px}.jw-flag-audio-player.jw-breakpoint-1 .jw-horizontal-volume-container.jw-open~.jw-slider-time,.jw-flag-audio-player.jw-breakpoint-2 .jw-horizontal-volume-container.jw-open~.jw-slider-time{opacity:0}.jw-flag-audio-player.jw-flag-small-player .jw-text-elapsed,.jw-flag-audio-player.jw-flag-small-player .jw-text-duration{display:none}.jw-flag-audio-player.jw-flag-ads .jw-slider-time{display:none}.jw-hidden{display:none}',""])}]]); \ No newline at end of file diff --git a/ui/v2.5/public/jwplayer/jwplayer.core.js b/ui/v2.5/public/jwplayer/jwplayer.core.js new file mode 100644 index 000000000..ed16e4c4b --- /dev/null +++ b/ui/v2.5/public/jwplayer/jwplayer.core.js @@ -0,0 +1,95 @@ +/*! +JW Player version 8.11.5 +Copyright (c) 2019, JW Player, All Rights Reserved +https://github.com/jwplayer/jwplayer/blob/v8.11.5/README.md + +This source code and its use and distribution is subject to the terms and conditions of the applicable license agreement. +https://www.jwplayer.com/tos/ + +This product includes portions of other software. For the full text of licenses, see below: + +JW Player Third Party Software Notices and/or Additional Terms and Conditions + +************************************************************************************************** +The following software is used under Apache License 2.0 +************************************************************************************************** + +vtt.js v0.13.0 +Copyright (c) 2019 Mozilla (http://mozilla.org) +https://github.com/mozilla/vtt.js/blob/v0.13.0/LICENSE + +* * * + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. + +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. + +************************************************************************************************** +The following software is used under MIT license +************************************************************************************************** + +Underscore.js v1.6.0 +Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative +https://github.com/jashkenas/underscore/blob/1.6.0/LICENSE + +Backbone backbone.events.js v1.1.2 +Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud +https://github.com/jashkenas/backbone/blob/1.1.2/LICENSE + +Promise Polyfill v7.1.1 +Copyright (c) 2014 Taylor Hakes and Forbes Lindesay +https://github.com/taylorhakes/promise-polyfill/blob/v7.1.1/LICENSE + +can-autoplay.js v3.0.0 +Copyright (c) 2017 video-dev +https://github.com/video-dev/can-autoplay/blob/v3.0.0/LICENSE + +* * * + +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. + +************************************************************************************************** +The following software is used under W3C license +************************************************************************************************** + +Intersection Observer v0.5.0 +Copyright (c) 2016 Google Inc. (http://google.com) +https://github.com/w3c/IntersectionObserver/blob/v0.5.0/LICENSE.md + +* * * + +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. + +This work is being provided by the copyright holders under the following license. + +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. + +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. + +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. +*/ +(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[2],{18:function(e,t,n){"use strict";n.r(t);var i=n(0),o=n(12),r=n(50),a=n(36);var s=n(44),l=n(51),c=n(26),u=n(25),d=n(3),f=n(46),g=n(2),h=n(7),p=n(34);function b(e){var t=!1;return{async:function(){var n=this,i=arguments;return Promise.resolve().then((function(){if(!t)return e.apply(n,i)}))},cancel:function(){t=!0},cancelled:function(){return t}}}var m=n(1);function w(e){return function(t,n){var o=e.mediaModel,r=Object(i.g)({},n,{type:t});switch(t){case d.T:if(o.get(d.T)===n.mediaType)return;o.set(d.T,n.mediaType);break;case d.U:return void o.set(d.U,Object(i.g)({},n));case d.M:if(n[t]===e.model.getMute())return;break;case d.bb:n.newstate===d.mb&&(e.thenPlayPromise.cancel(),o.srcReset());var a=o.attributes.mediaState;o.attributes.mediaState=n.newstate,o.trigger("change:mediaState",o,n.newstate,a);break;case d.F:return e.beforeComplete=!0,e.trigger(d.B,r),void(e.attached&&!e.background&&e._playbackComplete());case d.G:o.get("setup")?(e.thenPlayPromise.cancel(),o.srcReset()):(t=d.tb,r.code+=1e5);break;case d.K:r.metadataType||(r.metadataType="unknown");var s=n.duration;Object(i.u)(s)&&(o.set("seekRange",n.seekRange),o.set("duration",s));break;case d.D:o.set("buffer",n.bufferPercent);case d.S:o.set("seekRange",n.seekRange),o.set("position",n.position),o.set("currentTime",n.currentTime);var l=n.duration;Object(i.u)(l)&&o.set("duration",l),t===d.S&&Object(i.r)(e.item.starttime)&&delete e.item.starttime;break;case d.R:var c=e.mediaElement;c&&c.paused&&o.set("mediaState","paused");break;case d.I:o.set(d.I,n.levels);case d.J:var u=n.currentQuality,f=n.levels;u>-1&&f.length>1&&o.set("currentLevel",parseInt(u));break;case d.f:o.set(d.f,n.tracks);case d.g:var g=n.currentTrack,h=n.tracks;g>-1&&h.length>0&&g=Math.max(l,f.a)&&(e.preloadNextItem(),y=!0)}function E(e){var t={};w.tag&&(t.tag=w.tag),this.trigger(d.F,t),R.call(this,e)}function R(e){b={},r&&p+10?e:null,h&&h.model.set("skipOffset",s)}};Object(i.g)(le.prototype,h.a);var ce=le,ue=n(66),de=n(63),fe=function(e){var t=this,n=[],i={},o=0,r=0;function a(e){if(e.data=e.data||[],e.name=e.label||e.name||e.language,e._id=Object(de.a)(e,n.length),!e.name){var t=Object(de.b)(e,o);e.name=t.label,o=t.unknownCount}i[e._id]=e,n.push(e)}function s(){for(var e=[{id:"off",label:"Off"}],t=0;t')+'
    '},pe=n(35),be=44,me=function(e){var t=e.get("height");if(e.get("aspectratio"))return!1;if("string"==typeof t&&t.indexOf("%")>-1)return!1;var n=1*t||NaN;return!!(n=isNaN(n)?e.get("containerHeight"):n)&&(n&&n<=be)},we=n(54);function ve(e,t){if(e.get("fullscreen"))return 1;if(!e.get("activeTab"))return 0;if(e.get("isFloating"))return 1;var n=e.get("intersectionRatio");return void 0===n&&(n=function(e){var t=document.documentElement,n=document.body,i={top:0,left:0,right:t.clientWidth||n.clientWidth,width:t.clientWidth||n.clientWidth,bottom:t.clientHeight||n.clientHeight,height:t.clientHeight||n.clientHeight};if(!n.contains(e))return 0;if("none"===window.getComputedStyle(e).display)return 0;var o=ye(e);if(!o)return 0;var r=o,a=e.parentNode,s=!1;for(;!s;){var l=null;if(a===n||a===t||1!==a.nodeType?(s=!0,l=i):"visible"!==window.getComputedStyle(a).overflow&&(l=ye(a)),l&&(c=l,u=r,d=void 0,f=void 0,g=void 0,h=void 0,p=void 0,b=void 0,d=Math.max(c.top,u.top),f=Math.min(c.bottom,u.bottom),g=Math.max(c.left,u.left),h=Math.min(c.right,u.right),b=f-d,!(r=(p=h-g)>=0&&b>=0&&{top:d,bottom:f,left:g,right:h,width:p,height:b})))return 0;a=a.parentNode}var c,u,d,f,g,h,p,b;var m=o.width*o.height,w=r.width*r.height;return m?w/m:0}(t),window.top!==window.self&&n)?0:n}function ye(e){try{return e.getBoundingClientRect()}catch(e){}}var je=n(49),ke=n(42),Oe=n(58),xe=n(10);var Ce=n(32),Me=n(5),_e=n(6),Se=["fullscreenchange","webkitfullscreenchange","mozfullscreenchange","MSFullscreenChange"],Pe=function(e,t,n){for(var i=e.requestFullscreen||e.webkitRequestFullscreen||e.webkitRequestFullScreen||e.mozRequestFullScreen||e.msRequestFullscreen,o=t.exitFullscreen||t.webkitExitFullscreen||t.webkitCancelFullScreen||t.mozCancelFullScreen||t.msExitFullscreen,r=!(!i||!o),a=Se.length;a--;)t.addEventListener(Se[a],n);return{events:Se,supportsDomFullscreen:function(){return r},requestFullscreen:function(){i.call(e,{navigationUI:"hide"})},exitFullscreen:function(){null!==this.fullscreenElement()&&o.apply(t)},fullscreenElement:function(){var e=t.fullscreenElement,n=t.webkitCurrentFullScreenElement,i=t.mozFullScreenElement,o=t.msFullscreenElement;return null===e?e:e||n||i||o},destroy:function(){for(var e=Se.length;e--;)t.removeEventListener(Se[e],n)}}},Te=n(40);function Ae(e,t){for(var n=0;n')},Le={linktarget:"_blank",margin:8,hide:!1,position:"top-right"};function Ve(e){var t,n;Object(i.g)(this,h.a);var o=new Image;this.setup=function(){(n=Object(i.g)({},Le,e.get("logo"))).position=n.position||Le.position,n.hide="true"===n.hide.toString(),n.file&&"control-bar"!==n.position&&(t||(t=Object(Me.e)(Ie(n.position,n.hide))),e.set("logo",n),o.onload=function(){var i=this.height,o=this.width,r={backgroundImage:'url("'+this.src+'")'};if(n.margin!==Le.margin){var a=/(\w+)-(\w+)/.exec(n.position);3===a.length&&(r["margin-"+a[1]]=n.margin,r["margin-"+a[2]]=n.margin)}var s=.15*e.get("containerHeight"),l=.15*e.get("containerWidth");if(i>s||o>l){var c=o/i;l/s>c?(i=s,o=s*c):(o=l,i=l/c)}r.width=Math.round(o),r.height=Math.round(i),Object(xe.d)(t,r),e.set("logoWidth",r.width)},o.src=n.file,n.link&&(t.setAttribute("tabindex","0"),t.setAttribute("aria-label",e.get("localization").logo)),this.ui=new Te.a(t).on("click tap enter",(function(e){e&&e.stopPropagation&&e.stopPropagation(),this.trigger(d.A,{link:n.link,linktarget:n.linktarget})}),this))},this.setContainer=function(e){t&&e.appendChild(t)},this.element=function(){return t},this.position=function(){return n.position},this.destroy=function(){o.onload=null,this.ui&&this.ui.destroy()}}var Fe=function(e){this.model=e,this.image=null};Object(i.g)(Fe.prototype,{setup:function(e){this.el=e},setImage:function(e){var t=this.image;t&&(t.onload=null),this.image=null;var n="";"string"==typeof e&&(n='url("'+e+'")',(t=this.image=new Image).src=e),Object(xe.d)(this.el,{backgroundImage:n})},resize:function(e,t,n){if("uniform"===n){if(e&&(this.playerAspectRatio=e/t),!this.playerAspectRatio||!this.image||"complete"!==(s=this.model.get("state"))&&"idle"!==s&&"error"!==s&&"buffering"!==s)return;var i=this.image,o=null;if(i){if(0===i.width){var r=this;return void(i.onload=function(){r.resize(e,t,n)})}var a=i.width/i.height;Math.abs(this.playerAspectRatio-a)<.09&&(o="cover")}Object(xe.d)(this.el,{backgroundSize:o})}var s},element:function(){return this.el}});var ze=Fe,Ne=function(e){this.model=e.player};Object(i.g)(Ne.prototype,{hide:function(){Object(xe.d)(this.el,{display:"none"})},show:function(){Object(xe.d)(this.el,{display:""})},setup:function(e){this.el=e;var t=this.el.getElementsByTagName("div");this.title=t[0],this.description=t[1],this.model.on("change:logoWidth",this.update,this),this.model.change("playlistItem",this.playlistItem,this)},update:function(e){var t={},n=e.get("logo");if(n){var i=1*(""+n.margin).replace("px",""),o=e.get("logoWidth")+(isNaN(i)?0:i+10);"top-left"===n.position?t.paddingLeft=o:"top-right"===n.position&&(t.paddingRight=o)}Object(xe.d)(this.el,t)},playlistItem:function(e,t){if(t)if(e.get("displaytitle")||e.get("displaydescription")){var n="",i="";t.title&&e.get("displaytitle")&&(n=t.title),t.description&&e.get("displaydescription")&&(i=t.description),this.updateText(n,i)}else this.hide()},updateText:function(e,t){Object(Me.q)(this.title,e),Object(Me.q)(this.description,t),this.title.firstChild||this.description.firstChild?this.show():this.hide()},element:function(){return this.el}});var He=Ne;function Be(e,t){for(var n=0;ne)}if(t.get("controls")){var a=me(t);Object(Me.v)(u,"jw-flag-audio-player",a),t.set("audioMode",a)}}function V(){t.set("visibility",ve(t,u))}this.updateBounds=function(){Object(ke.a)(k);var e=t.get("isFloating")?f:u,n=document.body.contains(e),i=Object(Me.c)(e),a=Math.round(i.width),s=Math.round(i.height);if(P=Object(Me.c)(u),a===o&&s===r)return o&&r||R(),void t.set("inDom",n);a&&s||o&&r||R(),(a||s||n)&&(t.set("containerWidth",a),t.set("containerHeight",s)),t.set("inDom",n),n&&we.a.observe(u)},this.updateStyles=function(){var e=t.get("containerWidth"),n=t.get("containerHeight");L(e,n),A&&A.resize(e,n),Z(e,n),y.resize(),x&&B()},this.checkResized=function(){var e=t.get("containerWidth"),n=t.get("containerHeight"),i=t.get("isFloating");if(e!==o||n!==r){this.resizeListener||(this.resizeListener=new We.a(f,this,t)),o=e,r=n,l.trigger(d.hb,{width:e,height:n});var s=Object(Oe.a)(e);T!==s&&(T=s,l.trigger(d.j,{breakpoint:T}))}i!==a&&(a=i,l.trigger(d.x,{floating:i}),V())},this.responsiveListener=R,this.setup=function(){m.setup(u.querySelector(".jw-preview")),w.setup(u.querySelector(".jw-title")),(n=new Ve(t)).setup(),n.setContainer(f),n.on(d.A,G),y.setup(u.id,t.get("captions")),w.element().parentNode.insertBefore(y.element(),w.element()),C=function(e,t,n){var i=new Ee(t,n),o=t.get("controls");i.on({click:function(){l.trigger(d.p),A&&(ce()?A.settingsMenu.close():ue()?A.infoOverlay.close():e.playToggle({reason:"interaction"}))},tap:function(){l.trigger(d.p),ce()&&A.settingsMenu.close(),ue()&&A.infoOverlay.close();var n=t.get("state");if(o&&(n===d.mb||n===d.kb||t.get("instream")&&n===d.ob)&&e.playToggle({reason:"interaction"}),o&&n===d.ob){if(t.get("instream")||t.get("castActive")||"audio"===t.get("mediaType"))return;Object(Me.v)(u,"jw-flag-controls-hidden"),l.dismissible&&Object(Me.v)(u,"jw-floating-dismissible",Object(Me.i)(u,"jw-flag-controls-hidden")),y.renderCues(!0)}else A&&(A.showing?A.userInactive():A.userActive())},doubleClick:function(){return A&&e.setFullscreen()}}),Ue||(u.addEventListener("mousemove",U),u.addEventListener("mouseover",Q),u.addEventListener("mouseout",Y));return i}(e,t,p),_=new Te.a(u).on("click",(function(){})),M=Pe(u,document,te),t.on("change:hideAdsControls",(function(e,t){Object(Me.v)(u,"jw-flag-ads-hide-controls",t)})),t.on("change:scrubbing",(function(e,t){Object(Me.v)(u,"jw-flag-dragging",t)})),t.on("change:playRejected",(function(e,t){Object(Me.v)(u,"jw-flag-play-rejected",t)})),t.on(d.X,ee),t.on("change:".concat(d.U),(function(){Z(),y.resize()})),t.player.on("change:errorEvent",re),t.change("stretching",X);var i=t.get("width"),o=t.get("height"),r=$(i,o);Object(xe.d)(u,r),t.change("aspectratio",J),L(i,o),t.get("controls")||(Object(Me.a)(u,"jw-flag-controls-hidden"),Object(Me.o)(u,"jw-floating-dismissible")),Qe&&Object(Me.a)(u,"jw-ie");var a=t.get("skin")||{};a.name&&Object(Me.p)(u,/jw-skin-\S+/,"jw-skin-"+a.name);var s=function(e){e||(e={});var t=e.active,n=e.inactive,i=e.background,o={};return o.controlbar=function(e){if(e||t||n||i){var o={};return e=e||{},o.iconsActive=e.iconsActive||t,o.icons=e.icons||n,o.text=e.text||n,o.background=e.background||i,o}}(e.controlbar),o.timeslider=function(e){if(e||t){var n={};return e=e||{},n.progress=e.progress||t,n.rail=e.rail,n}}(e.timeslider),o.menus=function(e){if(e||t||n||i){var o={};return e=e||{},o.text=e.text||n,o.textActive=e.textActive||t,o.background=e.background||i,o}}(e.menus),o.tooltips=function(e){if(e||n||i){var t={};return e=e||{},t.text=e.text||n,t.background=e.background||i,t}}(e.tooltips),o}(a);!function(e,t){var n;function i(t,n,i,o){if(i){t=Object(g.f)(t,"#"+e+(o?"":" "));var r={};r[n]=i,Object(xe.b)(t.join(", "),r,e)}}t&&(t.controlbar&&function(t){i([".jw-controlbar .jw-icon-inline.jw-text",".jw-title-primary",".jw-title-secondary"],"color",t.text),t.icons&&(i([".jw-button-color:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:not(.jw-icon-cast)"],"color",t.icons),i([".jw-display-icon-container .jw-button-color"],"color",t.icons),Object(xe.b)("#".concat(e," .jw-icon-cast google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.icons,"}"),e));t.iconsActive&&(i([".jw-display-icon-container .jw-button-color:hover",".jw-display-icon-container .jw-button-color:focus"],"color",t.iconsActive),i([".jw-button-color.jw-toggle:not(.jw-icon-cast)",".jw-button-color:hover:not(.jw-icon-cast)",".jw-button-color:focus:not(.jw-icon-cast)",".jw-button-color.jw-toggle.jw-off:hover:not(.jw-icon-cast)"],"color",t.iconsActive),i([".jw-svg-icon-buffer"],"fill",t.icons),Object(xe.b)("#".concat(e," .jw-icon-cast:hover google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(xe.b)("#".concat(e," .jw-icon-cast:focus google-cast-launcher.jw-off"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(xe.b)("#".concat(e," .jw-icon-cast google-cast-launcher.jw-off:focus"),"{--disconnected-color: ".concat(t.iconsActive,"}"),e),Object(xe.b)("#".concat(e," .jw-icon-cast google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(xe.b)("#".concat(e," .jw-icon-cast google-cast-launcher:focus"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(xe.b)("#".concat(e," .jw-icon-cast:hover google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e),Object(xe.b)("#".concat(e," .jw-icon-cast:focus google-cast-launcher"),"{--connected-color: ".concat(t.iconsActive,"}"),e));i([" .jw-settings-topbar",":not(.jw-state-idle) .jw-controlbar",".jw-flag-audio-player .jw-controlbar"],"background",t.background,!0)}(t.controlbar),t.timeslider&&function(e){var t=e.progress;"none"!==t&&(i([".jw-progress",".jw-knob"],"background-color",t),i([".jw-buffer"],"background-color",Object(xe.c)(t,50)));i([".jw-rail"],"background-color",e.rail),i([".jw-background-color.jw-slider-time",".jw-slider-time .jw-cue"],"background-color",e.background)}(t.timeslider),t.menus&&(i([".jw-option",".jw-toggle.jw-off",".jw-skip .jw-skip-icon",".jw-nextup-tooltip",".jw-nextup-close",".jw-settings-content-item",".jw-related-title"],"color",(n=t.menus).text),i([".jw-option.jw-active-option",".jw-option:not(.jw-active-option):hover",".jw-option:not(.jw-active-option):focus",".jw-settings-content-item:hover",".jw-nextup-tooltip:hover",".jw-nextup-tooltip:focus",".jw-nextup-close:hover"],"color",n.textActive),i([".jw-nextup",".jw-settings-menu"],"background",n.background)),t.tooltips&&function(e){i([".jw-skip",".jw-tooltip .jw-text",".jw-time-tip .jw-text"],"background-color",e.background),i([".jw-time-tip",".jw-tooltip"],"color",e.background),i([".jw-skip"],"border","none"),i([".jw-skip .jw-text",".jw-skip .jw-icon",".jw-time-tip .jw-text",".jw-tooltip .jw-text"],"color",e.text)}(t.tooltips),t.menus&&function(t){if(t.textActive){var n={color:t.textActive,borderColor:t.textActive,stroke:t.textActive};Object(xe.b)("#".concat(e," .jw-color-active"),n,e),Object(xe.b)("#".concat(e," .jw-color-active-hover:hover"),n,e)}if(t.text){var i={color:t.text,borderColor:t.text,stroke:t.text};Object(xe.b)("#".concat(e," .jw-color-inactive"),i,e),Object(xe.b)("#".concat(e," .jw-color-inactive-hover:hover"),i,e)}}(t.menus))}(t.get("id"),s),t.set("mediaContainer",p),t.set("iFrame",v.Features.iframe),t.set("activeTab",Object(je.a)()),t.set("touchMode",Ue&&("string"==typeof o||o>=be)),we.a.add(this),t.get("enableGradient")&&!Qe&&Object(Me.a)(u,"jw-ab-drop-shadow"),this.isSetup=!0,t.trigger("viewSetup",u);var c=document.body.contains(u);c&&we.a.observe(u),t.set("inDom",c)},this.init=function(){this.updateBounds(),t.on("change:fullscreen",K),t.on("change:activeTab",V),t.on("change:fullscreen",V),t.on("change:intersectionRatio",V),t.on("change:visibility",W),t.on("instreamMode",(function(e){e?de():fe()})),V(),1!==we.a.size()||t.get("visibility")||W(t,1,0);var e=t.player;t.change("state",ae),e.change("controls",q),t.change("streamType",ie),t.change("mediaType",oe),e.change("playlistItem",(function(e,t){le(e,t)})),o=r=null,x&&Ue&&we.a.addScrollHandler(B),this.checkResized()};var F,z=62,N=!0;function H(){var e=t.get("isFloating"),n=P.top0&&void 0!==arguments[0])||arguments[0],t={x:0,y:0,width:o||0,height:r||0};return A&&e&&(t.height-=A.controlbarHeight()),t},this.setCaptions=function(e){y.clear(),y.setup(t.get("id"),e),y.resize()},this.setIntersection=function(e){var n=Math.round(100*e.intersectionRatio)/100;t.set("intersectionRatio",n),x&&!E()&&(S=S||n>=.5)&&ge(n)},this.stopFloating=function(e,n){if(e&&(x=null,we.a.removeScrollHandler(B)),Ye===u){Ye=null,t.set("isFloating",!1);var i=function(){Object(Me.o)(u,"jw-flag-floating"),J(t,t.get("aspectratio")),Object(xe.d)(u,{backgroundImage:null}),Object(xe.d)(f,{maxWidth:null,width:null,height:null,left:null,right:null,top:null,bottom:null,margin:null,transform:null,transition:null,"transition-timing-function":null})};n?(Object(xe.d)(f,{transform:"translateY(-".concat(z-P.top,"px)"),"transition-timing-function":"ease-out"}),setTimeout(i,150)):i(),b.disable(),R()}},this.destroy=function(){t.destroy(),we.a.unobserve(u),we.a.remove(this),this.isSetup=!1,this.off(),Object(ke.a)(k),clearTimeout(j),Ye===u&&(Ye=null),_&&(_.destroy(),_=null),M&&(M.destroy(),M=null),A&&A.disable(t),C&&(C.destroy(),u.removeEventListener("mousemove",U),u.removeEventListener("mouseout",Y),u.removeEventListener("mouseover",Q),C=null),y.destroy(),n&&(n.destroy(),n=null),Object(xe.a)(t.get("id")),this.resizeListener&&(this.resizeListener.destroy(),delete this.resizeListener),x&&Ue&&we.a.removeScrollHandler(B)}};function Je(e,t,n){return(Je="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(e,t,n){var i=function(e,t){for(;!Object.prototype.hasOwnProperty.call(e,t)&&null!==(e=tt(e)););return e}(e,t);if(i){var o=Object.getOwnPropertyDescriptor(i,t);return o.get?o.get.call(n):o.value}})(e,t,n||e)}function Ge(e){return(Ge="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function Ke(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function $e(e,t){for(var n=0;nt&&e(),t=i}};function Ct(e,t){t.off(d.N,e._onPlayAttempt),t.off(d.fb,e._triggerFirstFrame),t.off(d.S,e._onTime),e.off("change:activeTab",e._onTabVisible)}var Mt=function(e,t){e.change("mediaModel",(function(e,n,i){e._qoeItem&&i&&e._qoeItem.end(i.get("mediaState")),e._qoeItem=new jt.a,e._qoeItem.getFirstFrame=function(){var e=this.between(d.N,d.H),t=this.between(Ot,d.H);return t>0&&t0&&ae(t,e.tracks)}),C).on(d.F,(function(){Promise.resolve().then(re)}),C).on(d.G,C.triggerError,C),Mt(M,F),M.on(d.w,C.triggerError,C),M.on("change:state",(function(e,t,n){X()||J.call(x,e,t,n)}),this),M.on("change:castState",(function(e,t){C.trigger(d.m,t)})),M.on("change:fullscreen",(function(e,t){C.trigger(d.y,{fullscreen:t}),t&&e.set("playOnViewable",!1)})),M.on("change:volume",(function(e,t){C.trigger(d.V,{volume:t})})),M.on("change:mute",(function(e){C.trigger(d.M,{mute:e.getMute()})})),M.on("change:playbackRate",(function(e,t){C.trigger(d.ab,{playbackRate:t,position:e.get("position")})}));var z=function e(t,n){"clickthrough"!==n&&"interaction"!==n&&"external"!==n||(M.set("playOnViewable",!1),M.off("change:playReason change:pauseReason",e))};function N(e,t){Object(i.t)(t)||M.set("viewable",Math.round(t))}function H(){de&&(!0!==M.get("autostart")||M.get("playOnViewable")||Z("autostart"),de.flush())}function B(e,t){C.trigger("viewable",{viewable:t}),q()}function q(){if((o.a[0]===t||1===M.get("viewable"))&&"idle"===M.get("state")&&!1===M.get("autostart"))if(!w.primed()&&v.OS.android){var e=w.getTestElement(),n=C.getMute();Promise.resolve().then((function(){return ht(e,{muted:n})})).then((function(){"idle"===M.get("state")&&F.preloadVideo()})).catch(Pt)}else F.preloadVideo()}function D(e){C._instreamAdapter.noResume=!e,e||te({reason:"viewable"})}function W(e){e||(C.pause({reason:"viewable"}),M.set("playOnViewable",!e))}function U(e,t){var n=X();if(e.get("playOnViewable")){if(t){var i=e.get("autoPause").pauseAds,o=e.get("pauseReason");G()===d.mb?Z("viewable"):n&&!i||"interaction"===o||K({reason:"viewable"})}else v.OS.mobile&&!n&&(C.pause({reason:"autostart"}),M.set("playOnViewable",!0));v.OS.mobile&&n&&D(t)}}function Q(e,t){var n=e.get("state"),i=X(),o=e.get("playReason");i?e.get("autoPause").pauseAds?W(t):D(t):n===d.pb||n===d.jb?W(t):n===d.mb&&"playlist"===o&&e.once("change:state",(function(){W(t)}))}function X(){var e=C._instreamAdapter;return!!e&&e.getState()}function G(){var e=X();return e||M.get("state")}function K(e){if(T.cancel(),S=!1,M.get("state")===d.lb)return Promise.resolve();var n=$(e);return M.set("playReason",n),X()?(t.pauseAd(!1,e),Promise.resolve()):(M.get("state")===d.kb&&(ee(!0),C.setItemIndex(0)),!_&&(_=!0,C.trigger(d.C,{playReason:n,startTime:e&&e.startTime?e.startTime:M.get("playlistItem").starttime}),_=!1,yt()&&!w.primed()&&w.prime(),"playlist"===n&&M.get("autoPause").viewability&&Q(M,M.get("viewable")),O)?(yt()&&!L&&M.get("mediaElement").load(),O=!1,k=null,Promise.resolve()):F.playVideo(n).then(w.played))}function $(e){return e&&e.reason?e.reason:"unknown"}function Z(e){if(G()===d.mb){T=b(H);var t=M.get("advertising");(function(e,t){var n=t.cancelable,i=t.muted,o=void 0!==i&&i,r=t.allowMuted,a=void 0!==r&&r,s=t.timeout,l=void 0===s?1e4:s,c=e.getTestElement(),u=o?"muted":"".concat(a);wt[u]||(wt[u]=ht(c,{muted:o}).catch((function(e){if(!n.cancelled()&&!1===o&&a)return ht(c,{muted:o=!0});throw e})).then((function(){return o?(wt[u]=null,bt):pt})).catch((function(e){throw clearTimeout(d),wt[u]=null,e.reason=mt,e})));var d,f=wt[u].then((function(e){if(clearTimeout(d),n.cancelled()){var t=new Error("Autoplay test was cancelled");throw t.reason="cancelled",t}return e})),g=new Promise((function(e,t){d=setTimeout((function(){wt[u]=null;var e=new Error("Autoplay test timed out");e.reason="timeout",t(e)}),l)}));return Promise.race([f,g])})(w,{cancelable:T,muted:C.getMute(),allowMuted:!t||t.autoplayadsmuted}).then((function(t){return M.set("canAutoplay",t),t!==bt||C.getMute()||(M.set("autostartMuted",!0),ue(),M.once("change:autostartMuted",(function(e){e.off("change:viewable",U),C.trigger(d.M,{mute:M.getMute()})}))),C.getMute()&&M.get("enableDefaultCaptions")&&j.selectDefaultIndex(1),K({reason:e}).catch((function(){C._instreamAdapter||M.set("autostartFailed",!0),k=null}))})).catch((function(e){if(M.set("canAutoplay",mt),M.set("autostart",!1),!T.cancelled()){var t=Object(m.w)(e);C.trigger(d.h,{reason:e.reason,code:t,error:e})}}))}}function ee(e){if(T.cancel(),de.empty(),X()){var t=C._instreamAdapter;return t&&(t.noResume=!0),void(k=function(){return F.stopVideo()})}k=null,!e&&(S=!0),_&&(O=!0),M.set("errorEvent",void 0),F.stopVideo()}function te(e){var t=$(e);M.set("pauseReason",t),M.set("playOnViewable","viewable"===t)}function ne(e){k=null,T.cancel();var n=X();if(n&&n!==d.ob)return te(e),void t.pauseAd(!0,e);switch(M.get("state")){case d.lb:return;case d.pb:case d.jb:te(e),F.pause();break;default:_&&(O=!0)}}function ie(e,t){ee(!0),C.setItemIndex(e),C.play(t)}function oe(e){ie(M.get("item")+1,e)}function re(){C.completeCancelled()||(k=C.completeHandler,C.shouldAutoAdvance()?C.nextItem():M.get("repeat")?oe({reason:"repeat"}):(v.OS.iOS&&le(!1),M.set("playOnViewable",!1),M.set("state",d.kb),C.trigger(d.cb,{})))}function ae(e,t){e=parseInt(e,10)||0,M.persistVideoSubtitleTrack(e,t),F.subtitles=e,C.trigger(d.k,{tracks:se(),track:e})}function se(){return j.getCaptionsList()}function le(e){Object(i.n)(e)||(e=!M.get("fullscreen")),M.set("fullscreen",e),C._instreamAdapter&&C._instreamAdapter._adModel&&C._instreamAdapter._adModel.set("fullscreen",e)}function ue(){F.mute=M.getMute(),F.volume=M.get("volume")}M.on("change:playReason change:pauseReason",z),C.on(d.c,(function(e){return z(0,e.playReason)})),C.on(d.b,(function(e){return z(0,e.pauseReason)})),M.on("change:scrubbing",(function(e,t){t?(P=M.get("state")!==d.ob,ne()):P&&K({reason:"interaction"})})),M.on("change:captionsList",(function(e,t){C.trigger(d.l,{tracks:t,track:M.get("captionsIndex")||0})})),M.on("change:mediaModel",(function(e,t){var n=this;e.set("errorEvent",void 0),t.change("mediaState",(function(t,n){var i;e.get("errorEvent")||e.set(d.bb,(i=n)===d.nb||i===d.qb?d.jb:i)}),this),t.change("duration",(function(t,n){if(0!==n){var i=e.get("minDvrWindow"),o=Object(vt.b)(n,i);e.setStreamType(o)}}),this);var i=e.get("item")+1,o="autoplay"===(e.get("related")||{}).oncomplete,r=e.get("playlist")[i];if((r||o)&&L){t.on("change:position",(function e(i,a){var s=r&&!r.daiSetting,l=t.get("duration");s&&a&&l>0&&a>=l-f.b?(t.off("change:position",e,n),F.backgroundLoad(r)):o&&(r=M.get("nextUp"))}),this)}})),(j=new ge(M)).on("all",I,C),V.on("viewSetup",(function(e){Object(r.b)(x,e)})),this.playerReady=function(){y.once(d.hb,(function(){try{!function(){M.change("visibility",N),E.off(),C.trigger(d.gb,{setupTime:0}),M.change("playlist",(function(e,t){if(t.length){var n={playlist:t},o=M.get("feedData");o&&(n.feedData=Object(i.g)({},o)),C.trigger(d.eb,n)}})),M.change("playlistItem",(function(e,t){if(t){var n=t.title,i=t.image;if("mediaSession"in navigator&&window.MediaMetadata&&(n||i))try{navigator.mediaSession.metadata=new window.MediaMetadata({title:n,artist:window.location.hostname,artwork:[{src:i||""}]})}catch(e){}e.set("cues",[]),C.trigger(d.db,{index:M.get("item"),item:t})}})),E.flush(),E.destroy(),E=null,M.change("viewable",B),M.change("viewable",U),M.get("autoPause").viewability?M.change("viewable",Q):M.once("change:autostartFailed change:mute",(function(e){e.off("change:viewable",U)}));H(),M.on("change:itemReady",(function(e,t){t&&de.flush()}))}()}catch(e){C.triggerError(Object(m.v)(m.m,m.a,e))}})),y.init()},this.preload=q,this.load=function(e,t){var n,i=C._instreamAdapter;switch(i&&(i.noResume=!0),C.trigger("destroyPlugin",{}),ee(!0),T.cancel(),T=b(H),A.cancel(),yt()&&w.prime(),_t(e)){case"string":M.attributes.item=0,M.attributes.itemReady=!1,A=b((function(e){if(e)return C.updatePlaylist(Object(c.a)(e.playlist),e)})),n=function(e){var t=this;return new Promise((function(n,i){var o=new l.a;o.on(d.eb,(function(e){n(e)})),o.on(d.w,i,t),o.load(e)}))}(e).then(A.async);break;case"object":M.attributes.item=0,n=C.updatePlaylist(Object(c.a)(e),t||{});break;case"number":n=C.setItemIndex(e);break;default:return}n.catch((function(e){C.triggerError(Object(m.u)(e,m.c))})),n.then(T.async).catch(Pt)},this.play=function(e){return K(e).catch(Pt)},this.pause=ne,this.seek=function(e,t){var n=M.get("state");if(n!==d.lb){F.position=e;var i=n===d.mb;M.get("scrubbing")||!i&&n!==d.kb||(i&&((t=t||{}).startTime=e),this.play(t))}},this.stop=ee,this.playlistItem=ie,this.playlistNext=oe,this.playlistPrev=function(e){ie(M.get("item")-1,e)},this.setCurrentCaptions=ae,this.setCurrentQuality=function(e){F.quality=e},this.setFullscreen=le,this.getCurrentQuality=function(){return F.quality},this.getQualityLevels=function(){return F.qualities},this.setCurrentAudioTrack=function(e){F.audioTrack=e},this.getCurrentAudioTrack=function(){return F.audioTrack},this.getAudioTracks=function(){return F.audioTracks},this.getCurrentCaptions=function(){return j.getCurrentIndex()},this.getCaptionsList=se,this.getVisualQuality=function(){var e=this._model.get("mediaModel");return e?e.get(d.U):null},this.getConfig=function(){return this._model?this._model.getConfiguration():void 0},this.getState=G,this.next=Pt,this.completeHandler=re,this.completeCancelled=function(){return(e=M.get("state"))!==d.mb&&e!==d.kb&&e!==d.lb||!!S&&(S=!1,!0);var e},this.shouldAutoAdvance=function(){return M.get("item")!==M.get("playlist").length-1},this.nextItem=function(){oe({reason:"playlist"})},this.setConfig=function(e){!function(e,t){var n=e._model,i=n.attributes;t.height&&(t.height=Object(a.b)(t.height),t.width=t.width||i.width),t.width&&(t.width=Object(a.b)(t.width),t.aspectratio?(i.width=t.width,delete t.width):t.height=i.height),t.width&&t.height&&!t.aspectratio&&e._view.resize(t.width,t.height),Object.keys(t).forEach((function(o){var r=t[o];if(void 0!==r)switch(o){case"aspectratio":n.set(o,Object(a.a)(r,i.width));break;case"autostart":!function(e,t,n){e.setAutoStart(n),"idle"===e.get("state")&&!0===n&&t.play({reason:"autostart"})}(n,e,r);break;case"mute":e.setMute(r);break;case"volume":e.setVolume(r);break;case"playbackRateControls":case"playbackRates":case"repeat":case"stretching":n.set(o,r)}}))}(C,e)},this.setItemIndex=function(e){F.stopVideo();var t=M.get("playlist").length;return(e=(parseInt(e,10)||0)%t)<0&&(e+=t),F.setActiveItem(e).catch((function(e){e.code>=151&&e.code<=162&&(e=Object(m.u)(e,m.e)),x.triggerError(Object(m.v)(m.k,m.d,e))}))},this.detachMedia=function(){if(_&&(O=!0),M.get("autoPause").viewability&&Q(M,M.get("viewable")),!L)return F.setAttached(!1);F.backgroundActiveMedia()},this.attachMedia=function(){L?F.restoreBackgroundMedia():F.setAttached(!0),"function"==typeof k&&k()},this.routeEvents=function(e){return F.routeEvents(e)},this.forwardEvents=function(){return F.forwardEvents()},this.playVideo=function(e){return F.playVideo(e)},this.stopVideo=function(){return F.stopVideo()},this.castVideo=function(e,t){return F.castVideo(e,t)},this.stopCast=function(){return F.stopCast()},this.backgroundActiveMedia=function(){return F.backgroundActiveMedia()},this.restoreBackgroundMedia=function(){return F.restoreBackgroundMedia()},this.preloadNextItem=function(){F.background.currentMedia&&F.preloadVideo()},this.isBeforeComplete=function(){return F.beforeComplete},this.setVolume=function(e){M.setVolume(e),ue()},this.setMute=function(e){M.setMute(e),ue()},this.setPlaybackRate=function(e){M.setPlaybackRate(e)},this.getProvider=function(){return M.get("provider")},this.getWidth=function(){return M.get("containerWidth")},this.getHeight=function(){return M.get("containerHeight")},this.getItemQoe=function(){return M._qoeItem},this.addButton=function(e,t,n,i,o){var r=M.get("customButtons")||[],a=!1,s={img:e,tooltip:t,callback:n,id:i,btnClass:o};r=r.reduce((function(e,t){return t.id===i?(a=!0,e.push(s)):e.push(t),e}),[]),a||r.unshift(s),M.set("customButtons",r)},this.removeButton=function(e){var t=M.get("customButtons")||[];t=t.filter((function(t){return t.id!==e})),M.set("customButtons",t)},this.resize=y.resize,this.getSafeRegion=y.getSafeRegion,this.setCaptions=y.setCaptions,this.checkBeforePlay=function(){return _},this.setControls=function(e){Object(i.n)(e)||(e=!M.get("controls")),M.set("controls",e),F.controls=e},this.addCues=function(e){this.setCues(M.get("cues").concat(e))},this.setCues=function(e){M.set("cues",e)},this.updatePlaylist=function(e,t){try{var n=Object(c.b)(e,M,t);Object(c.e)(n);var o=Object(i.g)({},t);delete o.playlist,M.set("feedData",o),M.set("playlist",n)}catch(e){return Promise.reject(e)}return this.setItemIndex(M.get("item"))},this.setPlaylistItem=function(e,t){(t=Object(c.d)(M,new u.a(t),t.feedData||{}))&&(M.get("playlist")[e]=t,e===M.get("item")&&"idle"===M.get("state")&&this.setItemIndex(e))},this.playerDestroy=function(){this.off(),this.stop(),Object(r.b)(this,this.originalContainer),y&&y.destroy(),M&&M.destroy(),de&&de.destroy(),j&&j.destroy(),F&&F.destroy(),this.instreamDestroy()},this.isBeforePlay=this.checkBeforePlay,this.createInstream=function(){return this.instreamDestroy(),this._instreamAdapter=new ce(this,M,y,w),this._instreamAdapter},this.instreamDestroy=function(){C._instreamAdapter&&(C._instreamAdapter.destroy(),C._instreamAdapter=null)};var de=new s.a(this,["play","pause","setCurrentAudioTrack","setCurrentCaptions","setCurrentQuality","setFullscreen"],(function(){return!x._model.get("itemReady")||E}));de.queue.push.apply(de.queue,p),y.setup()},get:function(e){if(e in j.a){var t=this._model.get("mediaModel");return t?t.get(e):j.a[e]}return this._model.get(e)},getContainer:function(){return this.currentContainer||this.originalContainer},getMute:function(){return this._model.getMute()},triggerError:function(e){var t=this._model;e.message=t.get("localization").errors[e.key],delete e.key,t.set("errorEvent",e),t.set("state",d.lb),t.once("change:state",(function(){this.set("errorEvent",void 0)}),t),this.trigger(d.w,e)}});t.default=St},57:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n(2);function o(e){var t=[],n=(e=Object(i.i)(e)).split("\r\n\r\n");1===n.length&&(n=e.split("\n\n"));for(var o=0;o0&&(o=0),n.length>o+1&&n[o+1]){var r=n[o],a=r.indexOf(" --\x3e ");a>0&&(t.begin=Object(i.g)(r.substr(0,a)),t.end=Object(i.g)(r.substr(a+5)),t.text=n.slice(o+1).join("\r\n"))}return t}},58:function(e,t,n){"use strict";n.d(t,"a",(function(){return o})),n.d(t,"b",(function(){return r}));var i=n(5);function o(e){var t=-1;return e>=1280?t=7:e>=960?t=6:e>=800?t=5:e>=640?t=4:e>=540?t=3:e>=420?t=2:e>=320?t=1:e>=250&&(t=0),t}function r(e,t){var n="jw-breakpoint-"+t;Object(i.p)(e,/jw-breakpoint--?\d+/,n)}},59:function(e,t,n){"use strict";n.d(t,"a",(function(){return d}));var i,o=n(0),r=n(8),a=n(16),s=n(7),l=n(3),c=n(10),u=n(5),d={back:!0,backgroundOpacity:50,edgeStyle:null,fontSize:14,fontOpacity:100,fontScale:.05,preprocessor:o.k,windowOpacity:0},f=function(e){var t,s,f,g,h,p,b,m,w,v=this,y=e.player;function j(){Object(o.o)(t.fontSize)&&(y.get("containerHeight")?m=d.fontScale*(t.userFontScale||1)*t.fontSize/d.fontSize:y.once("change:containerHeight",j,this))}function k(){var e=y.get("containerHeight");if(e){var t;if(y.get("fullscreen")&&r.OS.iOS)t=null;else{var n=e*m;t=Math.round(10*function(e){var t=y.get("mediaElement");if(t&&t.videoHeight){var n=t.videoWidth,i=t.videoHeight,o=n/i,a=y.get("containerHeight"),s=y.get("containerWidth");if(y.get("fullscreen")&&r.OS.mobile){var l=window.screen;l.orientation&&(a=l.availHeight,s=l.availWidth)}if(s&&a&&n&&i)return(s/a>o?a:i*s/n)*m}return e}(n))/10}y.get("renderCaptionsNatively")?function(e,t){var n="#".concat(e," .jw-video::-webkit-media-text-track-display");t&&(t+="px",r.OS.iOS&&Object(c.b)(n,{fontSize:"inherit"},e,!0));w.fontSize=t,Object(c.b)(n,w,e,!0)}(y.get("id"),t):Object(c.d)(h,{fontSize:t})}}function O(e,t,n){var i=Object(c.c)("#000000",n);"dropshadow"===e?t.textShadow="0 2px 1px "+i:"raised"===e?t.textShadow="0 0 5px "+i+", 0 1px 5px "+i+", 0 2px 5px "+i:"depressed"===e?t.textShadow="0 -2px 1px "+i:"uniform"===e&&(t.textShadow="-2px 0 1px "+i+",2px 0 1px "+i+",0 -2px 1px "+i+",0 2px 1px "+i+",-1px 1px 1px "+i+",1px 1px 1px "+i+",1px -1px 1px "+i+",1px 1px 1px "+i)}(h=document.createElement("div")).className="jw-captions jw-reset",this.show=function(){Object(u.a)(h,"jw-captions-enabled")},this.hide=function(){Object(u.o)(h,"jw-captions-enabled")},this.populate=function(e){y.get("renderCaptionsNatively")||(f=[],s=e,e?this.selectCues(e,g):this.renderCues())},this.resize=function(){k(),this.renderCues(!0)},this.renderCues=function(e){e=!!e,i&&i.processCues(window,f,h,e)},this.selectCues=function(e,t){if(e&&e.data&&t&&!y.get("renderCaptionsNatively")){var n=this.getAlignmentPosition(e,t);!1!==n&&(f=this.getCurrentCues(e.data,n),this.renderCues(!0))}},this.getCurrentCues=function(e,t){return Object(o.h)(e,(function(e){return t>=e.startTime&&(!e.endTime||t<=e.endTime)}))},this.getAlignmentPosition=function(e,t){var n=e.source,i=t.metadata,r=t.currentTime;return n&&i&&Object(o.r)(i[n])&&(r=i[n]),r},this.clear=function(){Object(u.g)(h)},this.setup=function(e,n){p=document.createElement("div"),b=document.createElement("span"),p.className="jw-captions-window jw-reset",b.className="jw-captions-text jw-reset",t=Object(o.g)({},d,n),m=d.fontScale;var i=function(){if(!y.get("renderCaptionsNatively")){j(t.fontSize);var n=t.windowColor,i=t.windowOpacity,o=t.edgeStyle;w={};var a={};!function(e,t){var n=t.color,i=t.fontOpacity;(n||i!==d.fontOpacity)&&(e.color=Object(c.c)(n||"#ffffff",i));if(t.back){var o=t.backgroundColor,r=t.backgroundOpacity;o===d.backgroundColor&&r===d.backgroundOpacity||(e.backgroundColor=Object(c.c)(o,r))}else e.background="transparent";t.fontFamily&&(e.fontFamily=t.fontFamily);t.fontStyle&&(e.fontStyle=t.fontStyle);t.fontWeight&&(e.fontWeight=t.fontWeight);t.textDecoration&&(e.textDecoration=t.textDecoration)}(a,t),(n||i!==d.windowOpacity)&&(w.backgroundColor=Object(c.c)(n||"#000000",i)),O(o,a,t.fontOpacity),t.back||null!==o||O("uniform",a),Object(c.d)(p,w),Object(c.d)(b,a),function(e,t){k(),function(e,t){r.Browser.safari&&Object(c.b)("#"+e+" .jw-video::-webkit-media-text-track-display-backdrop",{backgroundColor:t.backgroundColor},e,!0);Object(c.b)("#"+e+" .jw-video::-webkit-media-text-track-display",w,e,!0),Object(c.b)("#"+e+" .jw-video::cue",t,e,!0)}(e,t),function(e,t){Object(c.b)("#"+e+" .jw-text-track-display",w,e),Object(c.b)("#"+e+" .jw-text-track-cue",t,e)}(e,t)}(e,a)}};i(),p.appendChild(b),h.appendChild(p),y.change("captionsTrack",(function(e,t){this.populate(t)}),this),y.set("captions",t),y.on("change:captions",(function(e,n){t=n,i()}))},this.element=function(){return h},this.destroy=function(){y.off(null,null,this),this.off()};var x=function(e){g=e,v.selectCues(s,g)};y.on("change:playlistItem",(function(){g=null,f=[]}),this),y.on(l.Q,(function(e){f=[],x(e)}),this),y.on(l.S,x,this),y.on("subtitlesTrackData",(function(){this.selectCues(s,g)}),this),y.on("change:captionsList",(function e(t,o){var r=this;1!==o.length&&(t.get("renderCaptionsNatively")||i||(n.e(8).then(function(e){i=n(68).default}.bind(null,n)).catch(Object(a.c)(301121)).catch((function(e){r.trigger(l.tb,e)})),t.off("change:captionsList",e,this)))}),this)};Object(o.g)(f.prototype,s.a),t.b=f},60:function(e,t,n){"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n=function(e,t){var n=e[1]||"",i=e[3];if(!i)return n;if(t&&"function"==typeof btoa){var o=(a=i,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(a))))+" */"),r=i.sources.map((function(e){return"/*# sourceURL="+i.sourceRoot+e+" */"}));return[n].concat(r).concat([o]).join("\n")}var a;return[n].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n})).join("")},t.i=function(e,n){"string"==typeof e&&(e=[[null,e,""]]);for(var i={},o=0;o1&&(n+=" ["+t+"]")),{label:n,unknownCount:t}}n.d(t,"a",(function(){return i})),n.d(t,"b",(function(){return o}))},64:function(e,t,n){"use strict";function i(e){return new Promise((function(t,n){if(e.paused)return n(o("NotAllowedError",0,"play() failed."));var i=function(){e.removeEventListener("play",r),e.removeEventListener("playing",a),e.removeEventListener("pause",a),e.removeEventListener("abort",a),e.removeEventListener("error",a)},r=function(){e.addEventListener("playing",a),e.addEventListener("abort",a),e.addEventListener("error",a),e.addEventListener("pause",a)},a=function(e){if(i(),"playing"===e.type)t();else{var r='The play() request was interrupted by a "'.concat(e.type,'" event.');"error"===e.type?n(o("NotSupportedError",9,r)):n(o("AbortError",20,r))}};e.addEventListener("play",r)}))}function o(e,t,n){var i=new Error(n);return i.name=e,i.code=t,i}n.d(t,"a",(function(){return i}))},65:function(e,t,n){"use strict";function i(e,t){return e!==1/0&&Math.abs(e)>=Math.max(r(t),0)}function o(e,t){var n="VOD";return e===1/0?n="LIVE":e<0&&(n=i(e,r(t))?"DVR":"LIVE"),n}function r(e){return void 0===e?120:Math.max(e,0)}n.d(t,"a",(function(){return i})),n.d(t,"b",(function(){return o}))},66:function(e,t,n){"use strict";var i=n(67),o=n(16),r=n(22),a=n(4),s=n(57),l=n(2),c=n(1);function u(e){throw new c.n(null,e)}function d(e,t,i){e.xhr=Object(r.a)(e.file,(function(r){!function(e,t,i,r){var d,f,h=e.responseXML?e.responseXML.firstChild:null;if(h)for("xml"===Object(a.b)(h)&&(h=h.nextSibling);h.nodeType===h.COMMENT_NODE;)h=h.nextSibling;try{if(h&&"tt"===Object(a.b)(h))d=function(e){e||u(306007);var t=[],n=e.getElementsByTagName("p"),i=30,o=e.getElementsByTagName("tt");if(o&&o[0]){var r=parseFloat(o[0].getAttribute("ttp:frameRate"));isNaN(r)||(i=r)}n||u(306005),n.length||(n=e.getElementsByTagName("tt:p")).length||(n=e.getElementsByTagName("tts:p"));for(var a=0;a\s+<").replace(/(<\/?)tts?:/g,"$1").replace(//g,"\r\n");if(h){var p=s.getAttribute("begin"),b=s.getAttribute("dur"),m=s.getAttribute("end"),w={begin:Object(l.g)(p,i),text:h};m?w.end=Object(l.g)(m,i):b&&(w.end=w.begin+Object(l.g)(b,i)),t.push(w)}}return t.length||u(306005),t}(e.responseXML),f=g(d),delete t.xhr,i(f);else{var p=e.responseText;p.indexOf("WEBVTT")>=0?n.e(10).then(function(e){return n(97).default}.bind(null,n)).catch(Object(o.c)(301131)).then((function(e){var n=new e(window);f=[],n.oncue=function(e){f.push(e)},n.onflush=function(){delete t.xhr,i(f)},n.parse(p)})).catch((function(e){delete t.xhr,r(Object(c.v)(null,c.b,e))})):(d=Object(s.a)(p),f=g(d),delete t.xhr,i(f))}}catch(e){delete t.xhr,r(Object(c.v)(null,c.b,e))}}(r,e,t,i)}),(function(e,t,n,o){i(Object(c.u)(o,c.b))}))}function f(e){e&&e.forEach((function(e){var t=e.xhr;t&&(t.onload=null,t.onreadystatechange=null,t.onerror=null,"abort"in t&&t.abort()),delete e.xhr}))}function g(e){return e.map((function(e){return new i.a(e.begin,e.end,e.text)}))}n.d(t,"c",(function(){return d})),n.d(t,"a",(function(){return f})),n.d(t,"b",(function(){return g}))},67:function(e,t,n){"use strict";var i=window.VTTCue;function o(e){if("string"!=typeof e)return!1;return!!{start:!0,middle:!0,end:!0,left:!0,right:!0}[e.toLowerCase()]&&e.toLowerCase()}if(!i){(i=function(e,t,n){var i=this;i.hasBeenReset=!1;var r="",a=!1,s=e,l=t,c=n,u=null,d="",f=!0,g="auto",h="start",p="auto",b=100,m="middle";Object.defineProperty(i,"id",{enumerable:!0,get:function(){return r},set:function(e){r=""+e}}),Object.defineProperty(i,"pauseOnExit",{enumerable:!0,get:function(){return a},set:function(e){a=!!e}}),Object.defineProperty(i,"startTime",{enumerable:!0,get:function(){return s},set:function(e){if("number"!=typeof e)throw new TypeError("Start time must be set to a number.");s=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"endTime",{enumerable:!0,get:function(){return l},set:function(e){if("number"!=typeof e)throw new TypeError("End time must be set to a number.");l=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"text",{enumerable:!0,get:function(){return c},set:function(e){c=""+e,this.hasBeenReset=!0}}),Object.defineProperty(i,"region",{enumerable:!0,get:function(){return u},set:function(e){u=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"vertical",{enumerable:!0,get:function(){return d},set:function(e){var t=function(e){return"string"==typeof e&&(!!{"":!0,lr:!0,rl:!0}[e.toLowerCase()]&&e.toLowerCase())}(e);if(!1===t)throw new SyntaxError("An invalid or illegal string was specified.");d=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"snapToLines",{enumerable:!0,get:function(){return f},set:function(e){f=!!e,this.hasBeenReset=!0}}),Object.defineProperty(i,"line",{enumerable:!0,get:function(){return g},set:function(e){if("number"!=typeof e&&"auto"!==e)throw new SyntaxError("An invalid number or illegal string was specified.");g=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"lineAlign",{enumerable:!0,get:function(){return h},set:function(e){var t=o(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");h=t,this.hasBeenReset=!0}}),Object.defineProperty(i,"position",{enumerable:!0,get:function(){return p},set:function(e){if(e<0||e>100)throw new Error("Position must be between 0 and 100.");p=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"size",{enumerable:!0,get:function(){return b},set:function(e){if(e<0||e>100)throw new Error("Size must be between 0 and 100.");b=e,this.hasBeenReset=!0}}),Object.defineProperty(i,"align",{enumerable:!0,get:function(){return m},set:function(e){var t=o(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");m=t,this.hasBeenReset=!0}}),i.displayState=void 0}).prototype.getCueAsHTML=function(){return window.WebVTT.convertCueToDOMTree(window,this.text)}}t.a=i},69:function(e,t,n){var i=n(70);"string"==typeof i&&(i=[["all-players",i,""]]),n(61).style(i,"all-players"),i.locals&&(e.exports=i.locals)},70:function(e,t,n){(e.exports=n(60)(!1)).push([e.i,'.jw-reset{text-align:left;direction:ltr}.jw-reset-text,.jw-reset{color:inherit;background-color:transparent;padding:0;margin:0;float:none;font-family:Arial,Helvetica,sans-serif;font-size:1em;line-height:1em;list-style:none;text-transform:none;vertical-align:baseline;border:0;font-variant:inherit;font-stretch:inherit;-webkit-tap-highlight-color:rgba(255,255,255,0)}body .jw-error,body .jwplayer.jw-state-error{height:100%;width:100%}.jw-title{position:absolute;top:0}.jw-background-color{background:rgba(0,0,0,0.4)}.jw-text{color:rgba(255,255,255,0.8)}.jw-knob{color:rgba(255,255,255,0.8);background-color:#fff}.jw-button-color{color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):focus,:not(.jw-flag-touch) .jw-button-color:not(.jw-logo-button):hover{color:#fff}.jw-toggle{color:#fff}.jw-toggle.jw-off{color:rgba(255,255,255,0.8)}.jw-toggle.jw-off:focus{color:#fff}.jw-toggle:focus{outline:none}:not(.jw-flag-touch) .jw-toggle.jw-off:hover{color:#fff}.jw-rail{background:rgba(255,255,255,0.3)}.jw-buffer{background:rgba(255,255,255,0.3)}.jw-progress{background:#f2f2f2}.jw-time-tip,.jw-volume-tip{border:0}.jw-slider-volume.jw-volume-tip.jw-background-color.jw-slider-vertical{background:none}.jw-skip{padding:.5em;outline:none}.jw-skip .jw-skiptext,.jw-skip .jw-skip-icon{color:rgba(255,255,255,0.8)}.jw-skip.jw-skippable:hover .jw-skip-icon,.jw-skip.jw-skippable:focus .jw-skip-icon{color:#fff}.jw-icon-cast google-cast-launcher{--connected-color:#fff;--disconnected-color:rgba(255,255,255,0.8)}.jw-icon-cast google-cast-launcher:focus{outline:none}.jw-icon-cast google-cast-launcher.jw-off{--connected-color:rgba(255,255,255,0.8)}.jw-icon-cast:focus google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-icon-cast:hover google-cast-launcher{--connected-color:#fff;--disconnected-color:#fff}.jw-nextup-container{bottom:2.5em;padding:5px .5em}.jw-nextup{border-radius:0}.jw-color-active{color:#fff;stroke:#fff;border-color:#fff}:not(.jw-flag-touch) .jw-color-active-hover:hover,:not(.jw-flag-touch) .jw-color-active-hover:focus{color:#fff;stroke:#fff;border-color:#fff}.jw-color-inactive{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}:not(.jw-flag-touch) .jw-color-inactive-hover:hover{color:rgba(255,255,255,0.8);stroke:rgba(255,255,255,0.8);border-color:rgba(255,255,255,0.8)}.jw-option{color:rgba(255,255,255,0.8)}.jw-option.jw-active-option{color:#fff;background-color:rgba(255,255,255,0.1)}:not(.jw-flag-touch) .jw-option:hover{color:#fff}.jwplayer{width:100%;font-size:16px;position:relative;display:block;min-height:0;overflow:hidden;box-sizing:border-box;font-family:Arial,Helvetica,sans-serif;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:none}.jwplayer *{box-sizing:inherit}.jwplayer.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jwplayer.jw-flag-aspect-mode{height:auto !important}.jwplayer.jw-flag-aspect-mode .jw-aspect{display:block}.jwplayer .jw-aspect{display:none}.jwplayer .jw-swf{outline:none}.jw-media,.jw-preview{position:absolute;width:100%;height:100%;top:0;left:0;bottom:0;right:0}.jw-media{overflow:hidden;cursor:pointer}.jw-plugin{position:absolute;bottom:66px}.jw-breakpoint-7 .jw-plugin{bottom:132px}.jw-plugin .jw-banner{max-width:100%;opacity:0;cursor:pointer;position:absolute;margin:auto auto 0;left:0;right:0;bottom:0;display:block}.jw-preview,.jw-captions,.jw-title{pointer-events:none}.jw-media,.jw-logo{pointer-events:all}.jw-wrapper{background-color:#000;position:absolute;top:0;left:0;right:0;bottom:0}.jw-hidden-accessibility{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.jw-contract-trigger::before{content:"";overflow:hidden;width:200%;height:200%;display:block;position:absolute;top:0;left:0}.jwplayer .jw-media video{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;margin:auto;background:transparent}.jwplayer .jw-media video::-webkit-media-controls-start-playback-button{display:none}.jwplayer.jw-stretch-uniform .jw-media video{object-fit:contain}.jwplayer.jw-stretch-none .jw-media video{object-fit:none}.jwplayer.jw-stretch-fill .jw-media video{object-fit:cover}.jwplayer.jw-stretch-exactfit .jw-media video{object-fit:fill}.jw-preview{position:absolute;display:none;opacity:1;visibility:visible;width:100%;height:100%;background:#000 no-repeat 50% 50%}.jwplayer .jw-preview,.jw-error .jw-preview{background-size:contain}.jw-stretch-none .jw-preview{background-size:auto auto}.jw-stretch-fill .jw-preview{background-size:cover}.jw-stretch-exactfit .jw-preview{background-size:100% 100%}.jw-title{display:none;padding-top:20px;width:100%;z-index:1}.jw-title-primary,.jw-title-secondary{color:#fff;padding-left:20px;padding-right:20px;padding-bottom:.5em;overflow:hidden;text-overflow:ellipsis;direction:unset;white-space:nowrap;width:100%}.jw-title-primary{font-size:1.625em}.jw-breakpoint-2 .jw-title-primary,.jw-breakpoint-3 .jw-title-primary{font-size:1.5em}.jw-flag-small-player .jw-title-primary{font-size:1.25em}.jw-flag-small-player .jw-title-secondary,.jw-title-secondary:empty{display:none}.jw-captions{position:absolute;width:100%;height:100%;text-align:center;display:none;letter-spacing:normal;word-spacing:normal;text-transform:none;text-indent:0;text-decoration:none;pointer-events:none;overflow:hidden;top:0}.jw-captions.jw-captions-enabled{display:block}.jw-captions-window{display:none;padding:.25em;border-radius:.25em}.jw-captions-window.jw-captions-window-active{display:inline-block}.jw-captions-text{display:inline-block;color:#fff;background-color:#000;word-wrap:normal;word-break:normal;white-space:pre-line;font-style:normal;font-weight:normal;text-align:center;text-decoration:none}.jw-text-track-display{font-size:inherit;line-height:1.5}.jw-text-track-cue{background-color:rgba(0,0,0,0.5);color:#fff;padding:.1em .3em}.jwplayer video::-webkit-media-controls{display:none;justify-content:flex-start}.jwplayer video::-webkit-media-text-track-display{min-width:-webkit-min-content}.jwplayer video::cue{background-color:rgba(0,0,0,0.5)}.jwplayer video::-webkit-media-controls-panel-container{display:none}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing) .jw-captions,.jwplayer.jw-flag-media-audio.jw-state-playing .jw-captions,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden) .jw-captions{max-height:calc(100% - 60px)}.jwplayer:not(.jw-flag-controls-hidden):not(.jw-state-playing):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-flag-media-audio.jw-state-playing:not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container,.jwplayer.jw-state-playing:not(.jw-flag-user-inactive):not(.jw-flag-controls-hidden):not(.jw-flag-ios-fullscreen) video::-webkit-media-text-track-container{max-height:calc(100% - 60px)}.jw-logo{position:absolute;margin:20px;cursor:pointer;pointer-events:all;background-repeat:no-repeat;background-size:contain;top:auto;right:auto;left:auto;bottom:auto;outline:none}.jw-logo.jw-tab-focus:focus{outline:solid 2px #4d90fe}.jw-flag-audio-player .jw-logo{display:none}.jw-logo-top-right{top:0;right:0}.jw-logo-top-left{top:0;left:0}.jw-logo-bottom-left{left:0}.jw-logo-bottom-right{right:0}.jw-logo-bottom-left,.jw-logo-bottom-right{bottom:44px;transition:bottom 150ms cubic-bezier(0, .25, .25, 1)}.jw-state-idle .jw-logo{z-index:1}.jw-state-setup .jw-wrapper{background-color:inherit}.jw-state-setup .jw-logo,.jw-state-setup .jw-controls,.jw-state-setup .jw-controls-backdrop{visibility:hidden}span.jw-break{display:block}body .jw-error,body .jwplayer.jw-state-error{background-color:#333;color:#fff;font-size:16px;display:table;opacity:1;position:relative}body .jw-error .jw-display,body .jwplayer.jw-state-error .jw-display{display:none}body .jw-error .jw-media,body .jwplayer.jw-state-error .jw-media{cursor:default}body .jw-error .jw-preview,body .jwplayer.jw-state-error .jw-preview{background-color:#333}body .jw-error .jw-error-msg,body .jwplayer.jw-state-error .jw-error-msg{background-color:#000;border-radius:2px;display:flex;flex-direction:row;align-items:stretch;padding:20px}body .jw-error .jw-error-msg .jw-icon,body .jwplayer.jw-state-error .jw-error-msg .jw-icon{height:30px;width:30px;margin-right:20px;flex:0 0 auto;align-self:center}body .jw-error .jw-error-msg .jw-icon:empty,body .jwplayer.jw-state-error .jw-error-msg .jw-icon:empty{display:none}body .jw-error .jw-error-msg .jw-info-container,body .jwplayer.jw-state-error .jw-error-msg .jw-info-container{margin:0;padding:0}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg{flex-direction:column}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-error-text,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-error-text{text-align:center}body .jw-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-flag-small-player .jw-error-msg .jw-icon,body .jw-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon,body .jwplayer.jw-state-error:not(.jw-flag-audio-player).jw-breakpoint-2 .jw-error-msg .jw-icon{flex:.5 0 auto;margin-right:0;margin-bottom:20px}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break{display:inline}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-flag-small-player .jw-error-msg .jw-break:before,.jwplayer.jw-state-error.jw-breakpoint-2 .jw-error-msg .jw-break:before{content:" "}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg{height:100%;width:100%;top:0;position:absolute;left:0;background:#000;-webkit-transform:none;transform:none;padding:4px 16px;z-index:1}.jwplayer.jw-state-error.jw-flag-audio-player .jw-error-msg.jw-info-overlay{max-width:none;max-height:none}body .jwplayer.jw-state-error .jw-title,.jw-state-idle .jw-title,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-title{display:block}body .jwplayer.jw-state-error .jw-preview,.jw-state-idle .jw-preview,.jwplayer.jw-state-complete:not(.jw-flag-casting):not(.jw-flag-audio-player):not(.jw-flag-overlay-open-related) .jw-preview{display:block}.jw-state-idle .jw-captions,.jwplayer.jw-state-complete .jw-captions,body .jwplayer.jw-state-error .jw-captions{display:none}.jw-state-idle video::-webkit-media-text-track-container,.jwplayer.jw-state-complete video::-webkit-media-text-track-container,body .jwplayer.jw-state-error video::-webkit-media-text-track-container{display:none}.jwplayer.jw-flag-fullscreen{width:100% !important;height:100% !important;top:0;right:0;bottom:0;left:0;z-index:1000;margin:0;position:fixed}body .jwplayer.jw-flag-flash-blocked .jw-title{display:block}.jwplayer.jw-flag-controls-hidden .jw-media{cursor:default}.jw-flag-audio-player:not(.jw-flag-flash-blocked) .jw-media{visibility:hidden}.jw-flag-audio-player .jw-title{background:none}.jw-flag-audio-player object{min-height:45px}.jw-flag-floating{background-size:cover;background-color:#000}.jw-flag-floating .jw-wrapper{position:fixed;z-index:2147483647;-webkit-animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;animation:jw-float-to-bottom 150ms cubic-bezier(0, .25, .25, 1) forwards 1;top:auto;bottom:1rem;left:auto;right:1rem;max-width:400px;max-height:400px;margin:0 auto}@media screen and (max-width:480px){.jw-flag-floating .jw-wrapper{width:100%;left:0;right:0}}.jw-flag-floating .jw-wrapper .jw-media{touch-action:none}@media screen and (max-device-width:480px) and (orientation:portrait){.jw-flag-touch.jw-flag-floating .jw-wrapper{-webkit-animation:none;animation:none;top:62px;bottom:auto;left:0;right:0;max-width:none;max-height:none}}.jw-flag-floating .jw-float-icon{pointer-events:all;cursor:pointer;display:none}.jw-flag-floating .jw-float-icon .jw-svg-icon{-webkit-filter:drop-shadow(0 0 1px #000);filter:drop-shadow(0 0 1px #000)}.jw-flag-floating.jw-floating-dismissible .jw-dismiss-icon{display:none}.jw-flag-floating.jw-floating-dismissible.jw-flag-ads .jw-float-icon{display:flex}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-logo,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-logo{display:none}.jw-flag-floating.jw-floating-dismissible.jw-state-paused .jw-float-icon,.jw-flag-floating.jw-floating-dismissible:not(.jw-flag-user-inactive) .jw-float-icon{display:flex}.jw-float-icon{display:none;position:absolute;top:3px;right:5px;align-items:center;justify-content:center}@-webkit-keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes jw-float-to-bottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}to{-webkit-transform:translateY(0);transform:translateY(0)}}.jw-flag-top{margin-top:2em;overflow:visible}.jw-top{height:2em;line-height:2;pointer-events:none;text-align:center;opacity:.8;position:absolute;top:-2em;width:100%}.jw-top .jw-icon{cursor:pointer;pointer-events:all;height:auto;width:auto}.jw-top .jw-text{color:#555}',""])}}]); \ No newline at end of file diff --git a/ui/v2.5/public/jwplayer/jwplayer.js b/ui/v2.5/public/jwplayer/jwplayer.js new file mode 100644 index 000000000..6b9881bb6 --- /dev/null +++ b/ui/v2.5/public/jwplayer/jwplayer.js @@ -0,0 +1,95 @@ +/*! +JW Player version 8.11.5 +Copyright (c) 2019, JW Player, All Rights Reserved +https://github.com/jwplayer/jwplayer/blob/v8.11.5/README.md + +This source code and its use and distribution is subject to the terms and conditions of the applicable license agreement. +https://www.jwplayer.com/tos/ + +This product includes portions of other software. For the full text of licenses, see below: + +JW Player Third Party Software Notices and/or Additional Terms and Conditions + +************************************************************************************************** +The following software is used under Apache License 2.0 +************************************************************************************************** + +vtt.js v0.13.0 +Copyright (c) 2019 Mozilla (http://mozilla.org) +https://github.com/mozilla/vtt.js/blob/v0.13.0/LICENSE + +* * * + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. + +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. + +************************************************************************************************** +The following software is used under MIT license +************************************************************************************************** + +Underscore.js v1.6.0 +Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative +https://github.com/jashkenas/underscore/blob/1.6.0/LICENSE + +Backbone backbone.events.js v1.1.2 +Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud +https://github.com/jashkenas/backbone/blob/1.1.2/LICENSE + +Promise Polyfill v7.1.1 +Copyright (c) 2014 Taylor Hakes and Forbes Lindesay +https://github.com/taylorhakes/promise-polyfill/blob/v7.1.1/LICENSE + +can-autoplay.js v3.0.0 +Copyright (c) 2017 video-dev +https://github.com/video-dev/can-autoplay/blob/v3.0.0/LICENSE + +* * * + +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. + +************************************************************************************************** +The following software is used under W3C license +************************************************************************************************** + +Intersection Observer v0.5.0 +Copyright (c) 2016 Google Inc. (http://google.com) +https://github.com/w3c/IntersectionObserver/blob/v0.5.0/LICENSE.md + +* * * + +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. + +This work is being provided by the copyright holders under the following license. + +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. + +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. + +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. +*/ +window.jwplayer=function(t){function e(e){for(var n,i,o=e[0],u=e[1],a=0,s=[];a2;if(null==t&&(t=[]),p&&t.reduce===p)return r&&(e=G(e,r)),i?t.reduce(e,n):t.reduce(e);if(k(t,(function(t,o,u){i?n=e.call(r,n,t,o,u):(n=t,i=!0)})),!i)throw new TypeError(S);return n},T=E,A=E,_=function(t,e,n){var r;return R(t,(function(t,i,o){if(e.call(n,t,i,o))return r=t,!0})),r},F=_,L=function(t,e,n){var r=[];return null==t?r:v&&t.filter===v?t.filter(e,n):(k(t,(function(t,i,o){e.call(n,t,i,o)&&r.push(t)})),r)},I=L,M=function(t,e,n){e||(e=kt);var r=!0;return null==t?r:g&&t.every===g?t.every(e,n):(k(t,(function(t,o,u){if(!(r=r&&e.call(n,t,o,u)))return i})),!!r)},N=M,R=function(t,e,n){e||(e=kt);var r=!1;return null==t?r:b&&t.some===b?t.some(e,n):(k(t,(function(t,o,u){if(r||(r=e.call(n,t,o,u)))return i})),!!r)},D=R,B=function(t,e){var n;return function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=null),n}},q=function(t){return null==t?kt:vt(t)?t:xt(t)},z=function(t){return function(e,n,r){var i={};return n=q(n),k(e,(function(o,u){var a=n.call(r,o,u,e);t(i,a,o)})),i}},V=z((function(t,e,n){Ot(t,e)?t[e].push(n):t[e]=[n]})),Q=z((function(t,e,n){t[e]=n})),W=function(t,e,n,r){for(var i=(n=q(n)).call(r,e),o=0,u=t.length;o>>1;n.call(r,t[a])=0)},H=X,Y=function(t,e){return _(t,Ct(e))},U=function(t){var e=s.apply(o,c.call(arguments,1));return L(t,(function(t){return!X(e,t)}))},J=function(t,e,n){if(null==t)return-1;var r=0,i=t.length;if(n){if("number"!=typeof n)return t[r=W(t,e)]===e?r:-1;r=n<0?Math.max(0,i+n):n}if(m&&t.indexOf===m)return t.indexOf(e,n);for(;r1&&void 0!==arguments[1]?arguments[1]:100;return function(){for(var r=this,i=arguments.length,o=new Array(i),u=0;ui&&(r=t,i=a)})),r},memoize:tt,now:Pt,omit:function(t){var e={},n=s.apply(o,c.call(arguments,1));for(var r in t)X(n,r)||(e[r]=t[r]);return e},once:Z,partial:K,pick:st,pluck:function(t,e){return C(t,xt(e))},property:xt,propertyOf:function(t){return null==t?function(){}:function(e){return t[e]}},reduce:E,reject:function(t,e,n){return L(t,(function(t,r,i){return!e.call(n,t,r,i)}),n)},result:function(t,e){if(null!=t){var n=t[e];return vt(n)?n.call(t):n}},select:I,size:function(t){return null==t?0:t.length===+t.length?t.length:it(t).length},some:D,sortedIndex:W,throttle:rt,where:function(t,e){return L(t,Ct(e))},without:function(t){return U(t,c.call(arguments,1))}}},function(t,e,n){"use strict";n.d(e,"t",(function(){return o})),n.d(e,"s",(function(){return u})),n.d(e,"r",(function(){return a})),n.d(e,"o",(function(){return c})),n.d(e,"p",(function(){return s})),n.d(e,"a",(function(){return l})),n.d(e,"c",(function(){return f})),n.d(e,"q",(function(){return d})),n.d(e,"d",(function(){return p})),n.d(e,"h",(function(){return h})),n.d(e,"e",(function(){return v})),n.d(e,"b",(function(){return O})),n.d(e,"f",(function(){return k})),n.d(e,"g",(function(){return x})),n.d(e,"k",(function(){return C})),n.d(e,"i",(function(){return P})),n.d(e,"j",(function(){return S})),n.d(e,"l",(function(){return E})),n.d(e,"m",(function(){return T})),n.d(e,"n",(function(){return A})),n.d(e,"v",(function(){return _})),n.d(e,"u",(function(){return F})),n.d(e,"w",(function(){return L}));var r=n(0);function i(t,e){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:null;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.code=Object(r.u)(n)?n:0,this.sourceError=i,e&&(this.key=e)}var e,n,o;return e=t,o=[{key:"logMessage",value:function(t){var e=t%1e3,n=Math.floor((t-e)/1e3),r=t;return e>=400&&e<600&&(r="".concat(n,"400-").concat(n,"599")),"JW Player ".concat(t>299999&&t<4e5?"Warning":"Error"," ").concat(t,". For more information see https://developer.jwplayer.com/jw-player/docs/developer-guide/api/errors-reference#").concat(r)}}],(n=null)&&i(e.prototype,n),o&&i(e,o),t}();function _(t,e,n){return n instanceof A&&n.code?n:new A(t,e,n)}function F(t,e){var n=_(T,e,t);return n.code=(t&&t.code||0)+e,n}function L(t){var e=t.name,n=t.message;switch(e){case"AbortError":return/pause/.test(n)?y:/load/.test(n)?m:b;case"NotAllowedError":return w;case"NotSupportedError":return j;default:return g}}},function(t,e,n){"use strict";n.d(e,"i",(function(){return o})),n.d(e,"e",(function(){return u})),n.d(e,"j",(function(){return a})),n.d(e,"a",(function(){return c})),n.d(e,"b",(function(){return s})),n.d(e,"g",(function(){return l})),n.d(e,"d",(function(){return f})),n.d(e,"f",(function(){return d})),n.d(e,"h",(function(){return p})),n.d(e,"c",(function(){return h}));var r=n(0),i=window.parseFloat;function o(t){return t.replace(/^\s+|\s+$/g,"")}function u(t,e,n){for(t=""+t,n=n||"0";t.length-1?t.substr(t.lastIndexOf(".")+1,t.length).toLowerCase():void 0}function s(t){var e=(t/60|0)%60,n=t%60;return u(t/3600|0,2)+":"+u(e,2)+":"+u(n.toFixed(3),6)}function l(t,e){if(!t)return 0;if(Object(r.u)(t))return t;var n=t.replace(",","."),o=n.slice(-1),u=n.split(":"),a=u.length,c=0;if("s"===o)c=i(n);else if("m"===o)c=60*i(n);else if("h"===o)c=3600*i(n);else if(a>1){var s=a-1;4===a&&(e&&(c=i(u[s])/e),s-=1),c+=i(u[s]),c+=60*i(u[s-1]),a>=3&&(c+=3600*i(u[s-2]))}else c=i(n);return Object(r.u)(c)?c:0}function f(t,e,n){if(Object(r.s)(t)&&"%"===t.slice(-1)){var o=i(t);return e&&Object(r.u)(e)&&Object(r.u)(o)?e*o/100:null}return l(t,n)}function d(t,e){return t.map((function(t){return e+t}))}function p(t,e){return t.map((function(t){return t+e}))}function h(t){return"string"==typeof t&&"%"===t.slice(-1)}},function(t,e,n){"use strict";n.d(e,"jb",(function(){return r})),n.d(e,"mb",(function(){return i})),n.d(e,"kb",(function(){return o})),n.d(e,"ob",(function(){return u})),n.d(e,"pb",(function(){return a})),n.d(e,"lb",(function(){return c})),n.d(e,"nb",(function(){return s})),n.d(e,"qb",(function(){return l})),n.d(e,"s",(function(){return f})),n.d(e,"u",(function(){return d})),n.d(e,"t",(function(){return p})),n.d(e,"n",(function(){return h})),n.d(e,"q",(function(){return v})),n.d(e,"rb",(function(){return g})),n.d(e,"r",(function(){return b})),n.d(e,"Z",(function(){return m})),n.d(e,"W",(function(){return y})),n.d(e,"v",(function(){return w})),n.d(e,"Y",(function(){return j})),n.d(e,"w",(function(){return O})),n.d(e,"tb",(function(){return k})),n.d(e,"a",(function(){return x})),n.d(e,"b",(function(){return C})),n.d(e,"c",(function(){return P})),n.d(e,"d",(function(){return S})),n.d(e,"e",(function(){return E})),n.d(e,"h",(function(){return T})),n.d(e,"F",(function(){return A})),n.d(e,"gb",(function(){return _})),n.d(e,"Q",(function(){return F})),n.d(e,"C",(function(){return L})),n.d(e,"B",(function(){return I})),n.d(e,"E",(function(){return M})),n.d(e,"p",(function(){return N})),n.d(e,"cb",(function(){return R})),n.d(e,"m",(function(){return D})),n.d(e,"G",(function(){return B})),n.d(e,"H",(function(){return q})),n.d(e,"N",(function(){return z})),n.d(e,"O",(function(){return V})),n.d(e,"R",(function(){return Q})),n.d(e,"ib",(function(){return W})),n.d(e,"bb",(function(){return X})),n.d(e,"D",(function(){return H})),n.d(e,"S",(function(){return Y})),n.d(e,"P",(function(){return U})),n.d(e,"T",(function(){return J})),n.d(e,"V",(function(){return $})),n.d(e,"M",(function(){return G})),n.d(e,"L",(function(){return K})),n.d(e,"K",(function(){return Z})),n.d(e,"I",(function(){return tt})),n.d(e,"J",(function(){return et})),n.d(e,"U",(function(){return nt})),n.d(e,"o",(function(){return rt})),n.d(e,"y",(function(){return it})),n.d(e,"hb",(function(){return ot})),n.d(e,"db",(function(){return ut})),n.d(e,"eb",(function(){return at})),n.d(e,"f",(function(){return ct})),n.d(e,"g",(function(){return st})),n.d(e,"ab",(function(){return lt})),n.d(e,"A",(function(){return ft})),n.d(e,"l",(function(){return dt})),n.d(e,"k",(function(){return pt})),n.d(e,"fb",(function(){return ht})),n.d(e,"sb",(function(){return vt})),n.d(e,"z",(function(){return gt})),n.d(e,"j",(function(){return bt})),n.d(e,"X",(function(){return mt})),n.d(e,"i",(function(){return yt})),n.d(e,"x",(function(){return wt}));var r="buffering",i="idle",o="complete",u="paused",a="playing",c="error",s="loading",l="stalled",f="drag",d="dragStart",p="dragEnd",h="click",v="doubleClick",g="tap",b="doubleTap",m="over",y="move",w="enter",j="out",O=c,k="warning",x="adClick",C="adPause",P="adPlay",S="adSkipped",E="adTime",T="autostartNotAllowed",A=o,_="ready",F="seek",L="beforePlay",I="beforeComplete",M="bufferFull",N="displayClick",R="playlistComplete",D="cast",B="mediaError",q="firstFrame",z="playAttempt",V="playAttemptFailed",Q="seeked",W="setupError",X="state",H="bufferChange",Y="time",U="ratechange",J="mediaType",$="volume",G="mute",K="metadataCueParsed",Z="meta",tt="levels",et="levelsChanged",nt="visualQuality",rt="controls",it="fullscreen",ot="resize",ut="playlistItem",at="playlist",ct="audioTracks",st="audioTrackChanged",lt="playbackRateChanged",ft="logoClick",dt="captionsList",pt="captionsChanged",ht="providerFirstFrame",vt="userAction",gt="instreamClick",bt="breakpoint",mt="fullscreenchange",yt="bandwidthEstimate",wt="float"},function(t,e,n){"use strict";n.d(e,"b",(function(){return i})),n.d(e,"d",(function(){return o})),n.d(e,"a",(function(){return u})),n.d(e,"c",(function(){return a}));var r=n(2);function i(t){var e="";return t&&(t.localName?e=t.localName:t.baseName&&(e=t.baseName)),e}function o(t){var e="";return t&&(t.textContent?e=Object(r.i)(t.textContent):t.text&&(e=Object(r.i)(t.text))),e}function u(t,e){return t.childNodes[e]}function a(t){return t.childNodes?t.childNodes.length:0}},function(t,e,n){"use strict";n.d(e,"i",(function(){return a})),n.d(e,"e",(function(){return c})),n.d(e,"q",(function(){return s})),n.d(e,"j",(function(){return l})),n.d(e,"s",(function(){return f})),n.d(e,"r",(function(){return d})),n.d(e,"u",(function(){return p})),n.d(e,"d",(function(){return g})),n.d(e,"a",(function(){return b})),n.d(e,"o",(function(){return m})),n.d(e,"p",(function(){return y})),n.d(e,"v",(function(){return w})),n.d(e,"t",(function(){return j})),n.d(e,"h",(function(){return O})),n.d(e,"b",(function(){return k})),n.d(e,"g",(function(){return x})),n.d(e,"c",(function(){return C})),n.d(e,"m",(function(){return P})),n.d(e,"k",(function(){return S})),n.d(e,"n",(function(){return E})),n.d(e,"l",(function(){return T})),n.d(e,"f",(function(){return A}));var r,i=n(0),o=n(2),u=n(8);function a(t,e){return t.classList.contains(e)}function c(t){return l(t).firstChild}function s(t,e){O(t),function(t,e){if(!e)return;for(var n=document.createDocumentFragment(),r=l(e).childNodes,i=0;i0?"":"px")}function h(t){return Object(i.s)(t.className)?t.className.split(" "):[]}function v(t,e){e=Object(o.i)(e),t.className!==e&&(t.className=e)}function g(t){return t.classList?t.classList:h(t)}function b(t,e){var n=h(t);(Array.isArray(e)?e:e.split(" ")).forEach((function(t){Object(i.b)(n,t)||n.push(t)})),v(t,n.join(" "))}function m(t,e){var n=h(t),r=Array.isArray(e)?e:e.split(" ");v(t,Object(i.e)(n,r).join(" "))}function y(t,e,n){var r=t.className||"";e.test(r)?r=r.replace(e,n):n&&(r+=" "+n),v(t,r)}function w(t,e,n){var r=a(t,e);(n=Object(i.n)(n)?n:!r)!==r&&(n?b(t,e):m(t,e))}function j(t,e,n){t.setAttribute(e,n)}function O(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function k(t){var e=document.createElement("link");e.rel="stylesheet",e.href=t,document.getElementsByTagName("head")[0].appendChild(e)}function x(t){t&&O(t)}function C(t){var e={left:0,right:0,width:0,height:0,top:0,bottom:0};if(!t||!document.body.contains(t))return e;var n=t.getBoundingClientRect(),r=window.pageYOffset,i=window.pageXOffset;return n.width||n.height||n.left||n.top?(e.left=n.left+i,e.right=n.right+i,e.top=n.top+r,e.bottom=n.bottom+r,e.width=n.right-n.left,e.height=n.bottom-n.top,e):e}function P(t,e){t.insertBefore(e,t.firstChild)}function S(t){return t.nextElementSibling}function E(t){return t.previousElementSibling}function T(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=document.createElement("a");r.href=t,r.target=e,r=Object(i.g)(r,n),u.Browser.firefox?r.dispatchEvent(new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window})):r.click()}function A(){var t=window.screen.orientation;return!!t&&("landscape-primary"===t.type||"landscape-secondary"===t.type)||90===window.orientation||-90===window.orientation}},function(t,e,n){"use strict";n.d(e,"h",(function(){return u})),n.d(e,"f",(function(){return a})),n.d(e,"l",(function(){return s})),n.d(e,"k",(function(){return f})),n.d(e,"p",(function(){return d})),n.d(e,"g",(function(){return p})),n.d(e,"e",(function(){return h})),n.d(e,"n",(function(){return v})),n.d(e,"d",(function(){return g})),n.d(e,"i",(function(){return b})),n.d(e,"q",(function(){return m})),n.d(e,"j",(function(){return y})),n.d(e,"c",(function(){return w})),n.d(e,"b",(function(){return j})),n.d(e,"o",(function(){return O})),n.d(e,"m",(function(){return k})),n.d(e,"a",(function(){return x}));var r=navigator.userAgent;function i(t){return null!==r.match(t)}function o(t){return function(){return i(t)}}function u(){var t=x();return!!(t&&t>=18)}var a=o(/gecko\//i),c=o(/trident\/.+rv:\s*11/i),s=o(/iP(hone|od)/i),l="MacIntel"===navigator.platform&&navigator.maxTouchPoints>1,f=function(){return i(/iPad/i)||l},d=function(){return i(/Macintosh/i)&&!l},p=o(/FBAV/i);function h(){return i(/\sEdge\/\d+/i)}function v(){return i(/msie/i)}function g(){return i(/\s(?:(?:Headless)?Chrome|CriOS)\//i)&&!h()&&!i(/UCBrowser/i)}function b(){return h()||c()||v()}function m(){return i(/safari/i)&&!i(/(?:Chrome|CriOS|chromium|android|phantom)/i)}function y(){return i(/iP(hone|ad|od)/i)||l}function w(){return!(i(/chrome\/[123456789]/i)&&!i(/chrome\/18/i)&&!a())&&j()}function j(){return i(/Android/i)&&!i(/Windows Phone/i)}function O(){return y()||j()||i(/Windows Phone/i)}function k(){try{return window.self!==window.top}catch(t){return!0}}function x(){if(j())return 0;var t,e=navigator.plugins;if(e&&(t=e["Shockwave Flash"])&&t.description)return parseFloat(t.description.replace(/\D+(\d+\.?\d*).*/,"$1"));if(void 0!==window.ActiveXObject){try{if(t=new window.ActiveXObject("ShockwaveFlash.ShockwaveFlash"))return parseFloat(t.GetVariable("$version").split(" ")[1].replace(/\s*,\s*/,"."))}catch(t){return 0}return t}return 0}},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function i(t,e){for(var n=0;ne)return t[e]}var o=n(0);n.d(e,"Browser",(function(){return a})),n.d(e,"OS",(function(){return c})),n.d(e,"Features",(function(){return s}));var u=navigator.userAgent;var a={},c={},s={};Object.defineProperties(a,{androidNative:{get:Object(o.x)(r.c),enumerable:!0},chrome:{get:Object(o.x)(r.d),enumerable:!0},edge:{get:Object(o.x)(r.e),enumerable:!0},facebook:{get:Object(o.x)(r.g),enumerable:!0},firefox:{get:Object(o.x)(r.f),enumerable:!0},ie:{get:Object(o.x)(r.i),enumerable:!0},msie:{get:Object(o.x)(r.n),enumerable:!0},safari:{get:Object(o.x)(r.q),enumerable:!0},version:{get:Object(o.x)(function(t,e){var n,r,i,o;return t.chrome?n=-1!==e.indexOf("Chrome")?e.substring(e.indexOf("Chrome")+7):e.substring(e.indexOf("CriOS")+6):t.safari?n=e.substring(e.indexOf("Version")+8):t.firefox?n=e.substring(e.indexOf("Firefox")+8):t.edge?n=e.substring(e.indexOf("Edge")+5):t.ie&&(-1!==e.indexOf("rv:")?n=e.substring(e.indexOf("rv:")+3):-1!==e.indexOf("MSIE")&&(n=e.substring(e.indexOf("MSIE")+5))),n&&(-1!==(o=n.indexOf(";"))&&(n=n.substring(0,o)),-1!==(o=n.indexOf(" "))&&(n=n.substring(0,o)),-1!==(o=n.indexOf(")"))&&(n=n.substring(0,o)),r=parseInt(n,10),i=parseInt(n.split(".")[1],10)),{version:n,major:r,minor:i}}.bind(void 0,a,u)),enumerable:!0}}),Object.defineProperties(c,{android:{get:Object(o.x)(r.b),enumerable:!0},iOS:{get:Object(o.x)(r.j),enumerable:!0},mobile:{get:Object(o.x)(r.o),enumerable:!0},mac:{get:Object(o.x)(r.p),enumerable:!0},iPad:{get:Object(o.x)(r.k),enumerable:!0},iPhone:{get:Object(o.x)(r.l),enumerable:!0},windows:{get:Object(o.x)((function(){return u.indexOf("Windows")>-1})),enumerable:!0},version:{get:Object(o.x)(function(t,e){var n,r,o;if(t.windows)switch(n=i(/Windows(?: NT|)? ([._\d]+)/.exec(e),1)){case"6.1":n="7.0";break;case"6.2":n="8.0";break;case"6.3":n="8.1"}else t.android?n=i(/Android ([._\d]+)/.exec(e),1):t.iOS?n=i(/OS ([._\d]+)/.exec(e),1):t.mac&&(n=i(/Mac OS X (10[._\d]+)/.exec(e),1));if(n){r=parseInt(n,10);var u=n.split(/[._]/);u&&(o=parseInt(u[1],10))}return{version:n,major:r,minor:o}}.bind(void 0,c,u)),enumerable:!0}}),Object.defineProperties(s,{flash:{get:Object(o.x)(r.h),enumerable:!0},flashVersion:{get:Object(o.x)(r.a),enumerable:!0},iframe:{get:Object(o.x)(r.m),enumerable:!0},passiveEvents:{get:Object(o.x)((function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){return t=!0}});window.addEventListener("testPassive",null,e),window.removeEventListener("testPassive",null,e)}catch(t){}return t})),enumerable:!0},backgroundLoading:{get:Object(o.x)((function(){return!(c.iOS||a.safari)})),enumerable:!0}})},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}n.r(e),n.d(e,"exists",(function(){return o})),n.d(e,"isHTTPS",(function(){return u})),n.d(e,"isFileProtocol",(function(){return a})),n.d(e,"isRtmp",(function(){return c})),n.d(e,"isYouTube",(function(){return s})),n.d(e,"typeOf",(function(){return l})),n.d(e,"isDeepKeyCompliant",(function(){return f}));var i=window.location.protocol;function o(t){switch(r(t)){case"string":return t.length>0;case"object":return null!==t;case"undefined":return!1;default:return!0}}function u(){return"https:"===i}function a(){return"file:"===i}function c(t,e){return 0===t.indexOf("rtmp:")||"rtmp"===e}function s(t,e){return"youtube"===e||/^(http|\/\/).*(youtube\.com|youtu\.be)\/.+/.test(t)}function l(t){if(null===t)return"null";var e=r(t);return"object"===e&&Array.isArray(t)?"array":e}function f(t,e,n){var i=Object.keys(t);return Object.keys(e).length>=i.length&&i.every((function(i){var o=t[i],u=e[i];return o&&"object"===r(o)?!(!u||"object"!==r(u))&&f(o,u,n):n(i,t)}))}},function(t,e,n){"use strict";n.d(e,"a",(function(){return c})),n.d(e,"b",(function(){return s})),n.d(e,"d",(function(){return l})),n.d(e,"e",(function(){return p})),n.d(e,"c",(function(){return h}));var r=n(2),i=n(39),o=n.n(i);function u(t){return(u="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var a,c=o.a.clear;function s(t,e,n,r){n=n||"all-players";var i="";if("object"===u(e)){var a=document.createElement("div");l(a,e);var c=a.style.cssText;Object.prototype.hasOwnProperty.call(e,"content")&&c&&(c="".concat(c,' content: "').concat(e.content,'";')),r&&c&&(c=c.replace(/;/g," !important;")),i="{"+c+"}"}else"string"==typeof e&&(i=e);""!==i&&"{}"!==i?o.a.style([[t,t+i]],n):o.a.clear(n,t)}function l(t,e){if(null!=t){var n;void 0===t.length&&(t=[t]);var r={};for(n in e)Object.prototype.hasOwnProperty.call(e,n)&&(r[n]=d(n,e[n]));for(var i=0;i-1?t:parseInt(t.replace("px",""),10):t}function l(t,e){if(t<=0&&!e||Object(i.q)(parseInt(t)))return"00:00";var n=t<0?"-":"";t=Math.abs(t);var r=Math.floor(t/3600),o=Math.floor((t-3600*r)/60),u=Math.floor(t%60);return n+(r?r+":":"")+(o<10?"0":"")+o+":"+(u<10?"0":"")+u}},function(t,e,n){"use strict";e.a=[]},function(t,e,n){"use strict";n.d(e,"h",(function(){return d})),n.d(e,"c",(function(){return h})),n.d(e,"e",(function(){return g})),n.d(e,"f",(function(){return b})),n.d(e,"b",(function(){return m})),n.d(e,"d",(function(){return w})),n.d(e,"g",(function(){return j})),n.d(e,"a",(function(){return O}));var r=n(0),i=n(6),o=n(22),u=n(9),a=n(33),c={},s={zh:"Chinese",nl:"Dutch",en:"English",fr:"French",de:"German",it:"Italian",ja:"Japanese",pt:"Portuguese",ru:"Russian",es:"Spanish",el:"Greek",fi:"Finnish",id:"Indonesian",ko:"Korean",th:"Thai",vi:"Vietnamese"};Object(r.m)(s);function l(t){var e=f(t),n=e.indexOf("_");return-1===n?e:e.substring(0,n)}function f(t){return t.toLowerCase().replace("-","_")}function d(t){return t?Object.keys(t).reduce((function(e,n){return e[f(n)]=t[n],e}),{}):{}}function p(t){var e=t.querySelector("html");return e?e.getAttribute("lang"):null}function h(){var t=p(document);if(!t&&Object(i.m)())try{t=p(window.top.document)}catch(t){}return t||navigator.language||"en"}var v=["ar","da","de","el","es","fi","fr","he","id","it","ja","ko","nl","no","oc","pt","ro","ru","sl","sv","th","tr","vi","zh"];function g(t){return 8207===t.charCodeAt(0)||/^[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/.test(t)}function b(t){return v.indexOf(l(t))>=0}function m(t,e,n){return Object(r.g)({},function(t){var e=t.advertising,n=t.related,i=t.sharing,o=t.abouttext,u=Object(r.g)({},t.localization);e&&(u.advertising=u.advertising||{},y(u.advertising,e,"admessage"),y(u.advertising,e,"cuetext"),y(u.advertising,e,"loadingAd"),y(u.advertising,e,"podmessage"),y(u.advertising,e,"skipmessage"),y(u.advertising,e,"skiptext"));"string"==typeof u.related?u.related={heading:u.related}:u.related=u.related||{};n&&y(u.related,n,"autoplaymessage");i&&(u.sharing=u.sharing||{},y(u.sharing,i,"heading"),y(u.sharing,i,"copied"));o&&y(u,t,"abouttext");var a=u.close||u.nextUpClose;a&&(u.close=a);return u}(t),e[l(n)],e[f(n)])}function y(t,e,n){var r=t[n]||e[n];r&&(t[n]=r)}function w(t){return Object(u.isDeepKeyCompliant)(a.a,t,(function(t,e){return"string"==typeof e[t]}))}function j(t,e){var n=c[e];if(!n){var r="".concat(t,"translations/").concat(l(e),".json");c[e]=n=new Promise((function(t,n){Object(o.a)({url:r,oncomplete:t,onerror:function(t,r,i,o){c[e]=null,n(o)},responseType:"json"})}))}return n}function O(t,e){var n=Object(r.g)({},t,e);return k(n,"errors",t,e),k(n,"related",t,e),k(n,"sharing",t,e),k(n,"advertising",t,e),k(n,"shortcuts",t,e),n}function k(t,e,n,i){t[e]=Object(r.g)({},n[e],i[e])}},function(t,e,n){"use strict";var r=n(52),i=n(9),o=document.createElement("video"),u={aac:"audio/mp4",mp4:"video/mp4",f4v:"video/mp4",m4v:"video/mp4",mov:"video/mp4",mp3:"audio/mpeg",mpeg:"audio/mpeg",ogv:"video/ogg",ogg:"video/ogg",oga:"video/ogg",vorbis:"video/ogg",webm:"video/webm",f4a:"video/aac",m3u8:"application/vnd.apple.mpegurl",m3u:"application/vnd.apple.mpegurl",hls:"application/vnd.apple.mpegurl"},a=[{name:"html5",supports:function(t){if(!1===Object(r.a)(t))return!1;if(!o.canPlayType)return!1;var e=t.file,n=t.type;if(Object(i.isRtmp)(e,n))return!1;var a=t.mimeType||u[n];if(!a)return!1;var c=t.mediaTypes;c&&c.length&&(a=[a].concat(c.slice()).join("; "));return!!o.canPlayType(a)}}];e.a=a},function(t,e,n){"use strict";n.d(e,"a",(function(){return r}));var r=Date.now||function(){return(new Date).getTime()}},function(t,e,n){"use strict";n.d(e,"a",(function(){return l})),n.d(e,"d",(function(){return f})),n.d(e,"b",(function(){return d})),n.d(e,"c",(function(){return p}));var r=n(25),i=n(26),o=n(14),u=n(21),a=n(32),c=n(1),s=null,l={};function f(t){return s||(s=function(t){var e=t.get("controls"),s=h(),f=function(t,e){var n=t.get("playlist");if(Array.isArray(n)&&n.length)for(var u=Object(i.c)(Object(r.a)(n[0]),t),a=0;a=0)return r.substr(0,i+1)}}return""}),o=function(){return i("jwplayer.js")},u=function(t){var e=("0"+t).split(/\W/),n=r.a.split(/\W/),i=parseFloat(e[0]),o=parseFloat(n[0]);return!(i>o)&&!(i===o&&parseFloat("0"+e[1])>parseFloat(n[1]))},a=function(){return i("jwplayer.js")}},function(t,e,n){"use strict";n.d(e,"a",(function(){return a}));var r=n(28),i=n(14),o=n(53),u=n(0);function a(t){var e=t.getName().name;if(!r.a[e]){if(!Object(u.i)(i.a,Object(u.w)({name:e}))){if(!Object(u.p)(t.supports))throw new Error("Tried to register a provider with an invalid object");i.a.unshift({name:e,supports:t.supports})}Object(u.d)(t.prototype,o.a),r.a[e]=t}}},function(t,e,n){"use strict";n.d(e,"a",(function(){return m}));var r=n(0),i=n(11),o=n(9),u=n(1),a=1,c=2,s=3,l=4,f=5,d=6,p=7,h=601,v=602,g=611,b=function(){};function m(t,e,n,h){var O;t===Object(t)&&(t=(h=t).url);var k=Object(r.g)({xhr:null,url:t,withCredentials:!1,retryWithoutCredentials:!1,timeout:6e4,timeoutId:-1,oncomplete:e||b,onerror:n||b,mimeType:h&&!h.responseType?"text/xml":"",requireValidXML:!1,responseType:h&&h.plainText?"text":"",useDomParser:!1,requestFilter:null},h),x=function(t,e){return function(t,n){var i=t.currentTarget||e.xhr;if(clearTimeout(e.timeoutId),e.retryWithoutCredentials&&e.xhr.withCredentials)return y(i),void m(Object(r.g)({},e,{xhr:null,withCredentials:!1,retryWithoutCredentials:!1}));!n&&i.status>=400&&i.status<600&&(n=i.status),w(e,n?u.k:u.m,n||d,t)}}(0,k);if("XMLHttpRequest"in window){if(O=k.xhr=k.xhr||new window.XMLHttpRequest,"function"==typeof k.requestFilter){var C;try{C=k.requestFilter({url:t,xhr:O})}catch(t){return x(t,f),O}C&&"open"in C&&"send"in C&&(O=k.xhr=C)}O.onreadystatechange=function(t){return function(e){var n=e.currentTarget||t.xhr;if(4===n.readyState){clearTimeout(t.timeoutId);var a=n.status;if(a>=400)return void w(t,u.k,a<600?a:d);if(200===a)return function(t){return function(e){var n=e.currentTarget||t.xhr;if(clearTimeout(t.timeoutId),t.responseType){if("json"===t.responseType)return function(t,e){if(!t.response||"string"==typeof t.response&&'"'!==t.responseText.substr(1))try{t=Object(r.g)({},t,{response:JSON.parse(t.responseText)})}catch(t){return void w(e,u.k,g,t)}return e.oncomplete(t)}(n,t)}else{var o,a=n.responseXML;if(a)try{o=a.firstChild}catch(t){}if(a&&o)return j(n,a,t);if(t.useDomParser&&n.responseText&&!a&&(a=Object(i.parseXML)(n.responseText))&&a.firstChild)return j(n,a,t);if(t.requireValidXML)return void w(t,u.k,v)}t.oncomplete(n)}}(t)(e);0===a&&Object(o.isFileProtocol)()&&!/^[a-z][a-z0-9+.-]*:/.test(t.url)&&w(t,u.k,p)}}}(k),O.onerror=x,"overrideMimeType"in O?k.mimeType&&O.overrideMimeType(k.mimeType):k.useDomParser=!0;try{t=t.replace(/#.*$/,""),O.open("GET",t,!0)}catch(t){return x(t,s),O}if(k.responseType)try{O.responseType=k.responseType}catch(t){}k.timeout&&(k.timeoutId=setTimeout((function(){y(O),w(k,u.m,a)}),k.timeout),O.onabort=function(){clearTimeout(k.timeoutId)});try{k.withCredentials&&"withCredentials"in O&&(O.withCredentials=!0),O.send()}catch(t){x(t,l)}return O}w(k,u.m,c)}function y(t){t.onload=null,t.onprogress=null,t.onreadystatechange=null,t.onerror=null,"abort"in t&&t.abort()}function w(t,e,n,r){t.onerror(e,t.url,t.xhr,new u.n(e,n,r))}function j(t,e,n){var i=e.documentElement;if(!n.requireValidXML||"parsererror"!==i.nodeName&&!i.getElementsByTagName("parsererror").length)return t.responseXML||(t=Object(r.g)({},t,{responseXML:e})),n.oncomplete(t);w(n,u.k,h)}},function(t,e,n){"use strict";n.d(e,"a",(function(){return r}));var r="8.11.5+local.2019-12-16-11-42-43-502"},function(t,e,n){"use strict";var r=n(0),i=n(15),o=window.performance||{timing:{}},u=o.timing.navigationStart||Object(i.a)();function a(){return u+o.now()}"now"in o||(o.now=function(){return Object(i.a)()-u});e.a=function(){var t={},e={},n={},i={};return{start:function(e){t[e]=a(),n[e]=n[e]+1||1},end:function(n){if(t[n]){var r=a()-t[n];delete t[n],e[n]=e[n]+r||r}},dump:function(){var o=Object(r.g)({},e);for(var u in t)if(Object.prototype.hasOwnProperty.call(t,u)){var c=a()-t[u];o[u]=o[u]+c||c}return{counts:Object(r.g)({},n),sums:o,events:Object(r.g)({},i)}},tick:function(t){i[t]=a()},clear:function(t){delete i[t]},between:function(t,e){return i[e]&&i[t]?i[e]-i[t]:null}}}},function(t,e,n){"use strict";var r=n(0),i=n(29),o=function(t){if(t&&t.file)return Object(r.g)({},{kind:"captions",default:!1},t)},u=Array.isArray;e.a=function(t){u((t=t||{}).tracks)||delete t.tracks;var e=Object(r.g)({},{sources:[],tracks:[],minDvrWindow:120,dvrSeekLimit:25},t);e.sources!==Object(e.sources)||u(e.sources)||(e.sources=[Object(i.a)(e.sources)]),u(e.sources)&&0!==e.sources.length||(t.levels?e.sources=t.levels:e.sources=[Object(i.a)(t)]);for(var n=0;n0)return d;var n=t.indexOf("/"),r=Object(f.a)(t);return!(e<0&&n<0)||r&&isNaN(r)?p:2}};var v=function(t){this.url=t,this.promise_=null};Object.defineProperties(v.prototype,{promise:{get:function(){return this.promise_||this.load()},set:function(){}}}),Object(i.g)(v.prototype,{load:function(){var t=this,e=this.promise_;if(!e){if(2===h(this.url))e=Promise.resolve(this);else{var n=new s.a(function(t){switch(h(t)){case d:return t;case p:return Object(l.getAbsolutePath)(t,window.location.href)}}(this.url));this.loader=n,e=n.load().then((function(){return t}))}this.promise_=e}return e},registerPlugin:function(t,e,n){this.name=t,this.target=e,this.js=n},getNewInstance:function(t,e,n){var i=this.js;if("function"!=typeof i)throw new r.n(null,u(this.url)+100);var o=new i(t,e,n);return o.addToPlayer=function(){var e=t.getContainer().querySelector(".jw-overlays");e&&(n.left=e.style.left,n.top=e.style.top,e.appendChild(n),o.displayArea=e)},o.resizeHandler=function(){var t=o.displayArea;t&&o.resize(t.clientWidth,t.clientHeight)},o}});var g=v,b=n(38),m={},y=function(){},w=y.prototype;w.setupPlugin=function(t){var e=this.getPlugin(t);return e?(e.url!==t&&Object(b.a)('JW Plugin "'.concat(o(t),'" already loaded from "').concat(e.url,'". Ignoring "').concat(t,'."')),e.promise):this.addPlugin(t).load()},w.addPlugin=function(t){var e=o(t),n=m[e];return n||(n=new g(t),m[e]=n),n},w.getPlugin=function(t){return m[o(t)]},w.removePlugin=function(t){delete m[o(t)]},w.getPlugins=function(){return m};var j=y;n.d(e,"b",(function(){return k})),n.d(e,"a",(function(){return x}));var O=new j,k=function(t,e,n){var r=O.addPlugin(t);r.js||r.registerPlugin(t,e,n)};function x(t,e){var n=t.get("plugins");return window.jwplayerPluginJsonp=k,(t.pluginLoader=t.pluginLoader||new c).load(e,O,n,t).then((function(e){if(!t.attributes._destroyed)return delete window.jwplayerPluginJsonp,e}))}},function(t,e,n){"use strict";e.a={}},function(t,e,n){"use strict";var r=n(0),i=n(9),o=n(2);e.a=function(t){if(t&&t.file){var e=Object(r.g)({},{default:!1},t);e.file=Object(o.i)(""+e.file);var n=/^[^/]+\/(?:x-)?([^/]+)$/;if(n.test(e.type)&&(e.mimeType=e.type,e.type=e.type.replace(n,"$1")),Object(i.isYouTube)(e.file)?e.type="youtube":Object(i.isRtmp)(e.file)?e.type="rtmp":e.type||(e.type=Object(o.a)(e.file)),e.type){switch(e.type){case"m3u8":case"vnd.apple.mpegurl":e.type="hls";break;case"dash+xml":e.type="dash";break;case"m4a":e.type="aac";break;case"smil":e.type="rtmp"}return Object.keys(e).forEach((function(t){""===e[t]&&delete e[t]})),e}}}},,,function(t,e,n){"use strict";n.d(e,"a",(function(){return o})),n.d(e,"b",(function(){return u}));var r=n(16),i=null,o={};function u(){return i||(i=n.e(1).then(function(t){var e=n(17).default;return o.controls=e,e}.bind(null,n)).catch((function(){i=null,Object(r.c)(301130)()}))),i}},function(t,e,n){"use strict";e.a={advertising:{admessage:"This ad will end in xx",cuetext:"Advertisement",displayHeading:"Advertisement",loadingAd:"Loading ad",podmessage:"Ad __AD_POD_CURRENT__ of __AD_POD_LENGTH__.",skipmessage:"Skip ad in xx",skiptext:"Skip"},airplay:"AirPlay",audioTracks:"Audio Tracks",auto:"Auto",buffer:"Loading",cast:"Chromecast",cc:"Closed Captions",close:"Close",errors:{badConnection:"This video cannot be played because of a problem with your internet connection.",cantLoadPlayer:"Sorry, the video player failed to load.",cantPlayInBrowser:"The video cannot be played in this browser.",cantPlayVideo:"This video file cannot be played.",errorCode:"Error Code",liveStreamDown:"The live stream is either down or has ended.",protectedContent:"There was a problem providing access to protected content.",technicalError:"This video cannot be played because of a technical error."},exitFullscreen:"Exit Fullscreen",fullscreen:"Fullscreen",hd:"Quality",liveBroadcast:"Live",logo:"Logo",mute:"Mute",next:"Next",nextUp:"Next Up",notLive:"Not Live",off:"Off",pause:"Pause",play:"Play",playback:"Play",playbackRates:"Playback Rates",player:"Video Player",poweredBy:"Powered by",prev:"Previous",related:{autoplaymessage:"Next up in xx",heading:"More Videos"},replay:"Replay",rewind:"Rewind 10 Seconds",settings:"Settings",sharing:{copied:"Copied",email:"Email",embed:"Embed",heading:"Share",link:"Link"},slider:"Seek",stop:"Stop",unmute:"Unmute",videoInfo:"About This Video",volume:"Volume",volumeSlider:"Volume",shortcuts:{playPause:"Play/Pause",volumeToggle:"Mute/Unmute",fullscreenToggle:"Fullscreen/Exit Fullscreen",seekPercent:"Seek %",keyboardShortcuts:"Keyboard Shortcuts",increaseVolume:"Increase Volume",decreaseVolume:"Decrease Volume",seekForward:"Seek Forward",seekBackward:"Seek Backward",spacebar:"SPACE",captionsToggle:"Captions On/Off"}}},function(t,e,n){"use strict";var r=n(0),i=n(14),o=n(21),u=n(28),a=n(16);function c(t){this.config=t||{}}var s={html5:function(){return n.e(9).then(function(t){var e=n(31).default;return Object(o.a)(e),e}.bind(null,n)).catch(Object(a.b)(152))}};Object(r.g)(c.prototype,{load:function(t){var e=s[t],n=function(){return Promise.reject(new Error("Failed to load media"))};return e?e().then((function(){var e=u.a[t];return e||n()})):n()},providerSupports:function(t,e){return t.supports(e)},choose:function(t){if(t===Object(t))for(var e=i.a.length,n=0;n')+'
    '+'
    '.concat(e||"",'').concat(i,"
    ")+"
    "},i=n(5),o=n(10);function u(t,e){var n=e.message,u=e.code,a=r(t.get("id"),n,t.get("localization").errors.errorCode,u),c=t.get("width"),s=t.get("height"),l=Object(i.e)(a);return Object(o.d)(l,{width:c.toString().indexOf("%")>0?c:"".concat(c,"px"),height:s.toString().indexOf("%")>0?s:"".concat(s,"px")}),l}n.d(e,"a",(function(){return u}))},function(t,e,n){"use strict";function r(t){return t.slice&&"px"===t.slice(-2)&&(t=t.slice(0,-2)),t}function i(t,e){if(-1===e.toString().indexOf("%"))return 0;if("string"!=typeof t||!t)return 0;if(/^\d*\.?\d+%$/.test(t))return t;var n=t.indexOf(":");if(-1===n)return 0;var r=parseFloat(t.substr(0,n)),i=parseFloat(t.substr(n+1));return r<=0||i<=0?0:i/r*100+"%"}n.d(e,"b",(function(){return r})),n.d(e,"a",(function(){return i}))},function(t,e,n){"use strict";var r=n(0),i=n(7),o=n(3),u={},a=45e3,c=2,s=3;function l(t){var e=document.createElement("link");return e.type="text/css",e.rel="stylesheet",e.href=t,e}function f(t,e){var n=document.createElement("script");return n.type="text/javascript",n.charset="utf-8",n.async=!0,n.timeout=e||a,n.src=t,n}var d=function(t,e,n){var r=this,i=0;function d(t){i=c,r.trigger(o.w,t).off()}function p(t){i=s,r.trigger(o.kb,t).off()}this.getStatus=function(){return i},this.load=function(){var r=u[t];return 0!==i?r:(r&&r.then(p).catch(d),i=1,r=new Promise((function(r,i){var o=(e?l:f)(t,n),u=function(){o.onerror=o.onload=null,clearTimeout(s)},c=function(t){u(),d(t),i(t)},s=setTimeout((function(){c(new Error("Network timeout ".concat(t)))}),a);o.onerror=function(){c(new Error("Failed to load ".concat(t)))},o.onload=function(t){u(),p(t),r(t)};var h=document.getElementsByTagName("head")[0]||document.documentElement;h.insertBefore(o,h.firstChild)})),u[t]=r,r)}};Object(r.g)(d.prototype,i.a),e.a=d},function(t,e,n){"use strict";n.d(e,"a",(function(){return r}));var r="function"==typeof console.log?console.log.bind(console):function(){}},function(t,e){var n,r,i={},o={},u=(n=function(){return document.head||document.getElementsByTagName("head")[0]},function(){return void 0===r&&(r=n.apply(this,arguments)),r});function a(t){var e=document.createElement("style");return e.type="text/css",e.setAttribute("data-jwplayer-id",t),function(t){u().appendChild(t)}(e),e}function c(t,e){var n,r,i,u=o[t];u||(u=o[t]={element:a(t),counter:0});var c=u.counter++;return n=u.element,i=function(){f(n,c,"")},(r=function(t){f(n,c,t)})(e.css),function(t){if(t){if(t.css===e.css&&t.media===e.media)return;r((e=t).css)}else i()}}t.exports={style:function(t,e){!function(t,e){for(var n=0;nk*k&&(N(t,i.u,e),t.dragged=!0,N(t,i.s,e))}n||"touchmove"!==e.type||D(e)},s=function(n){if(clearTimeout(h),t.el)if(I(t),L(t,y),t.dragged)t.dragged=!1,N(t,i.t,n);else if(-1===n.type.indexOf("cancel")&&e.contains(n.target)){if(Object(u.a)()-t.lastStart>C)return;var r="pointerup"===n.type||"pointercancel"===n.type,o="mouseup"===n.type||r&&"mouse"===n.pointerType;!function(t,e,n){if(t.enableDoubleTap)if(Object(u.a)()-t.lastClick4&&void 0!==arguments[4]?arguments[4]:O,o=t.handlers[e],u=t.options[e];if(o||(o=t.handlers[e]={},u=t.options[e]={}),o[n])throw new Error("".concat(e," ").concat(n," already registered"));o[n]=r,u[n]=i;var a=t.el;(e===y?_(a):a).addEventListener(n,r,i)}function L(t,e){var n=t.el,r=t.handlers,i=t.options,o=e===y?_(n):n,u=r[e],a=i[e];u&&(Object.keys(u).forEach((function(t){var e=a[t];"boolean"==typeof e?o.removeEventListener(t,u[t],e):o.removeEventListener(t,u[t])})),r[e]=null,i[e]=null)}function I(t){var e=t.el;null!==t.pointerId&&(e.releasePointerCapture(t.pointerId),t.pointerId=null)}function M(t,e,n){var r=t.el,i=n.target;t.trigger(e,{type:e,sourceEvent:n,currentTarget:r,target:i})}function N(t,e,n){var r=function(t,e,n){var r,i=e.target,o=e.touches,u=e.changedTouches,a=e.pointerType;o||u?(r=o&&o.length?o[0]:u[0],a=a||"touch"):(r=e,a=a||"mouse");var c=r,s=c.pageX,l=c.pageY;return{type:t,pointerType:a,pageX:s,pageY:l,sourceEvent:e,currentTarget:n,target:i}}(e,n,t.el);t.trigger(e,r)}function R(t){return 0===t.type.indexOf("touch")?(t.originalEvent||t).changedTouches[0]:t}function D(t){t.preventDefault&&t.preventDefault()}},function(t,e,n){"use strict";n.d(e,"b",(function(){return r})),n.d(e,"a",(function(){return i}));var r={audioMode:!1,flashBlocked:!1,item:0,itemMeta:{},playbackRate:1,playRejected:!1,state:n(3).mb,itemReady:!1,controlsEnabled:!1},i={position:0,duration:0,buffer:0,currentTime:0}},function(t,e,n){"use strict";n.d(e,"b",(function(){return r})),n.d(e,"a",(function(){return i}));var r=window.requestAnimationFrame||function(t){return setTimeout(t,17)},i=window.cancelAnimationFrame||clearTimeout},function(t,e,n){"use strict";n.d(e,"a",(function(){return r}));var r=function(t,e,n){return Math.max(Math.min(t,n),e)}},function(t,e,n){"use strict";function r(t,e,n){var r=[],i={};function o(){for(;r.length>0;){var e=r.shift(),n=e.command,o=e.args;(i[n]||t[n]).apply(t,o)}}e.forEach((function(e){var u=t[e];i[e]=u,t[e]=function(){var t=Array.prototype.slice.call(arguments,0);n()?r.push({command:e,args:t}):(o(),u&&u.apply(this,t))}})),Object.defineProperty(this,"queue",{enumerable:!0,get:function(){return r}}),this.flush=o,this.empty=function(){r.length=0},this.off=function(){e.forEach((function(e){var n=i[e];n&&(t[e]=n,delete i[e])}))},this.destroy=function(){this.off(),this.empty()}}n.d(e,"a",(function(){return r}))},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function i(t,e){for(var n=0;n=.25&&t<=4})).map((function(t){return Math.round(100*t)/100}))).indexOf(1)<0&&b.push(1),b.sort(),h.playbackRateControls=!0,h.playbackRates=b}(!h.playbackRateControls||h.playbackRates.indexOf(h.defaultPlaybackRate)<0)&&(h.defaultPlaybackRate=1),h.playbackRate=h.defaultPlaybackRate,h.aspectratio||delete h.aspectratio;var m=h.playlist;if(m)Array.isArray(m.playlist)&&(h.feedData=m,h.playlist=m.playlist);else{var y=Object(r.y)(h,["title","description","type","mediaid","image","images","file","sources","tracks","preload","duration"]);h.playlist=[y]}h.qualityLabels=h.qualityLabels||h.hlslabels,delete h.duration;var w=h.liveTimeout;null!==w&&(Object(r.u)(w)?0!==w&&(w=Math.max(30,w)):w=null,h.liveTimeout=w);var j,O,k,x=parseFloat(h.bandwidthEstimate),C=parseFloat(h.bitrateSelection);return h.bandwidthEstimate=Object(r.u)(x)?x:(j=h.defaultBandwidthEstimate,O=parseFloat(j),Object(r.u)(O)?Math.max(O,1):f.bandwidthEstimate),h.bitrateSelection=Object(r.u)(C)?C:f.bitrateSelection,h.liveSyncDuration=(k=h.liveSyncDuration)?k<5?5:k>30?30:k:25,h.backgroundLoading=Object(r.n)(h.backgroundLoading)?h.backgroundLoading:c.Features.backgroundLoading,h},p=n(16),h=n(27),v=n(3),g=n(51),b=n(26),m=n(37),y=n(1);function w(t,e,n){var r=t.attributes;r.playlist=Object(b.a)(e),r.feedData=n}function j(t){return function(t){var e=t.get("playlist");return new Promise((function(n,r){if("string"!=typeof e){var i=t.get("feedData")||{};return w(t,e,i),n()}var o=new g.a;o.on(v.eb,(function(e){var r=e.playlist;delete e.playlist,w(t,r,e),n()})),o.on(v.w,(function(e){w(t,[],{}),r(Object(y.u)(e,y.p))})),o.load(e)}))}(t).then((function(){if(!x(t)){var e=Object(b.b)(t.get("playlist"),t);t.attributes.playlist=e;try{Object(b.e)(e)}catch(t){throw t.code+=y.p,t}var n=t.getProviders(),r=n.choose(e[0].sources[0]),i=r.provider,o=r.name;return"function"==typeof i?i:p.a.html5&&"html5"===o?p.a.html5:n.load(o).catch((function(t){throw Object(y.u)(t,y.q)}))}}))}function O(t){var e=t.get("skin")?t.get("skin").url:void 0;if("string"==typeof e&&!function(t){for(var e=document.styleSheets,n=0,r=e.length;n0&&(n=t(l,n));break;case"title":n.title=Object(o.d)(l);break;case"description":n.description=Object(o.d)(l);break;case"guid":n.mediaid=Object(o.d)(l);break;case"thumbnail":n.image||(n.image=Object(u.j)(l,"url"));break;case"group":t(l,n);break;case"subtitle":var p={};p.file=Object(u.j)(l,"url"),p.kind="captions",Object(u.j)(l,"lang").length>0&&(p.label=(r=Object(u.j)(l,"lang"),i=void 0,(i={zh:"Chinese",nl:"Dutch",en:"English",fr:"French",de:"German",it:"Italian",ja:"Japanese",pt:"Portuguese",ru:"Russian",es:"Spanish"})[r]?i[r]:r)),c.push(p)}}}n.hasOwnProperty("tracks")||(n.tracks=[]);for(var h=0;h0&&(r[f][n]="true"===r[f][n],r[f].label.length||delete r[f].label,e.sources.push(r[f]))}if(i.length){e.tracks=[];for(var d=0;d0&&(i[d][n]="true"===i[d][n],i[d].kind=i[d].kind.length?i[d].kind:"captions",i[d].label.length||delete i[d].label,e.tracks.push(i[d]))}return e},f=n(25);function d(t){for(var e={},n=0;n=4.4):null}},function(t,e,n){"use strict";var r=n(3),i=function(){},o=function(){return!1},u={name:"default"},a={supports:o,play:i,pause:i,preload:i,load:i,stop:i,volume:i,mute:i,seek:i,resize:i,remove:i,destroy:i,setVisibility:i,setFullscreen:i,getFullscreen:o,supportsFullscreen:o,getContainer:i,setContainer:i,getName:function(){return u},getQualityLevels:i,getCurrentQuality:i,setCurrentQuality:i,getAudioTracks:i,getCurrentAudioTrack:i,setCurrentAudioTrack:i,getSeekRange:function(){return{start:0,end:this.getDuration()}},setPlaybackRate:i,getPlaybackRate:function(){return 1},getBandwidthEstimate:function(){return null},getLiveLatency:function(){return null},setControls:i,attachMedia:i,detachMedia:i,init:i,setState:function(t){this.state=t,this.trigger(r.bb,{newstate:t})},sendMediaType:function(t){var e=t[0],n=e.type,i=e.mimeType,o="aac"===n||"mp3"===n||"mpeg"===n||i&&0===i.indexOf("audio/");this.trigger(r.T,{mediaType:o?"audio":"video"})}};e.a=a},function(t,e,n){"use strict";var r,i=n(49),o=n(8),u=n(5),a=[],c=[],s=[],l={},f="screen"in window&&"orientation"in window.screen,d=o.OS.android&&o.Browser.chrome,p=!1;function h(t,e){for(var n=e.length;n--;){var r=e[n];if(t.target===r.getContainer()){r.setIntersection(t);break}}}function v(){a.forEach((function(t){var e=t.model;if(!(e.get("audioMode")||!e.get("controls")||e.get("visibility")<.75)){var n=e.get("state"),r=Object(u.f)();!r&&"paused"===n&&t.api.getFullscreen()?t.api.setFullscreen(!1):"playing"===n&&t.api.setFullscreen(r)}}))}function g(){a.forEach((function(t){t.model.set("activeTab",Object(i.a)())}))}function b(t,e){var n=e.indexOf(t);-1!==n&&e.splice(n,1)}function m(t){s.forEach((function(e){e(t)}))}document.addEventListener("visibilitychange",g),document.addEventListener("webkitvisibilitychange",g),d&&f&&window.screen.orientation.addEventListener("change",v),window.addEventListener("beforeunload",(function(){document.removeEventListener("visibilitychange",g),document.removeEventListener("webkitvisibilitychange",g),window.removeEventListener("scroll",m),d&&f&&window.screen.orientation.removeEventListener("change",v)})),e.a={add:function(t){a.push(t)},remove:function(t){b(t,a)},addScrollHandler:function(t){p||(p=!0,window.addEventListener("scroll",m)),s.push(t)},removeScrollHandler:function(t){var e=s.indexOf(t);-1!==e&&s.splice(e,1)},addWidget:function(t){c.push(t)},removeWidget:function(t){b(t,c)},size:function(){return a.length},observe:function(t){var e;e=window.IntersectionObserver,r||(r=new e((function(t){if(t&&t.length)for(var e=t.length;e--;){var n=t[e];h(n,a),h(n,c)}}),{threshold:[0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1]})),l[t.id]||(l[t.id]=!0,r.observe(t))},unobserve:function(t){r&&l[t.id]&&(delete l[t.id],r.unobserve(t))}}},function(t,e,n){"use strict";n.d(e,"a",(function(){return f}));var r=n(0),i=n(42),o=n(5),u=n(10);function a(t,e){for(var n=0;n
    '),d=f.firstChild,p=d.firstChild,h=d.nextSibling;Object(u.d)([d,h],Object(r.g)({overflow:"auto"},a,s)),Object(u.d)(f,Object(r.g)({},a,s)),this.expandElement=d,this.expandChild=p,this.contractElement=h,this.hiddenElement=f,this.element=e,this.view=n,this.model=i,this.width=0,this.resized=!1,e.firstChild?e.insertBefore(f,e.firstChild):e.appendChild(f),e.addEventListener("scroll",l,!0),c.push(this),l()}var e,n,i;return e=t,(n=[{key:"destroy",value:function(){if(this.view){var t=c.indexOf(this);-1!==t&&c.splice(t,1),this.element.removeEventListener("scroll",l,!0),this.element.removeChild(this.hiddenElement),this.view=this.model=null}}}])&&a(e.prototype,n),i&&a(e,i),t}()},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}n.r(e);var i=setTimeout;function o(){}function u(t){if(!(this instanceof u))throw new TypeError("Promises must be constructed via new");if("function"!=typeof t)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],d(t,this)}function a(t,e){for(;3===t._state;)t=t._value;0!==t._state?(t._handled=!0,u._immediateFn((function(){var n=1===t._state?e.onFulfilled:e.onRejected;if(null!==n){var r;try{r=n(t._value)}catch(t){return void s(e.promise,t)}c(e.promise,r)}else(1===t._state?c:s)(e.promise,t._value)}))):t._deferreds.push(e)}function c(t,e){try{if(e===t)throw new TypeError("A promise cannot be resolved with itself.");if(e&&("object"===r(e)||"function"==typeof e)){var n=e.then;if(e instanceof u)return t._state=3,t._value=e,void l(t);if("function"==typeof n)return void d((i=n,o=e,function(){i.apply(o,arguments)}),t)}t._state=1,t._value=e,l(t)}catch(e){s(t,e)}var i,o}function s(t,e){t._state=2,t._value=e,l(t)}function l(t){2===t._state&&0===t._deferreds.length&&u._immediateFn((function(){t._handled||u._unhandledRejectionFn(t._value)}));for(var e=0,n=t._deferreds.length;e2&&void 0!==arguments[2]?arguments[2]:[];if(O.a.debug)return t.apply(e||this,n);try{return t.apply(e||this,n)}catch(e){return new _(t.name,e)}},Error:_,Timer:P.a,log:R.a,genId:D.b,between:N.a,foreach:function(t,e){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&e(n,t[n])},flashVersion:F.a,isIframe:F.m,indexOf:j.l,trim:A.i,pad:A.e,extension:A.a,hms:A.b,seconds:A.g,prefix:A.f,suffix:A.h,noop:function(){}}),q=0;function z(t,e){var n=new x.a(e);return n.on(C.gb,(function(e){t._qoe.tick("ready"),e.setupTime=t._qoe.between("setup","ready")})),n.on("all",(function(e,n){t.trigger(e,n)})),n}function V(t,e){var n=t.plugins;Object.keys(n).forEach((function(t){delete n[t]})),e.get("setupConfig")&&t.trigger("remove"),t.off(),e.playerDestroy(),e.getContainer().removeAttribute("data-jwplayer-id")}function Q(t){var e=++q,n=t.id||"player-".concat(e),r=new P.a,i={},o=z(this,t);r.tick("init"),t.setAttribute("data-jwplayer-id",n),Object.defineProperties(this,{id:{enumerable:!0,get:function(){return n}},uniqueId:{enumerable:!0,get:function(){return e}},plugins:{enumerable:!0,get:function(){return i}},_qoe:{enumerable:!0,get:function(){return r}},version:{enumerable:!0,get:function(){return w.a}},Events:{enumerable:!0,get:function(){return S.a}},utils:{enumerable:!0,get:function(){return B}},_:{enumerable:!0,get:function(){return j.c}}}),Object(j.g)(this,{_events:{},setup:function(e){return r.clear("ready"),r.tick("setup"),V(this,o),(o=z(this,t)).init(e,this),this.on(e.events,null,this)},remove:function(){return function(t){for(var e=v.a.length;e--;)if(v.a[e].uniqueId===t.uniqueId){v.a.splice(e,1);break}}(this),V(this,o),this},qoe:function(){var t=o.getItemQoe();return{setupTime:this._qoe.between("setup","ready"),firstFrame:t.getFirstFrame?t.getFirstFrame():null,player:this._qoe.dump(),item:t.dump()}},addCues:function(t){return Array.isArray(t)&&o.addCues(t),this},getAudioTracks:function(){return o.getAudioTracks()},getBuffer:function(){return o.get("buffer")},getCaptions:function(){return o.get("captions")},getCaptionsList:function(){return o.getCaptionsList()},getConfig:function(){return o.getConfig()},getContainer:function(){return o.getContainer()},getControls:function(){return o.get("controls")},getCues:function(){return o.get("cues")},getCurrentAudioTrack:function(){return o.getCurrentAudioTrack()},getCurrentCaptions:function(){return o.getCurrentCaptions()},getCurrentQuality:function(){return o.getCurrentQuality()},getCurrentTime:function(){return o.get("currentTime")},getDuration:function(){return o.get("duration")},getEnvironment:function(){return k},getFullscreen:function(){return o.get("fullscreen")},getHeight:function(){return o.getHeight()},getItemMeta:function(){return o.get("itemMeta")||{}},getMute:function(){return o.getMute()},getPlaybackRate:function(){return o.get("playbackRate")},getPlaylist:function(){return o.get("playlist")},getPlaylistIndex:function(){return o.get("item")},getPlaylistItem:function(t){if(!B.exists(t))return o.get("playlistItem");var e=this.getPlaylist();return e?e[t]:null},getPosition:function(){return o.get("position")},getProvider:function(){return o.getProvider()},getQualityLevels:function(){return o.getQualityLevels()},getSafeRegion:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return o.getSafeRegion(t)},getState:function(){return o.getState()},getStretching:function(){return o.get("stretching")},getViewable:function(){return o.get("viewable")},getVisualQuality:function(){return o.getVisualQuality()},getVolume:function(){return o.get("volume")},getWidth:function(){return o.getWidth()},setCaptions:function(t){return o.setCaptions(t),this},setConfig:function(t){return o.setConfig(t),this},setControls:function(t){return o.setControls(t),this},setCurrentAudioTrack:function(t){o.setCurrentAudioTrack(t)},setCurrentCaptions:function(t){o.setCurrentCaptions(t)},setCurrentQuality:function(t){o.setCurrentQuality(t)},setFullscreen:function(t){return o.setFullscreen(t),this},setMute:function(t){return o.setMute(t),this},setPlaybackRate:function(t){return o.setPlaybackRate(t),this},setPlaylistItem:function(t,e){return o.setPlaylistItem(t,e),this},setCues:function(t){return Array.isArray(t)&&o.setCues(t),this},setVolume:function(t){return o.setVolume(t),this},load:function(t,e){return o.load(t,e),this},play:function(t){return o.play(t),this},pause:function(t){return o.pause(t),this},playToggle:function(t){switch(this.getState()){case C.pb:case C.jb:return this.pause(t);default:return this.play(t)}},seek:function(t,e){return o.seek(t,e),this},playlistItem:function(t,e){return o.playlistItem(t,e),this},playlistNext:function(t){return o.playlistNext(t),this},playlistPrev:function(t){return o.playlistPrev(t),this},next:function(t){return o.next(t),this},castToggle:function(){return o.castToggle(),this},createInstream:function(){return o.createInstream()},stop:function(){return o.stop(),this},resize:function(t,e){return o.resize(t,e),this},addButton:function(t,e,n,r,i){return o.addButton(t,e,n,r,i),this},removeButton:function(t){return o.removeButton(t),this},attachMedia:function(){return o.attachMedia(),this},detachMedia:function(){return o.detachMedia(),this},isBeforeComplete:function(){return o.isBeforeComplete()},isBeforePlay:function(){return o.isBeforePlay()}})}Object(j.g)(Q.prototype,{on:function(t,e,n){return S.c.call(this,t,e,n)},once:function(t,e,n){return S.d.call(this,t,e,n)},off:function(t,e,n){return S.b.call(this,t,e,n)},trigger:function(t,e){return(e=j.c.isObject(e)?Object(j.g)({},e):{}).type=t,O.a.debug?S.e.call(this,t,e):S.f.call(this,t,e)},getPlugin:function(t){return this.plugins[t]},addPlugin:function(t,e){this.plugins[t]=e,this.on("ready",e.addToPlayer),e.resize&&this.on("resize",e.resizeHandler)},registerPlugin:function(t,e,n){Object(y.b)(t,e,n)},getAdBlock:function(){return!1},playAd:function(t){},pauseAd:function(t){},skipAd:function(){}}),n.d(e,"assignLibraryProperties",(function(){return H})),n.p=Object(h.loadFrom)();var W=function(t){var e,n;if(t?"string"==typeof t?(e=X(t))||(n=document.getElementById(t)):"number"==typeof t?e=v.a[t]:t.nodeType&&(e=X((n=t).id||n.getAttribute("data-jwplayer-id"))):e=v.a[0],e)return e;if(n){var r=new Q(n);return v.a.push(r),r}return{registerPlugin:y.b}};function X(t){for(var e=0;e0}});else{var n=[];i.prototype.THROTTLE_TIMEOUT=100,i.prototype.POLL_INTERVAL=null,i.prototype.USE_MUTATION_OBSERVER=!0,i.prototype.observe=function(t){if(!this._observationTargets.some((function(e){return e.element==t}))){if(!t||1!=t.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:t,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},i.prototype.unobserve=function(t){this._observationTargets=this._observationTargets.filter((function(e){return e.element!=t})),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},i.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},i.prototype.takeRecords=function(){var t=this._queuedEntries.slice();return this._queuedEntries=[],t},i.prototype._initThresholds=function(t){var e=t||[0];return Array.isArray(e)||(e=[e]),e.sort().filter((function(t,e,n){if("number"!=typeof t||isNaN(t)||t<0||t>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return t!==n[e-1]}))},i.prototype._parseRootMargin=function(t){var e=(t||"0px").split(/\s+/).map((function(t){var e=/^(-?\d*\.?\d+)(px|%)$/.exec(t);if(!e)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(e[1]),unit:e[2]}}));return e[1]=e[1]||e[0],e[2]=e[2]||e[0],e[3]=e[3]||e[1],e},i.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(r(t,"resize",this._checkForIntersections,!0),r(e,"scroll",this._checkForIntersections,!0),this.USE_MUTATION_OBSERVER&&"MutationObserver"in t&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(e,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},i.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,s(t,"resize",this._checkForIntersections,!0),s(e,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},i.prototype._checkForIntersections=function(){var e=this._rootIsInDom(),n=e?this._getRootRect():{top:0,bottom:0,left:0,right:0,width:0,height:0};this._observationTargets.forEach((function(i){var r=i.element,s=h(r),c=this._rootContainsTarget(r),a=i.entry,u=e&&c&&this._computeTargetAndRootIntersection(r,n),p=i.entry=new o({time:t.performance&&performance.now&&performance.now(),target:r,boundingClientRect:s,rootBounds:n,intersectionRect:u});a?e&&c?this._hasCrossedThreshold(a,p)&&this._queuedEntries.push(p):a&&a.isIntersecting&&this._queuedEntries.push(p):this._queuedEntries.push(p)}),this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},i.prototype._computeTargetAndRootIntersection=function(n,o){if("none"!=t.getComputedStyle(n).display){for(var i,r,s,c,u,p,l,d,f=h(n),g=a(n),_=!1;!_;){var v=null,m=1==g.nodeType?t.getComputedStyle(g):{};if("none"==m.display)return;if(g==this.root||g==e?(_=!0,v=o):g!=e.body&&g!=e.documentElement&&"visible"!=m.overflow&&(v=h(g)),v&&(i=v,r=f,s=void 0,c=void 0,u=void 0,p=void 0,l=void 0,d=void 0,s=Math.max(i.top,r.top),c=Math.min(i.bottom,r.bottom),u=Math.max(i.left,r.left),p=Math.min(i.right,r.right),d=c-s,!(f=(l=p-u)>=0&&d>=0&&{top:s,bottom:c,left:u,right:p,width:l,height:d})))break;g=a(g)}return f}},i.prototype._getRootRect=function(){var t;if(this.root)t=h(this.root);else{var n=e.documentElement,o=e.body;t={top:0,left:0,right:n.clientWidth||o.clientWidth,width:n.clientWidth||o.clientWidth,bottom:n.clientHeight||o.clientHeight,height:n.clientHeight||o.clientHeight}}return this._expandRectByRootMargin(t)},i.prototype._expandRectByRootMargin=function(t){var e=this._rootMarginValues.map((function(e,n){return"px"==e.unit?e.value:e.value*(n%2?t.width:t.height)/100})),n={top:t.top-e[0],right:t.right+e[1],bottom:t.bottom+e[2],left:t.left-e[3]};return n.width=n.right-n.left,n.height=n.bottom-n.top,n},i.prototype._hasCrossedThreshold=function(t,e){var n=t&&t.isIntersecting?t.intersectionRatio||0:-1,o=e.isIntersecting?e.intersectionRatio||0:-1;if(n!==o)for(var i=0;i59?e(i[1],i[2],0,i[4]):e(0,i[1],i[2],i[4]):null}i.r(e),r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r.Errors={BadSignature:{code:0,message:"Malformed WebVTT signature."},BadTimeStamp:{code:1,message:"Malformed time stamp."}};var o={"&":"&","<":"<",">":">","‎":"‎","‏":"‏"," ":" "},a={c:"span",i:"i",b:"b",u:"u",ruby:"ruby",rt:"rt",v:"span",lang:"span"},s={v:"title",lang:"lang"},l={rt:"ruby"};function h(t,e){function i(){if(!e)return null;var t,i=e.match(/^([^<]*)(<[^>]+>?)?/);return t=i[1]?i[1]:i[2],e=e.substr(t.length),t}function r(t){return o[t]}function h(t){for(var e;e=t.match(/&(amp|lt|gt|lrm|rlm|nbsp);/);)t=t.replace(e[0],r);return t}function c(t,e){return!l[e.localName]||l[e.localName]===t.localName}function p(e,i){var r=a[e];if(!r)return null;var n=t.document.createElement(r),o=s[e];return o&&i&&(n[o]=i.trim()),n}for(var f,u=t.document.createElement("div"),d=u,g=[];null!==(f=i());)if("<"!==f[0])d.appendChild(t.document.createTextNode(h(f)));else{if("/"===f[1]){g.length&&g[g.length-1]===f.substr(2).replace(">","")&&(g.pop(),d=d.parentNode);continue}var m=n(f.substr(1,f.length-2)),v=void 0;if(m){v=t.document.createProcessingInstruction("timestamp",m),d.appendChild(v);continue}var y=f.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/);if(!y)continue;if(!(v=p(y[1],y[3])))continue;if(!c(d,v))continue;y[2]&&(v.className=y[2].substr(1).replace("."," ")),g.push(y[1]),d.appendChild(v),d=v}return u}var c=[[1470,1470],[1472,1472],[1475,1475],[1478,1478],[1488,1514],[1520,1524],[1544,1544],[1547,1547],[1549,1549],[1563,1563],[1566,1610],[1645,1647],[1649,1749],[1765,1766],[1774,1775],[1786,1805],[1807,1808],[1810,1839],[1869,1957],[1969,1969],[1984,2026],[2036,2037],[2042,2042],[2048,2069],[2074,2074],[2084,2084],[2088,2088],[2096,2110],[2112,2136],[2142,2142],[2208,2208],[2210,2220],[8207,8207],[64285,64285],[64287,64296],[64298,64310],[64312,64316],[64318,64318],[64320,64321],[64323,64324],[64326,64449],[64467,64829],[64848,64911],[64914,64967],[65008,65020],[65136,65140],[65142,65276],[67584,67589],[67592,67592],[67594,67637],[67639,67640],[67644,67644],[67647,67669],[67671,67679],[67840,67867],[67872,67897],[67903,67903],[67968,68023],[68030,68031],[68096,68096],[68112,68115],[68117,68119],[68121,68147],[68160,68167],[68176,68184],[68192,68223],[68352,68405],[68416,68437],[68440,68466],[68472,68479],[68608,68680],[126464,126467],[126469,126495],[126497,126498],[126500,126500],[126503,126503],[126505,126514],[126516,126519],[126521,126521],[126523,126523],[126530,126530],[126535,126535],[126537,126537],[126539,126539],[126541,126543],[126545,126546],[126548,126548],[126551,126551],[126553,126553],[126555,126555],[126557,126557],[126559,126559],[126561,126562],[126564,126564],[126567,126570],[126572,126578],[126580,126583],[126585,126588],[126590,126590],[126592,126601],[126603,126619],[126625,126627],[126629,126633],[126635,126651],[1114109,1114109]];function p(t){for(var e=0;e=i[0]&&t<=i[1])return!0}return!1}function f(t,e){for(var i=e.childNodes.length-1;i>=0;i--)t.push(e.childNodes[i])}function u(t){if(!t||!t.length)return null;var e=t.pop(),i=e.textContent||e.innerText;if(i){var r=i.match(/^.*(\n|\r)/);return r?(t.length=0,r[0]):i}return"ruby"===e.tagName?u(t):e.childNodes?(f(t,e),u(t)):void 0}function d(t){if(!t||!t.childNodes)return"ltr";var e,i=[];for(f(i,t);e=u(i);)for(var r=0;r=0&&t.line<=100))return t.line;if(!t.track||!t.track.textTrackList||!t.track.textTrackList.mediaElement)return-1;for(var e=t.track,i=e.textTrackList,r=0,n=0;nu&&(f=f<0?-1:1,f*=Math.ceil(u/c)*c),s<0)f+=a.vertical?i.width:i.height,f-=n*c,l=l.slice().reverse();f-=n,o.move(d,f)}else{var g=o.lineHeight/i.height*100;switch(a.lineAlign){case"middle":s-=g/2;break;case"end":s-=g}switch(a.vertical){case"":e.applyStyles({top:e.formatStyle(s,"%")});break;case"rl":e.applyStyles({left:e.formatStyle(s,"%")});break;case"lr":e.applyStyles({paddingRight:e.formatStyle(s,"%")})}l=["+y","-x","+x","-y"],o=new v(e)}var m=function t(e,n){for(var o,a,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,l=new v(e),h=0,c=0;ct.left&&this.topt.top},v.prototype.overlapsAny=function(t){for(var e=0;e=t.top&&this.bottom<=t.bottom&&this.left>=t.left&&this.right<=t.right},v.prototype.overlapsOppositeAxis=function(t,e){switch(e){case"+x":return this.leftt.right;case"+y":return this.topt.bottom}},v.prototype.intersectPercentage=function(t){return Math.max(0,Math.min(this.right,t.right)-Math.max(this.left,t.left))*Math.max(0,Math.min(this.bottom,t.bottom)-Math.max(this.top,t.top))/(this.height*this.width)},v.prototype.toCSSCompatValues=function(t){return{top:this.top-t.top,bottom:t.bottom-this.bottom,left:this.left-t.left,paddingRight:t.right-this.right,height:this.height,width:this.width}},v.getSimpleBoxPosition=function(t){var e=t.div?t.div.offsetHeight:t.tagName?t.offsetHeight:0,i=t.div?t.div.offsetWidth:t.tagName?t.offsetWidth:0,r=t.div?t.div.offsetTop:t.tagName?t.offsetTop:0,n=(t=t.div?t.div.getBoundingClientRect():t.tagName?t.getBoundingClientRect():t).height||e;return{left:t.left,right:t.right,top:t.top||r,height:n,bottom:t.bottom||r+n,width:t.width||i}},b.StringDecoder=function(){return{decode:function(t){if(!t)return"";if("string"!=typeof t)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(t))}}},b.convertCueToDOMTree=function(t,e){return t&&e?h(t,e):null};b.processCues=function(t,e,i,r){if(!t||!e||!i)return null;for(;i.firstChild;)i.removeChild(i.firstChild);if(!e.length)return null;var n=t.document.createElement("div");if(n.className="jw-text-track-container jw-reset",n.style.position="absolute",n.style.left="0",n.style.right="0",n.style.top="0",n.style.bottom="0",n.style.margin="1.5%",i.appendChild(n),function(t){for(var e=0;e=0&&(r.metadata.mpegts=n+t)}var a=this.getLiveLatency();null!==a&&(r.latency=a),(this.state===s.pb||this.seeking)&&this.trigger(s.S,r)}},click:function(e){this.trigger(s.n,e)},volumechange:function(){var e=this.video;this.trigger(s.V,{volume:Math.round(100*e.volume)}),this.trigger(s.M,{mute:e.muted})},seeked:function(){this.seeking&&(this.seeking=!1,this.trigger(s.R))},playing:function(){-1===this.stallTime&&this.setState(s.pb),this.trigger(s.fb)},pause:function(){this.state!==s.kb&&(this.video.ended||this.video.error||this.getVideoCurrentTime()!==this.getDuration()&&this.setState(s.ob))},progress:function(){var e=this.getDuration();if(!(e<=0||e===1/0)){var t=this.video.buffered;if(t&&0!==t.length){var i=Object(u.a)(t.end(t.length-1)/e,0,1);this.trigger(s.D,{bufferPercent:100*i,position:this.getCurrentTime(),duration:e,currentTime:this.getVideoCurrentTime(),seekRange:this.getSeekRange()})}}},ratechange:function(){this.trigger(s.P,{playbackRate:this.video.playbackRate})},ended:function(){this.videoHeight=0,this.streamBitrate=-1,this.state!==s.mb&&this.state!==s.kb&&this.trigger(s.F)},loadeddata:function(){this.renderNatively&&this.setTextTracks(this.video.textTracks)}},o=i(10);function d(e){return e&&e.length?e.end(e.length-1):0}var l={container:null,volume:function(e){this.video.volume=Math.min(Math.max(0,e/100),1)},mute:function(e){this.video.muted=!!e,this.video.muted||this.video.removeAttribute("muted")},resize:function(e,t,i){var r=this.video,a=r.videoWidth,s=r.videoHeight;if(e&&t&&a&&s){var u={objectFit:"",width:"",height:""};if("uniform"===i){var c=e/t,d=a/s,l=Math.abs(c-d);l<.09&&l>.0025&&(u.objectFit="fill",i="exactfit")}if(n.Browser.ie||n.OS.iOS&&n.OS.version.major<9||n.Browser.androidNative)if("uniform"!==i){u.objectFit="contain";var h=e/t,f=a/s,v=1,T=1;"none"===i?v=T=h>f?Math.ceil(100*s/t)/100:Math.ceil(100*a/e)/100:"fill"===i?v=T=h>f?h/f:f/h:"exactfit"===i&&(h>f?(v=h/f,T=1):(v=1,T=f/h)),Object(o.e)(r,"matrix(".concat(v.toFixed(2),", 0, 0, ").concat(T.toFixed(2),", 0, 0)"))}else u.top=u.left=u.margin="",Object(o.e)(r,"");Object(o.d)(r,u)}},getContainer:function(){return this.container},setContainer:function(e){this.container=e,this.video.parentNode!==e&&e.appendChild(this.video)},remove:function(){this.stop(),this.destroy();var e=this.container;e&&e===this.video.parentNode&&e.removeChild(this.video)},atEdgeOfLiveStream:function(){if(!this.isLive())return!1;return d(this.video.buffered)-this.video.currentTime<=2}},h={eventsOn_:function(){},eventsOff_:function(){},attachMedia:function(){this.eventsOn_()},detachMedia:function(){return this.eventsOff_()}},f=i(65),v=i(5),T=i(53),g=i(7),m=i(66),k=i(63),b={TIT2:"title",TT2:"title",WXXX:"url",TPE1:"artist",TP1:"artist",TALB:"album",TAL:"album"};function y(e,t){for(var i,r,n,a=e.length,s="",u=t||0;u>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:s+=String.fromCharCode(i);break;case 12:case 13:r=e[u++],s+=String.fromCharCode((31&i)<<6|63&r);break;case 14:r=e[u++],n=e[u++],s+=String.fromCharCode((15&i)<<12|(63&r)<<6|(63&n)<<0)}return s}function p(e){var t=function(e){for(var t="0x",i=0;i>1|(8323072&t)>>2|(2130706432&t)>>3}function x(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:[]).reduce((function(e,t){if(!("value"in t)&&"data"in t&&t.data instanceof ArrayBuffer){var i=new Uint8Array(t.data),r=i.length;t={value:{key:"",data:""}};for(var n=10;n<14&&n0){var o=y(i.subarray(a,a+=u),0);if("PRIV"===t.value.key){if("com.apple.streaming.transportStreamTimestamp"===o){var d=1&p(i.subarray(a,a+=4)),l=p(i.subarray(a,a+=4))+(d?4294967296:0);t.value.data=l}else t.value.data=y(i,a+1);t.value.info=o}else t.value.info=o,t.value.data=y(i,a+1)}else{var h=i[a];t.value.data=1===h||2===h?function(e,t){for(var i=e.length-1,r="",n=t||0;n=0&&n[a].startTime>t.startTime;a--)i.unshift(n[a]),e.removeCue(n[a]);try{e.addCue(t),i.forEach((function(t){return e.addCue(t)}))}catch(e){console.error(e)}e.mode=r}(t,r)}else try{t.addCue(i)}catch(e){console.error(e)}}function B(e,t){t&&t.length&&Object(r.f)(t,(function(t){if(!(n.Browser.ie&&e&&/^(native|subtitle|cc)/.test(t._id))){n.Browser.ie&&"disabled"===t.mode||(t.mode="disabled",t.mode="hidden");for(var i=t.cues.length;i--;)t.removeCue(t.cues[i]);t.embedded||(t.mode="disabled"),t.inuse=!1}}))}function E(e){return"subtitles"===e||"captions"===e}function S(e){var t,i=Object(k.b)(e,this._unknownCount),n=i.label;if(this._unknownCount=i.unknownCount,this.renderNatively||"metadata"===e.kind){var a=this.video.textTracks;(t=Object(r.j)(a,{label:n}))||(t=this.video.addTextTrack(e.kind,n,e.language||"")),t.default=e.default,t.mode="disabled",t.inuse=!0}else(t=e).data=t.data||[];return t._id||(t._id=Object(k.a)(e,this._textTracks.length)),t}function L(e){this._textTracks.push(e),this._tracksById[e._id]=e}function I(){if(this._textTracks){var e=this._textTracks.filter((function(e){return e.embedded||"subs"===e.groupid}));this._initTextTracks(),e.forEach((function(e){this._tracksById[e._id]=e})),this._textTracks=e}}function N(e){this.triggerActiveCues(e.currentTarget.activeCues)}function R(e,t,i){var r=e.kind;this._cachedVTTCues[e._id]||(this._cachedVTTCues[e._id]={});var n,a=this._cachedVTTCues[e._id];switch(r){case"captions":case"subtitles":n=i||Math.floor(20*t.startTime);var s="_"+t.line,u=Math.floor(20*t.endTime),c=a[n+s]||a[n+1+s]||a[n-1+s];return!(c&&Math.abs(c-u)<=1)&&(a[n+s]=u,!0);case"metadata":var o=t.data?new Uint8Array(t.data).join(""):t.text;return!a[n=i||t.startTime+o]&&(a[n]=t.endTime,!0);default:return!1}}function M(e){if(e.length>this._textTracks.length)return!0;for(var t=0;t=0&&(T.retries=0);var e=T.getVideoCurrentTime();T.currentTime=e,B&&O!==e&&Z(e),c.timeupdate.call(T),ve(),n.Browser.ie&&Y()},resize:Y,ended:function(){j=-1,Te(),c.ended.call(T)},loadedmetadata:function(){var e=T.getDuration();M&&e===1/0&&(e=0);var t={metadataType:"media",duration:e,height:y.videoHeight,width:y.videoWidth,seekRange:T.getSeekRange()};T.trigger(s.K,t),Y()},durationchange:function(){M||c.progress.call(T)},loadeddata:function(){var e;!function(){if(y.getStartDate){var e=y.getStartDate(),t=e.getTime?e.getTime():NaN;if(t!==T.startDateTime&&!isNaN(t)){T.startDateTime=t;var i=e.toISOString(),r=T.getSeekRange(),n=r.start,a=r.end,u={metadataType:"program-date-time",programDateTime:i,start:n,end:a},c=T.createCue(n,a,JSON.stringify(u));T.addVTTCue({type:"metadata",cue:c}),delete u.metadataType,T.trigger(s.L,{metadataType:"program-date-time",metadata:u})}}}(),c.loadeddata.call(T),function(e){if(S=null,!e)return;if(e.length){for(var t=0;t0&&(t=e.map((function(e,t){return{label:e.label||t}}))),t}function ie(e){T.currentTime=-1,m=e.minDvrWindow,b=e.sources,j=function(e){var i=Math.max(0,j),r=t.qualityLabel;if(e)for(var n=0;n0&&(w=-1,T.seek(e)),e>0&&T.getVideoCurrentTime()!==e&&T.seek(e);var r=te(b);r&&T.trigger(s.I,{levels:r,currentQuality:j}),b.length&&"hls"!==b[0].type&&fe()}function ae(e){S=null,L=-1,p.reason||(p.reason="initial choice",p.level={}),_=!1;var t=document.createElement("source");t.src=e.file,y.src!==t.src&&(y.src=e.file)}function se(){y&&(T.disableTextTrack(),y.removeAttribute("preload"),y.removeAttribute("src"),Object(v.h)(y),Object(o.d)(y,{objectFit:""}),j=-1,!n.Browser.msie&&"load"in y&&y.load())}function ue(){var e=1/0;return["buffered","seekable"].forEach((function(t){for(var i=y[t],n=i?i.length:0;n--;){var a=Math.min(e,i.start(n));Object(r.o)(a)&&(e=a)}})),e}function ce(){var e=0;return["buffered","seekable"].forEach((function(t){for(var i=y[t],n=i?i.length:0;n--;){var a=Math.max(e,i.end(n));Object(r.o)(a)&&(e=a)}})),e}function oe(){for(var e=-1,t=0;t-1&&e1)&&function(e){z=e.end,G=Math.min(0,T.getVideoCurrentTime()-z),$=Object(D.a)()}(t),Object(f.a)(t.end-t.start,m))return G}return e}(T.getVideoCurrentTime())},T.getDuration=function(){if(t.getDurationHook)return t.getDurationHook();var e=y.duration;if(M&&e===1/0&&0===T.getVideoCurrentTime()||isNaN(e))return 0;var i=ce();if(y.duration===1/0&&i){var r=i-ue();Object(f.a)(r,m)&&(e=-r)}return e},T.getSeekRange=function(){var e={start:0,end:T.getDuration()};return y.seekable.length&&(e.end=ce(),e.start=ue()),e},T.getLiveLatency=function(){var e=null,t=ce();return T.isLive()&&t&&(e=t+(Object(D.a)()-$)/1e3-T.getVideoCurrentTime()),e},this.stop=function(){Te(),se(),this.clearTracks(),n.Browser.ie&&y.pause(),this.setState(s.mb)},this.destroy=function(){E=q,J(k,y),this.removeTracksListener(y.audioTracks,"change",oe),this.removeTracksListener(y.textTracks,"change",T.textTrackChangeHandler),this.off()},this.init=function(e){T.retries=0,T.maxRetries=e.adType?0:3,ie(e);var t=b[j];(M=Object(a.a)(t))&&(T.supportsPlaybackRate=!1,k.waiting=q),T.eventsOn_(),b.length&&"hls"!==b[0].type&&this.sendMediaType(b),p.reason=""},this.preload=function(e){ie(e);var t=b[j],i=t.preload||"metadata";"none"!==i&&(y.setAttribute("preload",i),ae(t))},this.load=function(e){ie(e),ne(e.starttime),this.setupSideloadedTracks(e.tracks)},this.play=function(){return E(),re()},this.pause=function(){Te(),E=function(){if(y.paused&&T.getVideoCurrentTime()&&T.isLive()){var e=ce(),t=e-ue(),i=!Object(f.a)(t,m),n=e-T.getVideoCurrentTime();if(i&&e&&(n>15||n<0)){if(C=Math.max(e-10,e-t),!Object(r.o)(C))return;Z(T.getVideoCurrentTime()),y.currentTime=C}}},y.pause()},this.seek=function(e){if(t.seekHook)return t.seekHook(e,y);var i=T.getSeekRange(),r=e;if(e<0&&(r+=i.end),_||(_=!!ce()),_){w=0;try{if(T.seeking=!0,T.isLive()&&Object(f.a)(i.end-i.start,m))if(G=Math.min(0,r-z),e<0)r+=Math.min(12,(Object(D.a)()-$)/1e3);C=r,Z(T.getVideoCurrentTime()),y.currentTime=r}catch(e){T.seeking=!1,w=r}}else w=r,n.Browser.firefox&&y.paused&&re()},this.setVisibility=function(e){(e=!!e)||n.OS.android?Object(o.d)(T.container,{visibility:"visible",opacity:1}):Object(o.d)(T.container,{visibility:"",opacity:0})},this.setFullscreen=function(e){if(e=!!e){try{var t=y.webkitEnterFullscreen||y.webkitEnterFullScreen;t&&t.apply(y)}catch(e){return!1}return T.getFullScreen()}var i=y.webkitExitFullscreen||y.webkitExitFullScreen;return i&&i.apply(y),e},T.getFullScreen=function(){return B||!!y.webkitDisplayingFullscreen},this.setCurrentQuality=function(e){j!==e&&e>=0&&b&&b.length>e&&(j=e,p.reason="api",p.level={},this.trigger(s.J,{currentQuality:e,levels:te(b)}),t.qualityLabel=b[e].label,ne(T.getVideoCurrentTime()||0),re())},this.setPlaybackRate=function(e){y.playbackRate=y.defaultPlaybackRate=e},this.getPlaybackRate=function(){return y.playbackRate},this.getCurrentQuality=function(){return j},this.getQualityLevels=function(){return Array.isArray(b)?b.map((function(e){return function(e){return{bitrate:e.bitrate,label:e.label,width:e.width,height:e.height}}(e)})):[]},this.getName=function(){return{name:Q}},this.setCurrentAudioTrack=le,this.getAudioTracks=function(){return S||[]},this.getCurrentAudioTrack=function(){return L}}Object(r.g)(z.prototype,T.a),z.getName=function(){return{name:"html5"}};t.default=z;var K=220001},57:function(e,t,i){"use strict";i.d(t,"a",(function(){return n}));var r=i(2);function n(e){var t=[],i=(e=Object(r.i)(e)).split("\r\n\r\n");1===i.length&&(i=e.split("\n\n"));for(var n=0;n0&&(n=0),i.length>n+1&&i[n+1]){var a=i[n],s=a.indexOf(" --\x3e ");s>0&&(t.begin=Object(r.g)(a.substr(0,s)),t.end=Object(r.g)(a.substr(s+5)),t.text=i.slice(n+1).join("\r\n"))}return t}},63:function(e,t,i){"use strict";function r(e,t){var i=e.kind||"cc";return e.default||e.defaulttrack?"default":e._id||e.file||i+t}function n(e,t){var i=e.label||e.name||e.language;return i||(i="Unknown CC",(t+=1)>1&&(i+=" ["+t+"]")),{label:i,unknownCount:t}}i.d(t,"a",(function(){return r})),i.d(t,"b",(function(){return n}))},64:function(e,t,i){"use strict";function r(e){return new Promise((function(t,i){if(e.paused)return i(n("NotAllowedError",0,"play() failed."));var r=function(){e.removeEventListener("play",a),e.removeEventListener("playing",s),e.removeEventListener("pause",s),e.removeEventListener("abort",s),e.removeEventListener("error",s)},a=function(){e.addEventListener("playing",s),e.addEventListener("abort",s),e.addEventListener("error",s),e.addEventListener("pause",s)},s=function(e){if(r(),"playing"===e.type)t();else{var a='The play() request was interrupted by a "'.concat(e.type,'" event.');"error"===e.type?i(n("NotSupportedError",9,a)):i(n("AbortError",20,a))}};e.addEventListener("play",a)}))}function n(e,t,i){var r=new Error(i);return r.name=e,r.code=t,r}i.d(t,"a",(function(){return r}))},65:function(e,t,i){"use strict";function r(e,t){return e!==1/0&&Math.abs(e)>=Math.max(a(t),0)}function n(e,t){var i="VOD";return e===1/0?i="LIVE":e<0&&(i=r(e,a(t))?"DVR":"LIVE"),i}function a(e){return void 0===e?120:Math.max(e,0)}i.d(t,"a",(function(){return r})),i.d(t,"b",(function(){return n}))},66:function(e,t,i){"use strict";var r=i(67),n=i(16),a=i(22),s=i(4),u=i(57),c=i(2),o=i(1);function d(e){throw new o.n(null,e)}function l(e,t,r){e.xhr=Object(a.a)(e.file,(function(a){!function(e,t,r,a){var l,h,v=e.responseXML?e.responseXML.firstChild:null;if(v)for("xml"===Object(s.b)(v)&&(v=v.nextSibling);v.nodeType===v.COMMENT_NODE;)v=v.nextSibling;try{if(v&&"tt"===Object(s.b)(v))l=function(e){e||d(306007);var t=[],i=e.getElementsByTagName("p"),r=30,n=e.getElementsByTagName("tt");if(n&&n[0]){var a=parseFloat(n[0].getAttribute("ttp:frameRate"));isNaN(a)||(r=a)}i||d(306005),i.length||(i=e.getElementsByTagName("tt:p")).length||(i=e.getElementsByTagName("tts:p"));for(var s=0;s\s+<").replace(/(<\/?)tts?:/g,"$1").replace(//g,"\r\n");if(v){var T=u.getAttribute("begin"),g=u.getAttribute("dur"),m=u.getAttribute("end"),k={begin:Object(c.g)(T,r),text:v};m?k.end=Object(c.g)(m,r):g&&(k.end=k.begin+Object(c.g)(g,r)),t.push(k)}}return t.length||d(306005),t}(e.responseXML),h=f(l),delete t.xhr,r(h);else{var T=e.responseText;T.indexOf("WEBVTT")>=0?i.e(10).then(function(e){return i(97).default}.bind(null,i)).catch(Object(n.c)(301131)).then((function(e){var i=new e(window);h=[],i.oncue=function(e){h.push(e)},i.onflush=function(){delete t.xhr,r(h)},i.parse(T)})).catch((function(e){delete t.xhr,a(Object(o.v)(null,o.b,e))})):(l=Object(u.a)(T),h=f(l),delete t.xhr,r(h))}}catch(e){delete t.xhr,a(Object(o.v)(null,o.b,e))}}(a,e,t,r)}),(function(e,t,i,n){r(Object(o.u)(n,o.b))}))}function h(e){e&&e.forEach((function(e){var t=e.xhr;t&&(t.onload=null,t.onreadystatechange=null,t.onerror=null,"abort"in t&&t.abort()),delete e.xhr}))}function f(e){return e.map((function(e){return new r.a(e.begin,e.end,e.text)}))}i.d(t,"c",(function(){return l})),i.d(t,"a",(function(){return h})),i.d(t,"b",(function(){return f}))},67:function(e,t,i){"use strict";var r=window.VTTCue;function n(e){if("string"!=typeof e)return!1;return!!{start:!0,middle:!0,end:!0,left:!0,right:!0}[e.toLowerCase()]&&e.toLowerCase()}if(!r){(r=function(e,t,i){var r=this;r.hasBeenReset=!1;var a="",s=!1,u=e,c=t,o=i,d=null,l="",h=!0,f="auto",v="start",T="auto",g=100,m="middle";Object.defineProperty(r,"id",{enumerable:!0,get:function(){return a},set:function(e){a=""+e}}),Object.defineProperty(r,"pauseOnExit",{enumerable:!0,get:function(){return s},set:function(e){s=!!e}}),Object.defineProperty(r,"startTime",{enumerable:!0,get:function(){return u},set:function(e){if("number"!=typeof e)throw new TypeError("Start time must be set to a number.");u=e,this.hasBeenReset=!0}}),Object.defineProperty(r,"endTime",{enumerable:!0,get:function(){return c},set:function(e){if("number"!=typeof e)throw new TypeError("End time must be set to a number.");c=e,this.hasBeenReset=!0}}),Object.defineProperty(r,"text",{enumerable:!0,get:function(){return o},set:function(e){o=""+e,this.hasBeenReset=!0}}),Object.defineProperty(r,"region",{enumerable:!0,get:function(){return d},set:function(e){d=e,this.hasBeenReset=!0}}),Object.defineProperty(r,"vertical",{enumerable:!0,get:function(){return l},set:function(e){var t=function(e){return"string"==typeof e&&(!!{"":!0,lr:!0,rl:!0}[e.toLowerCase()]&&e.toLowerCase())}(e);if(!1===t)throw new SyntaxError("An invalid or illegal string was specified.");l=t,this.hasBeenReset=!0}}),Object.defineProperty(r,"snapToLines",{enumerable:!0,get:function(){return h},set:function(e){h=!!e,this.hasBeenReset=!0}}),Object.defineProperty(r,"line",{enumerable:!0,get:function(){return f},set:function(e){if("number"!=typeof e&&"auto"!==e)throw new SyntaxError("An invalid number or illegal string was specified.");f=e,this.hasBeenReset=!0}}),Object.defineProperty(r,"lineAlign",{enumerable:!0,get:function(){return v},set:function(e){var t=n(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");v=t,this.hasBeenReset=!0}}),Object.defineProperty(r,"position",{enumerable:!0,get:function(){return T},set:function(e){if(e<0||e>100)throw new Error("Position must be between 0 and 100.");T=e,this.hasBeenReset=!0}}),Object.defineProperty(r,"size",{enumerable:!0,get:function(){return g},set:function(e){if(e<0||e>100)throw new Error("Size must be between 0 and 100.");g=e,this.hasBeenReset=!0}}),Object.defineProperty(r,"align",{enumerable:!0,get:function(){return m},set:function(e){var t=n(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");m=t,this.hasBeenReset=!0}}),r.displayState=void 0}).prototype.getCueAsHTML=function(){return window.WebVTT.convertCueToDOMTree(window,this.text)}}t.a=r}}]); \ No newline at end of file diff --git a/ui/v2.5/public/jwplayer/vttparser.js b/ui/v2.5/public/jwplayer/vttparser.js new file mode 100644 index 000000000..571ab7065 --- /dev/null +++ b/ui/v2.5/public/jwplayer/vttparser.js @@ -0,0 +1,95 @@ +/*! +JW Player version 8.11.5 +Copyright (c) 2019, JW Player, All Rights Reserved +https://github.com/jwplayer/jwplayer/blob/v8.11.5/README.md + +This source code and its use and distribution is subject to the terms and conditions of the applicable license agreement. +https://www.jwplayer.com/tos/ + +This product includes portions of other software. For the full text of licenses, see below: + +JW Player Third Party Software Notices and/or Additional Terms and Conditions + +************************************************************************************************** +The following software is used under Apache License 2.0 +************************************************************************************************** + +vtt.js v0.13.0 +Copyright (c) 2019 Mozilla (http://mozilla.org) +https://github.com/mozilla/vtt.js/blob/v0.13.0/LICENSE + +* * * + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and +limitations under the License. + +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. + +************************************************************************************************** +The following software is used under MIT license +************************************************************************************************** + +Underscore.js v1.6.0 +Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative +https://github.com/jashkenas/underscore/blob/1.6.0/LICENSE + +Backbone backbone.events.js v1.1.2 +Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud +https://github.com/jashkenas/backbone/blob/1.1.2/LICENSE + +Promise Polyfill v7.1.1 +Copyright (c) 2014 Taylor Hakes and Forbes Lindesay +https://github.com/taylorhakes/promise-polyfill/blob/v7.1.1/LICENSE + +can-autoplay.js v3.0.0 +Copyright (c) 2017 video-dev +https://github.com/video-dev/can-autoplay/blob/v3.0.0/LICENSE + +* * * + +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. + +************************************************************************************************** +The following software is used under W3C license +************************************************************************************************** + +Intersection Observer v0.5.0 +Copyright (c) 2016 Google Inc. (http://google.com) +https://github.com/w3c/IntersectionObserver/blob/v0.5.0/LICENSE.md + +* * * + +W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. + +This work is being provided by the copyright holders under the following license. + +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. + +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. + +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." + +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders. +*/ +(window.webpackJsonpjwplayer=window.webpackJsonpjwplayer||[]).push([[10],{97:function(t,e,r){"use strict";r.r(e);var n=r(42),i=r(67),s=/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/,a=/^-?\d+$/,u=/\r\n|\n/,o=/^NOTE($|[ \t])/,c=/^[^\sa-zA-Z-]+/,l=/:/,f=/\s/,h=/^\s+/,g=/-->/,d=/^WEBVTT([ \t].*)?$/,p=function(t,e){this.window=t,this.state="INITIAL",this.buffer="",this.decoder=e||new b,this.regionList=[],this.maxCueBatch=1e3};function b(){return{decode:function(t){if(!t)return"";if("string"!=typeof t)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(t))}}}function v(){this.values=Object.create(null)}v.prototype={set:function(t,e){this.get(t)||""===e||(this.values[t]=e)},get:function(t,e,r){return r?this.has(t)?this.values[t]:e[r]:this.has(t)?this.values[t]:e},has:function(t){return t in this.values},alt:function(t,e,r){for(var n=0;n=0&&e<=100&&(this.set(t,e),!0)}};var E=new i.a(0,0,0),w="middle"===E.align?"middle":"center";function T(t,e,r){var n=t;function i(){var e=function(t){function e(t,e,r,n){return 3600*(0|t)+60*(0|e)+(0|r)+(0|n)/1e3}var r=t.match(s);return r?r[3]?e(r[1],r[2],r[3].replace(":",""),r[4]):r[1]>59?e(r[1],r[2],0,r[4]):e(0,r[1],r[2],r[4]):null}(t);if(null===e)throw new Error("Malformed timestamp: "+n);return t=t.replace(c,""),e}function a(){t=t.replace(h,"")}if(a(),e.startTime=i(),a(),"--\x3e"!==t.substr(0,3))throw new Error("Malformed time stamp (time stamps must be separated by '--\x3e'): "+n);t=t.substr(3),a(),e.endTime=i(),a(),function(t,e){var n=new v;!function(t,e,r,n){for(var i=n?t.split(n):[t],s=0;s<=i.length;s+=1)if("string"==typeof i[s]){var a=i[s].split(r);if(2===a.length)e(a[0],a[1])}}(t,(function(t,e){switch(t){case"region":for(var i=r.length-1;i>=0;i--)if(r[i].id===e){n.set(t,r[i].region);break}break;case"vertical":n.alt(t,e,["rl","lr"]);break;case"line":var s=e.split(","),a=s[0];n.integer(t,a),n.percent(t,a)&&n.set("snapToLines",!1),n.alt(t,a,["auto"]),2===s.length&&n.alt("lineAlign",s[1],["start",w,"end"]);break;case"position":var u=e.split(",");n.percent(t,u[0]),2===u.length&&n.alt("positionAlign",u[1],["start",w,"end","line-left","line-right","auto"]);break;case"size":n.percent(t,e);break;case"align":n.alt(t,e,["start",w,"end","left","right"])}}),l,f),e.region=n.get("region",null),e.vertical=n.get("vertical","");var i=n.get("line","auto");"auto"===i&&-1===E.line&&(i=-1),e.line=i,e.lineAlign=n.get("lineAlign","start"),e.snapToLines=n.get("snapToLines",!0),e.size=n.get("size",100),e.align=n.get("align",w);var s=n.get("position","auto");"auto"===s&&50===E.position&&(s="start"===e.align||"left"===e.align?0:"end"===e.align||"right"===e.align?100:50),e.position=s}(t,e)}p.prototype={parse:function(t,e){var r,s=this;function a(){for(var t=s.buffer,e=0;e { + const config = useConfiguration(); + const language = config.data?.configuration?.interface?.language ?? "en-US"; + const messageLanguage = language.slice(0, 2); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const messages = flattenMessages((locales as any)[messageLanguage]); + + return ( + + + + +
    + + + + + + + + + + + + +
    +
    +
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Changelog/Changelog.tsx b/ui/v2.5/src/components/Changelog/Changelog.tsx new file mode 100644 index 000000000..6d768b776 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/Changelog.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { useChangelogStorage } from "src/hooks"; +import Version from "./Version"; +import { V010, V011, V020 } from "./versions"; + +const Changelog: React.FC = () => { + const [{ data, loading }, setOpenState] = useChangelogStorage(); + + if (loading) return <>; + + const openState = data?.versions ?? {}; + + const setVersionOpenState = (key: string, state: boolean) => + setOpenState({ + versions: { + ...openState, + [key]: state, + }, + }); + + return ( + <> +

    Changelog:

    + + + + + + + + + + + ); +}; + +export default Changelog; diff --git a/ui/v2.5/src/components/Changelog/Version.tsx b/ui/v2.5/src/components/Changelog/Version.tsx new file mode 100644 index 000000000..7808ef803 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/Version.tsx @@ -0,0 +1,59 @@ +import React, { useState } from "react"; +import { Button, Card, Collapse } from "react-bootstrap"; +import { FormattedDate, FormattedMessage } from "react-intl"; +import { Icon } from "src/components/Shared"; + +interface IVersionProps { + version: string; + date?: string; + defaultOpen?: boolean; + setOpenState: (key: string, state: boolean) => void; + openState: Record; +} + +const Version: React.FC = ({ + version, + date, + defaultOpen, + openState, + setOpenState, + children, +}) => { + const [open, setOpen] = useState( + defaultOpen ?? openState[version + date] ?? false + ); + + const updateState = () => { + setOpenState(version + date, !open); + setOpen(!open); + }; + + return ( + + +

    + +

    +
    + + +
    {children}
    +
    +
    +
    + ); +}; + +export default Version; diff --git a/ui/v2.5/src/components/Changelog/styles.scss b/ui/v2.5/src/components/Changelog/styles.scss new file mode 100644 index 000000000..abdf45545 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/styles.scss @@ -0,0 +1,38 @@ +.changelog { + margin-bottom: 4rem; + margin-top: 4rem; + + .btn { + color: inherit; + font-size: inherit; + font-weight: inherit; + + &:focus { + text-decoration: unset; + } + + &:hover { + text-decoration: underline; + } + } + + .card, + .card-body { + padding: 0; + } + + ul { + list-style-type: none; + padding-left: 0.5rem; + } + + &-version { + &-body { + padding: 1rem 2rem; + } + + &-header { + color: $text-color; + } + } +} diff --git a/ui/v2.5/src/components/Changelog/versions/index.ts b/ui/v2.5/src/components/Changelog/versions/index.ts new file mode 100644 index 000000000..6351f1c60 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/versions/index.ts @@ -0,0 +1,3 @@ +export { default as V010 } from "./v010"; +export { default as V011 } from "./v011"; +export { default as V020 } from "./v020"; diff --git a/ui/v2.5/src/components/Changelog/versions/v010.tsx b/ui/v2.5/src/components/Changelog/versions/v010.tsx new file mode 100644 index 000000000..b440f5bd3 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/versions/v010.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import ReactMarkdown from "react-markdown"; + +const markup = ` +### ✨ New Features + +* Configurable custom performer scrapers +* Support looping of short videos. +* Optionally auto-start videos. +* Add scene auto-tagging from filename +* Add Play random button to scenes and scene markers page +* Allow uploading of custom scene covers +* Configurable custom scene metadata scrapers +* Add "Open Random" to performer list +* Add scenes tab to performer page +* Add version check +* Add "O-" (or "splooge-") counter +* Add external_host option + +### 🎨 Improvements + +* Improve scene wall layout +* Read config from current working directory before user profile directory +* Upload pull request builds to transfer.sh +* Save interface options +* Change marker time input to mm:ss +* Allow pasting image into performer/studio +* Scene UI improvements +* Update JWPlayer to 8.11.5 +* Beautify scene list table +* Add responsive menu +* Make scene metadata from file metadata optional +* Add transcode seeking support to JWPlayer and remove video.js +* Allow exclusion patterns for scanning +* Support scraping from other stash instances +* Display both server address and listening address in log +* Add scene duration filter +* Add useful links to about page +* Generate a new order when selecting random sorting +* Maintain filter parameters in session +* Change thumbnail default size and resize algorithm +* Improve caching of static files and performer images +* Improve position and cropping of performer images +* Improve stats page + +### 🐛 Bug fixes + +* Fix importing on Windows +* Fix previews sometimes taking a long time to generate +* Fix input fields losing focus when switching between windows +* Fix VTT for chapter display in scene players +* Fix usage of Box.Bytes causing depreciation message +`; + +export default () => ; diff --git a/ui/v2.5/src/components/Changelog/versions/v011.tsx b/ui/v2.5/src/components/Changelog/versions/v011.tsx new file mode 100644 index 000000000..06867d0cd --- /dev/null +++ b/ui/v2.5/src/components/Changelog/versions/v011.tsx @@ -0,0 +1,9 @@ +import React from "react"; +import ReactMarkdown from "react-markdown"; + +const markup = ` +### 🐛 Bug fixes +Fix version checking. +`; + +export default () => ; diff --git a/ui/v2.5/src/components/Changelog/versions/v020.tsx b/ui/v2.5/src/components/Changelog/versions/v020.tsx new file mode 100644 index 000000000..6848d6827 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/versions/v020.tsx @@ -0,0 +1,67 @@ +import React from "react"; +import ReactMarkdown from "react-markdown"; + +const markup = ` +#### 💥 **Note: After upgrading performance will be degraded until a full [scan](/settings?tab=tasks) has been completed.** +#### 💥 **Note: [Language](/settings?tab=interface) has been set to \`English (United States)\` by default, which affects number and date formatting.** + +  +### ✨ New Features +* Movies are now supported. +* Responsive layout for mobile phones. +* Add support for image scraping. +* Allow user to regenerate scene cover based on timestamp. +* Autoassociate galleries to scenes when scanning. +* Configurable scraper user agent string. +* Backup database if a migration is needed. +* Add modes for performer/tag for bulk scene editing. +* Add gender support for performer. +* Add SVG studio image support, and studio image caching. +* Enable sorting for galleries. +* Add scene rating to scene filename parser. +* Replace basic auth with cookie authentication. +* Add detection of container/video_codec/audio_codec compatibility for live file streaming or transcoding. +* Move image with cover.jpg in name to first place in Galleries. +* Add "reshuffle button" when sortby is random. +* Implement clean for missing galleries. +* Add parser support for 3-letter month. +* Add is-missing tags filter. + +### 🎨 Improvements +* Performance improvements and improved video support. +* Support for localized text, dates and numbers. +* Replace Blueprint with react-bootstrap. +* Add image count to gallery list. +* Add library size to main stats page. +* Add slim endpoints for entities to speed up filters. +* Export performance optimization. +* Add random male performer image. +* Added various missing filters to performer page. +* Add index/total count to end of pagination buttons. +* Add flags for performer countries. +* Overhaul look and feel of folder select. +* Add cache for gallery thumbnails. +* Add changelog to start page. +* Include subdirectories when searching for scraper configurations. +* Add debug logging for xpath scraping to assist scraper development. +* Encode pasted images to jpeg. +* Allow selection of wall preview type: video, animated image and static image. +* Localize dates and numbers. + +### 🐛 Bug fixes +* Update performer image in UI when it's replaced. +* Fix performer height filter. +* Fix error when viewing scenes related to objects with illegal characters in name. +* Make ethnicity freetext and fix freeones ethnicity panic. +* Delete marker preview on marker change or delete. +* Include scene o-counter in import/export. +* Make image extension check in zip files case insensitive. +* Fix incorrect stash directory setting when directory has spaces. +* Update built-in Freeones scraper for new API. +* Fix redirect loops in login, migrate and setup pages. +* Make studio, movies, tag, performers scrape/parser matching case insensitive. +* Fix files with special characters in filename not being scanned. + +`; + +export default () => ; diff --git a/ui/v2.5/src/components/ErrorBoundary.tsx b/ui/v2.5/src/components/ErrorBoundary.tsx new file mode 100644 index 000000000..302abb2cc --- /dev/null +++ b/ui/v2.5/src/components/ErrorBoundary.tsx @@ -0,0 +1,50 @@ +import React from "react"; + +interface IErrorBoundaryProps { + children?: React.ReactNode; +} + +type ErrorInfo = { + componentStack: string; +}; + +interface IErrorBoundaryState { + error?: Error; + errorInfo?: ErrorInfo; +} + +export class ErrorBoundary extends React.Component< + IErrorBoundaryProps, + IErrorBoundaryState +> { + constructor(props: IErrorBoundaryProps) { + super(props); + this.state = {}; + } + + public componentDidCatch(error: Error, errorInfo: ErrorInfo) { + this.setState({ + error, + errorInfo, + }); + } + + public render() { + if (this.state.errorInfo) { + // Error path + return ( +
    +

    Something went wrong.

    +
    + {this.state.error && this.state.error.toString()} +
    + {this.state.errorInfo.componentStack} +
    +
    + ); + } + + // Normally, just render children + return this.props.children; + } +} diff --git a/ui/v2.5/src/components/Galleries/Galleries.tsx b/ui/v2.5/src/components/Galleries/Galleries.tsx new file mode 100644 index 000000000..aad72ddd5 --- /dev/null +++ b/ui/v2.5/src/components/Galleries/Galleries.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import { Route, Switch } from "react-router-dom"; +import { Gallery } from "./Gallery"; +import { GalleryList } from "./GalleryList"; + +const Galleries = () => ( + + + + +); + +export default Galleries; diff --git a/ui/v2.5/src/components/Galleries/Gallery.tsx b/ui/v2.5/src/components/Galleries/Gallery.tsx new file mode 100644 index 000000000..f58a591ae --- /dev/null +++ b/ui/v2.5/src/components/Galleries/Gallery.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { useParams } from "react-router-dom"; +import { useFindGallery } from "src/core/StashService"; +import { LoadingIndicator } from "src/components/Shared"; +import { GalleryViewer } from "./GalleryViewer"; + +export const Gallery: React.FC = () => { + const { id = "" } = useParams(); + + const { data, error, loading } = useFindGallery(id); + const gallery = data?.findGallery; + + if (loading || !gallery) return ; + if (error) return
    {error.message}
    ; + + return ( +
    + +
    + ); +}; diff --git a/ui/v2.5/src/components/Galleries/GalleryList.tsx b/ui/v2.5/src/components/Galleries/GalleryList.tsx new file mode 100644 index 000000000..6067c82bf --- /dev/null +++ b/ui/v2.5/src/components/Galleries/GalleryList.tsx @@ -0,0 +1,65 @@ +import React from "react"; +import { Table } from "react-bootstrap"; +import { Link } from "react-router-dom"; +import { FindGalleriesQueryResult } from "src/core/generated-graphql"; +import { useGalleriesList } from "src/hooks"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { DisplayMode } from "src/models/list-filter/types"; + +export const GalleryList: React.FC = () => { + const listData = useGalleriesList({ + renderContent, + }); + + function renderContent( + result: FindGalleriesQueryResult, + filter: ListFilterModel + ) { + if (!result.data || !result.data.findGalleries) { + return; + } + if (filter.displayMode === DisplayMode.Grid) { + return

    TODO

    ; + } + if (filter.displayMode === DisplayMode.List) { + return ( + + + + + + + + + {result.data.findGalleries.galleries.map((gallery) => ( + + + + + ))} + +
    PreviewPath
    + + {gallery.files.length > 0 ? ( + {gallery.title + ) : undefined} + + + + {gallery.path} ({gallery.files.length}{" "} + {gallery.files.length === 1 ? "image" : "images"}) + +
    + ); + } + if (filter.displayMode === DisplayMode.Wall) { + return

    TODO

    ; + } + } + + return listData.template; +}; diff --git a/ui/v2.5/src/components/Galleries/GalleryViewer.tsx b/ui/v2.5/src/components/Galleries/GalleryViewer.tsx new file mode 100644 index 000000000..98785a2f9 --- /dev/null +++ b/ui/v2.5/src/components/Galleries/GalleryViewer.tsx @@ -0,0 +1,59 @@ +import React, { FunctionComponent, useState } from "react"; +import Lightbox from "react-images"; +import Gallery from "react-photo-gallery"; +import * as GQL from "src/core/generated-graphql"; + +interface IProps { + gallery: GQL.GalleryDataFragment; +} + +export const GalleryViewer: FunctionComponent = ({ gallery }) => { + const [currentImage, setCurrentImage] = useState(0); + const [lightboxIsOpen, setLightboxIsOpen] = useState(false); + + function openLightbox( + _event: React.MouseEvent, + obj: { index: number } + ) { + setCurrentImage(obj.index); + setLightboxIsOpen(true); + } + function closeLightbox() { + setCurrentImage(0); + setLightboxIsOpen(false); + } + function gotoPrevious() { + setCurrentImage(currentImage - 1); + } + function gotoNext() { + setCurrentImage(currentImage + 1); + } + + const photos = gallery.files.map((file) => ({ + src: file.path ?? "", + caption: file.name ?? "", + })); + const thumbs = gallery.files.map((file) => ({ + src: `${file.path}?thumb=true` || "", + width: 1, + height: 1, + })); + + return ( +
    + + + window.open(photos[currentImage].src ?? "", "_blank") + } + isOpen={lightboxIsOpen} + width={9999} + /> +
    + ); +}; diff --git a/ui/v2.5/src/components/Galleries/styles.scss b/ui/v2.5/src/components/Galleries/styles.scss new file mode 100644 index 000000000..ec64677fa --- /dev/null +++ b/ui/v2.5/src/components/Galleries/styles.scss @@ -0,0 +1,7 @@ +/* stylelint-disable selector-class-pattern */ +.react-photo-gallery--gallery { + img { + object-fit: contain; + } +} +/* stylelint-enable selector-class-pattern */ diff --git a/ui/v2.5/src/components/List/AddFilter.tsx b/ui/v2.5/src/components/List/AddFilter.tsx new file mode 100644 index 000000000..5ed6f1b37 --- /dev/null +++ b/ui/v2.5/src/components/List/AddFilter.tsx @@ -0,0 +1,257 @@ +import _ from "lodash"; +import React, { useEffect, useRef, useState } from "react"; +import { Button, Form, Modal, OverlayTrigger, Tooltip } from "react-bootstrap"; +import { Icon, FilterSelect, DurationInput } from "src/components/Shared"; +import { CriterionModifier } from "src/core/generated-graphql"; +import { + Criterion, + CriterionType, + DurationCriterion, + CriterionValue, +} from "src/models/list-filter/criteria/criterion"; +import { NoneCriterion } from "src/models/list-filter/criteria/none"; +import { makeCriteria } from "src/models/list-filter/criteria/utils"; +import { ListFilterModel } from "src/models/list-filter/filter"; + +interface IAddFilterProps { + onAddCriterion: (criterion: Criterion, oldId?: string) => void; + onCancel: () => void; + filter: ListFilterModel; + editingCriterion?: Criterion; +} + +export const AddFilter: React.FC = ( + props: IAddFilterProps +) => { + const defaultValue = useRef(); + + const [isOpen, setIsOpen] = useState(false); + const [criterion, setCriterion] = useState(new NoneCriterion()); + + const valueStage = useRef(criterion.value); + + // Configure if we are editing an existing criterion + useEffect(() => { + if (!props.editingCriterion) { + return; + } + setIsOpen(true); + setCriterion(props.editingCriterion); + }, [props.editingCriterion]); + + function onChangedCriteriaType(event: React.ChangeEvent) { + const newCriterionType = event.target.value as CriterionType; + const newCriterion = makeCriteria(newCriterionType); + setCriterion(newCriterion); + } + + function onChangedModifierSelect( + event: React.ChangeEvent + ) { + const newCriterion = _.cloneDeep(criterion); + newCriterion.modifier = event.target.value as CriterionModifier; + setCriterion(newCriterion); + } + + function onChangedSingleSelect(event: React.ChangeEvent) { + const newCriterion = _.cloneDeep(criterion); + newCriterion.value = event.target.value; + setCriterion(newCriterion); + } + + function onChangedInput(event: React.ChangeEvent) { + valueStage.current = event.target.value; + } + + function onChangedDuration(valueAsNumber: number) { + valueStage.current = valueAsNumber; + onBlurInput(); + } + + function onBlurInput() { + const newCriterion = _.cloneDeep(criterion); + newCriterion.value = valueStage.current; + setCriterion(newCriterion); + } + + function onAddFilter() { + if (!Array.isArray(criterion.value) && defaultValue.current !== undefined) { + const value = defaultValue.current; + if ( + criterion.options && + (value === undefined || value === "" || typeof value === "number") + ) { + criterion.value = criterion.options[0].toString(); + } else if (typeof value === "number" && value === undefined) { + criterion.value = 0; + } else if (value === undefined) { + criterion.value = ""; + } + } + const oldId = props.editingCriterion + ? props.editingCriterion.getId() + : undefined; + props.onAddCriterion(criterion, oldId); + onToggle(); + } + + function onToggle() { + if (isOpen) { + props.onCancel(); + } + setIsOpen(!isOpen); + setCriterion(makeCriteria()); + } + + const maybeRenderFilterPopoverContents = () => { + if (criterion.type === "none") { + return; + } + + function renderModifier() { + if (criterion.modifierOptions.length === 0) { + return; + } + return ( + + {criterion.modifierOptions.map((c) => ( + + ))} + + ); + } + + function renderSelect() { + // Hide the value select if the modifier is "IsNull" or "NotNull" + if ( + criterion.modifier === CriterionModifier.IsNull || + criterion.modifier === CriterionModifier.NotNull + ) { + return; + } + + if (Array.isArray(criterion.value)) { + if ( + criterion.type !== "performers" && + criterion.type !== "studios" && + criterion.type !== "tags" && + criterion.type !== "sceneTags" && + criterion.type !== "movies" + ) + return; + + return ( + { + const newCriterion = _.cloneDeep(criterion); + newCriterion.value = items.map((i) => ({ + id: i.id, + label: i.name!, + })); + setCriterion(newCriterion); + }} + ids={criterion.value.map((labeled) => labeled.id)} + /> + ); + } + if (criterion.options) { + defaultValue.current = criterion.value; + return ( + + {criterion.options.map((c) => ( + + ))} + + ); + } + if (criterion instanceof DurationCriterion) { + // render duration control + return ( + + ); + } + return ( + + ); + } + return ( + <> + {renderModifier()} + {renderSelect()} + + ); + }; + + function maybeRenderFilterSelect() { + if (props.editingCriterion) { + return; + } + return ( + + Filter + + {props.filter.criterionOptions.map((c) => ( + + ))} + + + ); + } + + const title = !props.editingCriterion ? "Add Filter" : "Update Filter"; + return ( + <> + Filter} + > + + + + onToggle()}> + {title} + +
    + {maybeRenderFilterSelect()} + {maybeRenderFilterPopoverContents()} +
    +
    + + + +
    + + ); +}; diff --git a/ui/v2.5/src/components/List/ListFilter.tsx b/ui/v2.5/src/components/List/ListFilter.tsx new file mode 100644 index 000000000..08db969c4 --- /dev/null +++ b/ui/v2.5/src/components/List/ListFilter.tsx @@ -0,0 +1,362 @@ +import { debounce } from "lodash"; +import React, { useState } from "react"; +import { SortDirectionEnum } from "src/core/generated-graphql"; +import { + Badge, + Button, + ButtonGroup, + Dropdown, + Form, + OverlayTrigger, + Tooltip, + SafeAnchorProps, +} from "react-bootstrap"; + +import { Icon } from "src/components/Shared"; +import { Criterion } from "src/models/list-filter/criteria/criterion"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { DisplayMode } from "src/models/list-filter/types"; +import { AddFilter } from "./AddFilter"; + +interface IListFilterOperation { + text: string; + onClick: () => void; +} + +interface IListFilterProps { + onChangePageSize: (pageSize: number) => void; + onChangeQuery: (query: string) => void; + onChangeSortDirection: (sortDirection: SortDirectionEnum) => void; + onChangeSortBy: (sortBy: string) => void; + onSortReshuffle: () => void; + onChangeDisplayMode: (displayMode: DisplayMode) => void; + onAddCriterion: (criterion: Criterion, oldId?: string) => void; + onRemoveCriterion: (criterion: Criterion) => void; + zoomIndex?: number; + onChangeZoom?: (zoomIndex: number) => void; + onSelectAll?: () => void; + onSelectNone?: () => void; + otherOperations?: IListFilterOperation[]; + filter: ListFilterModel; +} + +const PAGE_SIZE_OPTIONS = ["20", "40", "60", "120"]; + +export const ListFilter: React.FC = ( + props: IListFilterProps +) => { + const searchCallback = debounce((value: string) => { + props.onChangeQuery(value); + }, 500); + + const [editingCriterion, setEditingCriterion] = useState< + Criterion | undefined + >(undefined); + + function onChangePageSize(event: React.ChangeEvent) { + const val = event.currentTarget.value; + props.onChangePageSize(parseInt(val, 10)); + } + + function onChangeQuery(event: React.FormEvent) { + searchCallback(event.currentTarget.value); + } + + function onChangeSortDirection() { + if (props.filter.sortDirection === SortDirectionEnum.Asc) { + props.onChangeSortDirection(SortDirectionEnum.Desc); + } else { + props.onChangeSortDirection(SortDirectionEnum.Asc); + } + } + + function onChangeSortBy(event: React.MouseEvent) { + const target = event.currentTarget as HTMLAnchorElement; + props.onChangeSortBy(target.text); + } + + function onReshuffleRandomSort() { + props.onSortReshuffle(); + } + + function onChangeDisplayMode(displayMode: DisplayMode) { + props.onChangeDisplayMode(displayMode); + } + + function onAddCriterion(criterion: Criterion, oldId?: string) { + props.onAddCriterion(criterion, oldId); + } + + function onCancelAddCriterion() { + setEditingCriterion(undefined); + } + + let removedCriterionId = ""; + function onRemoveCriterionTag(criterion?: Criterion) { + if (!criterion) { + return; + } + setEditingCriterion(undefined); + removedCriterionId = criterion.getId(); + props.onRemoveCriterion(criterion); + } + function onClickCriterionTag(criterion?: Criterion) { + if (!criterion || removedCriterionId !== "") { + return; + } + setEditingCriterion(criterion); + } + + function renderSortByOptions() { + return props.filter.sortByOptions.map((option) => ( + + {option} + + )); + } + + function renderDisplayModeOptions() { + function getIcon(option: DisplayMode) { + switch (option) { + case DisplayMode.Grid: + return "th-large"; + case DisplayMode.List: + return "list"; + case DisplayMode.Wall: + return "square"; + } + } + function getLabel(option: DisplayMode) { + switch (option) { + case DisplayMode.Grid: + return "Grid"; + case DisplayMode.List: + return "List"; + case DisplayMode.Wall: + return "Wall"; + } + } + return props.filter.displayModeOptions.map((option) => ( + {getLabel(option)} + } + > + + + )); + } + + function renderFilterTags() { + return props.filter.criteria.map((criterion) => ( + onClickCriterionTag(criterion)} + > + {criterion.getLabel()} + + + )); + } + + function onSelectAll() { + if (props.onSelectAll) { + props.onSelectAll(); + } + } + + function onSelectNone() { + if (props.onSelectNone) { + props.onSelectNone(); + } + } + + function renderSelectAll() { + if (props.onSelectAll) { + return ( + onSelectAll()} + > + Select All + + ); + } + } + + function renderSelectNone() { + if (props.onSelectNone) { + return ( + onSelectNone()} + > + Select None + + ); + } + } + + function renderMore() { + const options = [renderSelectAll(), renderSelectNone()]; + + if (props.otherOperations) { + props.otherOperations.forEach((o) => { + options.push( + + {o.text} + + ); + }); + } + + if (options.length > 0) { + return ( + + + + + + {options} + + + ); + } + } + + function onChangeZoom(v: number) { + if (props.onChangeZoom) { + props.onChangeZoom(v); + } + } + + function maybeRenderZoom() { + if (props.onChangeZoom) { + return ( + ) => + onChangeZoom(Number.parseInt(e.currentTarget.value, 10)) + } + /> + ); + } + } + + function render() { + return ( + <> +
    + + + {PAGE_SIZE_OPTIONS.map((s) => ( + + ))} + + + + + {props.filter.sortBy} + + + {renderSortByOptions()} + + + {props.filter.sortDirection === SortDirectionEnum.Asc + ? "Ascending" + : "Descending"} + + } + > + + + {props.filter.sortBy === "random" && ( + Reshuffle + } + > + + + )} + + + + + + + {renderDisplayModeOptions()} + + + {maybeRenderZoom()} + + + {renderMore()} + +
    +
    + {renderFilterTags()} +
    + + ); + } + + return render(); +}; diff --git a/ui/v2.5/src/components/List/Pagination.tsx b/ui/v2.5/src/components/List/Pagination.tsx new file mode 100644 index 000000000..ec68b86d4 --- /dev/null +++ b/ui/v2.5/src/components/List/Pagination.tsx @@ -0,0 +1,135 @@ +import React from "react"; +import { Button, ButtonGroup } from "react-bootstrap"; +import { FormattedNumber, useIntl } from "react-intl"; + +interface IPaginationProps { + itemsPerPage: number; + currentPage: number; + totalItems: number; + onChangePage: (page: number) => void; +} + +interface IPaginationIndexProps { + itemsPerPage: number; + currentPage: number; + totalItems: number; +} + +export const Pagination: React.FC = ({ + itemsPerPage, + currentPage, + totalItems, + onChangePage, +}) => { + const totalPages = Math.ceil(totalItems / itemsPerPage); + + let startPage: number; + let endPage: number; + if (totalPages <= 10) { + // less than 10 total pages so show all + startPage = 1; + endPage = totalPages; + } else if (currentPage <= 6) { + startPage = 1; + endPage = 10; + } else if (currentPage + 4 >= totalPages) { + startPage = totalPages - 9; + endPage = totalPages; + } else { + startPage = currentPage - 5; + endPage = currentPage + 4; + } + + const pages = [...Array(endPage + 1 - startPage).keys()].map( + (i) => startPage + i + ); + + const calculatePageClass = (buttonPage: number) => { + if (pages.length <= 4) return ""; + + if (currentPage === 1 && buttonPage <= 4) return ""; + const maxPage = pages[pages.length - 1]; + if (currentPage === maxPage && buttonPage > maxPage - 3) return ""; + if (Math.abs(buttonPage - currentPage) <= 1) return ""; + return "d-none d-sm-block"; + }; + + const pageButtons = pages.map((page: number) => ( + + )); + + if (pages.length <= 1) return
    ; + + return ( + + + + {pageButtons} + + + + ); +}; + +export const PaginationIndex: React.FC = ({ + itemsPerPage, + currentPage, + totalItems, +}) => { + const intl = useIntl(); + + // Build the pagination index string + const firstItemCount: number = Math.min( + (currentPage - 1) * itemsPerPage + 1, + totalItems + ); + const lastItemCount: number = Math.min( + firstItemCount + (itemsPerPage - 1), + totalItems + ); + const indexText: string = `${intl.formatNumber( + firstItemCount + )}-${intl.formatNumber(lastItemCount)} of ${intl.formatNumber(totalItems)}`; + + return ( + + {indexText} + + ); +}; diff --git a/ui/v2.5/src/components/List/styles.scss b/ui/v2.5/src/components/List/styles.scss new file mode 100644 index 000000000..d6a6d3d65 --- /dev/null +++ b/ui/v2.5/src/components/List/styles.scss @@ -0,0 +1,15 @@ +.pagination { + .btn { + border-left: 1px solid $body-bg; + border-right: 1px solid $body-bg; + flex-grow: 0; + padding-left: 15px; + padding-right: 15px; + transition: none; + } +} + +.zoom-slider { + padding-left: 0; + padding-right: 0; +} diff --git a/ui/v2.5/src/components/MainNavbar.tsx b/ui/v2.5/src/components/MainNavbar.tsx new file mode 100644 index 000000000..851230c7c --- /dev/null +++ b/ui/v2.5/src/components/MainNavbar.tsx @@ -0,0 +1,201 @@ +import React, { useEffect, useRef, useState } from "react"; +import { + defineMessages, + FormattedMessage, + MessageDescriptor, + useIntl, +} from "react-intl"; +import { Nav, Navbar, Button } from "react-bootstrap"; +import { IconName } from "@fortawesome/fontawesome-svg-core"; +import { LinkContainer } from "react-router-bootstrap"; +import { Link, NavLink, useLocation } from "react-router-dom"; +import { SessionUtils } from "src/utils"; + +import { Icon } from "src/components/Shared"; + +interface IMenuItem { + message: MessageDescriptor; + href: string; + icon: IconName; +} + +const messages = defineMessages({ + scenes: { + id: "scenes", + defaultMessage: "Scenes", + }, + movies: { + id: "movies", + defaultMessage: "Movies", + }, + markers: { + id: "markers", + defaultMessage: "Markers", + }, + performers: { + id: "performers", + defaultMessage: "Performers", + }, + studios: { + id: "studios", + defaultMessage: "Studios", + }, + tags: { + id: "tags", + defaultMessage: "Tags", + }, + galleries: { + id: "galleries", + defaultMessage: "Galleries", + }, +}); + +const menuItems: IMenuItem[] = [ + { + icon: "play-circle", + message: messages.scenes, + href: "/scenes", + }, + { + href: "/movies", + icon: "film", + message: messages.movies, + }, + { + href: "/scenes/markers", + icon: "map-marker-alt", + message: messages.markers, + }, + { + href: "/galleries", + icon: "image", + message: messages.galleries, + }, + { + href: "/performers", + icon: "user", + message: messages.performers, + }, + { + href: "/studios", + icon: "video", + message: messages.studios, + }, + { + href: "/tags", + icon: "tag", + message: messages.tags, + }, +]; + +export const MainNavbar: React.FC = () => { + const location = useLocation(); + const [expanded, setExpanded] = useState(false); + // react-bootstrap typing bug + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const navbarRef = useRef(); + const intl = useIntl(); + + const maybeCollapse = (event: Event) => { + if ( + navbarRef.current && + event.target instanceof Node && + !navbarRef.current.contains(event.target) + ) { + setExpanded(false); + } + }; + + useEffect(() => { + if (expanded) { + document.addEventListener("click", maybeCollapse); + document.addEventListener("touchstart", maybeCollapse); + } + return () => { + document.removeEventListener("click", maybeCollapse); + document.removeEventListener("touchstart", maybeCollapse); + }; + }, [expanded]); + + const path = + location.pathname === "/performers" + ? "/performers/new" + : location.pathname === "/studios" + ? "/studios/new" + : location.pathname === "/movies" + ? "/movies/new" + : null; + const newButton = + path === null ? ( + "" + ) : ( + + + + ); + + function maybeRenderLogout() { + if (SessionUtils.isLoggedIn()) { + return ( + + ); + } + } + + return ( + + setExpanded(false)} + > + + + + + + + + + + + + ); +}; diff --git a/ui/v2.5/src/components/Movies/MovieCard.tsx b/ui/v2.5/src/components/Movies/MovieCard.tsx new file mode 100644 index 000000000..f90ab5088 --- /dev/null +++ b/ui/v2.5/src/components/Movies/MovieCard.tsx @@ -0,0 +1,61 @@ +import { Card } from "react-bootstrap"; +import React, { FunctionComponent } from "react"; +import { FormattedPlural } from "react-intl"; +import { Link } from "react-router-dom"; +import * as GQL from "src/core/generated-graphql"; + +interface IProps { + movie: GQL.MovieDataFragment; + sceneIndex?: number; +} + +export const MovieCard: FunctionComponent = (props: IProps) => { + function maybeRenderRatingBanner() { + if (!props.movie.rating) { + return; + } + return ( +
    + RATING: {props.movie.rating} +
    + ); + } + + function maybeRenderSceneNumber() { + if (!props.sceneIndex) { + return ( + + {props.movie.scene_count}  + + + ); + } + + return Scene number: {props.sceneIndex}; + } + + return ( + + + {props.movie.name + {maybeRenderRatingBanner()} + +
    +
    {props.movie.name}
    + {maybeRenderSceneNumber()} +
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx b/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx new file mode 100644 index 000000000..7a48cfe7a --- /dev/null +++ b/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx @@ -0,0 +1,322 @@ +/* eslint-disable react/no-this-in-sfc */ +import React, { useEffect, useState, useCallback } from "react"; +import { useIntl } from "react-intl"; +import * as GQL from "src/core/generated-graphql"; +import { + useFindMovie, + useMovieUpdate, + useMovieCreate, + useMovieDestroy, +} from "src/core/StashService"; +import { useParams, useHistory } from "react-router-dom"; +import cx from "classnames"; +import { + DetailsEditNavbar, + LoadingIndicator, + Modal, + StudioSelect, +} from "src/components/Shared"; +import { useToast } from "src/hooks"; +import { Table, Form } from "react-bootstrap"; +import { + TableUtils, + ImageUtils, + EditableTextUtils, + TextUtils, +} from "src/utils"; +import { MovieScenesPanel } from "./MovieScenesPanel"; + +export const Movie: React.FC = () => { + const history = useHistory(); + const Toast = useToast(); + const { id = "new" } = useParams(); + const isNew = id === "new"; + + // Editing state + const [isEditing, setIsEditing] = useState(isNew); + const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); + + // Editing movie state + const [frontImage, setFrontImage] = useState(undefined); + const [backImage, setBackImage] = useState(undefined); + const [name, setName] = useState(undefined); + const [aliases, setAliases] = useState(undefined); + const [duration, setDuration] = useState(undefined); + const [date, setDate] = useState(undefined); + const [rating, setRating] = useState(undefined); + const [studioId, setStudioId] = useState(); + const [director, setDirector] = useState(undefined); + const [synopsis, setSynopsis] = useState(undefined); + const [url, setUrl] = useState(undefined); + + // Movie state + const [movie, setMovie] = useState>({}); + const [imagePreview, setImagePreview] = useState( + undefined + ); + const [backimagePreview, setBackImagePreview] = useState( + undefined + ); + + // Network state + const { data, error, loading } = useFindMovie(id); + const [updateMovie] = useMovieUpdate(getMovieInput() as GQL.MovieUpdateInput); + const [createMovie] = useMovieCreate(getMovieInput() as GQL.MovieCreateInput); + const [deleteMovie] = useMovieDestroy( + getMovieInput() as GQL.MovieDestroyInput + ); + + const intl = useIntl(); + + function updateMovieEditState(state: Partial) { + setName(state.name ?? undefined); + setAliases(state.aliases ?? undefined); + setDuration(state.duration ?? undefined); + setDate(state.date ?? undefined); + setRating(state.rating ?? undefined); + setStudioId(state?.studio?.id ?? undefined); + setDirector(state.director ?? undefined); + setSynopsis(state.synopsis ?? undefined); + setUrl(state.url ?? undefined); + } + + const updateMovieData = useCallback( + (movieData: Partial) => { + setFrontImage(undefined); + setBackImage(undefined); + updateMovieEditState(movieData); + setImagePreview(movieData.front_image_path ?? undefined); + setBackImagePreview(movieData.back_image_path ?? undefined); + setMovie(movieData); + }, + [] + ); + + useEffect(() => { + if (data && data.findMovie) { + updateMovieData(data.findMovie); + } + }, [data, updateMovieData]); + + function onImageLoad(imageData: string) { + setImagePreview(imageData); + setFrontImage(imageData); + } + + function onBackImageLoad(imageData: string) { + setBackImagePreview(imageData); + setBackImage(imageData); + } + + const encodingFrontImage = ImageUtils.usePasteImage(onImageLoad, isEditing); + const encodingBackImage = ImageUtils.usePasteImage( + onBackImageLoad, + isEditing + ); + + if (!isNew && !isEditing) { + if (!data || !data.findMovie || loading) return ; + if (error) { + return <>{error!.message}; + } + } + + function getMovieInput() { + const input: Partial = { + name, + aliases, + duration, + date, + rating, + studio_id: studioId, + director, + synopsis, + url, + front_image: frontImage, + back_image: backImage, + }; + + if (!isNew) { + (input as GQL.MovieUpdateInput).id = id; + } + return input; + } + + async function onSave() { + try { + if (!isNew) { + const result = await updateMovie(); + if (result.data?.movieUpdate) { + updateMovieData(result.data.movieUpdate); + setIsEditing(false); + } + } else { + const result = await createMovie(); + if (result.data?.movieCreate?.id) { + history.push(`/movies/${result.data.movieCreate.id}`); + setIsEditing(false); + } + } + } catch (e) { + Toast.error(e); + } + } + + async function onDelete() { + try { + await deleteMovie(); + } catch (e) { + Toast.error(e); + } + + // redirect to movies page + history.push(`/movies`); + } + + function onImageChange(event: React.FormEvent) { + ImageUtils.onImageChange(event, onImageLoad); + } + + function onBackImageChange(event: React.FormEvent) { + ImageUtils.onImageChange(event, onBackImageLoad); + } + + function onToggleEdit() { + setIsEditing(!isEditing); + updateMovieData(movie); + } + + function renderDeleteAlert() { + return ( + setIsDeleteAlertOpen(false) }} + > +

    Are you sure you want to delete {name ?? "movie"}?

    +
    + ); + } + + // TODO: CSS class + return ( +
    +
    + {isNew &&

    Add Movie

    } +
    + {encodingFrontImage || encodingBackImage ? ( + + ) : ( + <> + {name} + {name} + + )} +
    + + + + {TableUtils.renderInputGroup({ + title: "Name", + value: name ?? "", + isEditing: !!isEditing, + onChange: setName, + })} + {TableUtils.renderInputGroup({ + title: "Aliases", + value: aliases, + isEditing, + onChange: setAliases, + })} + {TableUtils.renderDurationInput({ + title: "Duration", + value: duration ? duration.toString() : "", + isEditing, + onChange: (value: string | undefined) => + setDuration(value ? Number.parseInt(value, 10) : undefined), + })} + {TableUtils.renderInputGroup({ + title: `Date ${isEditing ? "(YYYY-MM-DD)" : ""}`, + value: isEditing ? date : TextUtils.formatDate(intl, date), + isEditing, + onChange: setDate, + })} + + + + + {TableUtils.renderInputGroup({ + title: "Director", + value: director, + isEditing, + onChange: setDirector, + })} + {TableUtils.renderHtmlSelect({ + title: "Rating", + value: rating ?? "", + isEditing, + onChange: (value: string) => + setRating(Number.parseInt(value, 10)), + selectOptions: ["", "1", "2", "3", "4", "5"], + })} + +
    Studio + + setStudioId(items.length > 0 ? items[0]?.id : undefined) + } + ids={studioId ? [studioId] : []} + /> +
    + + + URL +
    + {EditableTextUtils.renderInputGroup({ + isEditing, + onChange: setUrl, + value: url, + url: TextUtils.sanitiseURL(url), + })} +
    +
    + + + Synopsis + ) => + setSynopsis(newValue.currentTarget.value) + } + value={synopsis} + /> + + + +
    + {!isNew && ( +
    + +
    + )} + {renderDeleteAlert()} +
    + ); +}; diff --git a/ui/v2.5/src/components/Movies/MovieDetails/MovieScenesPanel.tsx b/ui/v2.5/src/components/Movies/MovieDetails/MovieScenesPanel.tsx new file mode 100644 index 000000000..a705942df --- /dev/null +++ b/ui/v2.5/src/components/Movies/MovieDetails/MovieScenesPanel.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import * as GQL from "src/core/generated-graphql"; +import { MoviesCriterion } from "src/models/list-filter/criteria/movies"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { SceneList } from "src/components/Scenes/SceneList"; + +interface IMovieScenesPanel { + movie: Partial; +} + +export const MovieScenesPanel: React.FC = ({ movie }) => { + function filterHook(filter: ListFilterModel) { + const movieValue = { id: movie.id!, label: movie.name! }; + // if movie is already present, then we modify it, otherwise add + let movieCriterion = filter.criteria.find((c) => { + return c.type === "movies"; + }) as MoviesCriterion; + + if ( + movieCriterion && + (movieCriterion.modifier === GQL.CriterionModifier.IncludesAll || + movieCriterion.modifier === GQL.CriterionModifier.Includes) + ) { + // add the movie if not present + if ( + !movieCriterion.value.find((p) => { + return p.id === movie.id; + }) + ) { + movieCriterion.value.push(movieValue); + } + + movieCriterion.modifier = GQL.CriterionModifier.IncludesAll; + } else { + // overwrite + movieCriterion = new MoviesCriterion(); + movieCriterion.value = [movieValue]; + filter.criteria.push(movieCriterion); + } + + return filter; + } + + if (movie && movie.id) { + return ; + } + return <>; +}; diff --git a/ui/v2.5/src/components/Movies/MovieList.tsx b/ui/v2.5/src/components/Movies/MovieList.tsx new file mode 100644 index 000000000..f58e02771 --- /dev/null +++ b/ui/v2.5/src/components/Movies/MovieList.tsx @@ -0,0 +1,35 @@ +import React from "react"; +import { FindMoviesQueryResult } from "src/core/generated-graphql"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { DisplayMode } from "src/models/list-filter/types"; +import { useMoviesList } from "src/hooks/ListHook"; +import { MovieCard } from "./MovieCard"; + +export const MovieList: React.FC = () => { + const listData = useMoviesList({ + renderContent, + }); + + function renderContent( + result: FindMoviesQueryResult, + filter: ListFilterModel + ) { + if (!result.data?.findMovies) { + return; + } + if (filter.displayMode === DisplayMode.Grid) { + return ( +
    + {result.data.findMovies.movies.map((p) => ( + + ))} +
    + ); + } + if (filter.displayMode === DisplayMode.List) { + return

    TODO

    ; + } + } + + return listData.template; +}; diff --git a/ui/v2.5/src/components/Movies/Movies.tsx b/ui/v2.5/src/components/Movies/Movies.tsx new file mode 100644 index 000000000..387f6391c --- /dev/null +++ b/ui/v2.5/src/components/Movies/Movies.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import { Route, Switch } from "react-router-dom"; +import { Movie } from "./MovieDetails/Movie"; +import { MovieList } from "./MovieList"; + +const Movies = () => ( + + + + +); + +export default Movies; diff --git a/ui/v2.5/src/components/Movies/styles.scss b/ui/v2.5/src/components/Movies/styles.scss new file mode 100644 index 000000000..ed0f4f057 --- /dev/null +++ b/ui/v2.5/src/components/Movies/styles.scss @@ -0,0 +1,26 @@ +.card.movie-card { + padding: 0 0 1rem 0; +} + +.movie-details { + max-width: 1200px; +} + +.movie-card { + &-header { + height: 240px; + line-height: 240px; + text-align: center; + } + + &-image { + max-height: 240px; + object-fit: contain; + vertical-align: middle; + width: 320px; + + @media (max-width: 576px) { + width: 100%; + } + } +} diff --git a/ui/v2.5/src/components/PageNotFound.tsx b/ui/v2.5/src/components/PageNotFound.tsx new file mode 100644 index 000000000..645709fcf --- /dev/null +++ b/ui/v2.5/src/components/PageNotFound.tsx @@ -0,0 +1,5 @@ +import React, { FunctionComponent } from "react"; + +export const PageNotFound: FunctionComponent = () => { + return

    Page not found.

    ; +}; diff --git a/ui/v2.5/src/components/Performers/PerformerCard.tsx b/ui/v2.5/src/components/Performers/PerformerCard.tsx new file mode 100644 index 000000000..5c379846f --- /dev/null +++ b/ui/v2.5/src/components/Performers/PerformerCard.tsx @@ -0,0 +1,58 @@ +import React from "react"; +import { Card } from "react-bootstrap"; +import { Link } from "react-router-dom"; +import { FormattedNumber, FormattedPlural } from "react-intl"; +import * as GQL from "src/core/generated-graphql"; +import { NavUtils, TextUtils } from "src/utils"; +import { CountryFlag } from "src/components/Shared"; + +interface IPerformerCardProps { + performer: GQL.PerformerDataFragment; + ageFromDate?: string; +} + +export const PerformerCard: React.FC = ({ + performer, + ageFromDate, +}) => { + const age = TextUtils.age(performer.birthdate, ageFromDate); + const ageString = `${age} years old${ageFromDate ? " in this scene." : "."}`; + + function maybeRenderFavoriteBanner() { + if (performer.favorite === false) { + return; + } + return
    FAVORITE
    ; + } + + return ( + + + {performer.name + {maybeRenderFavoriteBanner()} + +
    +
    {performer.name}
    + {age !== 0 ?
    {ageString}
    : ""} + +
    + Stars in  + +   + + + + . +
    +
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx new file mode 100644 index 000000000..561e32502 --- /dev/null +++ b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx @@ -0,0 +1,279 @@ +import React, { useEffect, useState } from "react"; +import { Button, Tabs, Tab } from "react-bootstrap"; +import { useParams, useHistory } from "react-router-dom"; +import cx from "classnames"; +import * as GQL from "src/core/generated-graphql"; +import { + useFindPerformer, + usePerformerUpdate, + usePerformerCreate, + usePerformerDestroy, +} from "src/core/StashService"; +import { CountryFlag, Icon, LoadingIndicator } from "src/components/Shared"; +import { useToast } from "src/hooks"; +import { TextUtils } from "src/utils"; +import Lightbox from "react-images"; +import { PerformerDetailsPanel } from "./PerformerDetailsPanel"; +import { PerformerOperationsPanel } from "./PerformerOperationsPanel"; +import { PerformerScenesPanel } from "./PerformerScenesPanel"; + +export const Performer: React.FC = () => { + const Toast = useToast(); + const history = useHistory(); + const { id = "new" } = useParams(); + const isNew = id === "new"; + + // Performer state + const [performer, setPerformer] = useState< + Partial + >({}); + const [imagePreview, setImagePreview] = useState(); + const [imageEncoding, setImageEncoding] = useState(false); + const [lightboxIsOpen, setLightboxIsOpen] = useState(false); + const activeImage = imagePreview ?? performer.image_path ?? ""; + + // Network state + const [isLoading, setIsLoading] = useState(false); + + const { data, error } = useFindPerformer(id); + const [updatePerformer] = usePerformerUpdate(); + const [createPerformer] = usePerformerCreate(); + const [deletePerformer] = usePerformerDestroy(); + + useEffect(() => { + setIsLoading(false); + if (data?.findPerformer) setPerformer(data.findPerformer); + }, [data]); + + const onImageChange = (image?: string) => setImagePreview(image); + + const onImageEncoding = (isEncoding = false) => setImageEncoding(isEncoding); + + if ((!isNew && (!data || !data.findPerformer)) || isLoading) + return ; + + if (error) return
    {error.message}
    ; + + async function onSave( + performerInput: + | Partial + | Partial + ) { + setIsLoading(true); + try { + if (!isNew) { + const result = await updatePerformer({ + variables: performerInput as GQL.PerformerUpdateInput, + }); + if (performerInput.image) { + // Refetch image to bust browser cache + await fetch(`/performer/${performer.id}/image`, { cache: "reload" }); + } + if (result.data?.performerUpdate) + setPerformer(result.data?.performerUpdate); + } else { + const result = await createPerformer({ + variables: performerInput as GQL.PerformerCreateInput, + }); + if (result.data?.performerCreate) { + setPerformer(result.data.performerCreate); + history.push(`/performers/${result.data.performerCreate.id}`); + } + } + } catch (e) { + Toast.error(e); + } + setIsLoading(false); + } + + async function onDelete() { + setIsLoading(true); + try { + await deletePerformer({ variables: { id } }); + } catch (e) { + Toast.error(e); + } + setIsLoading(false); + + // redirect to performers page + history.push("/performers"); + } + + const renderTabs = () => ( + + + + + + + + + + + + + + + ); + + function maybeRenderAge() { + if (performer?.birthdate) { + // calculate the age from birthdate. In future, this should probably be + // provided by the server + return ( +
    + {TextUtils.age(performer.birthdate)} + years old +
    + ); + } + } + + function maybeRenderAliases() { + if (performer?.aliases) { + return ( +
    + Also known as + {performer.aliases} +
    + ); + } + } + + function setFavorite(v: boolean) { + performer.favorite = v; + onSave(performer); + } + + const renderIcons = () => ( + + + {performer.url && ( + + )} + {performer.twitter && ( + + )} + {performer.instagram && ( + + )} + + ); + + function renderPerformerImage() { + if (imageEncoding) { + return ; + } + if (activeImage) { + return Performer; + } + } + + if (isNew) + return ( +
    +
    {renderPerformerImage()}
    +
    +

    Create Performer

    + +
    +
    + ); + + const photos = [{ src: activeImage, caption: "Image" }]; + + return ( +
    +
    + {imageEncoding ? ( + + ) : ( + + )} +
    +
    +
    +
    +

    + + {performer.name} + {renderIcons()} +

    + {maybeRenderAliases()} + {maybeRenderAge()} +
    +
    +
    +
    {renderTabs()}
    +
    +
    + setLightboxIsOpen(false)} + currentImage={0} + isOpen={lightboxIsOpen} + onClickImage={() => window.open(activeImage, "_blank")} + width={9999} + /> +
    + ); +}; diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx new file mode 100644 index 000000000..2db9c820f --- /dev/null +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx @@ -0,0 +1,567 @@ +/* eslint-disable react/no-this-in-sfc */ + +import React, { useEffect, useState } from "react"; +import { useIntl } from "react-intl"; +import { Button, Popover, OverlayTrigger, Table } from "react-bootstrap"; +import * as GQL from "src/core/generated-graphql"; +import { + getGenderStrings, + useListPerformerScrapers, + genderToString, + stringToGender, + queryScrapePerformer, + queryScrapePerformerURL, +} from "src/core/StashService"; +import { + Icon, + Modal, + ImageInput, + ScrapePerformerSuggest, + LoadingIndicator, +} from "src/components/Shared"; +import { + ImageUtils, + TableUtils, + TextUtils, + EditableTextUtils, +} from "src/utils"; +import { useToast } from "src/hooks"; + +interface IPerformerDetails { + performer: Partial; + isNew?: boolean; + isEditing?: boolean; + onSave?: ( + performer: + | Partial + | Partial + ) => void; + onDelete?: () => void; + onImageChange?: (image?: string) => void; + onImageEncoding?: (loading?: boolean) => void; +} + +export const PerformerDetailsPanel: React.FC = ({ + performer, + isNew, + isEditing, + onSave, + onDelete, + onImageChange, + onImageEncoding, +}) => { + const Toast = useToast(); + + // Editing state + const [isDisplayingScraperDialog, setIsDisplayingScraperDialog] = useState< + GQL.Scraper + >(); + const [scrapePerformerDetails, setScrapePerformerDetails] = useState< + GQL.ScrapedPerformerDataFragment + >(); + const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); + + // Editing performer state + const [image, setImage] = useState(); + const [name, setName] = useState(); + const [aliases, setAliases] = useState(); + const [favorite, setFavorite] = useState(); + const [birthdate, setBirthdate] = useState(); + const [ethnicity, setEthnicity] = useState(); + const [country, setCountry] = useState(); + const [eyeColor, setEyeColor] = useState(); + const [height, setHeight] = useState(); + const [measurements, setMeasurements] = useState(); + const [fakeTits, setFakeTits] = useState(); + const [careerLength, setCareerLength] = useState(); + const [tattoos, setTattoos] = useState(); + const [piercings, setPiercings] = useState(); + const [url, setUrl] = useState(); + const [twitter, setTwitter] = useState(); + const [instagram, setInstagram] = useState(); + const [gender, setGender] = useState(undefined); + + // Network state + const [isLoading, setIsLoading] = useState(false); + + const intl = useIntl(); + + const Scrapers = useListPerformerScrapers(); + const [queryableScrapers, setQueryableScrapers] = useState([]); + + const imageEncoding = ImageUtils.usePasteImage(onImageLoad, isEditing); + + function updatePerformerEditState( + state: Partial + ) { + if ((state as GQL.PerformerDataFragment).favorite !== undefined) { + setFavorite((state as GQL.PerformerDataFragment).favorite); + } + setName(state.name ?? undefined); + setAliases(state.aliases ?? undefined); + setBirthdate(state.birthdate ?? undefined); + setEthnicity(state.ethnicity ?? undefined); + setCountry(state.country ?? undefined); + setEyeColor(state.eye_color ?? undefined); + setHeight(state.height ?? undefined); + setMeasurements(state.measurements ?? undefined); + setFakeTits(state.fake_tits ?? undefined); + setCareerLength(state.career_length ?? undefined); + setTattoos(state.tattoos ?? undefined); + setPiercings(state.piercings ?? undefined); + setUrl(state.url ?? undefined); + setTwitter(state.twitter ?? undefined); + setInstagram(state.instagram ?? undefined); + setGender( + genderToString((state as GQL.PerformerDataFragment).gender ?? undefined) + ); + } + + function translateScrapedGender(scrapedGender?: string) { + if (!scrapedGender) { + return; + } + + let retEnum: GQL.GenderEnum | undefined; + + // try to translate from enum values first + const upperGender = scrapedGender?.toUpperCase(); + const asEnum = genderToString(upperGender as GQL.GenderEnum); + if (asEnum) { + retEnum = stringToGender(asEnum); + } else { + // try to match against gender strings + const caseInsensitive = true; + retEnum = stringToGender(scrapedGender, caseInsensitive); + } + + return genderToString(retEnum); + } + + function updatePerformerEditStateFromScraper( + state: Partial + ) { + updatePerformerEditState(state); + + // gender is a string in the scraper data + setGender(translateScrapedGender(state.gender ?? undefined)); + + // image is a base64 string + // #404: don't overwrite image if it has been modified by the user + if ( + image === undefined && + (state as GQL.ScrapedPerformerDataFragment).image !== undefined + ) { + const imageStr = (state as GQL.ScrapedPerformerDataFragment).image; + setImage(imageStr ?? undefined); + } + } + + function onImageLoad(imageData: string) { + setImage(imageData); + } + + useEffect(() => { + setImage(undefined); + updatePerformerEditState(performer); + }, [performer]); + + useEffect(() => { + if (onImageChange) { + onImageChange(image); + } + return () => onImageChange?.(); + }, [image, onImageChange]); + + useEffect(() => onImageEncoding?.(imageEncoding), [ + onImageEncoding, + imageEncoding, + ]); + + useEffect(() => { + const newQueryableScrapers = ( + Scrapers?.data?.listPerformerScrapers ?? [] + ).filter((s) => + s.performer?.supported_scrapes.includes(GQL.ScrapeType.Name) + ); + + setQueryableScrapers(newQueryableScrapers); + }, [Scrapers]); + + if (isLoading) return ; + + function getPerformerInput() { + const performerInput: Partial< + GQL.PerformerCreateInput | GQL.PerformerUpdateInput + > = { + name, + aliases, + favorite, + birthdate, + ethnicity, + country, + eye_color: eyeColor, + height, + measurements, + fake_tits: fakeTits, + career_length: careerLength, + tattoos, + piercings, + url, + twitter, + instagram, + image, + gender: stringToGender(gender), + }; + + if (!isNew) { + (performerInput as GQL.PerformerUpdateInput).id = performer.id!; + } + return performerInput; + } + + function onImageChangeHandler(event: React.FormEvent) { + ImageUtils.onImageChange(event, onImageLoad); + } + + function onDisplayFreeOnesDialog(scraper: GQL.Scraper) { + setIsDisplayingScraperDialog(scraper); + } + + function getQueryScraperPerformerInput() { + if (!scrapePerformerDetails) return {}; + + // image is not supported + const { __typename, image: _image, ...ret } = scrapePerformerDetails; + return ret; + } + + async function onScrapePerformer() { + setIsDisplayingScraperDialog(undefined); + try { + if (!scrapePerformerDetails || !isDisplayingScraperDialog) return; + setIsLoading(true); + const result = await queryScrapePerformer( + isDisplayingScraperDialog.id, + getQueryScraperPerformerInput() + ); + if (!result?.data?.scrapePerformer) return; + updatePerformerEditStateFromScraper(result.data.scrapePerformer); + } catch (e) { + Toast.error(e); + } finally { + setIsLoading(false); + } + } + + async function onScrapePerformerURL() { + if (!url) return; + setIsLoading(true); + try { + const result = await queryScrapePerformerURL(url); + if (!result.data || !result.data.scrapePerformerURL) { + return; + } + + // leave URL as is if not set explicitly + if (!result.data.scrapePerformerURL.url) { + result.data.scrapePerformerURL.url = url; + } + updatePerformerEditStateFromScraper(result.data.scrapePerformerURL); + } catch (e) { + Toast.error(e); + } finally { + setIsLoading(false); + } + } + + function renderEthnicity() { + return TableUtils.renderInputGroup({ + title: "Ethnicity", + value: ethnicity, + isEditing: !!isEditing, + placeholder: "Ethnicity", + onChange: setEthnicity, + }); + } + + function renderScraperMenu() { + if (!performer || !isEditing) { + return; + } + + const popover = ( + + +
    + {queryableScrapers + ? queryableScrapers.map((s) => ( +
    + +
    + )) + : ""} +
    +
    +
    + ); + + return ( + + + + ); + } + + function renderScraperDialog() { + return ( + setIsDisplayingScraperDialog(undefined)} + header="Scrape" + accept={{ onClick: onScrapePerformer, text: "Scrape" }} + > +
    + setScrapePerformerDetails(query)} + /> +
    +
    + ); + } + + function urlScrapable(scrapedUrl: string) { + return ( + !!scrapedUrl && + (Scrapers?.data?.listPerformerScrapers ?? []).some((s) => + (s?.performer?.urls ?? []).some((u) => scrapedUrl.includes(u)) + ) + ); + } + + function maybeRenderScrapeButton() { + if (!url || !isEditing || !urlScrapable(url)) { + return undefined; + } + return ( + + ); + } + + function renderURLField() { + return ( + + + URL + {maybeRenderScrapeButton()} + + + {EditableTextUtils.renderInputGroup({ + title: "URL", + value: url, + url: TextUtils.sanitiseURL(url), + isEditing: !!isEditing, + onChange: setUrl, + })} + + + ); + } + + function maybeRenderButtons() { + if (isEditing) { + return ( +
    + + {!isNew ? ( + + ) : ( + "" + )} + {renderScraperMenu()} + +
    + ); + } + } + + function renderDeleteAlert() { + return ( + setIsDeleteAlertOpen(false) }} + > +

    Are you sure you want to delete {name}?

    +
    + ); + } + + function maybeRenderName() { + if (isEditing) { + return TableUtils.renderInputGroup({ + title: "Name", + value: name, + isEditing: !!isEditing, + placeholder: "Name", + onChange: setName, + }); + } + } + + function maybeRenderAliases() { + if (isEditing) { + return TableUtils.renderInputGroup({ + title: "Aliases", + value: aliases, + isEditing: !!isEditing, + placeholder: "Aliases", + onChange: setAliases, + }); + } + } + + function renderGender() { + return TableUtils.renderHtmlSelect({ + title: "Gender", + value: gender, + isEditing: !!isEditing, + onChange: (value: string) => setGender(value), + selectOptions: [""].concat(getGenderStrings()), + }); + } + + const formatHeight = () => { + if (isEditing) { + return height; + } + if (!height) { + return ""; + } + return intl.formatNumber(Number.parseInt(height, 10), { + style: "unit", + unit: "centimeter", + unitDisplay: "narrow", + }); + }; + + return ( + <> + {renderDeleteAlert()} + {renderScraperDialog()} + + + + {maybeRenderName()} + {maybeRenderAliases()} + {renderGender()} + {TableUtils.renderInputGroup({ + title: "Birthdate", + value: isEditing + ? birthdate + : TextUtils.formatDate(intl, birthdate), + isEditing: !!isEditing, + onChange: setBirthdate, + })} + {renderEthnicity()} + {TableUtils.renderInputGroup({ + title: "Eye Color", + value: eyeColor, + isEditing: !!isEditing, + onChange: setEyeColor, + })} + {TableUtils.renderInputGroup({ + title: "Country", + value: country, + isEditing: !!isEditing, + onChange: setCountry, + })} + {TableUtils.renderInputGroup({ + title: `Height ${isEditing ? "(cm)" : ""}`, + value: formatHeight(), + isEditing: !!isEditing, + onChange: setHeight, + })} + {TableUtils.renderInputGroup({ + title: "Measurements", + value: measurements, + isEditing: !!isEditing, + onChange: setMeasurements, + })} + {TableUtils.renderInputGroup({ + title: "Fake Tits", + value: fakeTits, + isEditing: !!isEditing, + onChange: setFakeTits, + })} + {TableUtils.renderInputGroup({ + title: "Career Length", + value: careerLength, + isEditing: !!isEditing, + onChange: setCareerLength, + })} + {TableUtils.renderInputGroup({ + title: "Tattoos", + value: tattoos, + isEditing: !!isEditing, + onChange: setTattoos, + })} + {TableUtils.renderInputGroup({ + title: "Piercings", + value: piercings, + isEditing: !!isEditing, + onChange: setPiercings, + })} + {renderURLField()} + {TableUtils.renderInputGroup({ + title: "Twitter", + value: twitter, + url: TextUtils.sanitiseURL(twitter, TextUtils.twitterURL), + isEditing: !!isEditing, + onChange: setTwitter, + })} + {TableUtils.renderInputGroup({ + title: "Instagram", + value: instagram, + url: TextUtils.sanitiseURL(instagram, TextUtils.instagramURL), + isEditing: !!isEditing, + onChange: setInstagram, + })} + +
    + + {maybeRenderButtons()} + + ); +}; diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerOperationsPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerOperationsPanel.tsx new file mode 100644 index 000000000..dc9850a57 --- /dev/null +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerOperationsPanel.tsx @@ -0,0 +1,29 @@ +import { Button } from "react-bootstrap"; +import React from "react"; +import * as GQL from "src/core/generated-graphql"; +import { mutateMetadataAutoTag } from "src/core/StashService"; +import { useToast } from "src/hooks"; + +interface IPerformerOperationsProps { + performer: Partial; +} + +export const PerformerOperationsPanel: React.FC = ({ + performer, +}) => { + const Toast = useToast(); + + async function onAutoTag() { + if (!performer?.id) { + return; + } + try { + await mutateMetadataAutoTag({ performers: [performer.id] }); + Toast.success({ content: "Started auto tagging" }); + } catch (e) { + Toast.error(e); + } + } + + return ; +}; diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScenesPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScenesPanel.tsx new file mode 100644 index 000000000..1ca04cef4 --- /dev/null +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerScenesPanel.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import * as GQL from "src/core/generated-graphql"; +import { PerformersCriterion } from "src/models/list-filter/criteria/performers"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { SceneList } from "src/components/Scenes/SceneList"; + +interface IPerformerDetailsProps { + performer: Partial; +} + +export const PerformerScenesPanel: React.FC = ({ + performer, +}) => { + function filterHook(filter: ListFilterModel) { + const performerValue = { id: performer.id!, label: performer.name! }; + // if performers is already present, then we modify it, otherwise add + let performerCriterion = filter.criteria.find((c) => { + return c.type === "performers"; + }) as PerformersCriterion; + + if ( + performerCriterion && + (performerCriterion.modifier === GQL.CriterionModifier.IncludesAll || + performerCriterion.modifier === GQL.CriterionModifier.Includes) + ) { + // add the performer if not present + if ( + !performerCriterion.value.find((p) => { + return p.id === performer.id; + }) + ) { + performerCriterion.value.push(performerValue); + } + + performerCriterion.modifier = GQL.CriterionModifier.IncludesAll; + } else { + // overwrite + performerCriterion = new PerformersCriterion(); + performerCriterion.value = [performerValue]; + filter.criteria.push(performerCriterion); + } + + return filter; + } + + return ; +}; diff --git a/ui/v2.5/src/components/Performers/PerformerList.tsx b/ui/v2.5/src/components/Performers/PerformerList.tsx new file mode 100644 index 000000000..869f42b5a --- /dev/null +++ b/ui/v2.5/src/components/Performers/PerformerList.tsx @@ -0,0 +1,75 @@ +import _ from "lodash"; +import React from "react"; +import { useHistory } from "react-router-dom"; +import { FindPerformersQueryResult } from "src/core/generated-graphql"; +import { queryFindPerformers } from "src/core/StashService"; +import { usePerformersList } from "src/hooks"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { DisplayMode } from "src/models/list-filter/types"; +import { PerformerCard } from "./PerformerCard"; +import { PerformerListTable } from "./PerformerListTable"; + +export const PerformerList: React.FC = () => { + const history = useHistory(); + const otherOperations = [ + { + text: "Open Random", + onClick: getRandom, + }, + ]; + + const listData = usePerformersList({ + otherOperations, + renderContent, + }); + + async function getRandom( + result: FindPerformersQueryResult, + filter: ListFilterModel + ) { + if (result.data?.findPerformers) { + const { count } = result.data.findPerformers; + const index = Math.floor(Math.random() * count); + const filterCopy = _.cloneDeep(filter); + filterCopy.itemsPerPage = 1; + filterCopy.currentPage = index + 1; + const singleResult = await queryFindPerformers(filterCopy); + if ( + singleResult && + singleResult.data && + singleResult.data.findPerformers && + singleResult.data.findPerformers.performers.length === 1 + ) { + const { id } = singleResult!.data!.findPerformers!.performers[0]!; + history.push(`/performers/${id}`); + } + } + } + + function renderContent( + result: FindPerformersQueryResult, + filter: ListFilterModel + ) { + if (!result.data?.findPerformers) { + return; + } + if (filter.displayMode === DisplayMode.Grid) { + return ( +
    + {result.data.findPerformers.performers.map((p) => ( + + ))} +
    + ); + } + if (filter.displayMode === DisplayMode.List) { + return ( + + ); + } + } + + return listData.template; +}; diff --git a/ui/v2.5/src/components/Performers/PerformerListTable.tsx b/ui/v2.5/src/components/Performers/PerformerListTable.tsx new file mode 100644 index 000000000..97ddad3dd --- /dev/null +++ b/ui/v2.5/src/components/Performers/PerformerListTable.tsx @@ -0,0 +1,69 @@ +/* eslint-disable jsx-a11y/control-has-associated-label */ + +import React from "react"; +import { Button, Table } from "react-bootstrap"; +import { Link } from "react-router-dom"; +import * as GQL from "src/core/generated-graphql"; +import { Icon } from "src/components/Shared"; +import { NavUtils } from "src/utils"; + +interface IPerformerListTableProps { + performers: GQL.PerformerDataFragment[]; +} + +export const PerformerListTable: React.FC = ( + props: IPerformerListTableProps +) => { + const renderPerformerRow = (performer: GQL.PerformerDataFragment) => ( + + + + {performer.name + + + + +
    {performer.name}
    + + + {performer.aliases ? performer.aliases : ""} + + {performer.favorite && ( + + )} + + + +
    {performer.scene_count}
    + + + {performer.birthdate} + {performer.height} + + ); + + return ( +
    + + + + + + + + + + + + {props.performers.map(renderPerformerRow)} +
    + NameAliasesFavouriteScene CountBirthdateHeight
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Performers/Performers.tsx b/ui/v2.5/src/components/Performers/Performers.tsx new file mode 100644 index 000000000..fd2c77b91 --- /dev/null +++ b/ui/v2.5/src/components/Performers/Performers.tsx @@ -0,0 +1,13 @@ +import React from "react"; +import { Route, Switch } from "react-router-dom"; +import { Performer } from "./PerformerDetails/Performer"; +import { PerformerList } from "./PerformerList"; + +const Performers = () => ( + + + + +); + +export default Performers; diff --git a/ui/v2.5/src/components/Performers/styles.scss b/ui/v2.5/src/components/Performers/styles.scss new file mode 100644 index 000000000..cbdbb8ea0 --- /dev/null +++ b/ui/v2.5/src/components/Performers/styles.scss @@ -0,0 +1,73 @@ +#performer-details { + .scrape-url-button { + color: $text-color; + float: right; + margin-right: 0.5rem; + } +} + +#performer-page { + flex-direction: row; + margin: 10px auto; + overflow: hidden; + + .image-container .performer { + max-height: 960px; + max-width: 100%; + } + + .performer-head { + display: inline-block; + margin-bottom: 2rem; + vertical-align: top; + + .name-icons { + margin-left: 10px; + + .not-favorite { + color: rgba(191, 204, 214, 0.5); + } + + .favorite { + color: #ff7373; + } + + .link { + color: rgb(191, 204, 214); + } + + .instagram { + color: pink; + } + } + } + + .alias { + font-weight: bold; + } +} + +.new-view { + margin-bottom: 2rem; + + .photo { + padding: 1rem 1rem 1rem 2rem; + width: 100%; + } +} + +.performer-card { + .flag-icon { + bottom: 1rem; + height: 2rem; + position: absolute; + right: 1rem; + width: 3rem; + } +} + +.card { + &.performer-card { + padding: 0 0 1rem 0; + } +} diff --git a/ui/v2.5/src/components/SceneFilenameParser/ParserField.ts b/ui/v2.5/src/components/SceneFilenameParser/ParserField.ts new file mode 100644 index 000000000..0a7fc378e --- /dev/null +++ b/ui/v2.5/src/components/SceneFilenameParser/ParserField.ts @@ -0,0 +1,70 @@ +export class ParserField { + public field: string; + public helperText?: string; + + constructor(field: string, helperText?: string) { + this.field = field; + this.helperText = helperText; + } + + public getFieldPattern() { + return `{${this.field}}`; + } + + static Title = new ParserField("title"); + static Ext = new ParserField("ext", "File extension"); + static Rating = new ParserField("rating"); + + static I = new ParserField("i", "Matches any ignored word"); + static D = new ParserField("d", "Matches any delimiter (.-_)"); + + static Performer = new ParserField("performer"); + static Studio = new ParserField("studio"); + static Tag = new ParserField("tag"); + + // date fields + static Date = new ParserField("date", "YYYY-MM-DD"); + static YYYY = new ParserField("yyyy", "Year"); + static YY = new ParserField("yy", "Year (20YY)"); + static MM = new ParserField("mm", "Two digit month"); + static MMM = new ParserField("mmm", "Three letter month (eg Jan)"); + static DD = new ParserField("dd", "Two digit date"); + static YYYYMMDD = new ParserField("yyyymmdd"); + static YYMMDD = new ParserField("yymmdd"); + static DDMMYYYY = new ParserField("ddmmyyyy"); + static DDMMYY = new ParserField("ddmmyy"); + static MMDDYYYY = new ParserField("mmddyyyy"); + static MMDDYY = new ParserField("mmddyy"); + + static validFields = [ + ParserField.Title, + ParserField.Ext, + ParserField.D, + ParserField.I, + ParserField.Rating, + ParserField.Performer, + ParserField.Studio, + ParserField.Tag, + ParserField.Date, + ParserField.YYYY, + ParserField.YY, + ParserField.MM, + ParserField.MMM, + ParserField.DD, + ParserField.YYYYMMDD, + ParserField.YYMMDD, + ParserField.DDMMYYYY, + ParserField.DDMMYY, + ParserField.MMDDYYYY, + ParserField.MMDDYY, + ]; + + static fullDateFields = [ + ParserField.YYYYMMDD, + ParserField.YYMMDD, + ParserField.DDMMYYYY, + ParserField.DDMMYY, + ParserField.MMDDYYYY, + ParserField.MMDDYY, + ]; +} diff --git a/ui/v2.5/src/components/SceneFilenameParser/ParserInput.tsx b/ui/v2.5/src/components/SceneFilenameParser/ParserInput.tsx new file mode 100644 index 000000000..f3016d952 --- /dev/null +++ b/ui/v2.5/src/components/SceneFilenameParser/ParserInput.tsx @@ -0,0 +1,254 @@ +import React, { useState } from "react"; +import { + Button, + Dropdown, + DropdownButton, + Form, + InputGroup, +} from "react-bootstrap"; +import { ParserField } from "./ParserField"; +import { ShowFields } from "./ShowFields"; + +const builtInRecipes = [ + { + pattern: "{title}", + ignoreWords: [], + whitespaceCharacters: "", + capitalizeTitle: false, + description: "Filename", + }, + { + pattern: "{title}.{ext}", + ignoreWords: [], + whitespaceCharacters: "", + capitalizeTitle: false, + description: "Without extension", + }, + { + pattern: "{}.{yy}.{mm}.{dd}.{title}.XXX.{}.{ext}", + ignoreWords: [], + whitespaceCharacters: ".", + capitalizeTitle: true, + description: "", + }, + { + pattern: "{}.{yy}.{mm}.{dd}.{title}.{ext}", + ignoreWords: [], + whitespaceCharacters: ".", + capitalizeTitle: true, + description: "", + }, + { + pattern: "{title}.XXX.{}.{ext}", + ignoreWords: [], + whitespaceCharacters: ".", + capitalizeTitle: true, + description: "", + }, + { + pattern: "{}.{yy}.{mm}.{dd}.{title}.{i}.{ext}", + ignoreWords: ["cz", "fr"], + whitespaceCharacters: ".", + capitalizeTitle: true, + description: "Foreign language", + }, +]; + +export interface IParserInput { + pattern: string; + ignoreWords: string[]; + whitespaceCharacters: string; + capitalizeTitle: boolean; + page: number; + pageSize: number; + findClicked: boolean; +} + +interface IParserRecipe { + pattern: string; + ignoreWords: string[]; + whitespaceCharacters: string; + capitalizeTitle: boolean; + description: string; +} + +interface IParserInputProps { + input: IParserInput; + onFind: (input: IParserInput) => void; + onPageSizeChanged: (newSize: number) => void; + showFields: Map; + setShowFields: (fields: Map) => void; +} + +export const ParserInput: React.FC = ( + props: IParserInputProps +) => { + const [pattern, setPattern] = useState(props.input.pattern); + const [ignoreWords, setIgnoreWords] = useState( + props.input.ignoreWords.join(" ") + ); + const [whitespaceCharacters, setWhitespaceCharacters] = useState( + props.input.whitespaceCharacters + ); + const [capitalizeTitle, setCapitalizeTitle] = useState( + props.input.capitalizeTitle + ); + + function onFind() { + props.onFind({ + pattern, + ignoreWords: ignoreWords.split(" "), + whitespaceCharacters, + capitalizeTitle, + page: 1, + pageSize: props.input.pageSize, + findClicked: props.input.findClicked, + }); + } + + function setParserRecipe(recipe: IParserRecipe) { + setPattern(recipe.pattern); + setIgnoreWords(recipe.ignoreWords.join(" ")); + setWhitespaceCharacters(recipe.whitespaceCharacters); + setCapitalizeTitle(recipe.capitalizeTitle); + } + + const validFields = [new ParserField("", "Wildcard")].concat( + ParserField.validFields + ); + + function addParserField(field: ParserField) { + setPattern(pattern + field.getFieldPattern()); + } + + const PAGE_SIZE_OPTIONS = ["20", "40", "60", "120"]; + + return ( + + + + Filename Pattern + + + ) => + setPattern(e.currentTarget.value) + } + value={pattern} + /> + + + {validFields.map((item) => ( + addParserField(item)} + > + {item.field || "{}"} + {item.helperText} + + ))} + + + + + Use '\' to escape literal {} characters + + + + + Ignored words + + ) => + setIgnoreWords(e.currentTarget.value) + } + value={ignoreWords} + /> + + + Matches with {"{i}"} + + + +
    Title
    + + + Whitespace characters: + + + ) => + setWhitespaceCharacters(e.currentTarget.value) + } + value={whitespaceCharacters} + /> + + + These characters will be replaced with whitespace in the title + + + + setCapitalizeTitle(!capitalizeTitle)} + /> + Capitalize title + + + {/* TODO - mapping stuff will go here */} + + + + {builtInRecipes.map((item) => ( + setParserRecipe(item)} + > + {item.pattern} + {item.description} + + ))} + + + + + props.setShowFields(fields)} + /> + + + + + ) => + props.onPageSizeChanged(parseInt(e.currentTarget.value, 10)) + } + defaultValue={props.input.pageSize} + className="col-1 input-control filter-item" + > + {PAGE_SIZE_OPTIONS.map((val) => ( + + ))} + + +
    + ); +}; diff --git a/ui/v2.5/src/components/SceneFilenameParser/SceneFilenameParser.tsx b/ui/v2.5/src/components/SceneFilenameParser/SceneFilenameParser.tsx new file mode 100644 index 000000000..a5d28f717 --- /dev/null +++ b/ui/v2.5/src/components/SceneFilenameParser/SceneFilenameParser.tsx @@ -0,0 +1,389 @@ +/* eslint-disable no-param-reassign, jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */ + +import React, { useEffect, useState, useCallback, useRef } from "react"; +import { Button, Card, Form, Table } from "react-bootstrap"; +import _ from "lodash"; +import { + queryParseSceneFilenames, + useScenesUpdate, +} from "src/core/StashService"; +import * as GQL from "src/core/generated-graphql"; +import { LoadingIndicator } from "src/components/Shared"; +import { useToast } from "src/hooks"; +import { Pagination } from "src/components/List/Pagination"; +import { IParserInput, ParserInput } from "./ParserInput"; +import { ParserField } from "./ParserField"; +import { SceneParserResult, SceneParserRow } from "./SceneParserRow"; + +const initialParserInput = { + pattern: "{title}.{ext}", + ignoreWords: [], + whitespaceCharacters: "._", + capitalizeTitle: true, + page: 1, + pageSize: 20, + findClicked: false, +}; + +const initialShowFieldsState = new Map([ + ["Title", true], + ["Date", true], + ["Rating", true], + ["Performers", true], + ["Tags", true], + ["Studio", true], +]); + +export const SceneFilenameParser: React.FC = () => { + const Toast = useToast(); + const [parserResult, setParserResult] = useState([]); + const [parserInput, setParserInput] = useState( + initialParserInput + ); + const prevParserInputRef = useRef(); + const prevParserInput = prevParserInputRef.current; + + const [allTitleSet, setAllTitleSet] = useState(false); + const [allDateSet, setAllDateSet] = useState(false); + const [allRatingSet, setAllRatingSet] = useState(false); + const [allPerformerSet, setAllPerformerSet] = useState(false); + const [allTagSet, setAllTagSet] = useState(false); + const [allStudioSet, setAllStudioSet] = useState(false); + + const [showFields, setShowFields] = useState>( + initialShowFieldsState + ); + + const [totalItems, setTotalItems] = useState(0); + + // Network state + const [isLoading, setIsLoading] = useState(false); + + const [updateScenes] = useScenesUpdate(getScenesUpdateData()); + + useEffect(() => { + prevParserInputRef.current = parserInput; + }, [parserInput]); + + const determineFieldsToHide = useCallback(() => { + const { pattern } = parserInput; + const titleSet = pattern.includes("{title}"); + const dateSet = + pattern.includes("{date}") || + pattern.includes("{dd}") || // don't worry about other partial date fields since this should be implied + ParserField.fullDateFields.some((f) => { + return pattern.includes(`{${f.field}}`); + }); + const ratingSet = pattern.includes("{rating}"); + const performerSet = pattern.includes("{performer}"); + const tagSet = pattern.includes("{tag}"); + const studioSet = pattern.includes("{studio}"); + + const newShowFields = new Map([ + ["Title", titleSet], + ["Date", dateSet], + ["Rating", ratingSet], + ["Performers", performerSet], + ["Tags", tagSet], + ["Studio", studioSet], + ]); + + setShowFields(newShowFields); + }, [parserInput]); + + const parseResults = useCallback( + ( + results: GQL.ParseSceneFilenamesQuery["parseSceneFilenames"]["results"] + ) => { + if (results) { + const result = results + .map((r) => { + return new SceneParserResult(r); + }) + .filter((r) => !!r) as SceneParserResult[]; + + setParserResult(result); + determineFieldsToHide(); + } + }, + [determineFieldsToHide] + ); + + const parseSceneFilenames = useCallback(() => { + setParserResult([]); + setIsLoading(true); + + const parserFilter = { + q: parserInput.pattern, + page: parserInput.page, + per_page: parserInput.pageSize, + sort: "path", + direction: GQL.SortDirectionEnum.Asc, + }; + + const parserInputData = { + ignoreWords: parserInput.ignoreWords, + whitespaceCharacters: parserInput.whitespaceCharacters, + capitalizeTitle: parserInput.capitalizeTitle, + }; + + queryParseSceneFilenames(parserFilter, parserInputData) + .then((response) => { + const result = response.data.parseSceneFilenames; + if (result) { + parseResults(result.results); + setTotalItems(result.count); + } + }) + .catch((err) => Toast.error(err)) + .finally(() => setIsLoading(false)); + }, [parserInput, parseResults, Toast]); + + useEffect(() => { + // only refresh if parserInput actually changed + if (prevParserInput === parserInput) { + return; + } + + if (parserInput.findClicked) { + parseSceneFilenames(); + } + }, [parserInput, parseSceneFilenames, prevParserInput]); + + function onPageSizeChanged(newSize: number) { + const newInput = _.clone(parserInput); + newInput.page = 1; + newInput.pageSize = newSize; + setParserInput(newInput); + } + + function onPageChanged(newPage: number) { + if (newPage !== parserInput.page) { + const newInput = _.clone(parserInput); + newInput.page = newPage; + setParserInput(newInput); + } + } + + function onFindClicked(input: IParserInput) { + const newInput = _.clone(input); + newInput.page = 1; + newInput.findClicked = true; + setParserInput(newInput); + setTotalItems(0); + } + + function getScenesUpdateData() { + return parserResult + .filter((result) => result.isChanged()) + .map((result) => result.toSceneUpdateInput()); + } + + async function onApply() { + setIsLoading(true); + + try { + await updateScenes(); + Toast.success({ content: "Updated scenes" }); + } catch (e) { + Toast.error(e); + } + + setIsLoading(false); + + // trigger a refresh of the results + onFindClicked(parserInput); + } + + useEffect(() => { + const newAllTitleSet = !parserResult.some((r) => { + return !r.title.isSet; + }); + const newAllDateSet = !parserResult.some((r) => { + return !r.date.isSet; + }); + const newAllRatingSet = !parserResult.some((r) => { + return !r.rating.isSet; + }); + const newAllPerformerSet = !parserResult.some((r) => { + return !r.performers.isSet; + }); + const newAllTagSet = !parserResult.some((r) => { + return !r.tags.isSet; + }); + const newAllStudioSet = !parserResult.some((r) => { + return !r.studio.isSet; + }); + + setAllTitleSet(newAllTitleSet); + setAllDateSet(newAllDateSet); + setAllRatingSet(newAllRatingSet); + setAllTagSet(newAllPerformerSet); + setAllTagSet(newAllTagSet); + setAllStudioSet(newAllStudioSet); + }, [parserResult]); + + function onSelectAllTitleSet(selected: boolean) { + const newResult = [...parserResult]; + + newResult.forEach((r) => { + r.title.isSet = selected; + }); + + setParserResult(newResult); + setAllTitleSet(selected); + } + + function onSelectAllDateSet(selected: boolean) { + const newResult = [...parserResult]; + + newResult.forEach((r) => { + r.date.isSet = selected; + }); + + setParserResult(newResult); + setAllDateSet(selected); + } + + function onSelectAllRatingSet(selected: boolean) { + const newResult = [...parserResult]; + + newResult.forEach((r) => { + r.rating.isSet = selected; + }); + + setParserResult(newResult); + setAllRatingSet(selected); + } + + function onSelectAllPerformerSet(selected: boolean) { + const newResult = [...parserResult]; + + newResult.forEach((r) => { + r.performers.isSet = selected; + }); + + setParserResult(newResult); + setAllPerformerSet(selected); + } + + function onSelectAllTagSet(selected: boolean) { + const newResult = [...parserResult]; + + newResult.forEach((r) => { + r.tags.isSet = selected; + }); + + setParserResult(newResult); + setAllTagSet(selected); + } + + function onSelectAllStudioSet(selected: boolean) { + const newResult = [...parserResult]; + + newResult.forEach((r) => { + r.studio.isSet = selected; + }); + + setParserResult(newResult); + setAllStudioSet(selected); + } + + function onChange(scene: SceneParserResult, changedScene: SceneParserResult) { + const newResult = [...parserResult]; + + const index = newResult.indexOf(scene); + newResult[index] = changedScene; + + setParserResult(newResult); + } + + function renderHeader( + fieldName: string, + allSet: boolean, + onAllSet: (set: boolean) => void + ) { + if (!showFields.get(fieldName)) { + return null; + } + + return ( + <> + + { + onAllSet(!allSet); + }} + /> + + {fieldName} + + ); + } + + function renderTable() { + if (parserResult.length === 0) { + return undefined; + } + + return ( + <> +
    + + + + + {renderHeader("Title", allTitleSet, onSelectAllTitleSet)} + {renderHeader("Date", allDateSet, onSelectAllDateSet)} + {renderHeader("Rating", allRatingSet, onSelectAllRatingSet)} + {renderHeader( + "Performers", + allPerformerSet, + onSelectAllPerformerSet + )} + {renderHeader("Tags", allTagSet, onSelectAllTagSet)} + {renderHeader("Studio", allStudioSet, onSelectAllStudioSet)} + + + + {parserResult.map((scene) => ( + onChange(scene, changedScene)} + showFields={showFields} + /> + ))} + +
    Filename
    +
    + onPageChanged(page)} + /> + + + ); + } + + return ( + +

    Scene Filename Parser

    + onFindClicked(input)} + onPageSizeChanged={onPageSizeChanged} + showFields={showFields} + setShowFields={setShowFields} + /> + + {isLoading && } + {renderTable()} +
    + ); +}; diff --git a/ui/v2.5/src/components/SceneFilenameParser/SceneParserRow.tsx b/ui/v2.5/src/components/SceneFilenameParser/SceneParserRow.tsx new file mode 100644 index 000000000..b95308361 --- /dev/null +++ b/ui/v2.5/src/components/SceneFilenameParser/SceneParserRow.tsx @@ -0,0 +1,461 @@ +import React from "react"; +import _ from "lodash"; +import { Form } from "react-bootstrap"; +import { + ParseSceneFilenamesQuery, + SlimSceneDataFragment, +} from "src/core/generated-graphql"; +import { + PerformerSelect, + TagSelect, + StudioSelect, +} from "src/components/Shared"; +import { TextUtils } from "src/utils"; + +class ParserResult { + public value?: T; + public originalValue?: T; + public isSet: boolean = false; + + public setOriginalValue(value?: T) { + this.originalValue = value; + this.value = value; + } + + public setValue(value?: T) { + if (value) { + this.value = value; + this.isSet = !_.isEqual(this.value, this.originalValue); + } + } +} + +export class SceneParserResult { + public id: string; + public filename: string; + public title: ParserResult = new ParserResult(); + public date: ParserResult = new ParserResult(); + public rating: ParserResult = new ParserResult(); + + public studio: ParserResult = new ParserResult(); + public tags: ParserResult = new ParserResult(); + public performers: ParserResult = new ParserResult(); + + public scene: SlimSceneDataFragment; + + constructor( + result: ParseSceneFilenamesQuery["parseSceneFilenames"]["results"][0] + ) { + this.scene = result.scene; + + this.id = this.scene.id; + this.filename = TextUtils.fileNameFromPath(this.scene.path); + this.title.setOriginalValue(this.scene.title ?? undefined); + this.date.setOriginalValue(this.scene.date ?? undefined); + this.rating.setOriginalValue(this.scene.rating ?? undefined); + this.performers.setOriginalValue(this.scene.performers.map((p) => p.id)); + this.tags.setOriginalValue(this.scene.tags.map((t) => t.id)); + this.studio.setOriginalValue(this.scene.studio?.id); + + this.title.setValue(result.title ?? undefined); + this.date.setValue(result.date ?? undefined); + this.rating.setValue(result.rating ?? undefined); + + this.performers.setValue(result.performer_ids ?? undefined); + this.tags.setValue(result.tag_ids ?? undefined); + this.studio.setValue(result.studio_id ?? undefined); + } + + // returns true if any of its fields have set == true + public isChanged() { + return ( + this.title.isSet || + this.date.isSet || + this.rating.isSet || + this.performers.isSet || + this.studio.isSet || + this.tags.isSet + ); + } + + public toSceneUpdateInput() { + return { + id: this.id, + details: this.scene.details, + url: this.scene.url, + rating: this.rating.isSet ? this.rating.value : this.scene.rating, + gallery_id: this.scene.gallery?.id, + title: this.title.isSet ? this.title.value : this.scene.title, + date: this.date.isSet ? this.date.value : this.scene.date, + studio_id: this.studio.isSet ? this.studio.value : this.scene.studio?.id, + performer_ids: this.performers.isSet + ? this.performers.value + : this.scene.performers.map((performer) => performer.id), + tag_ids: this.tags.isSet + ? this.tags.value + : this.scene.tags.map((tag) => tag.id), + }; + } +} + +interface ISceneParserFieldProps { + parserResult: ParserResult; + className?: string; + fieldName: string; + onSetChanged: (isSet: boolean) => void; + onValueChanged: (value: T) => void; + originalParserResult?: ParserResult; +} + +function SceneParserStringField(props: ISceneParserFieldProps) { + function maybeValueChanged(value: string) { + if (value !== props.parserResult.value) { + props.onValueChanged(value); + } + } + + const result = props.originalParserResult || props.parserResult; + + return ( + <> + + { + props.onSetChanged(!props.parserResult.isSet); + }} + /> + + + + + ) => + maybeValueChanged(event.currentTarget.value) + } + /> + + + + ); +} + +function SceneParserRatingField( + props: ISceneParserFieldProps +) { + function maybeValueChanged(value?: number) { + if (value !== props.parserResult.value) { + props.onValueChanged(value); + } + } + + const result = props.originalParserResult || props.parserResult; + const options = ["", 1, 2, 3, 4, 5]; + + return ( + <> + + { + props.onSetChanged(!props.parserResult.isSet); + }} + /> + + + + + ) => + maybeValueChanged( + event.currentTarget.value === "" + ? undefined + : Number.parseInt(event.currentTarget.value, 10) + ) + } + > + {options.map((opt) => ( + + ))} + + + + + ); +} + +function SceneParserPerformerField(props: ISceneParserFieldProps) { + function maybeValueChanged(value: string[]) { + if (value !== props.parserResult.value) { + props.onValueChanged(value); + } + } + + const originalPerformers = (props.originalParserResult?.originalValue ?? + []) as string[]; + const newPerformers = props.parserResult.value ?? []; + + return ( + <> + + { + props.onSetChanged(!props.parserResult.isSet); + }} + /> + + + + + { + maybeValueChanged(items.map((i) => i.id)); + }} + ids={newPerformers} + /> + + + + ); +} + +function SceneParserTagField(props: ISceneParserFieldProps) { + function maybeValueChanged(value: string[]) { + if (value !== props.parserResult.value) { + props.onValueChanged(value); + } + } + + const originalTags = props.originalParserResult?.originalValue ?? []; + const newTags = props.parserResult.value ?? []; + + return ( + <> + + { + props.onSetChanged(!props.parserResult.isSet); + }} + /> + + + + + { + maybeValueChanged(items.map((i) => i.id)); + }} + ids={newTags} + /> + + + + ); +} + +function SceneParserStudioField(props: ISceneParserFieldProps) { + function maybeValueChanged(value: string) { + if (value !== props.parserResult.value) { + props.onValueChanged(value); + } + } + + const originalStudio = props.originalParserResult?.originalValue + ? [props.originalParserResult?.originalValue] + : []; + const newStudio = props.parserResult.value ? [props.parserResult.value] : []; + + return ( + <> + + { + props.onSetChanged(!props.parserResult.isSet); + }} + /> + + + + + { + maybeValueChanged(items[0].id); + }} + ids={newStudio} + /> + + + + ); +} + +interface ISceneParserRowProps { + scene: SceneParserResult; + onChange: (changedScene: SceneParserResult) => void; + showFields: Map; +} + +export const SceneParserRow = (props: ISceneParserRowProps) => { + function changeParser(result: ParserResult, isSet: boolean, value?: T) { + const newParser = _.clone(result); + newParser.isSet = isSet; + newParser.value = value; + return newParser; + } + + function onTitleChanged(set: boolean, value: string) { + const newResult = _.clone(props.scene); + newResult.title = changeParser(newResult.title, set, value); + props.onChange(newResult); + } + + function onDateChanged(set: boolean, value: string) { + const newResult = _.clone(props.scene); + newResult.date = changeParser(newResult.date, set, value); + props.onChange(newResult); + } + + function onRatingChanged(set: boolean, value?: number) { + const newResult = _.clone(props.scene); + newResult.rating = changeParser(newResult.rating, set, value); + props.onChange(newResult); + } + + function onPerformerIdsChanged(set: boolean, value: string[]) { + const newResult = _.clone(props.scene); + newResult.performers = changeParser(newResult.performers, set, value); + props.onChange(newResult); + } + + function onTagIdsChanged(set: boolean, value: string[]) { + const newResult = _.clone(props.scene); + newResult.tags = changeParser(newResult.tags, set, value); + props.onChange(newResult); + } + + function onStudioIdChanged(set: boolean, value: string) { + const newResult = _.clone(props.scene); + newResult.studio = changeParser(newResult.studio, set, value); + props.onChange(newResult); + } + + return ( + + + {props.scene.filename} + + {props.showFields.get("Title") && ( + + onTitleChanged(isSet, props.scene.title.value ?? "") + } + onValueChanged={(value) => + onTitleChanged(props.scene.title.isSet, value) + } + /> + )} + {props.showFields.get("Date") && ( + + onDateChanged(isSet, props.scene.date.value ?? "") + } + onValueChanged={(value) => + onDateChanged(props.scene.date.isSet, value) + } + /> + )} + {props.showFields.get("Rating") && ( + + onRatingChanged(isSet, props.scene.rating.value ?? undefined) + } + onValueChanged={(value) => + onRatingChanged(props.scene.rating.isSet, value) + } + /> + )} + {props.showFields.get("Performers") && ( + + onPerformerIdsChanged(set, props.scene.performers.value ?? []) + } + onValueChanged={(value) => + onPerformerIdsChanged(props.scene.performers.isSet, value) + } + /> + )} + {props.showFields.get("Tags") && ( + + onTagIdsChanged(isSet, props.scene.tags.value ?? []) + } + onValueChanged={(value) => + onTagIdsChanged(props.scene.tags.isSet, value) + } + /> + )} + {props.showFields.get("Studio") && ( + + onStudioIdChanged(set, props.scene.studio.value ?? "") + } + onValueChanged={(value) => + onStudioIdChanged(props.scene.studio.isSet, value) + } + /> + )} + + ); +}; diff --git a/ui/v2.5/src/components/SceneFilenameParser/ShowFields.tsx b/ui/v2.5/src/components/SceneFilenameParser/ShowFields.tsx new file mode 100644 index 000000000..d10060184 --- /dev/null +++ b/ui/v2.5/src/components/SceneFilenameParser/ShowFields.tsx @@ -0,0 +1,43 @@ +import React, { useState } from "react"; +import { Button, Collapse } from "react-bootstrap"; +import { Icon } from "src/components/Shared"; + +interface IShowFieldsProps { + fields: Map; + onShowFieldsChanged: (fields: Map) => void; +} + +export const ShowFields = (props: IShowFieldsProps) => { + const [open, setOpen] = useState(false); + + function handleClick(label: string) { + const copy = new Map(props.fields); + copy.set(label, !props.fields.get(label)); + props.onShowFieldsChanged(copy); + } + + const fieldRows = [...props.fields.entries()].map(([label, enabled]) => ( + + )); + + return ( +
    + + +
    {fieldRows}
    +
    +
    + ); +}; diff --git a/ui/v2.5/src/components/SceneFilenameParser/styles.scss b/ui/v2.5/src/components/SceneFilenameParser/styles.scss new file mode 100644 index 000000000..8a9bef656 --- /dev/null +++ b/ui/v2.5/src/components/SceneFilenameParser/styles.scss @@ -0,0 +1,49 @@ +#recipe-select::after { + content: none; +} + +.scene-parser-results { + margin-left: 31ch; + overflow-x: auto; +} + +.scene-parser-row { + .parser-field-filename { + left: 1ch; + position: absolute; + width: 30ch; + } + + .parser-field-title { + width: 40ch; + } + + .parser-field-date { + width: 13ch; + } + + .parser-field-performers { + width: 30ch; + } + + .parser-field-tags { + width: 30ch; + } + + .parser-field-studio { + width: 20ch; + } + + .form-control { + min-width: 10ch; + } + + .form-control + .form-control { + margin-top: 0.5rem; + } + + .badge-items { + background-color: #e9ecef; + margin-bottom: 0.25rem; + } +} diff --git a/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx b/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx new file mode 100644 index 000000000..c3451f3a2 --- /dev/null +++ b/ui/v2.5/src/components/ScenePlayer/ScenePlayer.tsx @@ -0,0 +1,225 @@ +import React from "react"; +import ReactJWPlayer from "react-jw-player"; +import * as GQL from "src/core/generated-graphql"; +import { useConfiguration } from "src/core/StashService"; +import { JWUtils } from "src/utils"; +import { ScenePlayerScrubber } from "./ScenePlayerScrubber"; + +interface IScenePlayerProps { + scene: GQL.SceneDataFragment; + timestamp: number; + autoplay?: boolean; + onReady?: () => void; + onSeeked?: () => void; + onTime?: () => void; + config?: GQL.ConfigInterfaceDataFragment; +} +interface IScenePlayerState { + scrubberPosition: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + config: Record; +} + +export class ScenePlayerImpl extends React.Component< + IScenePlayerProps, + IScenePlayerState +> { + // Typings for jwplayer are, unfortunately, very lacking + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private player: any; + private lastTime = 0; + + constructor(props: IScenePlayerProps) { + super(props); + this.onReady = this.onReady.bind(this); + this.onSeeked = this.onSeeked.bind(this); + this.onTime = this.onTime.bind(this); + + this.onScrubberSeek = this.onScrubberSeek.bind(this); + this.onScrubberScrolled = this.onScrubberScrolled.bind(this); + + this.state = { + scrubberPosition: 0, + config: this.makeJWPlayerConfig(props.scene), + }; + } + + public UNSAFE_componentWillReceiveProps(props: IScenePlayerProps) { + if (props.scene !== this.props.scene) { + this.setState((state) => ({ + ...state, + config: this.makeJWPlayerConfig(this.props.scene), + })); + } + } + + public componentDidUpdate(prevProps: IScenePlayerProps) { + if (prevProps.timestamp !== this.props.timestamp) { + this.player.seek(this.props.timestamp); + } + } + + onIncrease() { + const currentPlaybackRate = this.player ? this.player.getPlaybackRate() : 1; + this.player.setPlaybackRate(currentPlaybackRate + 0.5); + } + onDecrease() { + const currentPlaybackRate = this.player ? this.player.getPlaybackRate() : 1; + this.player.setPlaybackRate(currentPlaybackRate - 0.5); + } + + onReset() { + this.player.setPlaybackRate(1); + } + onPause() { + if (this.player.getState().paused) this.player.play(); + else this.player.pause(); + } + + private onReady() { + this.player = JWUtils.getPlayer(); + if (this.props.timestamp > 0) { + this.player.seek(this.props.timestamp); + } + } + + private onSeeked() { + const position = this.player.getPosition(); + this.setState({ scrubberPosition: position }); + this.player.play(); + } + + private onTime() { + const position = this.player.getPosition(); + const difference = Math.abs(position - this.lastTime); + if (difference > 1) { + this.lastTime = position; + this.setState({ scrubberPosition: position }); + } + } + + private onScrubberSeek(seconds: number) { + this.player.seek(seconds); + } + + private onScrubberScrolled() { + this.player.pause(); + } + + private shouldRepeat(scene: GQL.SceneDataFragment) { + const maxLoopDuration = this.state?.config.maximumLoopDuration ?? 0; + return ( + !!scene.file.duration && + !!maxLoopDuration && + scene.file.duration < maxLoopDuration + ); + } + + private makeJWPlayerConfig(scene: GQL.SceneDataFragment) { + if (!scene.paths.stream) { + return {}; + } + + const repeat = this.shouldRepeat(scene); + let getDurationHook: (() => GQL.Maybe) | undefined; + let seekHook: + | ((seekToPosition: number, _videoTag: HTMLVideoElement) => void) + | undefined; + let getCurrentTimeHook: + | ((_videoTag: HTMLVideoElement) => number) + | undefined; + + if (!this.props.scene.is_streamable) { + getDurationHook = () => { + return this.props.scene.file.duration ?? null; + }; + + seekHook = (seekToPosition: number, _videoTag: HTMLVideoElement) => { + /* eslint-disable no-param-reassign */ + _videoTag.dataset.start = seekToPosition.toString(); + _videoTag.src = `${this.props.scene.paths.stream}?start=${seekToPosition}`; + /* eslint-enable no-param-reassign */ + _videoTag.play(); + }; + + getCurrentTimeHook = (_videoTag: HTMLVideoElement) => { + const start = Number.parseInt(_videoTag.dataset?.start ?? "0", 10); + return _videoTag.currentTime + start; + }; + } + + const ret = { + file: scene.paths.stream, + image: scene.paths.screenshot, + tracks: [ + { + file: scene.paths.vtt, + kind: "thumbnails", + }, + { + file: scene.paths.chapters_vtt, + kind: "chapters", + }, + ], + aspectratio: "16:9", + width: "100%", + floating: { + dismissible: true, + }, + cast: {}, + primary: "html5", + autostart: + this.props.autoplay || + (this.props.config ? this.props.config.autostartVideo : false), + repeat, + playbackRateControls: true, + playbackRates: [0.75, 1, 1.5, 2, 3, 4], + getDurationHook, + seekHook, + getCurrentTimeHook, + }; + + return ret; + } + + public render() { + return ( +
    + + +
    + ); + } +} + +export const ScenePlayer: React.FC = ( + props: IScenePlayerProps +) => { + const config = useConfiguration(); + + return ( + + ); +}; diff --git a/ui/v2.5/src/components/ScenePlayer/ScenePlayerScrubber.tsx b/ui/v2.5/src/components/ScenePlayer/ScenePlayerScrubber.tsx new file mode 100644 index 000000000..ffbdff9ae --- /dev/null +++ b/ui/v2.5/src/components/ScenePlayer/ScenePlayerScrubber.tsx @@ -0,0 +1,387 @@ +/* eslint-disable react/no-array-index-key */ + +import React, { + CSSProperties, + useEffect, + useRef, + useState, + useCallback, +} from "react"; +import { Button } from "react-bootstrap"; +import axios from "axios"; +import * as GQL from "src/core/generated-graphql"; +import { TextUtils } from "src/utils"; + +interface IScenePlayerScrubberProps { + scene: GQL.SceneDataFragment; + position: number; + onSeek: (seconds: number) => void; + onScrolled: () => void; +} + +interface ISceneSpriteItem { + start: number; + end: number; + x: number; + y: number; + w: number; + h: number; +} + +async function fetchSpriteInfo(vttPath: string) { + const response = await axios.get(vttPath, { responseType: "text" }); + + // TODO: This is gnarly + const lines = response.data.split("\n"); + if (lines.shift() !== "WEBVTT") { + return; + } + if (lines.shift() !== "") { + return; + } + let item: ISceneSpriteItem = { start: 0, end: 0, x: 0, y: 0, w: 0, h: 0 }; + const newSpriteItems: ISceneSpriteItem[] = []; + while (lines.length) { + const line = lines.shift(); + if (line !== undefined) { + if (line.includes("#") && line.includes("=") && line.includes(",")) { + const size = line.split("#")[1].split("=")[1].split(","); + item.x = Number(size[0]); + item.y = Number(size[1]); + item.w = Number(size[2]); + item.h = Number(size[3]); + + newSpriteItems.push(item); + item = { start: 0, end: 0, x: 0, y: 0, w: 0, h: 0 }; + } else if (line.includes(" --> ")) { + const times = line.split(" --> "); + + const start = times[0].split(":"); + item.start = +start[0] * 60 * 60 + +start[1] * 60 + +start[2]; + + const end = times[1].split(":"); + item.end = +end[0] * 60 * 60 + +end[1] * 60 + +end[2]; + } + } + } + + return newSpriteItems; +} + +export const ScenePlayerScrubber: React.FC = ( + props: IScenePlayerScrubberProps +) => { + const contentEl = useRef(null); + const positionIndicatorEl = useRef(null); + const scrubberSliderEl = useRef(null); + const mouseDown = useRef(false); + const lastMouseEvent = useRef(null); + const startMouseEvent = useRef(null); + const velocity = useRef(0); + + const _position = useRef(0); + const getPosition = useCallback(() => _position.current, []); + const setPosition = useCallback( + (newPostion: number, shouldEmit: boolean = true) => { + if (!scrubberSliderEl.current || !positionIndicatorEl.current) { + return; + } + if (shouldEmit) { + props.onScrolled(); + } + + const midpointOffset = scrubberSliderEl.current.clientWidth / 2; + + const bounds = getBounds() * -1; + if (newPostion > midpointOffset) { + _position.current = midpointOffset; + } else if (newPostion < bounds - midpointOffset) { + _position.current = bounds - midpointOffset; + } else { + _position.current = newPostion; + } + + scrubberSliderEl.current.style.transform = `translateX(${_position.current}px)`; + + const indicatorPosition = + ((newPostion - midpointOffset) / (bounds - midpointOffset * 2)) * + scrubberSliderEl.current.clientWidth; + positionIndicatorEl.current.style.transform = `translateX(${indicatorPosition}px)`; + }, + [props] + ); + + const [spriteItems, setSpriteItems] = useState([]); + + useEffect(() => { + if (!scrubberSliderEl.current) { + return; + } + scrubberSliderEl.current.style.transform = `translateX(${ + scrubberSliderEl.current.clientWidth / 2 + }px)`; + }, [scrubberSliderEl]); + + useEffect(() => { + if (!props.scene.paths.vtt) return; + fetchSpriteInfo(props.scene.paths.vtt).then((sprites) => { + if (sprites) setSpriteItems(sprites); + }); + }, [props.scene]); + + useEffect(() => { + if (!scrubberSliderEl.current) { + return; + } + const duration = Number(props.scene.file.duration); + const percentage = props.position / duration; + const position = + (scrubberSliderEl.current.scrollWidth * percentage - + scrubberSliderEl.current.clientWidth / 2) * + -1; + setPosition(position, false); + }, [props.position, props.scene.file.duration, setPosition]); + + useEffect(() => { + window.addEventListener("mouseup", onMouseUp, false); + return () => { + window.removeEventListener("mouseup", onMouseUp); + }; + }); + + useEffect(() => { + if (!contentEl.current) { + return; + } + const el = contentEl.current; + el.addEventListener("mousedown", onMouseDown, false); + return () => { + if (!el) { + return; + } + el.removeEventListener("mousedown", onMouseDown); + }; + }); + + useEffect(() => { + if (!contentEl.current) { + return; + } + const el = contentEl.current; + el.addEventListener("mousemove", onMouseMove, false); + return () => { + if (!el) { + return; + } + el.removeEventListener("mousemove", onMouseMove); + }; + }); + + function onMouseUp(this: Window, event: MouseEvent) { + if (!startMouseEvent.current || !scrubberSliderEl.current) { + return; + } + mouseDown.current = false; + const delta = Math.abs(event.clientX - startMouseEvent.current.clientX); + if (delta < 1 && event.target instanceof HTMLDivElement) { + const { target } = event; + let seekSeconds: number | undefined; + + const spriteIdString = target.getAttribute("data-sprite-item-id"); + if (spriteIdString != null) { + const spritePercentage = event.offsetX / target.clientWidth; + const offset = + target.offsetLeft + target.clientWidth * spritePercentage; + const percentage = offset / scrubberSliderEl.current.scrollWidth; + seekSeconds = percentage * (props.scene.file.duration || 0); + } + + const markerIdString = target.getAttribute("data-marker-id"); + if (markerIdString != null) { + const marker = props.scene.scene_markers[Number(markerIdString)]; + seekSeconds = marker.seconds; + } + + if (seekSeconds) { + props.onSeek(seekSeconds); + } + } else if (Math.abs(velocity.current) > 25) { + const newPosition = getPosition() + velocity.current * 10; + setPosition(newPosition); + velocity.current = 0; + } + } + + function onMouseDown(this: HTMLDivElement, event: MouseEvent) { + event.preventDefault(); + mouseDown.current = true; + lastMouseEvent.current = event; + startMouseEvent.current = event; + velocity.current = 0; + } + + function onMouseMove(this: HTMLDivElement, event: MouseEvent) { + if (!mouseDown.current) { + return; + } + + // negative dragging right (past), positive left (future) + const delta = event.clientX - (lastMouseEvent.current?.clientX ?? 0); + + const movement = event.movementX; + velocity.current = movement; + + const newPostion = getPosition() + delta; + setPosition(newPostion); + lastMouseEvent.current = event; + } + + function getBounds(): number { + if (!scrubberSliderEl.current || !positionIndicatorEl.current) { + return 0; + } + return ( + scrubberSliderEl.current.scrollWidth - + scrubberSliderEl.current.clientWidth + ); + } + + function goBack() { + if (!scrubberSliderEl.current) { + return; + } + const newPosition = getPosition() + scrubberSliderEl.current.clientWidth; + setPosition(newPosition); + } + + function goForward() { + if (!scrubberSliderEl.current) { + return; + } + const newPosition = getPosition() - scrubberSliderEl.current.clientWidth; + setPosition(newPosition); + } + + function renderTags() { + function getTagStyle(i: number): CSSProperties { + if ( + !scrubberSliderEl.current || + spriteItems.length === 0 || + getBounds() === 0 + ) { + return {}; + } + + const tags = window.document.getElementsByClassName("scrubber-tag"); + if (tags.length === 0) { + return {}; + } + + let tag: Element | null; + for (let index = 0; index < tags.length; index++) { + tag = tags.item(index); + const id = tag?.getAttribute("data-marker-id") ?? null; + if (id === i.toString()) { + break; + } + } + + const marker = props.scene.scene_markers[i]; + const duration = Number(props.scene.file.duration); + const percentage = marker.seconds / duration; + + const left = + scrubberSliderEl.current.scrollWidth * percentage - + tag!.clientWidth / 2; + return { + left: `${left}px`, + height: 20, + }; + } + + return props.scene.scene_markers.map((marker, index) => { + const dataAttrs = { + "data-marker-id": index, + }; + return ( +
    + {marker.title} +
    + ); + }); + } + + function renderSprites() { + function getStyleForSprite(index: number): CSSProperties { + if (!props.scene.paths.vtt) { + return {}; + } + const sprite = spriteItems[index]; + const left = sprite.w * index; + const path = props.scene.paths.vtt.replace("_thumbs.vtt", "_sprite.jpg"); // TODO: Gnarly + return { + width: `${sprite.w}px`, + height: `${sprite.h}px`, + margin: "0px auto", + backgroundPosition: `${-sprite.x}px ${-sprite.y}px`, + backgroundImage: `url(${path})`, + left: `${left}px`, + }; + } + + return spriteItems.map((spriteItem, index) => { + const dataAttrs = { + "data-sprite-item-id": index, + }; + return ( +
    + + {TextUtils.secondsToTimestamp(spriteItem.start)} -{" "} + {TextUtils.secondsToTimestamp(spriteItem.end)} + +
    + ); + }); + } + + return ( +
    + +
    +
    +
    +
    +
    +
    +
    {renderTags()}
    + {renderSprites()} +
    +
    +
    + +
    + ); +}; diff --git a/ui/v2.5/src/components/ScenePlayer/index.ts b/ui/v2.5/src/components/ScenePlayer/index.ts new file mode 100644 index 000000000..d2780083c --- /dev/null +++ b/ui/v2.5/src/components/ScenePlayer/index.ts @@ -0,0 +1 @@ +export { ScenePlayer } from "./ScenePlayer"; diff --git a/ui/v2.5/src/components/ScenePlayer/styles.scss b/ui/v2.5/src/components/ScenePlayer/styles.scss new file mode 100644 index 000000000..3e6f2dab5 --- /dev/null +++ b/ui/v2.5/src/components/ScenePlayer/styles.scss @@ -0,0 +1,135 @@ +.scene-player:focus { + outline: 0; +} + +.scrubber-wrapper { + margin: 5px 0; + overflow: hidden; + position: relative; +} + +#scrubber-back { + float: left; +} + +#scrubber-forward { + float: right; +} + +.scrubber-button { + background-color: transparent; + border: 1px solid #555; + color: $link-color; + cursor: pointer; + font-size: 20px; + font-weight: 800; + height: 100%; + line-height: 120px; + padding: 0; + text-align: center; + width: 1.5%; +} + +.scrubber-content { + cursor: grab; + display: inline-block; + height: 120px; + margin: 0 0.5%; + overflow: hidden; + -webkit-overflow-scrolling: touch; + position: relative; + -webkit-user-select: none; + width: 96%; + + &.dragging { + cursor: grabbing; + } +} + +#scrubber-position-indicator { + background-color: #ccc; + height: 20px; + left: -100%; + position: absolute; + width: 100%; + z-index: 0; +} + +#scrubber-current-position { + background-color: #fff; + height: 30px; + left: 50%; + position: absolute; + width: 2px; + z-index: 1; +} + +.scrubber-viewport { + height: 100%; + overflow: hidden; + position: static; +} + +.scrubber-slider { + height: 100%; + left: 0; + position: absolute; + transition: 333ms ease-out; + width: 100%; +} + +.scrubber-tags { + height: 20px; + margin-bottom: 10px; + position: relative; + + &-background { + background-color: #555; + height: 20px; + left: 0; + position: absolute; + right: 0; + } +} + +.scrubber-tag { + background-color: #000; + cursor: pointer; + font-size: 10px; + padding: 0 10px; + position: absolute; + white-space: nowrap; + + &:hover { + background-color: #444; + z-index: 1; + } + + &::after { + border-left: solid 5px transparent; + border-right: solid 5px transparent; + border-top: solid 5px #000; + bottom: -5px; + content: ""; + left: 50%; + margin-left: -5px; + position: absolute; + } +} + +.scrubber-item { + color: white; + cursor: pointer; + display: flex; + font-size: 10px; + margin-right: 10px; + position: absolute; + text-align: center; + text-shadow: 1px 1px black; + + &-time { + align-self: flex-end; + display: inline-block; + width: 100%; + } +} diff --git a/ui/v2.5/src/components/Scenes/SceneCard.tsx b/ui/v2.5/src/components/Scenes/SceneCard.tsx new file mode 100644 index 000000000..07e5ca12d --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneCard.tsx @@ -0,0 +1,285 @@ +import React, { useState } from "react"; +import { Button, ButtonGroup, Card, Form } from "react-bootstrap"; +import { Link } from "react-router-dom"; +import cx from "classnames"; +import * as GQL from "src/core/generated-graphql"; +import { useConfiguration } from "src/core/StashService"; +import { useVideoHover } from "src/hooks"; +import { Icon, TagLink, HoverPopover, SweatDrops } from "src/components/Shared"; +import { TextUtils } from "src/utils"; + +interface ISceneCardProps { + scene: GQL.SlimSceneDataFragment; + selected: boolean | undefined; + zoomIndex: number; + onSelectedChanged: (selected: boolean, shiftKey: boolean) => void; +} + +export const SceneCard: React.FC = ( + props: ISceneCardProps +) => { + const [previewPath, setPreviewPath] = useState(); + const hoverHandler = useVideoHover({ + resetOnMouseLeave: false, + }); + + const config = useConfiguration(); + const showStudioAsText = + config?.data?.configuration.interface.showStudioAsText ?? false; + + function maybeRenderRatingBanner() { + if (!props.scene.rating) { + return; + } + return ( +
    + RATING: {props.scene.rating} +
    + ); + } + + function maybeRenderSceneSpecsOverlay() { + return ( +
    + {props.scene.file.height ? ( + + {" "} + {TextUtils.resolution(props.scene.file.height)} + + ) : ( + "" + )} + {(props.scene.file.duration ?? 0) >= 1 + ? TextUtils.secondsToTimestamp(props.scene.file.duration ?? 0) + : ""} +
    + ); + } + + function maybeRenderSceneStudioOverlay() { + if (!props.scene.studio) return; + + return ( +
    + + {showStudioAsText ? ( + props.scene.studio.name + ) : ( + {props.scene.studio.name} + )} + +
    + ); + } + + function maybeRenderTagPopoverButton() { + if (props.scene.tags.length <= 0) return; + + const popoverContent = props.scene.tags.map((tag) => ( + + )); + + return ( + + + + ); + } + + function maybeRenderPerformerPopoverButton() { + if (props.scene.performers.length <= 0) return; + + const popoverContent = props.scene.performers.map((performer) => ( +
    + + {performer.name + + +
    + )); + + return ( + + + + ); + } + + function maybeRenderMoviePopoverButton() { + if (props.scene.movies.length <= 0) return; + + const popoverContent = props.scene.movies.map((sceneMovie) => ( +
    + + {sceneMovie.movie.name + + +
    + )); + + return ( + + + + ); + } + + function maybeRenderSceneMarkerPopoverButton() { + if (props.scene.scene_markers.length <= 0) return; + + const popoverContent = props.scene.scene_markers.map((marker) => { + const markerPopover = { ...marker, scene: { id: props.scene.id } }; + return ; + }); + + return ( + + + + ); + } + + function maybeRenderOCounter() { + if (props.scene.o_counter) { + return ( +
    + +
    + ); + } + } + + function maybeRenderPopoverButtonGroup() { + if ( + props.scene.tags.length > 0 || + props.scene.performers.length > 0 || + props.scene.movies.length > 0 || + props.scene.scene_markers.length > 0 || + props.scene?.o_counter + ) { + return ( + <> +
    + + {maybeRenderTagPopoverButton()} + {maybeRenderPerformerPopoverButton()} + {maybeRenderMoviePopoverButton()} + {maybeRenderSceneMarkerPopoverButton()} + {maybeRenderOCounter()} + + + ); + } + } + + function onMouseEnter() { + if (!previewPath || previewPath === "") { + setPreviewPath(props.scene.paths.preview || ""); + } + hoverHandler.onMouseEnter(); + } + function onMouseLeave() { + hoverHandler.onMouseLeave(); + setPreviewPath(""); + } + + function isPortrait() { + const { file } = props.scene; + const width = file.width ? file.width : 0; + const height = file.height ? file.height : 0; + return height > width; + } + + let shiftKey = false; + + return ( + + props.onSelectedChanged(!props.selected, shiftKey)} + onClick={(event: React.MouseEvent) => { + // eslint-disable-next-line prefer-destructuring + shiftKey = event.shiftKey; + event.stopPropagation(); + }} + /> + + + {maybeRenderRatingBanner()} + {maybeRenderSceneStudioOverlay()} + {maybeRenderSceneSpecsOverlay()} + + +
    +
    + {props.scene.title + ? props.scene.title + : TextUtils.fileNameFromPath(props.scene.path)} +
    + {props.scene.date} +

    + {props.scene.details && + TextUtils.truncate(props.scene.details, 100, "... (continued)")} +

    +
    + + {maybeRenderPopoverButtonGroup()} +
    + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/OCounterButton.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/OCounterButton.tsx new file mode 100644 index 000000000..840959de8 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/OCounterButton.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import { Button, Spinner } from "react-bootstrap"; +import { Icon, HoverPopover, SweatDrops } from "src/components/Shared"; + +export interface IOCounterButtonProps { + loading: boolean; + value: number; + onIncrement: () => void; + onDecrement: () => void; + onReset: () => void; + onMenuOpened?: () => void; + onMenuClosed?: () => void; +} + +export const OCounterButton: React.FC = ( + props: IOCounterButtonProps +) => { + if (props.loading) return ; + + const renderButton = () => ( + + ); + + if (props.value) { + return ( + +
    + +
    +
    + +
    +
    + } + enterDelay={1000} + placement="bottom" + onOpen={props.onMenuOpened} + onClose={props.onMenuClosed} + > + {renderButton()} + + ); + } + return renderButton(); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/PrimaryTags.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/PrimaryTags.tsx new file mode 100644 index 000000000..15d6ffbd8 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/PrimaryTags.tsx @@ -0,0 +1,67 @@ +import React from "react"; +import * as GQL from "src/core/generated-graphql"; +import { Button, Badge, Card } from "react-bootstrap"; +import { TextUtils } from "src/utils"; + +interface IPrimaryTags { + sceneMarkers: GQL.SceneMarkerDataFragment[]; + onClickMarker: (marker: GQL.SceneMarkerDataFragment) => void; + onEdit: (marker: GQL.SceneMarkerDataFragment) => void; +} + +export const PrimaryTags: React.FC = ({ + sceneMarkers, + onClickMarker, + onEdit, +}) => { + if (!sceneMarkers?.length) return
    ; + + const primaries: Record = {}; + const primaryTags: Record = {}; + sceneMarkers.forEach((m) => { + if (primaryTags[m.primary_tag.id]) primaryTags[m.primary_tag.id].push(m); + else { + primaryTags[m.primary_tag.id] = [m]; + primaries[m.primary_tag.id] = m.primary_tag; + } + }); + + const primaryCards = Object.keys(primaryTags).map((id) => { + const markers = primaryTags[id].map((marker) => { + const tags = marker.tags.map((tag) => ( + + {tag.name} + + )); + + return ( +
    +
    +
    + + +
    +
    {TextUtils.secondsToTimestamp(marker.seconds)}
    +
    {tags}
    +
    + ); + }); + + return ( + +

    {primaries[id].name}

    + {markers} +
    + ); + }); + + return
    {primaryCards}
    ; +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx new file mode 100644 index 000000000..9dab63315 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx @@ -0,0 +1,168 @@ +import { Tab, Tabs } from "react-bootstrap"; +import queryString from "query-string"; +import React, { useEffect, useState } from "react"; +import { useParams, useLocation, useHistory } from "react-router-dom"; +import * as GQL from "src/core/generated-graphql"; +import { + useFindScene, + useSceneIncrementO, + useSceneDecrementO, + useSceneResetO, +} from "src/core/StashService"; +import { GalleryViewer } from "src/components/Galleries/GalleryViewer"; +import { LoadingIndicator } from "src/components/Shared"; +import { useToast } from "src/hooks"; +import { ScenePlayer } from "src/components/ScenePlayer"; +import { ScenePerformerPanel } from "./ScenePerformerPanel"; +import { SceneMarkersPanel } from "./SceneMarkersPanel"; +import { SceneFileInfoPanel } from "./SceneFileInfoPanel"; +import { SceneEditPanel } from "./SceneEditPanel"; +import { SceneDetailPanel } from "./SceneDetailPanel"; +import { OCounterButton } from "./OCounterButton"; +import { SceneOperationsPanel } from "./SceneOperationsPanel"; +import { SceneMoviePanel } from "./SceneMoviePanel"; + +export const Scene: React.FC = () => { + const { id = "new" } = useParams(); + const location = useLocation(); + const history = useHistory(); + const Toast = useToast(); + const [timestamp, setTimestamp] = useState(getInitialTimestamp()); + const [scene, setScene] = useState(); + const { data, error, loading } = useFindScene(id); + const [oLoading, setOLoading] = useState(false); + const [incrementO] = useSceneIncrementO(scene?.id ?? "0"); + const [decrementO] = useSceneDecrementO(scene?.id ?? "0"); + const [resetO] = useSceneResetO(scene?.id ?? "0"); + + const queryParams = queryString.parse(location.search); + const autoplay = queryParams?.autoplay === "true"; + + useEffect(() => { + if (data?.findScene) setScene(data.findScene); + }, [data]); + + function getInitialTimestamp() { + const params = queryString.parse(location.search); + const initialTimestamp = params?.t ?? "0"; + return Number.parseInt( + Array.isArray(initialTimestamp) ? initialTimestamp[0] : initialTimestamp, + 10 + ); + } + + const updateOCounter = (newValue: number) => { + const modifiedScene = { ...scene } as GQL.SceneDataFragment; + modifiedScene.o_counter = newValue; + setScene(modifiedScene); + }; + + const onIncrementClick = async () => { + try { + setOLoading(true); + const result = await incrementO(); + if (result.data) updateOCounter(result.data.sceneIncrementO); + } catch (e) { + Toast.error(e); + } finally { + setOLoading(false); + } + }; + + const onDecrementClick = async () => { + try { + setOLoading(true); + const result = await decrementO(); + if (result.data) updateOCounter(result.data.sceneDecrementO); + } catch (e) { + Toast.error(e); + } finally { + setOLoading(false); + } + }; + + const onResetClick = async () => { + try { + setOLoading(true); + const result = await resetO(); + if (result.data) updateOCounter(result.data.sceneResetO); + } catch (e) { + Toast.error(e); + } finally { + setOLoading(false); + } + }; + + function onClickMarker(marker: GQL.SceneMarkerDataFragment) { + setTimestamp(marker.seconds); + } + + if (loading || !scene || !data?.findScene) { + return ; + } + + if (error) return
    {error.message}
    ; + + return ( + <> + +
    +
    + +
    + + + + + + + + {scene.performers.length > 0 ? ( + + + + ) : ( + "" + )} + {scene.movies.length > 0 ? ( + + + + ) : ( + "" + )} + {scene.gallery ? ( + + + + ) : ( + "" + )} + + + + + setScene(newScene)} + onDelete={() => history.push("/scenes")} + /> + + + + + +
    + + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneDetailPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneDetailPanel.tsx new file mode 100644 index 000000000..f64f00a58 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneDetailPanel.tsx @@ -0,0 +1,67 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import { FormattedDate } from "react-intl"; +import * as GQL from "src/core/generated-graphql"; +import { TextUtils } from "src/utils"; +import { TagLink } from "src/components/Shared"; + +interface ISceneDetailProps { + scene: GQL.SceneDataFragment; +} + +export const SceneDetailPanel: React.FC = (props) => { + function renderDetails() { + if (!props.scene.details || props.scene.details === "") return; + return ( + <> +
    Details
    +

    {props.scene.details}

    + + ); + } + + function renderTags() { + if (props.scene.tags.length === 0) return; + const tags = props.scene.tags.map((tag) => ( + + )); + return ( + <> +
    Tags
    + {tags} + + ); + } + + return ( +
    +

    + {props.scene.title ?? TextUtils.fileNameFromPath(props.scene.path)} +

    +
    + {props.scene.date ? ( +

    + +

    + ) : undefined} + {props.scene.rating ?
    Rating: {props.scene.rating}
    : ""} + {props.scene.file.height && ( +
    Resolution: {TextUtils.resolution(props.scene.file.height)}
    + )} + {renderDetails()} + {renderTags()} +
    +
    + {props.scene.studio && ( + + {`${props.scene.studio.name} + + )} +
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx new file mode 100644 index 000000000..61251fcdf --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -0,0 +1,539 @@ +/* eslint-disable react/no-this-in-sfc */ + +import React, { useEffect, useState } from "react"; +import { Button, Dropdown, DropdownButton, Form, Table } from "react-bootstrap"; +import * as GQL from "src/core/generated-graphql"; +import { + queryScrapeScene, + queryScrapeSceneURL, + useListSceneScrapers, + useSceneUpdate, + useSceneDestroy, +} from "src/core/StashService"; +import { + PerformerSelect, + TagSelect, + StudioSelect, + SceneGallerySelect, + Modal, + Icon, + LoadingIndicator, + ImageInput, +} from "src/components/Shared"; +import { useToast } from "src/hooks"; +import { ImageUtils, TableUtils } from "src/utils"; +import { MovieSelect } from "src/components/Shared/Select"; +import { SceneMovieTable, MovieSceneIndexMap } from "./SceneMovieTable"; + +interface IProps { + scene: GQL.SceneDataFragment; + onUpdate: (scene: GQL.SceneDataFragment) => void; + onDelete: () => void; +} + +export const SceneEditPanel: React.FC = (props: IProps) => { + const Toast = useToast(); + const [title, setTitle] = useState(); + const [details, setDetails] = useState(); + const [url, setUrl] = useState(); + const [date, setDate] = useState(); + const [rating, setRating] = useState(); + const [galleryId, setGalleryId] = useState(); + const [studioId, setStudioId] = useState(); + const [performerIds, setPerformerIds] = useState(); + const [movieIds, setMovieIds] = useState(undefined); + const [movieSceneIndexes, setMovieSceneIndexes] = useState< + MovieSceneIndexMap + >(new Map()); + const [tagIds, setTagIds] = useState(); + const [coverImage, setCoverImage] = useState(); + + const Scrapers = useListSceneScrapers(); + const [queryableScrapers, setQueryableScrapers] = useState([]); + + const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); + const [deleteFile, setDeleteFile] = useState(false); + const [deleteGenerated, setDeleteGenerated] = useState(true); + + const [coverImagePreview, setCoverImagePreview] = useState(); + + // Network state + const [isLoading, setIsLoading] = useState(true); + + const [updateScene] = useSceneUpdate(getSceneInput()); + const [deleteScene] = useSceneDestroy(getSceneDeleteInput()); + + useEffect(() => { + const newQueryableScrapers = ( + Scrapers?.data?.listSceneScrapers ?? [] + ).filter((s) => + s.scene?.supported_scrapes.includes(GQL.ScrapeType.Fragment) + ); + + setQueryableScrapers(newQueryableScrapers); + }, [Scrapers]); + + useEffect(() => { + let changed = false; + const newMap: MovieSceneIndexMap = new Map(); + if (movieIds) { + movieIds.forEach((id) => { + if (!movieSceneIndexes.has(id)) { + changed = true; + newMap.set(id, undefined); + } else { + newMap.set(id, movieSceneIndexes.get(id)); + } + }); + + if (!changed) { + movieSceneIndexes.forEach((v, id) => { + if (!newMap.has(id)) { + // id was removed + changed = true; + } + }); + } + + if (changed) { + setMovieSceneIndexes(newMap); + } + } + }, [movieIds, movieSceneIndexes]); + + function updateSceneEditState(state: Partial) { + const perfIds = state.performers?.map((performer) => performer.id); + const tIds = state.tags ? state.tags.map((tag) => tag.id) : undefined; + const moviIds = state.movies + ? state.movies.map((sceneMovie) => sceneMovie.movie.id) + : undefined; + const movieSceneIdx: MovieSceneIndexMap = new Map(); + if (state.movies) { + state.movies.forEach((m) => { + movieSceneIdx.set(m.movie.id, m.scene_index ?? undefined); + }); + } + + setTitle(state.title ?? undefined); + setDetails(state.details ?? undefined); + setUrl(state.url ?? undefined); + setDate(state.date ?? undefined); + setRating(state.rating === null ? NaN : state.rating); + setGalleryId(state?.gallery?.id ?? undefined); + setStudioId(state?.studio?.id ?? undefined); + setMovieIds(moviIds); + setMovieSceneIndexes(movieSceneIdx); + setPerformerIds(perfIds); + setTagIds(tIds); + } + + useEffect(() => { + updateSceneEditState(props.scene); + setCoverImagePreview(props.scene?.paths?.screenshot ?? undefined); + setIsLoading(false); + }, [props.scene]); + + const imageEncoding = ImageUtils.usePasteImage(onImageLoad, true); + + function getSceneInput(): GQL.SceneUpdateInput { + return { + id: props.scene.id, + title, + details, + url, + date, + rating, + gallery_id: galleryId, + studio_id: studioId, + performer_ids: performerIds, + movies: makeMovieInputs(), + tag_ids: tagIds, + cover_image: coverImage, + }; + } + + function makeMovieInputs(): GQL.SceneMovieInput[] | undefined { + if (!movieIds) { + return undefined; + } + + let ret = movieIds.map((id) => { + const r: GQL.SceneMovieInput = { + movie_id: id, + }; + return r; + }); + + ret = ret.map((r) => { + return { scene_index: movieSceneIndexes.get(r.movie_id), ...r }; + }); + + return ret; + } + + async function onSave() { + setIsLoading(true); + try { + const result = await updateScene(); + if (result.data?.sceneUpdate) { + props.onUpdate(result.data.sceneUpdate); + Toast.success({ content: "Updated scene" }); + } + } catch (e) { + Toast.error(e); + } + setIsLoading(false); + } + + function getSceneDeleteInput(): GQL.SceneDestroyInput { + return { + id: props.scene.id, + delete_file: deleteFile, + delete_generated: deleteGenerated, + }; + } + + async function onDelete() { + setIsDeleteAlertOpen(false); + setIsLoading(true); + try { + await deleteScene(); + Toast.success({ content: "Deleted scene" }); + } catch (e) { + Toast.error(e); + } + setIsLoading(false); + props.onDelete(); + } + + function renderTableMovies() { + return ( + { + setMovieSceneIndexes(items); + }} + /> + ); + } + + function renderDeleteAlert() { + return ( + setIsDeleteAlertOpen(false), text: "Cancel" }} + > +

    + Are you sure you want to delete this scene? Unless the file is also + deleted, this scene will be re-added when scan is performed. +

    +
    + setDeleteFile(!deleteFile)} + /> + setDeleteGenerated(!deleteGenerated)} + /> + +
    + ); + } + + function onImageLoad(imageData: string) { + setCoverImagePreview(imageData); + setCoverImage(imageData); + } + + function onCoverImageChange(event: React.FormEvent) { + ImageUtils.onImageChange(event, onImageLoad); + } + + async function onScrapeClicked(scraper: GQL.Scraper) { + setIsLoading(true); + try { + const result = await queryScrapeScene(scraper.id, getSceneInput()); + if (!result.data || !result.data.scrapeScene) { + return; + } + updateSceneFromScrapedScene(result.data.scrapeScene); + } catch (e) { + Toast.error(e); + } finally { + setIsLoading(false); + } + } + + function renderScraperMenu() { + if (!queryableScrapers || queryableScrapers.length === 0) { + return; + } + + return ( + + {queryableScrapers.map((s) => ( + onScrapeClicked(s)}> + {s.name} + + ))} + + ); + } + + function urlScrapable(scrapedUrl: string): boolean { + return (Scrapers?.data?.listSceneScrapers ?? []).some((s) => + (s?.scene?.urls ?? []).some((u) => scrapedUrl.includes(u)) + ); + } + + function updateSceneFromScrapedScene(scene: GQL.ScrapedSceneDataFragment) { + if (!title && scene.title) { + setTitle(scene.title); + } + + if (!details && scene.details) { + setDetails(scene.details); + } + + if (!date && scene.date) { + setDate(scene.date); + } + + if (!url && scene.url) { + setUrl(scene.url); + } + + if (!studioId && scene.studio && scene.studio.id) { + setStudioId(scene.studio.id); + } + + if ( + (!performerIds || performerIds.length === 0) && + scene.performers && + scene.performers.length > 0 + ) { + const idPerfs = scene.performers.filter((p) => { + return p.id !== undefined && p.id !== null; + }); + + if (idPerfs.length > 0) { + const newIds = idPerfs.map((p) => p.id); + setPerformerIds(newIds as string[]); + } + } + + if ( + (!movieIds || movieIds.length === 0) && + scene.movies && + scene.movies.length > 0 + ) { + const idMovis = scene.movies.filter((p) => { + return p.id !== undefined && p.id !== null; + }); + + if (idMovis.length > 0) { + const newIds = idMovis.map((p) => p.id); + setMovieIds(newIds as string[]); + } + } + + if (!tagIds?.length && scene?.tags?.length) { + const idTags = scene.tags.filter((p) => { + return p.id !== undefined && p.id !== null; + }); + + if (idTags.length > 0) { + const newIds = idTags.map((p) => p.id); + setTagIds(newIds as string[]); + } + } + + if (scene.image) { + // image is a base64 string + setCoverImage(scene.image); + setCoverImagePreview(scene.image); + } + } + + async function onScrapeSceneURL() { + if (!url) { + return; + } + setIsLoading(true); + try { + const result = await queryScrapeSceneURL(url); + if (!result.data || !result.data.scrapeSceneURL) { + return; + } + updateSceneFromScrapedScene(result.data.scrapeSceneURL); + } catch (e) { + Toast.error(e); + } finally { + setIsLoading(false); + } + } + + function maybeRenderScrapeButton() { + if (!url || !urlScrapable(url)) { + return undefined; + } + return ( + + ); + } + + if (isLoading) return ; + + return ( +
    +
    + + + {TableUtils.renderInputGroup({ + title: "Title", + value: title, + onChange: setTitle, + isEditing: true, + })} + + + + + {TableUtils.renderInputGroup({ + title: "Date", + value: date, + isEditing: true, + onChange: setDate, + placeholder: "YYYY-MM-DD", + })} + {TableUtils.renderHtmlSelect({ + title: "Rating", + value: rating, + isEditing: true, + onChange: (value: string) => + setRating(Number.parseInt(value, 10)), + selectOptions: ["", 1, 2, 3, 4, 5], + })} + + + + + + + + + + + + + + + + + + + + + +
    URL + ) => + setUrl(newValue.currentTarget.value) + } + value={url} + placeholder="URL" + className="text-input" + /> + {maybeRenderScrapeButton()} +
    Gallery + setGalleryId(item ? item.id : undefined)} + /> +
    Studio + + setStudioId(items.length > 0 ? items[0]?.id : undefined) + } + ids={studioId ? [studioId] : []} + /> +
    Performers + + setPerformerIds(items.map((item) => item.id)) + } + ids={performerIds} + /> +
    Movies/Scenes + + setMovieIds(items.map((item) => item.id)) + } + ids={movieIds} + /> + {renderTableMovies()} +
    Tags + setTagIds(items.map((item) => item.id))} + ids={tagIds} + /> +
    +
    +
    + + Details + ) => + setDetails(newValue.currentTarget.value) + } + value={details} + /> + + +
    + + Cover Image + {imageEncoding ? ( + + ) : ( + Scene cover + )} + + +
    +
    +
    + + +
    + {renderScraperMenu()} + {renderDeleteAlert()} +
    + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneFileInfoPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneFileInfoPanel.tsx new file mode 100644 index 000000000..fc1ce90cb --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneFileInfoPanel.tsx @@ -0,0 +1,194 @@ +import React from "react"; +import { FormattedNumber } from "react-intl"; +import * as GQL from "src/core/generated-graphql"; +import { TextUtils } from "src/utils"; + +interface ISceneFileInfoPanelProps { + scene: GQL.SceneDataFragment; +} + +export const SceneFileInfoPanel: React.FC = ( + props: ISceneFileInfoPanelProps +) => { + function renderChecksum() { + return ( +
    + Checksum + {props.scene.checksum} +
    + ); + } + + function renderPath() { + const { + scene: { path }, + } = props; + return ( +
    + Path + + {`file://${props.scene.path}`}{" "} + +
    + ); + } + + function renderStream() { + return ( +
    + Stream + + + {props.scene.paths.stream} + {" "} + +
    + ); + } + + function renderFileSize() { + if (props.scene.file.size === undefined) { + return; + } + + const { size, unit } = TextUtils.fileSize( + Number.parseInt(props.scene.file.size ?? "0", 10) + ); + + return ( +
    + File Size + + + +
    + ); + } + + function renderDuration() { + if (props.scene.file.duration === undefined) { + return; + } + return ( +
    + Duration + + {TextUtils.secondsToTimestamp(props.scene.file.duration ?? 0)} + +
    + ); + } + + function renderDimensions() { + if (props.scene.file.duration === undefined) { + return; + } + return ( +
    + Dimensions + + {props.scene.file.width} x {props.scene.file.height} + +
    + ); + } + + function renderFrameRate() { + if (props.scene.file.framerate === undefined) { + return; + } + return ( +
    + Frame Rate + + frames per + second + +
    + ); + } + + function renderbitrate() { + // TODO: An upcoming react-intl version will support compound units, megabits-per-second + if (props.scene.file.bitrate === undefined) { + return; + } + return ( +
    + Bit Rate + + +  megabits per second + +
    + ); + } + + function renderVideoCodec() { + if (props.scene.file.video_codec === undefined) { + return; + } + return ( +
    + Video Codec + + {props.scene.file.video_codec} + +
    + ); + } + + function renderAudioCodec() { + if (props.scene.file.audio_codec === undefined) { + return; + } + return ( +
    + Audio Codec + + {props.scene.file.audio_codec} + +
    + ); + } + + function renderUrl() { + if (!props.scene.url || props.scene.url === "") { + return; + } + return ( +
    + Downloaded From + + {props.scene.url} + +
    + ); + } + + return ( +
    + {renderChecksum()} + {renderPath()} + {renderStream()} + {renderFileSize()} + {renderDuration()} + {renderDimensions()} + {renderFrameRate()} + {renderbitrate()} + {renderVideoCodec()} + {renderAudioCodec()} + {renderUrl()} +
    + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkerForm.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkerForm.tsx new file mode 100644 index 000000000..9e9568207 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkerForm.tsx @@ -0,0 +1,186 @@ +import React from "react"; +import { Button, Form } from "react-bootstrap"; +import { Field, FieldProps, Form as FormikForm, Formik } from "formik"; +import * as GQL from "src/core/generated-graphql"; +import { + useSceneMarkerCreate, + useSceneMarkerUpdate, + useSceneMarkerDestroy, +} from "src/core/StashService"; +import { + DurationInput, + TagSelect, + MarkerTitleSuggest, +} from "src/components/Shared"; +import { useToast } from "src/hooks"; +import { JWUtils } from "src/utils"; + +interface IFormFields { + title: string; + seconds: string; + primaryTagId: string; + tagIds: string[]; +} + +interface ISceneMarkerForm { + sceneID: string; + editingMarker?: GQL.SceneMarkerDataFragment; + onClose: () => void; +} + +export const SceneMarkerForm: React.FC = ({ + sceneID, + editingMarker, + onClose, +}) => { + const [sceneMarkerCreate] = useSceneMarkerCreate(); + const [sceneMarkerUpdate] = useSceneMarkerUpdate(); + const [sceneMarkerDestroy] = useSceneMarkerDestroy(); + const Toast = useToast(); + + const onSubmit = (values: IFormFields) => { + const variables: GQL.SceneMarkerUpdateInput | GQL.SceneMarkerCreateInput = { + title: values.title, + seconds: parseFloat(values.seconds), + scene_id: sceneID, + primary_tag_id: values.primaryTagId, + tag_ids: values.tagIds, + }; + if (!editingMarker) { + sceneMarkerCreate({ variables }) + .then(onClose) + .catch((err) => Toast.error(err)); + } else { + const updateVariables = variables as GQL.SceneMarkerUpdateInput; + updateVariables.id = editingMarker!.id; + sceneMarkerUpdate({ variables: updateVariables }) + .then(onClose) + .catch((err) => Toast.error(err)); + } + }; + + const onDelete = () => { + if (!editingMarker) return; + + sceneMarkerDestroy({ variables: { id: editingMarker.id } }) + .then(onClose) + .catch((err) => Toast.error(err)); + }; + const renderTitleField = (fieldProps: FieldProps) => ( +
    + + fieldProps.form.setFieldValue("title", query) + } + /> +
    + ); + + const renderSecondsField = (fieldProps: FieldProps) => ( +
    + fieldProps.form.setFieldValue("seconds", s)} + onReset={() => + fieldProps.form.setFieldValue( + "seconds", + Math.round(JWUtils.getPlayer()?.getPosition() ?? 0) + ) + } + numericValue={Number.parseInt(fieldProps.field.value ?? "0", 10)} + mandatory + /> +
    + ); + + const renderPrimaryTagField = (fieldProps: FieldProps) => ( + + fieldProps.form.setFieldValue("primaryTagId", tags[0]?.id) + } + ids={fieldProps.field.value ? [fieldProps.field.value] : []} + noSelectionString="Select or create tag..." + /> + ); + + const renderTagsField = (fieldProps: FieldProps) => ( + + fieldProps.form.setFieldValue( + "tagIds", + tags.map((tag) => tag.id) + ) + } + ids={fieldProps.field.value} + noSelectionString="Select or create tags..." + /> + ); + + const values: IFormFields = { + title: editingMarker?.title ?? "", + seconds: ( + editingMarker?.seconds ?? + Math.round(JWUtils.getPlayer()?.getPosition() ?? 0) + ).toString(), + primaryTagId: editingMarker?.primary_tag.id ?? "", + tagIds: editingMarker?.tags.map((tag) => tag.id) ?? [], + }; + + return ( + + +
    + + + Scene Marker Title + + {renderTitleField} + + + + Primary Tag + +
    + {renderPrimaryTagField} +
    + + Time + + {renderSecondsField} +
    + + + Tags + +
    + {renderTagsField} +
    +
    +
    +
    + + + {editingMarker && ( + + )} +
    +
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx new file mode 100644 index 000000000..67224fa29 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx @@ -0,0 +1,65 @@ +import React, { useState } from "react"; +import { Button } from "react-bootstrap"; +import * as GQL from "src/core/generated-graphql"; +import { WallPanel } from "src/components/Wall/WallPanel"; +import { PrimaryTags } from "./PrimaryTags"; +import { SceneMarkerForm } from "./SceneMarkerForm"; + +interface ISceneMarkersPanelProps { + scene: GQL.SceneDataFragment; + onClickMarker: (marker: GQL.SceneMarkerDataFragment) => void; +} + +export const SceneMarkersPanel: React.FC = ( + props: ISceneMarkersPanelProps +) => { + const [isEditorOpen, setIsEditorOpen] = useState(false); + const [editingMarker, setEditingMarker] = useState< + GQL.SceneMarkerDataFragment + >(); + + function onOpenEditor(marker?: GQL.SceneMarkerDataFragment) { + setIsEditorOpen(true); + setEditingMarker(marker ?? undefined); + } + + function onClickMarker(marker: GQL.SceneMarkerDataFragment) { + props.onClickMarker(marker); + } + + const closeEditor = () => { + setEditingMarker(undefined); + setIsEditorOpen(false); + }; + + if (isEditorOpen) + return ( + + ); + + return ( + <> + +
    + +
    +
    + { + window.scrollTo(0, 0); + onClickMarker(marker as GQL.SceneMarkerDataFragment); + }} + /> +
    + + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneMoviePanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMoviePanel.tsx new file mode 100644 index 000000000..e3df55308 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMoviePanel.tsx @@ -0,0 +1,25 @@ +import React, { FunctionComponent } from "react"; +import * as GQL from "src/core/generated-graphql"; +import { MovieCard } from "src/components/Movies/MovieCard"; + +interface ISceneMoviePanelProps { + scene: GQL.SceneDataFragment; +} + +export const SceneMoviePanel: FunctionComponent = ( + props: ISceneMoviePanelProps +) => { + const cards = props.scene.movies.map((sceneMovie) => ( + + )); + + return ( + <> +
    {cards}
    + + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneMovieTable.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMovieTable.tsx new file mode 100644 index 000000000..488ae67d9 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMovieTable.tsx @@ -0,0 +1,82 @@ +import * as React from "react"; +import * as GQL from "src/core/generated-graphql"; +import { useAllMoviesForFilter } from "src/core/StashService"; +import { Form } from "react-bootstrap"; + +type ValidTypes = GQL.SlimMovieDataFragment; + +export type MovieSceneIndexMap = Map; + +export interface IProps { + movieSceneIndexes: MovieSceneIndexMap; + onUpdate: (value: MovieSceneIndexMap) => void; +} + +export const SceneMovieTable: React.FunctionComponent = ( + props: IProps +) => { + const { data } = useAllMoviesForFilter(); + + const items = !!data && !!data.allMoviesSlim ? data.allMoviesSlim : []; + let itemsFilter: ValidTypes[] = []; + + if (!!props.movieSceneIndexes && !!items) { + props.movieSceneIndexes.forEach((_index, movieId) => { + itemsFilter = itemsFilter.concat(items.filter((x) => x.id === movieId)); + }); + } + + const storeIdx = itemsFilter.map((movie) => { + return props.movieSceneIndexes.get(movie.id); + }); + + const updateFieldChanged = (movieId: string, value: number) => { + const newMap = new Map(props.movieSceneIndexes); + newMap.set(movieId, value); + props.onUpdate(newMap); + }; + + function renderTableData() { + return ( + + {itemsFilter!.map((item, index: number) => ( + + {item.name} + + Scene number: + + ) => + updateFieldChanged( + item.id, + Number.parseInt( + e.currentTarget.value ? e.currentTarget.value : "0", + 10 + ) + ) + } + > + {["", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"].map( + (opt) => ( + + ) + )} + + + + ))} + + ); + } + + return ( +
    + {renderTableData()}
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneOperationsPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneOperationsPanel.tsx new file mode 100644 index 000000000..033967a46 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneOperationsPanel.tsx @@ -0,0 +1,41 @@ +import { Button } from "react-bootstrap"; +import React, { FunctionComponent } from "react"; +import * as GQL from "src/core/generated-graphql"; +import { useSceneGenerateScreenshot } from "src/core/StashService"; +import { useToast } from "src/hooks"; +import { JWUtils } from "src/utils"; + +interface IOperationsPanelProps { + scene: GQL.SceneDataFragment; +} + +export const SceneOperationsPanel: FunctionComponent = ( + props: IOperationsPanelProps +) => { + const Toast = useToast(); + const [generateScreenshot] = useSceneGenerateScreenshot(); + + async function onGenerateScreenshot(at?: number) { + await generateScreenshot({ + variables: { + id: props.scene.id, + at, + }, + }); + Toast.success({ content: "Generating screenshot" }); + } + + return ( + <> + + + + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/ScenePerformerPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/ScenePerformerPanel.tsx new file mode 100644 index 000000000..39c76388c --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/ScenePerformerPanel.tsx @@ -0,0 +1,25 @@ +import React, { FunctionComponent } from "react"; +import * as GQL from "src/core/generated-graphql"; +import { PerformerCard } from "src/components/Performers/PerformerCard"; + +interface IScenePerformerPanelProps { + scene: GQL.SceneDataFragment; +} + +export const ScenePerformerPanel: FunctionComponent = ( + props: IScenePerformerPanelProps +) => { + const cards = props.scene.performers.map((performer) => ( + + )); + + return ( + <> +
    {cards}
    + + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneList.tsx b/ui/v2.5/src/components/Scenes/SceneList.tsx new file mode 100644 index 000000000..a29d8502b --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneList.tsx @@ -0,0 +1,144 @@ +import React from "react"; +import _ from "lodash"; +import { useHistory } from "react-router-dom"; +import { + FindScenesQueryResult, + SlimSceneDataFragment, +} from "src/core/generated-graphql"; +import { queryFindScenes } from "src/core/StashService"; +import { useScenesList } from "src/hooks"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { DisplayMode } from "src/models/list-filter/types"; +import { WallPanel } from "../Wall/WallPanel"; +import { SceneCard } from "./SceneCard"; +import { SceneListTable } from "./SceneListTable"; +import { SceneSelectedOptions } from "./SceneSelectedOptions"; + +interface ISceneList { + subComponent?: boolean; + filterHook?: (filter: ListFilterModel) => ListFilterModel; +} + +export const SceneList: React.FC = ({ + subComponent, + filterHook, +}) => { + const history = useHistory(); + const otherOperations = [ + { + text: "Play Random", + onClick: playRandom, + }, + ]; + + const listData = useScenesList({ + zoomable: true, + otherOperations, + renderContent, + renderSelectedOptions, + subComponent, + filterHook, + }); + + async function playRandom( + result: FindScenesQueryResult, + filter: ListFilterModel + ) { + // query for a random scene + if (result.data && result.data.findScenes) { + const { count } = result.data.findScenes; + + const index = Math.floor(Math.random() * count); + const filterCopy = _.cloneDeep(filter); + filterCopy.itemsPerPage = 1; + filterCopy.currentPage = index + 1; + const singleResult = await queryFindScenes(filterCopy); + if ( + singleResult && + singleResult.data && + singleResult.data.findScenes && + singleResult.data.findScenes.scenes.length === 1 + ) { + const { id } = singleResult!.data!.findScenes!.scenes[0]; + // navigate to the scene player page + history.push(`/scenes/${id}?autoplay=true`); + } + } + } + + function renderSelectedOptions( + result: FindScenesQueryResult, + selectedIds: Set + ) { + // find the selected items from the ids + if (!result.data || !result.data.findScenes) { + return undefined; + } + + const { scenes } = result.data.findScenes; + + const selectedScenes: SlimSceneDataFragment[] = []; + selectedIds.forEach((id) => { + const scene = scenes.find((s) => s.id === id); + + if (scene) { + selectedScenes.push(scene); + } + }); + + return ( + <> + {}} + /> + + ); + } + + function renderSceneCard( + scene: SlimSceneDataFragment, + selectedIds: Set, + zoomIndex: number + ) { + return ( + + listData.onSelectChange(scene.id, selected, shiftKey) + } + /> + ); + } + + function renderContent( + result: FindScenesQueryResult, + filter: ListFilterModel, + selectedIds: Set, + zoomIndex: number + ) { + if (!result.data || !result.data.findScenes) { + return; + } + if (filter.displayMode === DisplayMode.Grid) { + return ( +
    + {result.data.findScenes.scenes.map((scene) => + renderSceneCard(scene, selectedIds, zoomIndex) + )} +
    + ); + } + if (filter.displayMode === DisplayMode.List) { + return ; + } + if (filter.displayMode === DisplayMode.Wall) { + return ; + } + } + + return listData.template; +}; diff --git a/ui/v2.5/src/components/Scenes/SceneListTable.tsx b/ui/v2.5/src/components/Scenes/SceneListTable.tsx new file mode 100644 index 000000000..c33cb4e13 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneListTable.tsx @@ -0,0 +1,94 @@ +/* eslint-disable jsx-a11y/control-has-associated-label */ +import React from "react"; +import { Table } from "react-bootstrap"; +import { Link } from "react-router-dom"; +import * as GQL from "src/core/generated-graphql"; +import { NavUtils, TextUtils } from "src/utils"; + +interface ISceneListTableProps { + scenes: GQL.SlimSceneDataFragment[]; +} + +export const SceneListTable: React.FC = ( + props: ISceneListTableProps +) => { + const renderTags = (tags: GQL.Tag[]) => + tags.map((tag) => ( + +
    {tag.name}
    + + )); + + const renderPerformers = (performers: Partial[]) => + performers.map((performer) => ( + +
    {performer.name}
    + + )); + + const renderMovies = (movies: Partial[]) => { + return movies.map((sceneMovie) => + !sceneMovie.movie ? undefined : ( + +
    {sceneMovie.movie.name}
    + + ) + ); + }; + + const renderSceneRow = (scene: GQL.SlimSceneDataFragment) => ( + + + + {scene.title + + + + +
    + {scene.title ?? TextUtils.fileNameFromPath(scene.path)} +
    + + + {scene.rating ? scene.rating : ""} + + {scene.file.duration && + TextUtils.secondsToTimestamp(scene.file.duration)} + + {renderTags(scene.tags)} + {renderPerformers(scene.performers)} + + {scene.studio && ( + +
    {scene.studio.name}
    + + )} + + {renderMovies(scene.movies)} + + ); + + return ( +
    + + + + + + + + + + + + + {props.scenes.map(renderSceneRow)} +
    + TitleRatingDurationTagsPerformersStudioMovies
    +
    + ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneMarkerList.tsx b/ui/v2.5/src/components/Scenes/SceneMarkerList.tsx new file mode 100644 index 000000000..a0f1d929d --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneMarkerList.tsx @@ -0,0 +1,62 @@ +import _ from "lodash"; +import React from "react"; +import { useHistory } from "react-router-dom"; +import { FindSceneMarkersQueryResult } from "src/core/generated-graphql"; +import { queryFindSceneMarkers } from "src/core/StashService"; +import { NavUtils } from "src/utils"; +import { useSceneMarkersList } from "src/hooks"; +import { ListFilterModel } from "src/models/list-filter/filter"; +import { DisplayMode } from "src/models/list-filter/types"; +import { WallPanel } from "../Wall/WallPanel"; + +export const SceneMarkerList: React.FC = () => { + const history = useHistory(); + const otherOperations = [ + { + text: "Play Random", + onClick: playRandom, + }, + ]; + + const listData = useSceneMarkersList({ + otherOperations, + renderContent, + }); + + async function playRandom( + result: FindSceneMarkersQueryResult, + filter: ListFilterModel + ) { + // query for a random scene + if (result.data?.findSceneMarkers) { + const { count } = result.data.findSceneMarkers; + + const index = Math.floor(Math.random() * count); + const filterCopy = _.cloneDeep(filter); + filterCopy.itemsPerPage = 1; + filterCopy.currentPage = index + 1; + const singleResult = await queryFindSceneMarkers(filterCopy); + if (singleResult?.data?.findSceneMarkers?.scene_markers?.length === 1) { + // navigate to the scene player page + const url = NavUtils.makeSceneMarkerUrl( + singleResult.data.findSceneMarkers.scene_markers[0] + ); + history.push(url); + } + } + } + + function renderContent( + result: FindSceneMarkersQueryResult, + filter: ListFilterModel + ) { + if (!result?.data?.findSceneMarkers) return; + if (filter.displayMode === DisplayMode.Wall) { + return ( + + ); + } + } + + return listData.template; +}; diff --git a/ui/v2.5/src/components/Scenes/SceneSelectedOptions.tsx b/ui/v2.5/src/components/Scenes/SceneSelectedOptions.tsx new file mode 100644 index 000000000..8646ce840 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneSelectedOptions.tsx @@ -0,0 +1,359 @@ +import React, { useEffect, useState } from "react"; +import { Button, Form } from "react-bootstrap"; +import _ from "lodash"; +import { useBulkSceneUpdate } from "src/core/StashService"; +import * as GQL from "src/core/generated-graphql"; +import { StudioSelect, LoadingIndicator } from "src/components/Shared"; +import { useToast } from "src/hooks"; +import MultiSet from "../Shared/MultiSet"; + +interface IListOperationProps { + selected: GQL.SlimSceneDataFragment[]; + onScenesUpdated: () => void; +} + +export const SceneSelectedOptions: React.FC = ( + props: IListOperationProps +) => { + const Toast = useToast(); + const [rating, setRating] = useState(""); + const [studioId, setStudioId] = useState(); + const [performerMode, setPerformerMode] = React.useState< + GQL.BulkUpdateIdMode + >(GQL.BulkUpdateIdMode.Add); + const [performerIds, setPerformerIds] = useState(); + const [tagMode, setTagMode] = React.useState( + GQL.BulkUpdateIdMode.Add + ); + const [tagIds, setTagIds] = useState(); + + const [updateScenes] = useBulkSceneUpdate(getSceneInput()); + + // Network state + const [isLoading, setIsLoading] = useState(true); + + function makeBulkUpdateIds( + ids: string[], + mode: GQL.BulkUpdateIdMode + ): GQL.BulkUpdateIds { + return { + mode, + ids, + }; + } + + function getSceneInput(): GQL.BulkSceneUpdateInput { + // need to determine what we are actually setting on each scene + const aggregateRating = getRating(props.selected); + const aggregateStudioId = getStudioId(props.selected); + const aggregatePerformerIds = getPerformerIds(props.selected); + const aggregateTagIds = getTagIds(props.selected); + + const sceneInput: GQL.BulkSceneUpdateInput = { + ids: props.selected.map((scene) => { + return scene.id; + }), + }; + + // if rating is undefined + if (rating === "") { + // and all scenes have the same rating, then we are unsetting the rating. + if (aggregateRating) { + // an undefined rating is ignored in the server, so set it to 0 instead + sceneInput.rating = 0; + } + // otherwise not setting the rating + } else { + // if rating is set, then we are setting the rating for all + sceneInput.rating = Number.parseInt(rating, 10); + } + + // if studioId is undefined + if (studioId === undefined) { + // and all scenes have the same studioId, + // then unset the studioId, otherwise ignoring studioId + if (aggregateStudioId) { + // an undefined studio_id is ignored in the server, so set it to empty string instead + sceneInput.studio_id = ""; + } + } else { + // if studioId is set, then we are setting it + sceneInput.studio_id = studioId; + } + + // if performerIds are empty + if ( + performerMode === GQL.BulkUpdateIdMode.Set && + (!performerIds || performerIds.length === 0) + ) { + // and all scenes have the same ids, + if (aggregatePerformerIds.length > 0) { + // then unset the performerIds, otherwise ignore + sceneInput.performer_ids = makeBulkUpdateIds( + performerIds || [], + performerMode + ); + } + } else { + // if performerIds non-empty, then we are setting them + sceneInput.performer_ids = makeBulkUpdateIds( + performerIds || [], + performerMode + ); + } + + // if tagIds non-empty, then we are setting them + if ( + tagMode === GQL.BulkUpdateIdMode.Set && + (!tagIds || tagIds.length === 0) + ) { + // and all scenes have the same ids, + if (aggregateTagIds.length > 0) { + // then unset the tagIds, otherwise ignore + sceneInput.tag_ids = makeBulkUpdateIds(tagIds || [], tagMode); + } + } else { + // if tagIds non-empty, then we are setting them + sceneInput.tag_ids = makeBulkUpdateIds(tagIds || [], tagMode); + } + + return sceneInput; + } + + async function onSave() { + setIsLoading(true); + try { + await updateScenes(); + Toast.success({ content: "Updated scenes" }); + } catch (e) { + Toast.error(e); + } + setIsLoading(false); + props.onScenesUpdated(); + } + + function getRating(state: GQL.SlimSceneDataFragment[]) { + let ret: number | undefined; + let first = true; + + state.forEach((scene: GQL.SlimSceneDataFragment) => { + if (first) { + ret = scene.rating ?? undefined; + first = false; + } else if (ret !== scene.rating) { + ret = undefined; + } + }); + + return ret; + } + + function getStudioId(state: GQL.SlimSceneDataFragment[]) { + let ret: string | undefined; + let first = true; + + state.forEach((scene: GQL.SlimSceneDataFragment) => { + if (first) { + ret = scene?.studio?.id; + first = false; + } else { + const studio = scene?.studio?.id; + if (ret !== studio) { + ret = undefined; + } + } + }); + + return ret; + } + + function getPerformerIds(state: GQL.SlimSceneDataFragment[]) { + let ret: string[] = []; + let first = true; + + state.forEach((scene: GQL.SlimSceneDataFragment) => { + if (first) { + ret = scene.performers ? scene.performers.map((p) => p.id).sort() : []; + first = false; + } else { + const perfIds = scene.performers + ? scene.performers.map((p) => p.id).sort() + : []; + + if (!_.isEqual(ret, perfIds)) { + ret = []; + } + } + }); + + return ret; + } + + function getTagIds(state: GQL.SlimSceneDataFragment[]) { + let ret: string[] = []; + let first = true; + + state.forEach((scene: GQL.SlimSceneDataFragment) => { + if (first) { + ret = scene.tags ? scene.tags.map((t) => t.id).sort() : []; + first = false; + } else { + const tIds = scene.tags ? scene.tags.map((t) => t.id).sort() : []; + + if (!_.isEqual(ret, tIds)) { + ret = []; + } + } + }); + + return ret; + } + + useEffect(() => { + const state = props.selected; + let updateRating = ""; + let updateStudioID: string | undefined; + let updatePerformerIds: string[] = []; + let updateTagIds: string[] = []; + let first = true; + + state.forEach((scene: GQL.SlimSceneDataFragment) => { + const sceneRating = scene.rating?.toString() ?? ""; + const sceneStudioID = scene?.studio?.id; + const scenePerformerIDs = (scene.performers ?? []) + .map((p) => p.id) + .sort(); + const sceneTagIDs = (scene.tags ?? []).map((p) => p.id).sort(); + + if (first) { + updateRating = sceneRating; + updateStudioID = sceneStudioID; + updatePerformerIds = scenePerformerIDs; + updateTagIds = sceneTagIDs; + first = false; + } else { + if (sceneRating !== updateRating) { + updateRating = ""; + } + if (sceneStudioID !== updateStudioID) { + updateStudioID = undefined; + } + if (!_.isEqual(scenePerformerIDs, updatePerformerIds)) { + updatePerformerIds = []; + } + if (!_.isEqual(sceneTagIDs, updateTagIds)) { + updateTagIds = []; + } + } + }); + + setRating(updateRating); + setStudioId(updateStudioID); + if (performerMode === GQL.BulkUpdateIdMode.Set) { + setPerformerIds(updatePerformerIds); + } + + if (tagMode === GQL.BulkUpdateIdMode.Set) { + setTagIds(updateTagIds); + } + + setIsLoading(false); + }, [props.selected, performerMode, tagMode]); + + function renderMultiSelect( + type: "performers" | "tags", + ids: string[] | undefined + ) { + let mode = GQL.BulkUpdateIdMode.Add; + switch (type) { + case "performers": + mode = performerMode; + break; + case "tags": + mode = tagMode; + break; + } + + return ( + { + const itemIDs = items.map((i) => i.id); + switch (type) { + case "performers": + setPerformerIds(itemIDs); + break; + case "tags": + setTagIds(itemIDs); + break; + } + }} + onSetMode={(newMode) => { + switch (type) { + case "performers": + setPerformerMode(newMode); + break; + case "tags": + setTagMode(newMode); + break; + } + }} + ids={ids ?? []} + mode={mode} + /> + ); + } + + if (isLoading) return ; + + function render() { + return ( +
    + + Rating + ) => + setRating(event.currentTarget.value) + } + > + {["", "1", "2", "3", "4", "5"].map((opt) => ( + + ))} + + + + + Studio + setStudioId(items[0]?.id)} + ids={studioId ? [studioId] : []} + /> + + + + Performers + {renderMultiSelect("performers", performerIds)} + + + + Tags + {renderMultiSelect("tags", tagIds)} + + + +
    + ); + } + + return render(); +}; diff --git a/ui/v2.5/src/components/Scenes/Scenes.tsx b/ui/v2.5/src/components/Scenes/Scenes.tsx new file mode 100644 index 000000000..da5ec7fd5 --- /dev/null +++ b/ui/v2.5/src/components/Scenes/Scenes.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { Route, Switch } from "react-router-dom"; +import { Scene } from "./SceneDetails/Scene"; +import { SceneList } from "./SceneList"; +import { SceneMarkerList } from "./SceneMarkerList"; + +const Scenes = () => ( + + + + + +); + +export default Scenes; diff --git a/ui/v2.5/src/components/Scenes/styles.scss b/ui/v2.5/src/components/Scenes/styles.scss new file mode 100644 index 000000000..c7af5c17e --- /dev/null +++ b/ui/v2.5/src/components/Scenes/styles.scss @@ -0,0 +1,220 @@ +.scene-popovers { + display: flex; + justify-content: center; + margin-bottom: 10px; + + .btn { + padding-bottom: 3px; + padding-top: 3px; + } + + .fa-icon { + margin-right: 7px; + } +} + +.card-section { + margin-bottom: 0; + padding: 0.5rem 1rem 0 1rem; + + &-title { + overflow: hidden; + overflow-wrap: normal; + text-overflow: ellipsis; + } +} + +.scene-card-check { + left: 0.5rem; + margin-top: -12px; + opacity: 0.5; + padding-left: 15px; + position: absolute; + top: 0.7rem; + width: 1.2rem; + z-index: 1; +} + +.performer-tag-container, +.movie-tag-container { + display: inline-block; + margin: 5px; +} + +.performer-tag.image, +.movie-tag.image { + background-position: center; + background-repeat: no-repeat; + background-size: cover; + height: 150px; + margin: 0 auto; + width: 100%; +} + +.operation-container { + .operation-item { + min-width: 240px; + } + + .rating-operation { + min-width: 20px; + } + + .apply-operation { + margin-top: 2rem; + } +} + +.marker-container { + display: "flex"; + flex-wrap: "nowrap"; + margin-bottom: "20px"; + overflow-x: "scroll"; + overflow-y: "hidden"; + white-space: "nowrap"; +} + +.studio-logo { + margin-top: 1rem; + max-width: 100%; +} + +.scene-header { + flex-basis: auto; +} + +#scene-details-container { + .tab-content { + min-height: 15rem; + } + + .scene-description { + width: 100%; + } +} + +.file-info-panel { + div { + margin-bottom: 0.5rem; + } +} + +#details { + min-height: 150px; +} + +.primary-card { + margin: 1rem 0; + + &-body { + max-height: 15rem; + overflow-y: auto; + } +} + +.studio-card { + padding: 0.5rem; + + &-header { + height: 150px; + line-height: 150px; + text-align: center; + } + + &-image { + max-height: 150px; + object-fit: contain; + vertical-align: middle; + width: 320px; + + @media (max-width: 576px) { + width: 100%; + } + } +} + +.scene-specs-overlay { + bottom: 1rem; + color: $text-color; + display: block; + font-weight: 400; + letter-spacing: -0.03rem; + position: absolute; + right: 0.7rem; + text-shadow: 0 0 3px #000; +} + +.scene-studio-overlay { + display: block; + font-weight: 900; + height: 10%; + max-width: 40%; + opacity: 0.75; + position: absolute; + right: 0.7rem; + top: 0.7rem; + z-index: 9; + + .image-thumbnail { + height: auto; + max-height: 50px; + max-width: 100%; + } + + a { + color: $text-color; + display: inline-block; + letter-spacing: -0.03rem; + text-align: right; + text-decoration: none; + text-shadow: 0 0 3px #000; + } +} + +.overlay-resolution { + font-weight: 900; + margin-right: 0.3rem; + text-transform: uppercase; +} + +.scene-card { + &.card { + overflow: hidden; + padding: 0; + } + + &-link { + position: relative; + } + + .scene-specs-overlay, + .rating-banner, + .scene-studio-overlay { + transition: opacity 0.5s; + } + + &:hover { + .scene-specs-overlay, + .rating-banner, + .scene-studio-overlay { + opacity: 0; + transition: opacity 0.5s; + } + + .scene-studio-overlay:hover { + opacity: 0.75; + transition: opacity 0.5s; + } + } +} + +.scene-cover { + display: block; + margin-bottom: 10px; + margin-top: 10px; + max-width: 100%; +} + +.movie-table td { + vertical-align: middle; +} diff --git a/ui/v2.5/src/components/Settings/Settings.tsx b/ui/v2.5/src/components/Settings/Settings.tsx new file mode 100644 index 000000000..500f572cd --- /dev/null +++ b/ui/v2.5/src/components/Settings/Settings.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import queryString from "query-string"; +import { Card, Tab, Nav, Row, Col } from "react-bootstrap"; +import { useHistory, useLocation } from "react-router-dom"; +import { SettingsAboutPanel } from "./SettingsAboutPanel"; +import { SettingsConfigurationPanel } from "./SettingsConfigurationPanel"; +import { SettingsInterfacePanel } from "./SettingsInterfacePanel"; +import { SettingsLogsPanel } from "./SettingsLogsPanel"; +import { SettingsTasksPanel } from "./SettingsTasksPanel/SettingsTasksPanel"; + +export const Settings: React.FC = () => { + const location = useLocation(); + const history = useHistory(); + const defaultTab = queryString.parse(location.search).tab ?? "tasks"; + + const onSelect = (val: string) => history.push(`?tab=${val}`); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/ui/v2.5/src/components/Settings/SettingsAboutPanel.tsx b/ui/v2.5/src/components/Settings/SettingsAboutPanel.tsx new file mode 100644 index 000000000..15bd35850 --- /dev/null +++ b/ui/v2.5/src/components/Settings/SettingsAboutPanel.tsx @@ -0,0 +1,162 @@ +import React from "react"; +import { Button, Table } from "react-bootstrap"; +import { LoadingIndicator } from "src/components/Shared"; +import { useVersion, useLatestVersion } from "src/core/StashService"; + +export const SettingsAboutPanel: React.FC = () => { + const { data, error, loading } = useVersion(); + const { + data: dataLatest, + error: errorLatest, + loading: loadingLatest, + refetch, + networkStatus, + } = useLatestVersion(); + + function maybeRenderTag() { + if (!data || !data.version || !data.version.version) { + return; + } + return ( + + Version: + {data.version.version} + + ); + } + + function maybeRenderLatestVersion() { + if ( + !dataLatest?.latestversion.shorthash || + !dataLatest?.latestversion.url + ) { + return; + } + if (!data || !data.version || !data.version.hash) { + return <>{dataLatest.latestversion.shorthash}; + } + + if (data.version.hash !== dataLatest.latestversion.shorthash) { + return ( + <> + {dataLatest.latestversion.shorthash} [NEW] + Download + + ); + } + + return <>{dataLatest.latestversion.shorthash}; + } + + function renderLatestVersion() { + if (!data || !data.version || !data.version.version) { + return; + } // if there is no "version" latest version check is obviously not supported + return ( + + + + + + + + + + +
    Latest Version Build Hash: {maybeRenderLatestVersion()}
    + +
    + ); + } + + function renderVersion() { + if (!data || !data.version) { + return; + } + return ( + <> + + + {maybeRenderTag()} + + + + + + + + + +
    Build hash:{data.version.hash}
    Build time:{data.version.build_time}
    + + ); + } + return ( + <> +

    About

    + + + + + + + + + + + + + + + +
    + Stash home at{" "} + + Github + +
    + Stash{" "} + + Wiki + {" "} + page +
    + Join our{" "} + + Discord + {" "} + channel +
    + Support us through{" "} + + Open Collective + +
    + {!data || loading ? : ""} + {error && {error.message}} + {errorLatest && {errorLatest.message}} + {renderVersion()} + {!dataLatest || loadingLatest || networkStatus === 4 ? ( + + ) : ( + renderLatestVersion() + )} + + ); +}; diff --git a/ui/v2.5/src/components/Settings/SettingsConfigurationPanel.tsx b/ui/v2.5/src/components/Settings/SettingsConfigurationPanel.tsx new file mode 100644 index 000000000..daede0ded --- /dev/null +++ b/ui/v2.5/src/components/Settings/SettingsConfigurationPanel.tsx @@ -0,0 +1,477 @@ +import React, { useEffect, useState } from "react"; +import { Button, Form, InputGroup } from "react-bootstrap"; +import * as GQL from "src/core/generated-graphql"; +import { useConfiguration, useConfigureGeneral } from "src/core/StashService"; +import { useToast } from "src/hooks"; +import { Icon, LoadingIndicator } from "src/components/Shared"; +import { FolderSelect } from "src/components/Shared/FolderSelect/FolderSelect"; + +export const SettingsConfigurationPanel: React.FC = () => { + const Toast = useToast(); + // Editing config state + const [stashes, setStashes] = useState([]); + const [databasePath, setDatabasePath] = useState( + undefined + ); + const [generatedPath, setGeneratedPath] = useState( + undefined + ); + const [cachePath, setCachePath] = useState(undefined); + const [maxTranscodeSize, setMaxTranscodeSize] = useState< + GQL.StreamingResolutionEnum | undefined + >(undefined); + const [maxStreamingTranscodeSize, setMaxStreamingTranscodeSize] = useState< + GQL.StreamingResolutionEnum | undefined + >(undefined); + const [forceMkv, setForceMkv] = useState(false); + const [forceHevc, setForceHevc] = useState(false); + const [username, setUsername] = useState(undefined); + const [password, setPassword] = useState(undefined); + const [maxSessionAge, setMaxSessionAge] = useState(0); + const [logFile, setLogFile] = useState(); + const [logOut, setLogOut] = useState(true); + const [logLevel, setLogLevel] = useState("Info"); + const [logAccess, setLogAccess] = useState(true); + const [excludes, setExcludes] = useState([]); + const [scraperUserAgent, setScraperUserAgent] = useState( + undefined + ); + + const { data, error, loading } = useConfiguration(); + + const [updateGeneralConfig] = useConfigureGeneral({ + stashes, + databasePath, + generatedPath, + cachePath, + maxTranscodeSize, + maxStreamingTranscodeSize, + forceMkv, + forceHevc, + username, + password, + maxSessionAge, + logFile, + logOut, + logLevel, + logAccess, + excludes, + scraperUserAgent, + }); + + useEffect(() => { + if (!data?.configuration || error) return; + + const conf = data.configuration; + if (conf.general) { + setStashes(conf.general.stashes ?? []); + setDatabasePath(conf.general.databasePath); + setGeneratedPath(conf.general.generatedPath); + setCachePath(conf.general.cachePath); + setMaxTranscodeSize(conf.general.maxTranscodeSize ?? undefined); + setMaxStreamingTranscodeSize( + conf.general.maxStreamingTranscodeSize ?? undefined + ); + setForceMkv(conf.general.forceMkv); + setForceHevc(conf.general.forceHevc); + setUsername(conf.general.username); + setPassword(conf.general.password); + setMaxSessionAge(conf.general.maxSessionAge); + setLogFile(conf.general.logFile ?? undefined); + setLogOut(conf.general.logOut); + setLogLevel(conf.general.logLevel); + setLogAccess(conf.general.logAccess); + setExcludes(conf.general.excludes); + setScraperUserAgent(conf.general.scraperUserAgent ?? undefined); + } + }, [data, error]); + + function onStashesChanged(directories: string[]) { + setStashes(directories); + } + + function excludeRegexChanged(idx: number, value: string) { + const newExcludes = excludes.map((regex, i) => { + const ret = idx !== i ? regex : value; + return ret; + }); + setExcludes(newExcludes); + } + + function excludeRemoveRegex(idx: number) { + const newExcludes = excludes.filter((_regex, i) => i !== idx); + + setExcludes(newExcludes); + } + + function excludeAddRegex() { + const demo = "sample\\.mp4$"; + const newExcludes = excludes.concat(demo); + + setExcludes(newExcludes); + } + + async function onSave() { + try { + const result = await updateGeneralConfig(); + // eslint-disable-next-line no-console + console.log(result); + Toast.success({ content: "Updated config" }); + } catch (e) { + Toast.error(e); + } + } + + const transcodeQualities = [ + GQL.StreamingResolutionEnum.Low, + GQL.StreamingResolutionEnum.Standard, + GQL.StreamingResolutionEnum.StandardHd, + GQL.StreamingResolutionEnum.FullHd, + GQL.StreamingResolutionEnum.FourK, + GQL.StreamingResolutionEnum.Original, + ].map(resolutionToString); + + function resolutionToString(r: GQL.StreamingResolutionEnum | undefined) { + switch (r) { + case GQL.StreamingResolutionEnum.Low: + return "240p"; + case GQL.StreamingResolutionEnum.Standard: + return "480p"; + case GQL.StreamingResolutionEnum.StandardHd: + return "720p"; + case GQL.StreamingResolutionEnum.FullHd: + return "1080p"; + case GQL.StreamingResolutionEnum.FourK: + return "4k"; + case GQL.StreamingResolutionEnum.Original: + return "Original"; + } + + return "Original"; + } + + function translateQuality(quality: string) { + switch (quality) { + case "240p": + return GQL.StreamingResolutionEnum.Low; + case "480p": + return GQL.StreamingResolutionEnum.Standard; + case "720p": + return GQL.StreamingResolutionEnum.StandardHd; + case "1080p": + return GQL.StreamingResolutionEnum.FullHd; + case "4k": + return GQL.StreamingResolutionEnum.FourK; + case "Original": + return GQL.StreamingResolutionEnum.Original; + } + + return GQL.StreamingResolutionEnum.Original; + } + + if (error) return

    {error.message}

    ; + if (!data?.configuration || loading) return ; + + return ( + <> +

    Library

    + + +
    Stashes
    + + + Directory locations to your content + +
    + + +
    Database Path
    + ) => + setDatabasePath(e.currentTarget.value) + } + /> + + File location for the SQLite database (requires restart) + +
    + + +
    Generated Path
    + ) => + setGeneratedPath(e.currentTarget.value) + } + /> + + Directory location for the generated files (scene markers, scene + previews, sprites, etc) + +
    + + +
    Cache Path
    + ) => + setCachePath(e.currentTarget.value) + } + /> + + Directory location of the cache + +
    + + +
    Excluded Patterns
    + + {excludes && + excludes.map((regexp, i) => ( + + ) => + excludeRegexChanged(i, e.currentTarget.value) + } + /> + + + + + ))} + + + + Regexps of files/paths to exclude from Scan and add to Clean + + + + +
    +
    + +
    + + +

    Video

    + +
    Maximum transcode size
    + ) => + setMaxTranscodeSize(translateQuality(event.currentTarget.value)) + } + value={resolutionToString(maxTranscodeSize)} + > + {transcodeQualities.map((q) => ( + + ))} + + + Maximum size for generated transcodes + +
    + +
    Maximum streaming transcode size
    + ) => + setMaxStreamingTranscodeSize( + translateQuality(event.currentTarget.value) + ) + } + value={resolutionToString(maxStreamingTranscodeSize)} + > + {transcodeQualities.map((q) => ( + + ))} + + + Maximum size for transcoded streams + +
    + + setForceMkv(!forceMkv)} + /> + + Treat Matroska (MKV) as a supported container. Recommended for + Chromium based browsers + + + + setForceHevc(!forceHevc)} + /> + + Treat HEVC as a supported codec. Recommended for Safari or some + Android based browsers + + +
    + +
    + + +
    Scraping
    + ) => + setScraperUserAgent(e.currentTarget.value) + } + /> + + User-Agent string used during scrape http requests + +
    + +
    + + +

    Authentication

    + +
    Username
    + ) => + setUsername(e.currentTarget.value) + } + /> + + Username to access Stash. Leave blank to disable user authentication + +
    + +
    Password
    + ) => + setPassword(e.currentTarget.value) + } + /> + + Password to access Stash. Leave blank to disable user authentication + +
    + + +
    Maximum Session Age
    + ) => + setMaxSessionAge(Number.parseInt(e.currentTarget.value, 10)) + } + /> + + Maximum idle time before a login session is expired, in seconds. + +
    +
    + +
    + +

    Logging

    + +
    Log file
    + ) => + setLogFile(e.currentTarget.value) + } + /> + + Path to the file to output logging to. Blank to disable file logging. + Requires restart. + +
    + + + setLogOut(!logOut)} + /> + + Logs to the terminal in addition to a file. Always true if file + logging is disabled. Requires restart. + + + + +
    Log Level
    + ) => + setLogLevel(event.currentTarget.value) + } + value={logLevel} + > + {["Debug", "Info", "Warning", "Error"].map((o) => ( + + ))} + +
    + + + setLogAccess(!logAccess)} + /> + + Logs http access to the terminal. Requires restart. + + + +
    + + + + ); +}; diff --git a/ui/v2.5/src/components/Settings/SettingsInterfacePanel.tsx b/ui/v2.5/src/components/Settings/SettingsInterfacePanel.tsx new file mode 100644 index 000000000..4eeecd5ea --- /dev/null +++ b/ui/v2.5/src/components/Settings/SettingsInterfacePanel.tsx @@ -0,0 +1,180 @@ +import React, { useEffect, useState } from "react"; +import { Button, Form } from "react-bootstrap"; +import { DurationInput, LoadingIndicator } from "src/components/Shared"; +import { useConfiguration, useConfigureInterface } from "src/core/StashService"; +import { useToast } from "src/hooks"; + +export const SettingsInterfacePanel: React.FC = () => { + const Toast = useToast(); + const { data: config, error, loading } = useConfiguration(); + const [soundOnPreview, setSoundOnPreview] = useState(true); + const [wallShowTitle, setWallShowTitle] = useState(true); + const [wallPlayback, setWallPlayback] = useState("video"); + const [maximumLoopDuration, setMaximumLoopDuration] = useState(0); + const [autostartVideo, setAutostartVideo] = useState(false); + const [showStudioAsText, setShowStudioAsText] = useState(false); + const [css, setCSS] = useState(); + const [cssEnabled, setCSSEnabled] = useState(false); + const [language, setLanguage] = useState("en"); + + const [updateInterfaceConfig] = useConfigureInterface({ + soundOnPreview, + wallShowTitle, + wallPlayback, + maximumLoopDuration, + autostartVideo, + showStudioAsText, + css, + cssEnabled, + language, + }); + + useEffect(() => { + const iCfg = config?.configuration?.interface; + setSoundOnPreview(iCfg?.soundOnPreview ?? true); + setWallShowTitle(iCfg?.wallShowTitle ?? true); + setWallPlayback(iCfg?.wallPlayback ?? "video"); + setMaximumLoopDuration(iCfg?.maximumLoopDuration ?? 0); + setAutostartVideo(iCfg?.autostartVideo ?? false); + setShowStudioAsText(iCfg?.showStudioAsText ?? false); + setCSS(iCfg?.css ?? ""); + setCSSEnabled(iCfg?.cssEnabled ?? false); + setLanguage(iCfg?.language ?? "en-US"); + }, [config]); + + async function onSave() { + try { + const result = await updateInterfaceConfig(); + // eslint-disable-next-line no-console + console.log(result); + Toast.success({ content: "Updated config" }); + } catch (e) { + Toast.error(e); + } + } + + if (error) return

    {error.message}

    ; + if (loading) return ; + + return ( + <> +

    User Interface

    + +
    Language
    + ) => + setLanguage(e.currentTarget.value) + } + > + + + +
    + +
    Scene / Marker Wall
    + setWallShowTitle(!wallShowTitle)} + /> + setSoundOnPreview(!soundOnPreview)} + /> + +
    Preview Type
    +
    + ) => + setWallPlayback(e.currentTarget.value) + } + > + + + + + + Configuration for wall items + +
    + + +
    Scene List
    + { + setShowStudioAsText(!showStudioAsText); + }} + /> +
    + + +
    Scene Player
    + + { + setAutostartVideo(!autostartVideo); + }} + /> + + + +
    Maximum loop duration
    + setMaximumLoopDuration(duration ?? 0)} + /> + + Maximum scene duration where scene player will loop the video - 0 to + disable + +
    +
    + + +
    Custom CSS
    + { + setCSSEnabled(!cssEnabled); + }} + /> + + ) => + setCSS(e.currentTarget.value) + } + rows={16} + className="col col-sm-6 text-input code" + /> + + Page must be reloaded for changes to take effect. + +
    + +
    + + + ); +}; diff --git a/ui/v2.5/src/components/Settings/SettingsLogsPanel.tsx b/ui/v2.5/src/components/Settings/SettingsLogsPanel.tsx new file mode 100644 index 000000000..d7401b514 --- /dev/null +++ b/ui/v2.5/src/components/Settings/SettingsLogsPanel.tsx @@ -0,0 +1,133 @@ +import React, { useEffect, useReducer, useState } from "react"; +import { Form } from "react-bootstrap"; +import * as GQL from "src/core/generated-graphql"; +import { useLogs, useLoggingSubscribe } from "src/core/StashService"; + +function convertTime(logEntry: GQL.LogEntryDataFragment) { + function pad(val: number) { + let ret = val.toString(); + if (val <= 9) { + ret = `0${ret}`; + } + + return ret; + } + + const date = new Date(logEntry.time); + const month = date.getMonth() + 1; + const day = date.getDate(); + let dateStr = `${date.getFullYear()}-${pad(month)}-${pad(day)}`; + dateStr += ` ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad( + date.getSeconds() + )}`; + + return dateStr; +} + +function levelClass(level: string) { + return level.toLowerCase().trim(); +} + +interface ILogElementProps { + logEntry: LogEntry; +} + +const LogElement: React.FC = ({ logEntry }) => { + // pad to maximum length of level enum + const level = logEntry.level.padEnd(GQL.LogLevel.Progress.length); + + return ( +
    + {logEntry.time} + {level} + {logEntry.message} +
    + ); +}; + +class LogEntry { + public time: string; + public level: string; + public message: string; + public id: string; + + private static nextId: number = 0; + + public constructor(logEntry: GQL.LogEntryDataFragment) { + this.time = convertTime(logEntry); + this.level = logEntry.level; + this.message = logEntry.message; + + const id = LogEntry.nextId++; + this.id = id.toString(); + } +} + +// maximum number of log entries to display. Subsequent entries will truncate +// the list, dropping off the oldest entries first. +const MAX_LOG_ENTRIES = 200; +const logLevels = ["Debug", "Info", "Warning", "Error"]; + +const logReducer = (existingEntries: LogEntry[], newEntries: LogEntry[]) => [ + ...newEntries.reverse(), + ...existingEntries, +]; + +export const SettingsLogsPanel: React.FC = () => { + const { data, error } = useLoggingSubscribe(); + const { data: existingData } = useLogs(); + const [currentData, dispatchLogUpdate] = useReducer(logReducer, []); + const [logLevel, setLogLevel] = useState("Info"); + + useEffect(() => { + const newData = (data?.loggingSubscribe ?? []).map((e) => new LogEntry(e)); + dispatchLogUpdate(newData); + }, [data]); + + const oldData = (existingData?.logs ?? []).map((e) => new LogEntry(e)); + const filteredLogEntries = [...currentData, ...oldData] + .filter(filterByLogLevel) + .slice(0, MAX_LOG_ENTRIES); + + const maybeRenderError = error ? ( +
    Error connecting to log server: {error.message}
    + ) : ( + "" + ); + + function filterByLogLevel(logEntry: LogEntry) { + if (logLevel === "Debug") return true; + + const logLevelIndex = logLevels.indexOf(logLevel); + const levelIndex = logLevels.indexOf(logEntry.level); + + return levelIndex >= logLevelIndex; + } + + return ( + <> +

    Logs

    + + Log Level + setLogLevel(event.currentTarget.value)} + > + {logLevels.map((level) => ( + + ))} + + +
    + {maybeRenderError} + {filteredLogEntries.map((logEntry) => ( + + ))} +
    + + ); +}; diff --git a/ui/v2.5/src/components/Settings/SettingsTasksPanel/GenerateButton.tsx b/ui/v2.5/src/components/Settings/SettingsTasksPanel/GenerateButton.tsx new file mode 100644 index 000000000..22e5c8c66 --- /dev/null +++ b/ui/v2.5/src/components/Settings/SettingsTasksPanel/GenerateButton.tsx @@ -0,0 +1,121 @@ +import React, { useState } from "react"; +import { Button, Form } from "react-bootstrap"; +import { mutateMetadataGenerate } from "src/core/StashService"; +import { PreviewPreset } from "src/core/generated-graphql"; +import { useToast } from "src/hooks"; + +export const GenerateButton: React.FC = () => { + const Toast = useToast(); + const [sprites, setSprites] = useState(true); + const [previews, setPreviews] = useState(true); + const [markers, setMarkers] = useState(true); + const [transcodes, setTranscodes] = useState(false); + const [thumbnails, setThumbnails] = useState(false); + const [imagePreviews, setImagePreviews] = useState(false); + const [previewPreset, setPreviewPreset] = useState( + PreviewPreset.Slow + ); + + async function onGenerate() { + try { + await mutateMetadataGenerate({ + sprites, + previews, + imagePreviews: previews && imagePreviews, + markers, + transcodes, + thumbnails, + previewPreset: (previewPreset as PreviewPreset) ?? undefined, + }); + Toast.success({ content: "Started generating" }); + } catch (e) { + Toast.error(e); + } + } + + return ( + <> + + setPreviews(!previews)} + /> +
    +
    + setImagePreviews(!imagePreviews)} + className="ml-2 flex-grow" + /> +
    + + +
    Preview encoding preset
    +
    + ) => + setPreviewPreset(e.currentTarget.value) + } + disabled={!previews} + className="col-1" + > + {Object.keys(PreviewPreset).map((p) => ( + + ))} + + + The preset regulates size, quality and encoding time of preview + generation. Presets beyond “slow” have diminishing returns and are + not recommended. + +
    + setSprites(!sprites)} + /> + setMarkers(!markers)} + /> + setTranscodes(!transcodes)} + /> + setThumbnails(!thumbnails)} + /> +
    + + + + Generate supporting image, sprite, video, vtt and other files. + + + + ); +}; diff --git a/ui/v2.5/src/components/Settings/SettingsTasksPanel/SettingsTasksPanel.tsx b/ui/v2.5/src/components/Settings/SettingsTasksPanel/SettingsTasksPanel.tsx new file mode 100644 index 000000000..c392c3c29 --- /dev/null +++ b/ui/v2.5/src/components/Settings/SettingsTasksPanel/SettingsTasksPanel.tsx @@ -0,0 +1,313 @@ +import React, { useState, useEffect } from "react"; +import { Button, Form, ProgressBar } from "react-bootstrap"; +import { Link } from "react-router-dom"; +import { + useJobStatus, + useMetadataUpdate, + mutateMetadataImport, + mutateMetadataClean, + mutateMetadataScan, + mutateMetadataAutoTag, + mutateMetadataExport, + mutateStopJob, +} from "src/core/StashService"; +import { useToast } from "src/hooks"; +import { Modal } from "src/components/Shared"; +import { GenerateButton } from "./GenerateButton"; + +export const SettingsTasksPanel: React.FC = () => { + const Toast = useToast(); + const [isImportAlertOpen, setIsImportAlertOpen] = useState(false); + const [isCleanAlertOpen, setIsCleanAlertOpen] = useState(false); + const [useFileMetadata, setUseFileMetadata] = useState(false); + const [status, setStatus] = useState(""); + const [progress, setProgress] = useState(0); + + const [autoTagPerformers, setAutoTagPerformers] = useState(true); + const [autoTagStudios, setAutoTagStudios] = useState(true); + const [autoTagTags, setAutoTagTags] = useState(true); + + const jobStatus = useJobStatus(); + const metadataUpdate = useMetadataUpdate(); + + function statusToText(s: string) { + switch (s) { + case "Idle": + return "Idle"; + case "Scan": + return "Scanning for new content"; + case "Generate": + return "Generating supporting files"; + case "Clean": + return "Cleaning the database"; + case "Export": + return "Exporting to JSON"; + case "Import": + return "Importing from JSON"; + case "Auto Tag": + return "Auto tagging scenes"; + default: + return "Idle"; + } + } + + useEffect(() => { + if (jobStatus?.data?.jobStatus) { + setStatus(statusToText(jobStatus.data.jobStatus.status)); + const newProgress = jobStatus.data.jobStatus.progress; + if (newProgress < 0) { + setProgress(0); + } else { + setProgress(newProgress * 100); + } + } + }, [jobStatus]); + + useEffect(() => { + if (metadataUpdate?.data?.metadataUpdate) { + setStatus(statusToText(metadataUpdate.data.metadataUpdate.status)); + const newProgress = metadataUpdate.data.metadataUpdate.progress; + if (newProgress < 0) { + setProgress(0); + } else { + setProgress(newProgress * 100); + } + } + }, [metadataUpdate]); + + function onImport() { + setIsImportAlertOpen(false); + mutateMetadataImport().then(() => { + jobStatus.refetch(); + }); + } + + function renderImportAlert() { + return ( + setIsImportAlertOpen(false) }} + > +

    + Are you sure you want to import? This will delete the database and + re-import from your exported metadata. +

    +
    + ); + } + + function onClean() { + setIsCleanAlertOpen(false); + mutateMetadataClean().then(() => { + jobStatus.refetch(); + }); + } + + function renderCleanAlert() { + return ( + setIsCleanAlertOpen(false) }} + > +

    + Are you sure you want to Clean? This will delete database information + and generated content for all scenes and galleries that are no longer + found in the filesystem. +

    +
    + ); + } + + async function onScan() { + try { + await mutateMetadataScan({ useFileMetadata }); + Toast.success({ content: "Started scan" }); + jobStatus.refetch(); + } catch (e) { + Toast.error(e); + } + } + + function getAutoTagInput() { + const wildcard = ["*"]; + return { + performers: autoTagPerformers ? wildcard : [], + studios: autoTagStudios ? wildcard : [], + tags: autoTagTags ? wildcard : [], + }; + } + + async function onAutoTag() { + try { + await mutateMetadataAutoTag(getAutoTagInput()); + Toast.success({ content: "Started auto tagging" }); + jobStatus.refetch(); + } catch (e) { + Toast.error(e); + } + } + + function maybeRenderStop() { + if (!status || status === "Idle") { + return undefined; + } + + return ( + + + + ); + } + + function renderJobStatus() { + return ( + <> + +
    Status: {status}
    + {!!status && status !== "Idle" ? ( + + ) : ( + "" + )} +
    + {maybeRenderStop()} + + ); + } + + return ( + <> + {renderImportAlert()} + {renderCleanAlert()} + +

    Running Jobs

    + + {renderJobStatus()} + +
    + +
    Library
    + + setUseFileMetadata(!useFileMetadata)} + /> + + + + + Scan for new content and add it to the database. + + + +
    + +
    Auto Tagging
    + + + setAutoTagPerformers(!autoTagPerformers)} + /> + setAutoTagStudios(!autoTagStudios)} + /> + setAutoTagTags(!autoTagTags)} + /> + + + + + Auto-tag content based on filenames. + + + + + + + + + +
    + +
    Generated Content
    + + + + + Check for missing files and remove them from the database. This is a + destructive action. + + + +
    + +
    Metadata
    + + + + Export the database content into JSON format. + + + + + + + Import from exported JSON. This is a destructive action. + + + + ); +}; diff --git a/ui/v2.5/src/components/Settings/styles.scss b/ui/v2.5/src/components/Settings/styles.scss new file mode 100644 index 000000000..730cf1f2c --- /dev/null +++ b/ui/v2.5/src/components/Settings/styles.scss @@ -0,0 +1,38 @@ +.logs { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; + font-size: smaller; + max-height: 100vh; + overflow-x: hidden; + overflow-y: auto; + padding-top: 1rem; + white-space: pre-wrap; + + .debug { + color: lightgreen; + font-weight: bold; + } + + .info { + color: white; + font-weight: bold; + } + + .warning { + color: orange; + font-weight: bold; + } + + .error { + color: red; + font-weight: bold; + } +} + +.log-time { + margin-right: 1rem; +} + +#configuration-tabs-tabpane-about .table { + width: initial; +} diff --git a/ui/v2.5/src/components/Shared/CountryFlag.tsx b/ui/v2.5/src/components/Shared/CountryFlag.tsx new file mode 100644 index 000000000..32b1f666f --- /dev/null +++ b/ui/v2.5/src/components/Shared/CountryFlag.tsx @@ -0,0 +1,23 @@ +import React from "react"; +import { getISOCountry } from "src/utils"; + +interface ICountryFlag { + country?: string | null; + className?: string; +} + +const CountryFlag: React.FC = ({ className, country }) => { + const ISOCountry = getISOCountry(country); + if (!ISOCountry?.code) return <>; + + return ( + + ); +}; + +export default CountryFlag; diff --git a/ui/v2.5/src/components/Shared/DetailsEditNavbar.tsx b/ui/v2.5/src/components/Shared/DetailsEditNavbar.tsx new file mode 100644 index 000000000..de943ac75 --- /dev/null +++ b/ui/v2.5/src/components/Shared/DetailsEditNavbar.tsx @@ -0,0 +1,126 @@ +import { Button, Modal } from "react-bootstrap"; +import React, { useState } from "react"; +import { ImageInput } from "src/components/Shared"; + +interface IProps { + objectName?: string; + isNew: boolean; + isEditing: boolean; + onToggleEdit: () => void; + onSave: () => void; + onDelete: () => void; + onAutoTag?: () => void; + onImageChange: (event: React.FormEvent) => void; + onBackImageChange?: (event: React.FormEvent) => void; + acceptSVG?: boolean; +} + +export const DetailsEditNavbar: React.FC = (props: IProps) => { + const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); + + function renderEditButton() { + if (props.isNew) return; + return ( + + ); + } + + function renderSaveButton() { + if (!props.isEditing) return; + + return ( + + ); + } + + function renderDeleteButton() { + if (props.isNew || props.isEditing) return; + return ( + + ); + } + + function renderBackImageInput() { + if (!props.isEditing || !props.onBackImageChange) { + return; + } + return ( + + ); + } + + function renderAutoTagButton() { + if (props.isNew || props.isEditing) return; + + if (props.onAutoTag) { + return ( + + ); + } + } + + function renderDeleteAlert() { + return ( + + + Are you sure you want to delete {props.objectName}? + + + + + + + ); + } + + return ( +
    + {renderEditButton()} + + {renderBackImageInput()} + {renderAutoTagButton()} + {renderSaveButton()} + {renderDeleteButton()} + {renderDeleteAlert()} +
    + ); +}; diff --git a/ui/v2.5/src/components/Shared/DurationInput.tsx b/ui/v2.5/src/components/Shared/DurationInput.tsx new file mode 100644 index 000000000..d8363b882 --- /dev/null +++ b/ui/v2.5/src/components/Shared/DurationInput.tsx @@ -0,0 +1,120 @@ +import React, { useState, useEffect } from "react"; +import { Button, ButtonGroup, InputGroup, Form } from "react-bootstrap"; +import { Icon } from "src/components/Shared"; +import { DurationUtils } from "src/utils"; + +interface IProps { + disabled?: boolean; + numericValue: number | undefined; + mandatory?: boolean; + onValueChange( + valueAsNumber: number | undefined, + valueAsString?: string + ): void; + onReset?(): void; + className?: string; +} + +export const DurationInput: React.FC = (props: IProps) => { + const [value, setValue] = useState( + props.numericValue !== undefined + ? DurationUtils.secondsToString(props.numericValue) + : undefined + ); + + useEffect(() => { + if (props.numericValue !== undefined || props.mandatory) { + setValue(DurationUtils.secondsToString(props.numericValue ?? 0)); + } else { + setValue(undefined); + } + }, [props.numericValue, props.mandatory]); + + function increment() { + if (value === undefined) { + return; + } + + let seconds = DurationUtils.stringToSeconds(value); + seconds += 1; + props.onValueChange(seconds, DurationUtils.secondsToString(seconds)); + } + + function decrement() { + if (value === undefined) { + return; + } + + let seconds = DurationUtils.stringToSeconds(value); + seconds -= 1; + props.onValueChange(seconds, DurationUtils.secondsToString(seconds)); + } + + function renderButtons() { + if (!props.disabled) { + return ( + + + + + ); + } + } + + function onReset() { + if (props.onReset) { + props.onReset(); + } + } + + function maybeRenderReset() { + if (props.onReset) { + return ( + + ); + } + } + + return ( + + + ) => + setValue(e.currentTarget.value) + } + onBlur={() => { + if (props.mandatory || (value !== undefined && value !== "")) { + props.onValueChange(DurationUtils.stringToSeconds(value), value); + } else { + props.onValueChange(undefined); + } + }} + placeholder={!props.disabled ? "hh:mm:ss" : undefined} + /> + + {maybeRenderReset()} + {renderButtons()} + + + + ); +}; diff --git a/ui/v2.5/src/components/Shared/FolderSelect/FolderSelect.tsx b/ui/v2.5/src/components/Shared/FolderSelect/FolderSelect.tsx new file mode 100644 index 000000000..9f5c4286b --- /dev/null +++ b/ui/v2.5/src/components/Shared/FolderSelect/FolderSelect.tsx @@ -0,0 +1,133 @@ +import React, { useEffect, useState } from "react"; +import { FormattedMessage } from "react-intl"; +import { Button, InputGroup, Form, Modal } from "react-bootstrap"; +import { LoadingIndicator } from "src/components/Shared"; +import { useDirectory } from "src/core/StashService"; + +interface IProps { + directories: string[]; + onDirectoriesChanged: (directories: string[]) => void; +} + +export const FolderSelect: React.FC = (props: IProps) => { + const [currentDirectory, setCurrentDirectory] = useState(""); + const [isDisplayingDialog, setIsDisplayingDialog] = useState(false); + const [selectedDirectories, setSelectedDirectories] = useState([]); + const { data, error, loading } = useDirectory(currentDirectory); + + useEffect(() => { + setSelectedDirectories(props.directories); + }, [props.directories]); + + useEffect(() => { + if (currentDirectory === "" && data?.directory.path) + setCurrentDirectory(data.directory.path); + }, [currentDirectory, data]); + + const selectableDirectories: string[] = data?.directory.directories ?? []; + + function onSelectDirectory() { + selectedDirectories.push(currentDirectory); + setSelectedDirectories(selectedDirectories); + setCurrentDirectory(""); + setIsDisplayingDialog(false); + props.onDirectoriesChanged(selectedDirectories); + } + + function onRemoveDirectory(directory: string) { + const newSelectedDirectories = selectedDirectories.filter( + (dir) => dir !== directory + ); + setSelectedDirectories(newSelectedDirectories); + props.onDirectoriesChanged(newSelectedDirectories); + } + + const topDirectory = data?.directory?.parent ? ( +
  • + +
  • + ) : null; + + function renderDialog() { + return ( + setIsDisplayingDialog(false)} + title="" + > + Select Directory + +
    + + ) => + setCurrentDirectory(e.currentTarget.value) + } + value={currentDirectory} + spellCheck={false} + /> + + {!data || !data.directory || loading ? ( + + ) : ( + "" + )} + + +
      + {topDirectory} + {selectableDirectories.map((path) => { + return ( +
    • + +
    • + ); + })} +
    +
    +
    + + + +
    + ); + } + + return ( + <> + {error ?

    {error.message}

    : ""} + {renderDialog()} + + {selectedDirectories.map((path) => { + return ( +
    + {path}{" "} + +
    + ); + })} +
    + + + + ); +}; diff --git a/ui/v2.5/src/components/Shared/HoverPopover.tsx b/ui/v2.5/src/components/Shared/HoverPopover.tsx new file mode 100644 index 000000000..a00fa3f9d --- /dev/null +++ b/ui/v2.5/src/components/Shared/HoverPopover.tsx @@ -0,0 +1,76 @@ +import React, { useState, useCallback, useEffect, useRef } from "react"; +import { Overlay, Popover, OverlayProps } from "react-bootstrap"; + +interface IHoverPopover { + enterDelay?: number; + leaveDelay?: number; + content: JSX.Element[] | JSX.Element | string; + className?: string; + placement?: OverlayProps["placement"]; + onOpen?: () => void; + onClose?: () => void; +} + +export const HoverPopover: React.FC = ({ + enterDelay = 0, + leaveDelay = 400, + content, + children, + className, + placement = "top", + onOpen, + onClose, +}) => { + const [show, setShow] = useState(false); + const triggerRef = useRef(null); + const enterTimer = useRef(); + const leaveTimer = useRef(); + + const handleMouseEnter = useCallback(() => { + window.clearTimeout(leaveTimer.current); + enterTimer.current = window.setTimeout(() => { + setShow(true); + onOpen?.(); + }, enterDelay); + }, [enterDelay, onOpen]); + + const handleMouseLeave = useCallback(() => { + window.clearTimeout(enterTimer.current); + leaveTimer.current = window.setTimeout(() => { + setShow(false); + onClose?.(); + }, leaveDelay); + }, [leaveDelay, onClose]); + + useEffect( + () => () => { + window.clearTimeout(enterTimer.current); + window.clearTimeout(leaveTimer.current); + }, + [] + ); + + return ( + <> +
    + {children} +
    + {triggerRef.current && ( + + + {content} + + + )} + + ); +}; diff --git a/ui/v2.5/src/components/Shared/Icon.tsx b/ui/v2.5/src/components/Shared/Icon.tsx new file mode 100644 index 000000000..88b912893 --- /dev/null +++ b/ui/v2.5/src/components/Shared/Icon.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { IconName } from "@fortawesome/fontawesome-svg-core"; + +interface IIcon { + icon: IconName; + className?: string; + color?: string; +} + +const Icon: React.FC = ({ icon, className, color }) => ( + +); + +export default Icon; diff --git a/ui/v2.5/src/components/Shared/ImageInput.tsx b/ui/v2.5/src/components/Shared/ImageInput.tsx new file mode 100644 index 000000000..e2d3e39f4 --- /dev/null +++ b/ui/v2.5/src/components/Shared/ImageInput.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { Button, Form } from "react-bootstrap"; + +interface IImageInput { + isEditing: boolean; + text?: string; + onImageChange: (event: React.ChangeEvent) => void; + acceptSVG?: boolean; +} + +export const ImageInput: React.FC = ({ + isEditing, + text, + onImageChange, + acceptSVG = false, +}) => { + if (!isEditing) return
    ; + + return ( + + + + + ); +}; diff --git a/ui/v2.5/src/components/Shared/LoadingIndicator.tsx b/ui/v2.5/src/components/Shared/LoadingIndicator.tsx new file mode 100644 index 000000000..5fb99232e --- /dev/null +++ b/ui/v2.5/src/components/Shared/LoadingIndicator.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import { Spinner } from "react-bootstrap"; +import cx from "classnames"; + +interface ILoadingProps { + message?: string; + inline?: boolean; +} + +const CLASSNAME = "LoadingIndicator"; +const CLASSNAME_MESSAGE = `${CLASSNAME}-message`; + +const LoadingIndicator: React.FC = ({ + message, + inline = false, +}) => ( +
    + + Loading... + +

    {message ?? "Loading..."}

    +
    +); + +export default LoadingIndicator; diff --git a/ui/v2.5/src/components/Shared/Modal.tsx b/ui/v2.5/src/components/Shared/Modal.tsx new file mode 100644 index 000000000..ae8b88f4f --- /dev/null +++ b/ui/v2.5/src/components/Shared/Modal.tsx @@ -0,0 +1,59 @@ +import React from "react"; +import { Button, Modal } from "react-bootstrap"; +import { Icon } from "src/components/Shared"; +import { IconName } from "@fortawesome/fontawesome-svg-core"; + +interface IButton { + text?: string; + variant?: "danger" | "primary"; + onClick?: () => void; +} + +interface IModal { + show: boolean; + onHide?: () => void; + header?: string; + icon?: IconName; + cancel?: IButton; + accept?: IButton; +} + +const ModalComponent: React.FC = ({ + children, + show, + icon, + header, + cancel, + accept, + onHide, +}) => ( + + + {icon ? : ""} + {header ?? ""} + + {children} + +
    + {cancel ? ( + + ) : ( + "" + )} + +
    +
    +
    +); + +export default ModalComponent; diff --git a/ui/v2.5/src/components/Shared/MultiSet.tsx b/ui/v2.5/src/components/Shared/MultiSet.tsx new file mode 100644 index 000000000..2ce19367e --- /dev/null +++ b/ui/v2.5/src/components/Shared/MultiSet.tsx @@ -0,0 +1,85 @@ +import * as React from "react"; + +import * as GQL from "src/core/generated-graphql"; +import { Button, InputGroup } from "react-bootstrap"; +import { Icon } from "src/components/Shared"; +import { FilterSelect } from "./Select"; + +type ValidTypes = + | GQL.SlimPerformerDataFragment + | GQL.Tag + | GQL.SlimStudioDataFragment; + +interface IMultiSetProps { + type: "performers" | "studios" | "tags"; + ids?: string[]; + mode: GQL.BulkUpdateIdMode; + onUpdate: (items: ValidTypes[]) => void; + onSetMode: (mode: GQL.BulkUpdateIdMode) => void; +} + +const MultiSet: React.FunctionComponent = ( + props: IMultiSetProps +) => { + function onUpdate(items: ValidTypes[]) { + props.onUpdate(items); + } + + function getModeIcon() { + switch (props.mode) { + case GQL.BulkUpdateIdMode.Set: + return "pencil-alt"; + case GQL.BulkUpdateIdMode.Add: + return "plus"; + case GQL.BulkUpdateIdMode.Remove: + return "times"; + } + } + + function getModeText() { + switch (props.mode) { + case GQL.BulkUpdateIdMode.Set: + return "Set"; + case GQL.BulkUpdateIdMode.Add: + return "Add"; + case GQL.BulkUpdateIdMode.Remove: + return "Remove"; + } + } + + function nextMode() { + switch (props.mode) { + case GQL.BulkUpdateIdMode.Set: + return GQL.BulkUpdateIdMode.Add; + case GQL.BulkUpdateIdMode.Add: + return GQL.BulkUpdateIdMode.Remove; + case GQL.BulkUpdateIdMode.Remove: + return GQL.BulkUpdateIdMode.Set; + } + } + + return ( + + + + + + + + ); +}; + +export default MultiSet; diff --git a/ui/v2.5/src/components/Shared/Select.tsx b/ui/v2.5/src/components/Shared/Select.tsx new file mode 100644 index 000000000..737705dcc --- /dev/null +++ b/ui/v2.5/src/components/Shared/Select.tsx @@ -0,0 +1,446 @@ +import React, { useState, CSSProperties } from "react"; +import Select, { ValueType } from "react-select"; +import CreatableSelect from "react-select/creatable"; +import { debounce } from "lodash"; + +import * as GQL from "src/core/generated-graphql"; +import { + useAllTagsForFilter, + useAllMoviesForFilter, + useAllStudiosForFilter, + useAllPerformersForFilter, + useMarkerStrings, + useScrapePerformerList, + useValidGalleriesForScene, + useTagCreate, +} from "src/core/StashService"; +import { useToast } from "src/hooks"; + +type ValidTypes = + | GQL.SlimPerformerDataFragment + | GQL.Tag + | GQL.SlimStudioDataFragment; +type Option = { value: string; label: string }; + +interface ITypeProps { + type?: "performers" | "studios" | "tags" | "sceneTags" | "movies"; +} +interface IFilterProps { + ids?: string[]; + initialIds?: string[]; + onSelect?: (item: ValidTypes[]) => void; + noSelectionString?: string; + className?: string; + isMulti?: boolean; + isClearable?: boolean; + isDisabled?: boolean; +} +interface ISelectProps { + className?: string; + items: Option[]; + selectedOptions?: Option[]; + creatable?: boolean; + onCreateOption?: (value: string) => void; + isLoading: boolean; + isDisabled?: boolean; + onChange: (item: ValueType