From f7a8899d901bcbec1f8cb7f41e169c00e9a1e291 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Tue, 23 Feb 2021 12:56:01 +1100 Subject: [PATCH 01/46] Add rescan option to overflow dropdown (#1119) * Make scan options optional * Add scene rescan * Add image rescan * Add gallery rescan * Add changelog --- graphql/schema/types/metadata.graphql | 10 +++---- pkg/image/image.go | 7 +++++ pkg/manager/manager_tasks.go | 10 +++---- pkg/manager/task_scan.go | 6 +++++ pkg/utils/boolean.go | 5 ++++ .../src/components/Changelog/Changelog.tsx | 11 +++++++- .../src/components/Changelog/versions/v060.md | 2 ++ .../Galleries/GalleryDetails/Gallery.tsx | 27 ++++++++++++++++++- .../components/Images/ImageDetails/Image.tsx | 20 ++++++++++++++ .../components/Scenes/SceneDetails/Scene.tsx | 21 +++++++++++++++ 10 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 ui/v2.5/src/components/Changelog/versions/v060.md diff --git a/graphql/schema/types/metadata.graphql b/graphql/schema/types/metadata.graphql index d00e2846c..f83f3ad78 100644 --- a/graphql/schema/types/metadata.graphql +++ b/graphql/schema/types/metadata.graphql @@ -33,15 +33,15 @@ input GeneratePreviewOptionsInput { input ScanMetadataInput { paths: [String!] """Set name, date, details from metadata (if present)""" - useFileMetadata: Boolean! + useFileMetadata: Boolean """Strip file extension from title""" - stripFileExtension: Boolean! + stripFileExtension: Boolean """Generate previews during scan""" - scanGeneratePreviews: Boolean! + scanGeneratePreviews: Boolean """Generate image previews during scan""" - scanGenerateImagePreviews: Boolean! + scanGenerateImagePreviews: Boolean """Generate sprites during scan""" - scanGenerateSprites: Boolean! + scanGenerateSprites: Boolean } input CleanMetadataInput { diff --git a/pkg/image/image.go b/pkg/image/image.go index ec781afb7..f11579a0f 100644 --- a/pkg/image/image.go +++ b/pkg/image/image.go @@ -59,6 +59,13 @@ func ZipFilename(zipFilename, filenameInZip string) string { return zipFilename + zipSeparator + filenameInZip } +// IsZipPath returns true if the path includes the zip separator byte, +// indicating it is within a zip file. +// TODO - this should be moved to utils +func IsZipPath(p string) bool { + return strings.Contains(p, zipSeparator) +} + type imageReadCloser struct { src io.ReadCloser zrc *zip.ReadCloser diff --git a/pkg/manager/manager_tasks.go b/pkg/manager/manager_tasks.go index cf36f4c67..28e42022b 100644 --- a/pkg/manager/manager_tasks.go +++ b/pkg/manager/manager_tasks.go @@ -215,13 +215,13 @@ func (s *singleton) Scan(input models.ScanMetadataInput) { task := ScanTask{ TxnManager: s.TxnManager, FilePath: path, - UseFileMetadata: input.UseFileMetadata, - StripFileExtension: input.StripFileExtension, + UseFileMetadata: utils.IsTrue(input.UseFileMetadata), + StripFileExtension: utils.IsTrue(input.StripFileExtension), fileNamingAlgorithm: fileNamingAlgo, calculateMD5: calculateMD5, - GeneratePreview: input.ScanGeneratePreviews, - GenerateImagePreview: input.ScanGenerateImagePreviews, - GenerateSprite: input.ScanGenerateSprites, + GeneratePreview: utils.IsTrue(input.ScanGeneratePreviews), + GenerateImagePreview: utils.IsTrue(input.ScanGenerateImagePreviews), + GenerateSprite: utils.IsTrue(input.ScanGenerateSprites), } go task.Start(&wg) diff --git a/pkg/manager/task_scan.go b/pkg/manager/task_scan.go index f89600149..e2ac3834c 100644 --- a/pkg/manager/task_scan.go +++ b/pkg/manager/task_scan.go @@ -1044,6 +1044,12 @@ func walkFilesToScan(s *models.StashConfig, f filepath.WalkFunc) error { excludeVidRegex := generateRegexps(config.GetExcludes()) excludeImgRegex := generateRegexps(config.GetImageExcludes()) + // don't scan zip images directly + if image.IsZipPath(s.Path) { + logger.Warnf("Cannot rescan zip image %s. Rescan zip gallery instead.", s.Path) + return nil + } + generatedPath := config.GetGeneratedPath() return utils.SymWalk(s.Path, func(path string, info os.FileInfo, err error) error { diff --git a/pkg/utils/boolean.go b/pkg/utils/boolean.go index f0abd02c3..a5f23733b 100644 --- a/pkg/utils/boolean.go +++ b/pkg/utils/boolean.go @@ -7,3 +7,8 @@ func Btoi(b bool) int { } return 0 } + +// IsTrue returns true if the bool pointer is not nil and true. +func IsTrue(b *bool) bool { + return b != nil && *b +} diff --git a/ui/v2.5/src/components/Changelog/Changelog.tsx b/ui/v2.5/src/components/Changelog/Changelog.tsx index 1d8d321e8..7d0434a3c 100644 --- a/ui/v2.5/src/components/Changelog/Changelog.tsx +++ b/ui/v2.5/src/components/Changelog/Changelog.tsx @@ -8,6 +8,7 @@ import V021 from "./versions/v021.md"; import V030 from "./versions/v030.md"; import V040 from "./versions/v040.md"; import V050 from "./versions/v050.md"; +import V060 from "./versions/v060.md"; import { MarkdownPage } from "../Shared/MarkdownPage"; const Changelog: React.FC = () => { @@ -37,11 +38,19 @@ const Changelog: React.FC = () => { <>

Changelog:

+ + + diff --git a/ui/v2.5/src/components/Changelog/versions/v060.md b/ui/v2.5/src/components/Changelog/versions/v060.md new file mode 100644 index 000000000..1ffc59935 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/versions/v060.md @@ -0,0 +1,2 @@ +### 🎨 Improvements +* Added Rescan button to scene, image, gallery details overflow button. diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx index b4353fdde..f947bd658 100644 --- a/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx @@ -1,7 +1,11 @@ import { Tab, Nav, Dropdown } from "react-bootstrap"; import React, { useEffect, useState } from "react"; import { useParams, useHistory, Link } from "react-router-dom"; -import { useFindGallery, useGalleryUpdate } from "src/core/StashService"; +import { + mutateMetadataScan, + useFindGallery, + useGalleryUpdate, +} from "src/core/StashService"; import { ErrorMessage, LoadingIndicator, Icon } from "src/components/Shared"; import { TextUtils } from "src/utils"; import * as Mousetrap from "mousetrap"; @@ -60,6 +64,18 @@ export const Gallery: React.FC = () => { } }; + async function onRescan() { + if (!gallery || !gallery.path) { + return; + } + + await mutateMetadataScan({ + paths: [gallery.path], + }); + + Toast.success({ content: "Rescanning image" }); + } + const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); function onDeleteDialogClosed(deleted: boolean) { @@ -92,6 +108,15 @@ export const Gallery: React.FC = () => { + {gallery?.path ? ( + onRescan()} + > + Rescan + + ) : undefined} { const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); + async function onRescan() { + if (!image) { + return; + } + + await mutateMetadataScan({ + paths: [image.path], + }); + + Toast.success({ content: "Rescanning image" }); + } + const onOrganizedClick = async () => { try { setOrganizedLoading(true); @@ -121,6 +134,13 @@ export const Image: React.FC = () => { + onRescan()} + > + Rescan + { error: streamableError, loading: streamableLoading, } = useSceneStreams(id); + const [oLoading, setOLoading] = useState(false); const [incrementO] = useSceneIncrementO(scene?.id ?? "0"); const [decrementO] = useSceneDecrementO(scene?.id ?? "0"); @@ -130,6 +132,18 @@ export const Scene: React.FC = () => { setTimestamp(marker.seconds); } + async function onRescan() { + if (!scene) { + return; + } + + await mutateMetadataScan({ + paths: [scene.path], + }); + + Toast.success({ content: "Rescanning scene" }); + } + async function onGenerateScreenshot(at?: number) { if (!scene) { return; @@ -184,6 +198,13 @@ export const Scene: React.FC = () => { + onRescan()} + > + Rescan + Date: Tue, 23 Feb 2021 03:03:02 +0100 Subject: [PATCH 02/46] Enable keepalive for websocket connection (#1134) --- pkg/api/server.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/api/server.go b/pkg/api/server.go index 0fc201cc6..331e203f3 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -14,6 +14,7 @@ import ( "runtime/debug" "strconv" "strings" + "time" "github.com/99designs/gqlgen/handler" "github.com/go-chi/chi" @@ -135,12 +136,14 @@ func Start() { }, }) maxUploadSize := handler.UploadMaxSize(config.GetMaxUploadSize()) + websocketKeepAliveDuration := handler.WebsocketKeepAliveDuration(10 * time.Second) txnManager := manager.GetInstance().TxnManager resolver := &Resolver{ txnManager: txnManager, } - gqlHandler := handler.GraphQL(models.NewExecutableSchema(models.Config{Resolvers: resolver}), recoverFunc, websocketUpgrader, maxUploadSize) + + gqlHandler := handler.GraphQL(models.NewExecutableSchema(models.Config{Resolvers: resolver}), recoverFunc, websocketUpgrader, websocketKeepAliveDuration, maxUploadSize) r.Handle("/graphql", gqlHandler) r.Handle("/playground", handler.Playground("GraphQL playground", "/graphql")) From acbdee76dee7dd178059693dd8da0093f815ea3c Mon Sep 17 00:00:00 2001 From: SpedNSFW <68614336+SpedNSFW@users.noreply.github.com> Date: Tue, 23 Feb 2021 13:40:43 +1100 Subject: [PATCH 03/46] Random strings for cookie values (#1122) --- pkg/scraper/config.go | 9 ++++--- pkg/scraper/cookies.go | 12 +++++++-- pkg/utils/strings.go | 17 ++++++++++++ .../src/components/Changelog/versions/v060.md | 1 + ui/v2.5/src/docs/en/Scraping.md | 27 +++++++++++++++++++ 5 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 pkg/utils/strings.go diff --git a/pkg/scraper/config.go b/pkg/scraper/config.go index c81fb2061..7d5d49ebf 100644 --- a/pkg/scraper/config.go +++ b/pkg/scraper/config.go @@ -158,10 +158,11 @@ type scraperDebugOptions struct { } type scraperCookies struct { - Name string `yaml:"Name"` - Value string `yaml:"Value"` - Domain string `yaml:"Domain"` - Path string `yaml:"Path"` + Name string `yaml:"Name"` + Value string `yaml:"Value"` + ValueRandom int `yaml:"ValueRandom"` + Domain string `yaml:"Domain"` + Path string `yaml:"Path"` } type cookieOptions struct { diff --git a/pkg/scraper/cookies.go b/pkg/scraper/cookies.go index 0e3ae3d70..fbcc05d50 100644 --- a/pkg/scraper/cookies.go +++ b/pkg/scraper/cookies.go @@ -13,6 +13,7 @@ import ( "github.com/chromedp/chromedp" "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/utils" ) // set cookies for the native http client @@ -32,7 +33,7 @@ func setCookies(jar *cookiejar.Jar, scraperConfig config) { for _, cookie := range ckURL.Cookies { httpCookie = &http.Cookie{ Name: cookie.Name, - Value: cookie.Value, + Value: getCookieValue(cookie), Path: cookie.Path, Domain: cookie.Domain, } @@ -53,6 +54,13 @@ func setCookies(jar *cookiejar.Jar, scraperConfig config) { } } +func getCookieValue(cookie *scraperCookies) string { + if cookie.ValueRandom > 0 { + return utils.RandomSequence(cookie.ValueRandom) + } + return cookie.Value +} + // print all cookies from the jar of the native http client func printCookies(jar *cookiejar.Jar, scraperConfig config, msg string) { driverOptions := scraperConfig.DriverOptions @@ -92,7 +100,7 @@ func setCDPCookies(driverOptions scraperDriverOptions) chromedp.Tasks { for _, ckURL := range driverOptions.Cookies { for _, cookie := range ckURL.Cookies { - success, err := network.SetCookie(cookie.Name, cookie.Value). + success, err := network.SetCookie(cookie.Name, getCookieValue(cookie)). WithExpires(&expr). WithDomain(cookie.Domain). WithPath(cookie.Path). diff --git a/pkg/utils/strings.go b/pkg/utils/strings.go new file mode 100644 index 000000000..f0b8d93d4 --- /dev/null +++ b/pkg/utils/strings.go @@ -0,0 +1,17 @@ +package utils + +import ( + "math/rand" + "time" +) + +var characters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") + +func RandomSequence(n int) string { + b := make([]rune, n) + rand.Seed(time.Now().UnixNano()) + for i := range b { + b[i] = characters[rand.Intn(len(characters))] + } + return string(b) +} diff --git a/ui/v2.5/src/components/Changelog/versions/v060.md b/ui/v2.5/src/components/Changelog/versions/v060.md index 1ffc59935..0cbc0caf1 100644 --- a/ui/v2.5/src/components/Changelog/versions/v060.md +++ b/ui/v2.5/src/components/Changelog/versions/v060.md @@ -1,2 +1,3 @@ ### 🎨 Improvements +* Support random strings for scraper cookie values. * Added Rescan button to scene, image, gallery details overflow button. diff --git a/ui/v2.5/src/docs/en/Scraping.md b/ui/v2.5/src/docs/en/Scraping.md index d65630eeb..3c9cd2692 100644 --- a/ui/v2.5/src/docs/en/Scraping.md +++ b/ui/v2.5/src/docs/en/Scraping.md @@ -489,6 +489,33 @@ driver: Domain: ".somewhere.com" ``` +For some sites, the value of the cookie itself doesn't actually matter. In these cases, we can use the `ValueRandom` +property instead of `Value`. Unlike `Value`, `ValueRandom` requires an integer value greater than `0` where the value +indicates how long the cookie string should be. + +In the following example, we will adapt the previous cookies to use `ValueRandom` instead. We set the `_test2` cookie +to randomly generate a value with a length of 6 characters and the `_warn` cookie to a length of 3. + +```yaml +driver: + cookies: + - CookieURL: "https://www.example.com" + Cookies: + - Name: "_warning" + Domain: ".example.com" + Value: "true" + Path: "/" + - Name: "_test2" + ValueRandom: 6 + Domain: ".example.com" + Path: "/" + - CookieURL: "https://api.somewhere.com" + Cookies: + - Name: "_warn" + ValueRandom: 3 + Domain: ".somewhere.com" +``` + When developing a scraper you can have a look at the cookies set by a site by adding * a `CookieURL` if you use the direct xpath scraper From 777956f0abd25c8fa2a48701a0285fd9f6495d80 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Wed, 24 Feb 2021 11:26:48 +1100 Subject: [PATCH 04/46] GitHub actions (#1146) --- .github/workflows/build.yml | 151 ++++++++++++++++++++++++++++ .travis.yml => .travis.yml.disabled | 0 scripts/check-gofmt.sh | 4 +- scripts/cross-compile.sh | 2 +- 4 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/build.yml rename .travis.yml => .travis.yml.disabled (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..2824165fc --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,151 @@ +name: Build + +on: + push: + branches: [ develop, master ] + pull_request: + branches: [ develop ] + release: + types: [ published ] + +jobs: + build: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: Checkout + run: git fetch --prune --unshallow --tags + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.13 + + - name: Set up Node + uses: actions/setup-node@v2 + with: + node-version: '12' + + - name: Cache node modules + uses: actions/cache@v2 + env: + cache-name: cache-node_modules + with: + path: ui/v2.5/node_modules + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Pre-install + run: make pre-ui + + - name: Generate + run: make generate + + - name: Validate + run: make ui-validate fmt-check vet it + + - name: Build UI + run: make ui-only + + - name: Cross Compile + run: | + docker pull stashapp/compiler:4 + ./scripts/cross-compile.sh + + - name: Generate checksums + run: | + git describe --tags --exclude latest_develop | tee CHECKSUMS_SHA1 + sha1sum dist/stash-* | sed 's/dist\///g' | tee -a CHECKSUMS_SHA1 + echo "STASH_VERSION=$(git describe --tags --exclude latest_develop)" >> $GITHUB_ENV + echo "RELEASE_DATE=$(date +'%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_ENV + + - name: Upload Windows binary + # only upload binaries for pull requests + if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/develop' && github.base_ref != 'refs/heads/master'}} + uses: actions/upload-artifact@v2 + with: + name: stash-win.exe + path: dist/stash-win.exe + + - name: Upload OSX binary + # only upload binaries for pull requests + if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/develop' && github.base_ref != 'refs/heads/master'}} + uses: actions/upload-artifact@v2 + with: + name: stash-osx + path: dist/stash-osx + + - name: Upload Linux binary + # only upload binaries for pull requests + if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/develop' && github.base_ref != 'refs/heads/master'}} + uses: actions/upload-artifact@v2 + with: + name: stash-linux + path: dist/stash-linux + + - name: Development Release + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} + uses: meeDamian/github-release@2.0 + with: + token: "${{ secrets.GITHUB_TOKEN }}" + prerelease: true + allow_override: true + tag: latest_develop + name: "${{ env.STASH_VERSION }}: Latest development build" + body: "**${{ env.RELEASE_DATE }}**\n This is always the latest committed version on the develop branch. Use as your own risk!" + files: | + dist/stash-osx + dist/stash-win.exe + dist/stash-linux + dist/stash-linux-arm64v8 + dist/stash-linux-arm32v7 + dist/stash-pi + CHECKSUMS_SHA1 + gzip: false + + - name: Master release + if: ${{ github.event_name == 'release' && github.ref != 'refs/tags/latest_develop' }} + uses: meeDamian/github-release@2.0 + with: + token: "${{ secrets.GITHUB_TOKEN }}" + files: | + dist/stash-osx + dist/stash-win.exe + dist/stash-linux + dist/stash-linux-arm64v8 + dist/stash-linux-arm32v7 + dist/stash-pi + CHECKSUMS_SHA1 + gzip: false + + - name: Development Docker + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} + env: + DOCKER_CLI_EXPERIMENTAL: enabled + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + run: | + docker run --rm --privileged docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64 + docker info + docker buildx create --name builder --use + docker buildx inspect --bootstrap + docker buildx ls + bash ./docker/ci/x86_64/docker_push.sh development + + - name: Release Docker + if: ${{ github.event_name == 'release' && github.ref != 'refs/tags/latest_develop' }} + env: + DOCKER_CLI_EXPERIMENTAL: enabled + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + run: | + docker run --rm --privileged docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64 + docker info + docker buildx create --name builder --use + docker buildx inspect --bootstrap + docker buildx ls + bash ./docker/ci/x86_64/docker_push.sh latest diff --git a/.travis.yml b/.travis.yml.disabled similarity index 100% rename from .travis.yml rename to .travis.yml.disabled diff --git a/scripts/check-gofmt.sh b/scripts/check-gofmt.sh index 7ea5015c8..24fa914a5 100644 --- a/scripts/check-gofmt.sh +++ b/scripts/check-gofmt.sh @@ -28,8 +28,8 @@ # (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 +gofiles=./pkg/ +[ "$OS" = "Windows_NT" ] && gofiles=.\\pkg\\ unformatted=$(gofmt -l $gofiles) [ -z "$unformatted" ] && exit 0 diff --git a/scripts/cross-compile.sh b/scripts/cross-compile.sh index e6774d94c..5e6d302d4 100755 --- a/scripts/cross-compile.sh +++ b/scripts/cross-compile.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # "stashapp/compiler:develop" "stashapp/compiler:4" COMPILER_CONTAINER="stashapp/compiler:4" From 8ec25ef161b20b7386eb1580526d65820436f19d Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Wed, 24 Feb 2021 13:48:56 +1100 Subject: [PATCH 05/46] Add commitish for dev release --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2824165fc..0dd3b911a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -95,6 +95,7 @@ jobs: prerelease: true allow_override: true tag: latest_develop + commitish: develop name: "${{ env.STASH_VERSION }}: Latest development build" body: "**${{ env.RELEASE_DATE }}**\n This is always the latest committed version on the develop branch. Use as your own risk!" files: | From af6b21a428e6411f5c1f483fbe40bb3f3564b18b Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Wed, 24 Feb 2021 14:36:39 +1100 Subject: [PATCH 06/46] Update latest_develop tag --- .github/workflows/build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0dd3b911a..c343fa522 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -86,6 +86,10 @@ jobs: with: name: stash-linux path: dist/stash-linux + + - name: Update latest_develop tag + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} + run : git tag -f latest_develop; git push -f --tags - name: Development Release if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} @@ -95,7 +99,6 @@ jobs: prerelease: true allow_override: true tag: latest_develop - commitish: develop name: "${{ env.STASH_VERSION }}: Latest development build" body: "**${{ env.RELEASE_DATE }}**\n This is always the latest committed version on the develop branch. Use as your own risk!" files: | From a9ac176e910f75e58584b2f0b7637dfa720e6d24 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Fri, 26 Feb 2021 16:13:34 +1100 Subject: [PATCH 07/46] Mobile UI improvements (#1104) * Use dropdown for o-counter instead of hover * Always show previews on non-hoverable device * Add IntersectionObserver polyfill * Prevent video previews playing fullscreen --- ui/v2.5/package.json | 1 + .../src/components/Changelog/versions/v060.md | 5 ++ ui/v2.5/src/components/Scenes/SceneCard.tsx | 21 +++-- .../Scenes/SceneDetails/OCounterButton.tsx | 77 +++++++++---------- ui/v2.5/src/components/Scenes/styles.scss | 44 +++++++++-- ui/v2.5/src/components/Wall/WallItem.tsx | 2 + ui/v2.5/src/polyfills.ts | 1 + ui/v2.5/src/styles/_theme.scss | 2 +- ui/v2.5/yarn.lock | 5 ++ 9 files changed, 98 insertions(+), 60 deletions(-) diff --git a/ui/v2.5/package.json b/ui/v2.5/package.json index 8f4ad36a3..9be6ccd81 100644 --- a/ui/v2.5/package.json +++ b/ui/v2.5/package.json @@ -46,6 +46,7 @@ "graphql": "^15.4.0", "graphql-tag": "^2.11.0", "i18n-iso-countries": "^6.4.0", + "intersection-observer": "^0.12.0", "jimp": "^0.16.1", "localforage": "1.9.0", "lodash": "^4.17.20", diff --git a/ui/v2.5/src/components/Changelog/versions/v060.md b/ui/v2.5/src/components/Changelog/versions/v060.md index 0cbc0caf1..f03ccad4f 100644 --- a/ui/v2.5/src/components/Changelog/versions/v060.md +++ b/ui/v2.5/src/components/Changelog/versions/v060.md @@ -1,3 +1,8 @@ ### 🎨 Improvements +* Auto-play video previews on mobile devices. +* Replace hover menu with dropdown menu for O-Counter. * Support random strings for scraper cookie values. * Added Rescan button to scene, image, gallery details overflow button. + +### 🐛 Bug fixes +* Prevent scene card previews playing in full-screen on iOS devices. diff --git a/ui/v2.5/src/components/Scenes/SceneCard.tsx b/ui/v2.5/src/components/Scenes/SceneCard.tsx index c9ea31e82..a5db7d230 100644 --- a/ui/v2.5/src/components/Scenes/SceneCard.tsx +++ b/ui/v2.5/src/components/Scenes/SceneCard.tsx @@ -29,17 +29,14 @@ export const ScenePreview: React.FC = ({ const videoEl = useRef(null); useEffect(() => { - const observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.intersectionRatio > 0) - // Catch is necessary due to DOMException if user hovers before clicking on page - videoEl.current?.play().catch(() => {}); - else videoEl.current?.pause(); - }); - }, - { root: document.documentElement } - ); + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.intersectionRatio > 0) + // Catch is necessary due to DOMException if user hovers before clicking on page + videoEl.current?.play().catch(() => {}); + else videoEl.current?.pause(); + }); + }); if (videoEl.current) observer.observe(videoEl.current); }); @@ -53,6 +50,8 @@ export const ScenePreview: React.FC = ({
- } - enterDelay={1000} - placement="bottom" - onOpen={props.onMenuOpened} - onClose={props.onMenuClosed} - > - {renderButton()} - - ); - } - return renderButton(); + const maybeRenderDropdown = () => { + if (props.value) { + return ( + + + + Decrement + + + + Reset + + + ); + } + }; + + return ( + + {renderButton()} + {maybeRenderDropdown()} + + ); }; diff --git a/ui/v2.5/src/components/Scenes/styles.scss b/ui/v2.5/src/components/Scenes/styles.scss index 73538c968..e04288211 100644 --- a/ui/v2.5/src/components/Scenes/styles.scss +++ b/ui/v2.5/src/components/Scenes/styles.scss @@ -209,15 +209,36 @@ textarea.scene-description { } } - &:hover { - .scene-specs-overlay, - .rating-banner, - .scene-studio-overlay { - opacity: 0; - transition: opacity 0.5s; - } + @media (pointer: fine) { + &:hover { + .scene-specs-overlay, + .rating-banner, + .scene-studio-overlay { + opacity: 0; + transition: opacity 0.5s; + } - .scene-studio-overlay:hover { + .scene-studio-overlay:hover { + opacity: 0.75; + transition: opacity 0.5s; + } + + .scene-card-check { + opacity: 0.75; + transition: opacity 0.5s; + } + + .scene-card-preview-video { + top: 0; + transition-delay: 0.2s; + } + } + } + + /* replicate hover for non-hoverable interfaces */ + @media (hover: none), (pointer: coarse), (pointer: none) { + /* don't hide overlays */ + .scene-studio-overlay { opacity: 0.75; transition: opacity 0.5s; } @@ -545,3 +566,10 @@ input[type="range"].blue-slider { color: #664c3f; } } + +.o-counter .dropdown-toggle { + background-color: rgba(0, 0, 0, 0); + border: none; + padding-left: 0; + padding-right: 0.25rem; +} diff --git a/ui/v2.5/src/components/Wall/WallItem.tsx b/ui/v2.5/src/components/Wall/WallItem.tsx index 4d2b36c3d..24ccdb92d 100644 --- a/ui/v2.5/src/components/Wall/WallItem.tsx +++ b/ui/v2.5/src/components/Wall/WallItem.tsx @@ -57,6 +57,8 @@ const Preview: React.FC<{ ); const video = (