mirror of
https://github.com/stashapp/stash.git
synced 2026-06-11 07:41:08 -05:00
Compare commits
14 Commits
v0.0.0-alp
...
v0.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71ca30e8f4 | ||
|
|
691a8c23c0 | ||
|
|
8d57629af3 | ||
|
|
bf49a23df8 | ||
|
|
776727140f | ||
|
|
df3d3d24f5 | ||
|
|
aa8bfaf407 | ||
|
|
df890dca79 | ||
|
|
ae5aa6a6ec | ||
|
|
c99ba68181 | ||
|
|
1d9913d268 | ||
|
|
40de2caa95 | ||
|
|
254d6978d0 | ||
|
|
3c1eeb3d47 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -6,7 +6,7 @@ open_collective: stashapp
|
||||
# ko_fi: # Replace with a single Ko-fi username
|
||||
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: StashApp
|
||||
# liberapay: StashApp
|
||||
# issuehunt: # Replace with a single IssueHunt username
|
||||
# otechie: # Replace with a single Otechie username
|
||||
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
|
||||
18
.github/PULL_REQUEST_TEMPLATE/BugFix.md
vendored
Normal file
18
.github/PULL_REQUEST_TEMPLATE/BugFix.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: Bug Fix
|
||||
about: Add a bug fix this project!
|
||||
title: "[Bug Fix] Short Form Title (50 chars or less.)"
|
||||
labels: bug
|
||||
assignees: 'WithoutPants, bnkai, Leopere'
|
||||
|
||||
---
|
||||
<!-- Please make sure to read https://github.com/stashapp/stash/docs/CONTRIBUTING.md and check that you understand and have followed it as best as possible -->
|
||||
<!-- Explain what your bugfix seeks to remedy in a short paragraph. -->
|
||||
# Scope
|
||||
|
||||
<!-- Declare any issues by typing `fixes #1` or `closes #1` for example so that the automation can kick in when this is merged -->
|
||||
## Closes/Fixes Issues
|
||||
|
||||
<!-- What have you tested specifically and what possible impacts/areas there are that may need retesting by others. -->
|
||||
## Other testing QA Notes
|
||||
|
||||
17
.github/PULL_REQUEST_TEMPLATE/Feature.md
vendored
Normal file
17
.github/PULL_REQUEST_TEMPLATE/Feature.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature Addition
|
||||
about: Add a feature to this project!
|
||||
title: "[Feature] Short Form Title (50 chars or less.)"
|
||||
labels: enhancement
|
||||
assignees: 'WithoutPants, bnkai, Leopere'
|
||||
|
||||
---
|
||||
<!-- Please make sure to read https://github.com/stashapp/stash/docs/CONTRIBUTING.md and check that you understand and have followed it as best as possible
|
||||
Explain what your feature does in a short paragraph. -->
|
||||
# Scope
|
||||
|
||||
<!-- Declare any issues by typing `fixes #1` or `closes #1` for example so that the automation can kick in when this is merged -->
|
||||
## Closes/Fixes Issues
|
||||
|
||||
<!-- What have you tested specifically and what possible impacts/areas there are that may need retesting by others. -->
|
||||
## Other testing QA Notes
|
||||
67
.travis.yml
67
.travis.yml
@@ -18,32 +18,57 @@ script:
|
||||
#- make vet
|
||||
- make it
|
||||
after_success:
|
||||
- if [ "$TRAVIS_BRANCH" = "develop" ]; then export TAG_SUFFIX="_dev"; elif [ "$TRAVIS_BRANCH" != "master" ]; then export TAG_SUFFIX="_$TRAVIS_BRANCH"; fi
|
||||
- export STASH_VERSION="v0.0.0-alpha${TAG_SUFFIX}"
|
||||
- docker pull stashapp/compiler:develop
|
||||
- sh ./scripts/cross-compile.sh ${STASH_VERSION}
|
||||
- sh ./scripts/cross-compile.sh
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then sh ./scripts/upload-pull-request.sh; fi'
|
||||
before_deploy:
|
||||
- if [ "$TRAVIS_BRANCH" = "develop" ]; then export TAG_SUFFIX="_dev"; fi
|
||||
- git tag -f ${STASH_VERSION}
|
||||
- git push -f --tags
|
||||
# push the latest tag when on the develop branch
|
||||
- if [ "$TRAVIS_BRANCH" = "develop" ]; then git tag -f latest_develop; git push -f --tags; fi
|
||||
- export RELEASE_DATE=$(date +'%Y-%m-%d %H:%M:%S %Z')
|
||||
- export STASH_VERSION=$(git describe --tags --exclude latest_develop)
|
||||
# set TRAVIS_TAG explcitly to the version so that it doesn't pick up latest_develop
|
||||
- if [ "$TRAVIS_BRANCH" = "master"]; then export TRAVIS_TAG=${STASH_VERSION}; fi
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: tGJ2q62CfPdayid2qEtW2aGRhMgCl3lBXYYQqp3eH0vFgIIf6cs7IDX7YC/x3XKMEQ/iMLZmtCXZvSTqNrD6Sk7MSnt30GIs+4uxIZDnnd8mV5X3K4n4gjD+NAORc4DrQBvUGrYMKJsR5gtkH0nu6diWb1o1If7OiJEuCPRhrmQYcza7NUdABnA9Z2wn2RNUV9Ga33WUCqLMEU5GtNBlfQPiP/khCQrqn/ocR6wUjYut3J6YagzqH4wsfJi3glHyWtowcNIw1LZi5zFxHD/bRBT4Tln7yypkjWNq9eQILA6i6kRUGf7ggyTx26/k8n4tnu+QD0vVh4EcjlThpU/LGyUXzKrrxjRwaDZnM0oYxg5AfHcBuAiAdo0eWnV3lEWRfTJMIVb9MPf4qDmzR4RREfB5OXOxwq3ODeCcJE8sTIMD/wBPZrlqS/QrRpND2gn2X4snkVukN9t9F4CMTFMtVSzFV7TDJW5E5Lq6VEExulteQhs6kcK9NRPNAaLgRQAw7X9kVWfDtiGUP+fE2i8F9Bo8bm7sOT5O5VPMPykx3EgeNg1IqIgMTCsMlhMJT4xBJoQUgmd2wWyf3Ryw+P+sFgdb5Sd7+lFgJBjMUUoOxMxAOiEgdFvCXcr+/Udyz2RdtetU1/6VzXzLPcKOw0wubZeBkISqu7o9gpfdMP9Eq00=
|
||||
file:
|
||||
- dist/stash-osx
|
||||
- dist/stash-win.exe
|
||||
- dist/stash-linux
|
||||
- dist/stash-pi
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
body: ${RELEASE_DATE}
|
||||
on:
|
||||
repo: stashapp/stash
|
||||
all_branches: true
|
||||
condition: $TRAVIS_BRANCH =~ ^(master|develop)$
|
||||
# latest develop release
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: tGJ2q62CfPdayid2qEtW2aGRhMgCl3lBXYYQqp3eH0vFgIIf6cs7IDX7YC/x3XKMEQ/iMLZmtCXZvSTqNrD6Sk7MSnt30GIs+4uxIZDnnd8mV5X3K4n4gjD+NAORc4DrQBvUGrYMKJsR5gtkH0nu6diWb1o1If7OiJEuCPRhrmQYcza7NUdABnA9Z2wn2RNUV9Ga33WUCqLMEU5GtNBlfQPiP/khCQrqn/ocR6wUjYut3J6YagzqH4wsfJi3glHyWtowcNIw1LZi5zFxHD/bRBT4Tln7yypkjWNq9eQILA6i6kRUGf7ggyTx26/k8n4tnu+QD0vVh4EcjlThpU/LGyUXzKrrxjRwaDZnM0oYxg5AfHcBuAiAdo0eWnV3lEWRfTJMIVb9MPf4qDmzR4RREfB5OXOxwq3ODeCcJE8sTIMD/wBPZrlqS/QrRpND2gn2X4snkVukN9t9F4CMTFMtVSzFV7TDJW5E5Lq6VEExulteQhs6kcK9NRPNAaLgRQAw7X9kVWfDtiGUP+fE2i8F9Bo8bm7sOT5O5VPMPykx3EgeNg1IqIgMTCsMlhMJT4xBJoQUgmd2wWyf3Ryw+P+sFgdb5Sd7+lFgJBjMUUoOxMxAOiEgdFvCXcr+/Udyz2RdtetU1/6VzXzLPcKOw0wubZeBkISqu7o9gpfdMP9Eq00=
|
||||
file:
|
||||
- dist/stash-osx
|
||||
- dist/stash-win.exe
|
||||
- dist/stash-linux
|
||||
- dist/stash-pi
|
||||
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!
|
||||
prerelease: true
|
||||
on:
|
||||
repo: stashapp/stash
|
||||
branch: develop
|
||||
# official master release - only build when tagged
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: tGJ2q62CfPdayid2qEtW2aGRhMgCl3lBXYYQqp3eH0vFgIIf6cs7IDX7YC/x3XKMEQ/iMLZmtCXZvSTqNrD6Sk7MSnt30GIs+4uxIZDnnd8mV5X3K4n4gjD+NAORc4DrQBvUGrYMKJsR5gtkH0nu6diWb1o1If7OiJEuCPRhrmQYcza7NUdABnA9Z2wn2RNUV9Ga33WUCqLMEU5GtNBlfQPiP/khCQrqn/ocR6wUjYut3J6YagzqH4wsfJi3glHyWtowcNIw1LZi5zFxHD/bRBT4Tln7yypkjWNq9eQILA6i6kRUGf7ggyTx26/k8n4tnu+QD0vVh4EcjlThpU/LGyUXzKrrxjRwaDZnM0oYxg5AfHcBuAiAdo0eWnV3lEWRfTJMIVb9MPf4qDmzR4RREfB5OXOxwq3ODeCcJE8sTIMD/wBPZrlqS/QrRpND2gn2X4snkVukN9t9F4CMTFMtVSzFV7TDJW5E5Lq6VEExulteQhs6kcK9NRPNAaLgRQAw7X9kVWfDtiGUP+fE2i8F9Bo8bm7sOT5O5VPMPykx3EgeNg1IqIgMTCsMlhMJT4xBJoQUgmd2wWyf3Ryw+P+sFgdb5Sd7+lFgJBjMUUoOxMxAOiEgdFvCXcr+/Udyz2RdtetU1/6VzXzLPcKOw0wubZeBkISqu7o9gpfdMP9Eq00=
|
||||
file:
|
||||
- dist/stash-osx
|
||||
- dist/stash-win.exe
|
||||
- dist/stash-linux
|
||||
- dist/stash-pi
|
||||
# make the release a draft so the maintainers can confirm before releasing
|
||||
draft: true
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
# don't write the body. To be done manually for now. In future we might
|
||||
# want to generate the changelog or get it from a file
|
||||
name: ${STASH_VERSION}
|
||||
on:
|
||||
repo: stashapp/stash
|
||||
branch: master
|
||||
tags: true
|
||||
# make sure we don't release using the latest_develop tag
|
||||
condition: $TRAVIS_TAG != latest_develop
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
3
Makefile
3
Makefile
@@ -8,7 +8,8 @@ release: generate ui build
|
||||
build:
|
||||
$(eval DATE := $(shell go run scripts/getDate.go))
|
||||
$(eval GITHASH := $(shell git rev-parse --short HEAD))
|
||||
$(SET) CGO_ENABLED=1 $(SEPARATOR) go build -mod=vendor -v -ldflags "-X 'github.com/stashapp/stash/pkg/api.buildstamp=$(DATE)' -X 'github.com/stashapp/stash/pkg/api.githash=$(GITHASH)'"
|
||||
$(eval STASH_VERSION := $(shell git describe --tags --exclude latest_develop))
|
||||
$(SET) CGO_ENABLED=1 $(SEPARATOR) go build -mod=vendor -v -ldflags "-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)'"
|
||||
|
||||
install:
|
||||
packr2 install
|
||||
|
||||
55
docker/build/x86_64/Dockerfile
Normal file
55
docker/build/x86_64/Dockerfile
Normal file
@@ -0,0 +1,55 @@
|
||||
# this dockerfile must be built from the top-level stash directory
|
||||
# ie from top=level stash:
|
||||
# docker build -t stash/build -f docker/build/x86_64/Dockerfile .
|
||||
|
||||
FROM golang:1.11.13 as compiler
|
||||
|
||||
RUN apt-get update && apt-get install -y apt-transport-https
|
||||
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
|
||||
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
|
||||
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y nodejs yarn xz-utils --no-install-recommends || exit 1; \
|
||||
rm -rf /var/lib/apt/lists/*;
|
||||
|
||||
ENV PACKR2_VERSION=2.0.2
|
||||
ENV PACKR2_SHA=f95ff4c96d7a28813220df030ad91700b8464fe292ab3e1dc9582305c2a338d2
|
||||
ENV PACKR2_DOWNLOAD_FILE=packr_${PACKR2_VERSION}_linux_amd64.tar.gz
|
||||
ENV PACKR2_DOWNLOAD_URL=https://github.com/gobuffalo/packr/releases/download/v${PACKR2_VERSION}/${PACKR2_DOWNLOAD_FILE}
|
||||
|
||||
WORKDIR /
|
||||
RUN wget ${PACKR2_DOWNLOAD_URL}; \
|
||||
echo "$PACKR2_SHA $PACKR2_DOWNLOAD_FILE" | sha256sum -c - || exit 1; \
|
||||
tar -xzf $PACKR2_DOWNLOAD_FILE -C /usr/bin/ packr2; \
|
||||
rm $PACKR2_DOWNLOAD_FILE;
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
RUN wget -O /ffmpeg.tar.xz https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \
|
||||
tar xf /ffmpeg.tar.xz && \
|
||||
rm ffmpeg.tar.xz && \
|
||||
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/
|
||||
|
||||
WORKDIR /stash
|
||||
RUN yarn --cwd ui/v2 install --frozen-lockfile
|
||||
|
||||
COPY . /stash/
|
||||
ENV GO111MODULE=on
|
||||
|
||||
RUN make generate
|
||||
RUN make ui
|
||||
RUN make build
|
||||
|
||||
FROM ubuntu:19.10 as app
|
||||
|
||||
RUN apt-get update && apt-get -y install ca-certificates
|
||||
COPY --from=compiler /stash/stash /ffmpeg/ffmpeg /ffmpeg/ffprobe /usr/bin/
|
||||
|
||||
EXPOSE 9999
|
||||
CMD ["stash"]
|
||||
|
||||
|
||||
67
docker/build/x86_64/README.md
Normal file
67
docker/build/x86_64/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Introduction
|
||||
|
||||
This dockerfile is used to build a stash docker container using the current source code.
|
||||
|
||||
# Building the docker container
|
||||
|
||||
From the top-level directory (should contain `main.go` file):
|
||||
|
||||
```
|
||||
docker build -t stash/build -f ./docker/build/x86_64/Dockerfile .
|
||||
|
||||
```
|
||||
|
||||
# Running the docker container
|
||||
|
||||
## Using docker-compose
|
||||
|
||||
See the `README.md` file in `docker/production` for instructions on how to get docker-compose if needed.
|
||||
|
||||
The `stash/build` container can be run with the `docker-compose.yml` file in `docker/production` by changing the `image` value to be `stash/build`. See the instructions in `docker/production` for how to run docker-compose.
|
||||
|
||||
## Using `docker run`
|
||||
|
||||
After building the container:
|
||||
|
||||
```
|
||||
docker run \
|
||||
-e STASH_STASH=/data/ \
|
||||
-e STASH_METADATA=/metadata/ \
|
||||
-e STASH_CACHE=/cache/ \
|
||||
-e STASH_GENERATED=/generated/ \
|
||||
-v <path to config dir>:/root/.stash \
|
||||
-v <path to media>:/data \
|
||||
-v <path to metadata>:/metadata \
|
||||
-v <path to cache>:/cache \
|
||||
-v <path to generated>:/generated \
|
||||
-p 9999:9999 \
|
||||
stash/build:latest
|
||||
```
|
||||
|
||||
Change the `<xxx>` to the appropriate paths. Note that the `<path to media>` directory should be separate from the cache, generated and metadata directories. It is recommended to have the cache, generated and metadata directories in the same parent directory, for example:
|
||||
|
||||
```
|
||||
/stash
|
||||
/config
|
||||
/metadata
|
||||
/generated
|
||||
/cache
|
||||
/media
|
||||
```
|
||||
|
||||
Using this example directory structure, the above command would be:
|
||||
|
||||
```
|
||||
docker run \
|
||||
-e STASH_STASH=/data/ \
|
||||
-e STASH_METADATA=/metadata/ \
|
||||
-e STASH_CACHE=/cache/ \
|
||||
-e STASH_GENERATED=/generated/ \
|
||||
-v /stash/config:/root/.stash \
|
||||
-v /media:/data \
|
||||
-v /stash/metadata:/metadata \
|
||||
-v /stash/cache:/cache \
|
||||
-v /stash/generated:/generated \
|
||||
-p 9999:9999 \
|
||||
stash/build:latest
|
||||
```
|
||||
21
docker/develop/x86_64/Dockerfile
Normal file
21
docker/develop/x86_64/Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
||||
FROM ubuntu:18.04 as prep
|
||||
LABEL MAINTAINER="https://discord.gg/Uz29ny"
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y install curl xz-utils && \
|
||||
apt-get autoclean -y && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN curl -L -o /stash $(curl -s https://api.github.com/repos/stashapp/stash/releases/tags/latest_develop | awk '/browser_download_url/ && /stash-linux/' | sed -e 's/.*: "\(.*\)"/\1/') && \
|
||||
chmod +x /stash && \
|
||||
curl --http1.1 -o /ffmpeg.tar.xz https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \
|
||||
tar xf /ffmpeg.tar.xz && \
|
||||
rm ffmpeg.tar.xz && \
|
||||
mv /ffmpeg*/ /ffmpeg/
|
||||
|
||||
FROM ubuntu:18.04 as app
|
||||
RUN apt-get update && apt-get -y install ca-certificates
|
||||
COPY --from=prep /stash /ffmpeg/ffmpeg /ffmpeg/ffprobe /usr/bin/
|
||||
EXPOSE 9999
|
||||
CMD ["stash"]
|
||||
@@ -7,17 +7,15 @@ RUN apt-get update && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN curl -L -o /stash $(curl -s https://api.github.com/repos/stashapp/stash/releases | grep -F 'stash-linux' | grep download | head -n 1 | cut -d'"' -f4) && \
|
||||
RUN curl -L -o /stash $(curl -s https://api.github.com/repos/stashapp/stash/releases/latest | awk '/browser_download_url/ && /stash-linux/' | sed -e 's/.*: "\(.*\)"/\1/') && \
|
||||
chmod +x /stash && \
|
||||
curl -o /ffmpeg.tar.xz https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \
|
||||
curl --http1.1 -o /ffmpeg.tar.xz https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \
|
||||
tar xf /ffmpeg.tar.xz && \
|
||||
rm ffmpeg.tar.xz && \
|
||||
mv /ffmpeg*/ /ffmpeg/
|
||||
|
||||
FROM ubuntu:18.04 as app
|
||||
RUN apt-get update && \
|
||||
apt-get -y install ca-certificates && \
|
||||
adduser stash --gecos GECOS --shell /bin/bash --disabled-password --home /home/stash
|
||||
RUN apt-get update && apt-get -y install ca-certificates
|
||||
COPY --from=prep /stash /ffmpeg/ffmpeg /ffmpeg/ffprobe /usr/bin/
|
||||
EXPOSE 9999
|
||||
CMD ["stash"]
|
||||
|
||||
14
docs/CONTRIBUTING.md
Normal file
14
docs/CONTRIBUTING.md
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
## Technical Debt
|
||||
Please be sure to consider how heavily your contribution impacts the maintainability of the project long term, sometimes less is more. We don't want to merge collossal pull requests with hundreds of dependencies by a driveby contributor.
|
||||
|
||||
## Contributor Checklist
|
||||
Please make sure that you've considered the following before you submit your Pull Requests as ready for merging.
|
||||
* I've run Code linters and [gofmt](https://golang.org/cmd/gofmt/) to make sure that my code is readable.
|
||||
* I have read through formerly submitted [pull requests](https://github.com/stashapp/stash/pulls) and [git issues](https://github.com/stashapp/stash/issues) to make sure that this contribution is required and isn't a duplicate. Also, so that I can manage to close any git Issues needing closed relating to this feature submission.
|
||||
* I commented adequately on my code with the expectation in mind that anyone else should be able to look at this code I've submitted and know exactly what's happening and what the expectations are.
|
||||
|
||||
### Legal Agreements
|
||||
* I acknowledge that if applicable to me, submitting and subsequent acceptance of this Pull Request I, the code contributor of this Pull Request, agree and acknowledge my understanding that the new code license has now been updated to [AGPL](/LICENSE.md). I agree that all code before this Pull Request, which I've previously submitted, is now to be re-licensed under the new license AGPL and no longer the former MIT license.
|
||||
|
||||
**In case you were unable to follow any of the above include an explanation as to why not in your Pull Request.**
|
||||
@@ -3,17 +3,19 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
)
|
||||
|
||||
//we use the github REST V3 API as no login is required
|
||||
const apiURL string = "https://api.github.com/repos/stashapp/stash/tags"
|
||||
const apiReleases string = "https://api.github.com/repos/stashapp/stash/releases"
|
||||
const apiAcceptHeader string = "application/vnd.github.v3+json"
|
||||
const developmentTag string = "latest_develop"
|
||||
|
||||
var stashReleases = func() map[string]string {
|
||||
return map[string]string{
|
||||
@@ -24,17 +26,6 @@ var stashReleases = func() map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
type githubTagResponse struct {
|
||||
Name string
|
||||
Zipball_url string
|
||||
Tarball_url string
|
||||
Commit struct {
|
||||
Sha string
|
||||
Url string
|
||||
}
|
||||
Node_id string
|
||||
}
|
||||
|
||||
type githubReleasesResponse struct {
|
||||
Url string
|
||||
Assets_url string
|
||||
@@ -93,74 +84,85 @@ type githubAsset struct {
|
||||
Browser_download_url string
|
||||
}
|
||||
|
||||
//gets latest version (git commit hash) from github API
|
||||
//the repo's tags are used to find the latest version
|
||||
//of the "master" or "develop" branch
|
||||
// GetLatestVersion gets latest version (git commit hash) from github API
|
||||
// If running a build from the "master" branch, then the latest full release
|
||||
// is used, otherwise it uses the release that is tagged with "latest_develop"
|
||||
// which is the latest pre-release build.
|
||||
func GetLatestVersion(shortHash bool) (latestVersion string, latestRelease string, err error) {
|
||||
|
||||
platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
wantedRelease := stashReleases()[platform]
|
||||
|
||||
branch, _, _ := GetVersion()
|
||||
if branch == "" {
|
||||
version, _, _ := GetVersion()
|
||||
if version == "" {
|
||||
return "", "", fmt.Errorf("Stash doesn't have a version. Version check not supported.")
|
||||
}
|
||||
|
||||
// if the version is suffixed with -x-xxxx, then we are running a development build
|
||||
usePreRelease := false
|
||||
re := regexp.MustCompile(`-\d+-g\w+$`)
|
||||
if re.MatchString(version) {
|
||||
usePreRelease = true
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("GET", apiReleases, nil)
|
||||
url := apiReleases
|
||||
if !usePreRelease {
|
||||
// just get the latest full release
|
||||
url += "/latest"
|
||||
} else {
|
||||
// get the release tagged with the development tag
|
||||
url += "/tags/" + developmentTag
|
||||
}
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
|
||||
req.Header.Add("Accept", apiAcceptHeader) // gh api recommendation , send header with api version
|
||||
response, err := client.Do(req)
|
||||
|
||||
input := make([]githubReleasesResponse, 0)
|
||||
release := githubReleasesResponse{}
|
||||
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Github API request failed: %s", err)
|
||||
} else {
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return "", "", fmt.Errorf("Github API request failed: %s", response.Status)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Github API read response failed: %s", err)
|
||||
defer response.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Github API read response failed: %s", err)
|
||||
}
|
||||
err = json.Unmarshal(data, &release)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Unmarshalling Github API response failed: %s", err)
|
||||
}
|
||||
|
||||
if release.Prerelease == usePreRelease {
|
||||
if shortHash {
|
||||
latestVersion = release.Target_commitish[0:7] //shorthash is first 7 digits of git commit hash
|
||||
} else {
|
||||
err = json.Unmarshal(data, &input)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Unmarshalling Github API response failed: %s", err)
|
||||
} else {
|
||||
|
||||
for _, ghApi := range input {
|
||||
if ghApi.Tag_name == branch {
|
||||
|
||||
if shortHash {
|
||||
latestVersion = ghApi.Target_commitish[0:7] //shorthash is first 7 digits of git commit hash
|
||||
} else {
|
||||
latestVersion = ghApi.Target_commitish
|
||||
}
|
||||
if wantedRelease != "" {
|
||||
for _, asset := range ghApi.Assets {
|
||||
if asset.Name == wantedRelease {
|
||||
latestRelease = asset.Browser_download_url
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
latestVersion = release.Target_commitish
|
||||
}
|
||||
if wantedRelease != "" {
|
||||
for _, asset := range release.Assets {
|
||||
if asset.Name == wantedRelease {
|
||||
latestRelease = asset.Browser_download_url
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if latestVersion == "" {
|
||||
return "", "", fmt.Errorf("No version found for \"%s\"", branch)
|
||||
}
|
||||
}
|
||||
|
||||
if latestVersion == "" {
|
||||
return "", "", fmt.Errorf("No version found for \"%s\"", version)
|
||||
}
|
||||
return latestVersion, latestRelease, nil
|
||||
|
||||
}
|
||||
|
||||
func printLatestVersion() {
|
||||
@@ -175,5 +177,4 @@ func printLatestVersion() {
|
||||
logger.Infof("New version: (%s) available.", latest)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -163,10 +163,6 @@ func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, tx *sqlx.T
|
||||
|
||||
// only update the cover image if provided and everything else was successful
|
||||
if coverImageData != nil {
|
||||
scene, err := qb.Find(sceneID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = manager.SetSceneScreenshot(scene.Checksum, coverImageData)
|
||||
if err != nil {
|
||||
|
||||
@@ -296,6 +296,11 @@ func BaseURLMiddleware(next http.Handler) http.Handler {
|
||||
}
|
||||
baseURL := scheme + "://" + r.Host
|
||||
|
||||
externalHost := config.GetExternalHost()
|
||||
if externalHost != "" {
|
||||
baseURL = externalHost
|
||||
}
|
||||
|
||||
r = r.WithContext(context.WithValue(ctx, BaseURLCtxKey, baseURL))
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
@@ -30,6 +30,7 @@ const MaxStreamingTranscodeSize = "max_streaming_transcode_size"
|
||||
|
||||
const Host = "host"
|
||||
const Port = "port"
|
||||
const ExternalHost = "external_host"
|
||||
|
||||
// Interface options
|
||||
const SoundOnPreview = "sound_on_preview"
|
||||
@@ -108,6 +109,10 @@ func GetPort() int {
|
||||
return viper.GetInt(Port)
|
||||
}
|
||||
|
||||
func GetExternalHost() string {
|
||||
return viper.GetString(ExternalHost)
|
||||
}
|
||||
|
||||
func GetMaxTranscodeSize() models.StreamingResolutionEnum {
|
||||
ret := viper.GetString(MaxTranscodeSize)
|
||||
|
||||
|
||||
@@ -110,13 +110,14 @@ func initFlags() {
|
||||
}
|
||||
|
||||
func initEnvs() {
|
||||
viper.SetEnvPrefix("stash") // will be uppercased automatically
|
||||
viper.BindEnv("host") // STASH_HOST
|
||||
viper.BindEnv("port") // STASH_PORT
|
||||
viper.BindEnv("stash") // STASH_STASH
|
||||
viper.BindEnv("generated") // STASH_GENERATED
|
||||
viper.BindEnv("metadata") // STASH_METADATA
|
||||
viper.BindEnv("cache") // STASH_CACHE
|
||||
viper.SetEnvPrefix("stash") // will be uppercased automatically
|
||||
viper.BindEnv("host") // STASH_HOST
|
||||
viper.BindEnv("port") // STASH_PORT
|
||||
viper.BindEnv("external_host") // STASH_EXTERNAL_HOST
|
||||
viper.BindEnv("stash") // STASH_STASH
|
||||
viper.BindEnv("generated") // STASH_GENERATED
|
||||
viper.BindEnv("metadata") // STASH_METADATA
|
||||
viper.BindEnv("cache") // STASH_CACHE
|
||||
}
|
||||
|
||||
func initFFMPEG() {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
STASH_VERSION="$1"
|
||||
|
||||
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;"
|
||||
|
||||
@@ -5,10 +5,11 @@ uploadFile()
|
||||
{
|
||||
FILE=$1
|
||||
BASENAME="$(basename "${FILE}")"
|
||||
uploadedTo=`curl --upload-file $FILE "https://transfer.sh/$BASENAME"`
|
||||
# abort if it takes more than two minutes to upload
|
||||
uploadedTo=`curl -m 120 --upload-file $FILE "https://transfer.sh/$BASENAME"`
|
||||
echo "$BASENAME uploaded to url: $uploadedTo"
|
||||
}
|
||||
|
||||
uploadFile "dist/stash-osx"
|
||||
uploadFile "dist/stash-win.exe"
|
||||
uploadFile "dist/stash-linux"
|
||||
uploadFile "dist/stash-linux"
|
||||
|
||||
@@ -8,35 +8,35 @@ export const Stats: FunctionComponent = () => {
|
||||
function renderStats() {
|
||||
if (!data || !data.stats) { return; }
|
||||
return (
|
||||
<nav id="details-container" className="level">
|
||||
<nav id="details-container" className="level stats">
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Scenes</p>
|
||||
<p className="title">{data.stats.scene_count}</p>
|
||||
<p className="heading">Scenes</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Galleries</p>
|
||||
<p className="title">{data.stats.gallery_count}</p>
|
||||
<p className="heading">Galleries</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Performers</p>
|
||||
<p className="title">{data.stats.performer_count}</p>
|
||||
<p className="heading">Performers</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Studios</p>
|
||||
<p className="title">{data.stats.studio_count}</p>
|
||||
<p className="heading">Studios</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Tags</p>
|
||||
<p className="title">{data.stats.tag_count}</p>
|
||||
<p className="heading">Tags</p>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -48,13 +48,6 @@ export const Stats: FunctionComponent = () => {
|
||||
{!data || loading ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined}
|
||||
{!!error ? <span>error.message</span> : undefined}
|
||||
{renderStats()}
|
||||
|
||||
<h3>Notes</h3>
|
||||
<pre>
|
||||
{`
|
||||
This is still an early version, some things are still a work in progress.
|
||||
`}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -95,6 +95,21 @@ export interface IListHookOptions {
|
||||
renderSelectedOptions?: (result: QueryHookResult<any, any>, selectedIds: Set<string>) => JSX.Element | undefined;
|
||||
}
|
||||
|
||||
function updateFromQueryString(queryStr: string, setFilter: (value: React.SetStateAction<ListFilterModel>) => void, forageData?: any) {
|
||||
const queryParams = queryString.parse(queryStr);
|
||||
setFilter((f) => {
|
||||
const newFilter = _.cloneDeep(f);
|
||||
newFilter.configureFromQueryParameters(queryParams);
|
||||
|
||||
if (forageData) {
|
||||
const forageParams = queryString.parse(forageData.filter);
|
||||
newFilter.overridePrefs(queryParams, forageParams);
|
||||
}
|
||||
|
||||
return newFilter;
|
||||
});
|
||||
}
|
||||
|
||||
export class ListHook {
|
||||
public static useList(options: IListHookOptions): IListHookData {
|
||||
const [filter, setFilter] = useState<ListFilterModel>(new ListFilterModel(options.filterMode));
|
||||
@@ -108,8 +123,7 @@ export class ListHook {
|
||||
|
||||
const filterListImpl = getFilterListImpl(options.filterMode);
|
||||
|
||||
// Update the filter when the query parameters change
|
||||
// we want to use the local forage only when the location search has not been set
|
||||
// Initialise from interface forage when loaded
|
||||
useEffect(() => {
|
||||
function updateFromLocalForage(queryData: any) {
|
||||
const queryParams = queryString.parse(queryData.filter);
|
||||
@@ -123,33 +137,46 @@ export class ListHook {
|
||||
});
|
||||
}
|
||||
|
||||
function updateFromQueryString(queryStr: string) {
|
||||
const queryParams = queryString.parse(queryStr);
|
||||
setFilter((f) => {
|
||||
const newFilter = _.cloneDeep(f);
|
||||
newFilter.configureFromQueryParameters(queryParams);
|
||||
return newFilter;
|
||||
});
|
||||
function initialise() {
|
||||
forageInitialised.current = true;
|
||||
|
||||
let forageData: any;
|
||||
|
||||
if (interfaceForage.data && interfaceForage.data.queries[options.filterMode]) {
|
||||
forageData = interfaceForage.data.queries[options.filterMode];
|
||||
}
|
||||
|
||||
if (!options.props!.location.search && forageData) {
|
||||
// we have some data, try to load it
|
||||
updateFromLocalForage(forageData);
|
||||
} else {
|
||||
// use query string instead - include the forageData to include the following
|
||||
// preferences if not specified: displayMode, itemsPerPage, sortBy and sortDir
|
||||
updateFromQueryString(options.props!.location.search, setFilter, forageData);
|
||||
}
|
||||
}
|
||||
|
||||
// don't use query parameters for sub-components
|
||||
if (!options.subComponent) {
|
||||
// do this only once after local forage has been initialised
|
||||
// initialise once when the forage is loaded
|
||||
if (!forageInitialised.current && !interfaceForage.loading) {
|
||||
forageInitialised.current = true;
|
||||
|
||||
if (!options.props!.location.search && interfaceForage.data && interfaceForage.data.queries[options.filterMode]) {
|
||||
let queryData = interfaceForage.data.queries[options.filterMode];
|
||||
// we have some data, try to load it
|
||||
updateFromLocalForage(queryData);
|
||||
} else if (interfaceForage.data) {
|
||||
// else fallback to query string
|
||||
updateFromQueryString(options.props!.location.search);
|
||||
}
|
||||
initialise();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, [interfaceForage.data, interfaceForage.loading, options.props, options.filterMode, options.subComponent]);
|
||||
|
||||
// Update the filter when the query parameters change
|
||||
useEffect(() => {
|
||||
// don't use query parameters for sub-components
|
||||
if (!options.subComponent) {
|
||||
// only update from the URL if the forage is initialised
|
||||
if (forageInitialised.current) {
|
||||
updateFromQueryString(options.props!.location.search, setFilter);
|
||||
}
|
||||
}
|
||||
}, [options.props, options.filterMode, options.subComponent]);
|
||||
|
||||
function getFilter() {
|
||||
if (!options.filterHook) {
|
||||
return filter;
|
||||
@@ -178,8 +205,12 @@ export class ListHook {
|
||||
// don't update this until local forage is loaded
|
||||
if (forageInitialised.current) {
|
||||
const location = Object.assign({}, options.props.history.location);
|
||||
location.search = filter.makeQueryParameters();
|
||||
options.props.history.replace(location);
|
||||
const includePrefs = true;
|
||||
location.search = "?" + filter.makeQueryParameters(includePrefs);
|
||||
|
||||
if (location.search !== options.props.history.location.search) {
|
||||
options.props.history.replace(location);
|
||||
}
|
||||
|
||||
setInterfaceForage((d) => {
|
||||
const dataClone = _.cloneDeep(d);
|
||||
@@ -290,12 +321,12 @@ export class ListHook {
|
||||
let thisIndex = -1;
|
||||
|
||||
if (!!lastClickedId) {
|
||||
startIndex = filterListImpl.getItems(result).findIndex((item) => {
|
||||
startIndex = filterListImpl.getItems(result.data).findIndex((item) => {
|
||||
return item.id === lastClickedId;
|
||||
});
|
||||
}
|
||||
|
||||
thisIndex = filterListImpl.getItems(result).findIndex((item) => {
|
||||
thisIndex = filterListImpl.getItems(result.data).findIndex((item) => {
|
||||
return item.id === id;
|
||||
});
|
||||
|
||||
@@ -309,7 +340,7 @@ export class ListHook {
|
||||
endIndex = tmp;
|
||||
}
|
||||
|
||||
const subset = filterListImpl.getItems(result).slice(startIndex, endIndex + 1);
|
||||
const subset = filterListImpl.getItems(result.data).slice(startIndex, endIndex + 1);
|
||||
const newSelectedIds : Set<string> = new Set();
|
||||
|
||||
subset.forEach((item) => {
|
||||
@@ -321,7 +352,7 @@ export class ListHook {
|
||||
|
||||
function onSelectAll() {
|
||||
const newSelectedIds : Set<string> = new Set();
|
||||
filterListImpl.getItems(result).forEach((item) => {
|
||||
filterListImpl.getItems(result.data).forEach((item) => {
|
||||
newSelectedIds.add(item.id);
|
||||
});
|
||||
|
||||
@@ -367,31 +398,42 @@ export class ListHook {
|
||||
}
|
||||
}
|
||||
|
||||
const template = (
|
||||
<div>
|
||||
<ListFilter
|
||||
onChangePageSize={onChangePageSize}
|
||||
onChangeQuery={onChangeQuery}
|
||||
onChangeSortDirection={onChangeSortDirection}
|
||||
onChangeSortBy={onChangeSortBy}
|
||||
onChangeDisplayMode={onChangeDisplayMode}
|
||||
onAddCriterion={onAddCriterion}
|
||||
onRemoveCriterion={onRemoveCriterion}
|
||||
onSelectAll={onSelectAll}
|
||||
onSelectNone={onSelectNone}
|
||||
zoomIndex={options.zoomable ? zoomIndex : undefined}
|
||||
onChangeZoom={options.zoomable ? onChangeZoom : undefined}
|
||||
otherOperations={otherOperations}
|
||||
filter={filter}
|
||||
/>
|
||||
{options.renderSelectedOptions && selectedIds.size > 0 ? options.renderSelectedOptions(result, selectedIds) : undefined}
|
||||
{result.loading || (!options.subComponent && !forageInitialised.current) ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined}
|
||||
{result.error ? <h1>{result.error.message}</h1> : undefined}
|
||||
{maybeRenderContent()}
|
||||
{maybeRenderPagination()}
|
||||
</div>
|
||||
);
|
||||
function getTemplate() {
|
||||
if (!options.subComponent && !forageInitialised.current) {
|
||||
return (
|
||||
<div>
|
||||
{!result.error ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined}
|
||||
{result.error ? <h1>{result.error.message}</h1> : undefined}
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<ListFilter
|
||||
onChangePageSize={onChangePageSize}
|
||||
onChangeQuery={onChangeQuery}
|
||||
onChangeSortDirection={onChangeSortDirection}
|
||||
onChangeSortBy={onChangeSortBy}
|
||||
onChangeDisplayMode={onChangeDisplayMode}
|
||||
onAddCriterion={onAddCriterion}
|
||||
onRemoveCriterion={onRemoveCriterion}
|
||||
onSelectAll={onSelectAll}
|
||||
onSelectNone={onSelectNone}
|
||||
zoomIndex={options.zoomable ? zoomIndex : undefined}
|
||||
onChangeZoom={options.zoomable ? onChangeZoom : undefined}
|
||||
otherOperations={otherOperations}
|
||||
filter={filter}
|
||||
/>
|
||||
{options.renderSelectedOptions && selectedIds.size > 0 ? options.renderSelectedOptions(result, selectedIds) : undefined}
|
||||
{result.loading || (!options.subComponent && !forageInitialised.current) ? <Spinner size={Spinner.SIZE_LARGE} /> : undefined}
|
||||
{result.error ? <h1>{result.error.message}</h1> : undefined}
|
||||
{maybeRenderContent()}
|
||||
{maybeRenderPagination()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return { filter, template, options, onSelectChange };
|
||||
return { filter, template: getTemplate(), options, onSelectChange };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ span.block {
|
||||
height: 50vh;
|
||||
min-height: 400px;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
background-position: top !important;
|
||||
background-repeat: no-repeat !important;
|
||||
}
|
||||
|
||||
@@ -598,3 +598,15 @@ span.block {
|
||||
transition: margin-left 0.5s;
|
||||
}
|
||||
}
|
||||
|
||||
.stats {
|
||||
& p.title {
|
||||
font-size: 3vw;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
& p.heading {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,23 +151,27 @@ export class ListFilterModel {
|
||||
this.sortByOptions = [...this.sortByOptions, "created_at", "updated_at"];
|
||||
}
|
||||
|
||||
private setSortBy(sortBy: any) {
|
||||
this.sortBy = sortBy;
|
||||
|
||||
// parse the random seed if provided
|
||||
const randomPrefix = "random_";
|
||||
if (this.sortBy && this.sortBy.startsWith(randomPrefix)) {
|
||||
let seedStr = this.sortBy.substring(randomPrefix.length);
|
||||
|
||||
this.sortBy = "random";
|
||||
try {
|
||||
this.randomSeed = Number.parseInt(seedStr);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public configureFromQueryParameters(rawParms: any) {
|
||||
const params = rawParms as IQueryParameters;
|
||||
if (params.sortby !== undefined) {
|
||||
this.sortBy = params.sortby;
|
||||
|
||||
// parse the random seed if provided
|
||||
const randomPrefix = "random_";
|
||||
if (this.sortBy && this.sortBy.startsWith(randomPrefix)) {
|
||||
let seedStr = this.sortBy.substring(randomPrefix.length);
|
||||
|
||||
this.sortBy = "random";
|
||||
try {
|
||||
this.randomSeed = Number.parseInt(seedStr);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
this.setSortBy(params.sortby);
|
||||
}
|
||||
if (params.sortdir === "asc" || params.sortdir === "desc") {
|
||||
this.sortDirection = params.sortdir;
|
||||
@@ -205,6 +209,26 @@ export class ListFilterModel {
|
||||
}
|
||||
}
|
||||
|
||||
public overridePrefs(original: any, override: any) {
|
||||
const originalParams = original as IQueryParameters;
|
||||
const overrideParams = override as IQueryParameters;
|
||||
|
||||
if (originalParams.sortby === undefined && overrideParams.sortby !== undefined) {
|
||||
this.setSortBy(overrideParams.sortby);
|
||||
}
|
||||
if (originalParams.sortdir === undefined && overrideParams.sortdir !== undefined) {
|
||||
if (overrideParams.sortdir === "asc" || overrideParams.sortdir === "desc") {
|
||||
this.sortDirection = overrideParams.sortdir;
|
||||
}
|
||||
}
|
||||
if (originalParams.disp === undefined && overrideParams.disp !== undefined) {
|
||||
this.displayMode = parseInt(overrideParams.disp, 10);
|
||||
}
|
||||
if (originalParams.perPage === undefined && overrideParams.perPage !== undefined) {
|
||||
this.itemsPerPage = Number(overrideParams.perPage);
|
||||
}
|
||||
}
|
||||
|
||||
private setRandomSeed() {
|
||||
if (this.sortBy == "random") {
|
||||
// #321 - set the random seed if it is not set
|
||||
@@ -227,7 +251,8 @@ export class ListFilterModel {
|
||||
return this.sortBy;
|
||||
}
|
||||
|
||||
public makeQueryParameters(): string {
|
||||
// includePrefs includes displayMode, sortBy, sortDir and perPage
|
||||
public makeQueryParameters(includePrefs?: boolean): string {
|
||||
const encodedCriteria: string[] = [];
|
||||
this.criteria.forEach((criterion) => {
|
||||
const encodedCriterion: any = {};
|
||||
@@ -238,16 +263,18 @@ export class ListFilterModel {
|
||||
encodedCriteria.push(jsonCriterion);
|
||||
});
|
||||
|
||||
|
||||
const result = {
|
||||
sortby: this.getSortBy(),
|
||||
sortdir: this.sortDirection,
|
||||
disp: this.displayMode,
|
||||
const result: any = {
|
||||
q: this.searchTerm,
|
||||
p: this.currentPage,
|
||||
perPage: this.itemsPerPage,
|
||||
c: encodedCriteria,
|
||||
};
|
||||
|
||||
if (includePrefs) {
|
||||
result.disp = this.displayMode;
|
||||
result.perPage = this.itemsPerPage;
|
||||
result.sortby = this.getSortBy();
|
||||
result.sortdir = this.sortDirection;
|
||||
}
|
||||
return queryString.stringify(result, {encode: false});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user