mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2025-12-24 02:39:18 -05:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
@@ -899,6 +899,15 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "RemiRigal",
|
||||||
|
"name": "RemiRigal",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/19256051?v=4",
|
||||||
|
"profile": "https://github.com/RemiRigal",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"badgeTemplate": "<a href=\"#contributors-\"><img alt=\"All Contributors\" src=\"https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg\"/></a>",
|
"badgeTemplate": "<a href=\"#contributors-\"><img alt=\"All Contributors\" src=\"https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg\"/></a>",
|
||||||
|
|||||||
21
.gitattributes
vendored
21
.gitattributes
vendored
@@ -24,3 +24,24 @@
|
|||||||
*.woff binary
|
*.woff binary
|
||||||
*.pyc binary
|
*.pyc binary
|
||||||
*.pdf binary
|
*.pdf binary
|
||||||
|
|
||||||
|
#
|
||||||
|
## Theses files/directories should be excluded from git archives
|
||||||
|
#
|
||||||
|
|
||||||
|
.husky export-ignore
|
||||||
|
.vscode export-ignore
|
||||||
|
docs export-ignore
|
||||||
|
|
||||||
|
.git* export-ignore
|
||||||
|
*ignore export-ignore
|
||||||
|
*.md export-ignore
|
||||||
|
|
||||||
|
.all-contributorsrc export-ignore
|
||||||
|
.editorconfig export-ignore
|
||||||
|
Dockerfile.local export-ignore
|
||||||
|
docker-compose.yml export-ignore
|
||||||
|
stylelint.config.js export-ignore
|
||||||
|
|
||||||
|
public/os_logo_filled.png export-ignore
|
||||||
|
public/preview.jpg export-ignore
|
||||||
|
|||||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
name: Lint & Test Build
|
name: Lint & Test Build
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
container: node:16.17-alpine
|
container: node:20.9-alpine
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|||||||
11
Dockerfile
11
Dockerfile
@@ -1,4 +1,4 @@
|
|||||||
FROM node:16.17-alpine AS BUILD_IMAGE
|
FROM node:20.9-alpine AS BUILD_IMAGE
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -7,10 +7,9 @@ ENV TARGETPLATFORM=${TARGETPLATFORM:-linux/amd64}
|
|||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
case "${TARGETPLATFORM}" in \
|
case "${TARGETPLATFORM}" in \
|
||||||
'linux/arm64' | 'linux/arm/v7') \
|
'linux/arm64' | 'linux/arm/v7') \
|
||||||
apk add --no-cache python3 make g++ && \
|
apk add --no-cache python3 make g++ \
|
||||||
ln -s /usr/bin/python3 /usr/bin/python \
|
;; \
|
||||||
;; \
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
COPY package.json yarn.lock ./
|
COPY package.json yarn.lock ./
|
||||||
@@ -33,7 +32,7 @@ RUN touch config/DOCKER
|
|||||||
RUN echo "{\"commitTag\": \"${COMMIT_TAG}\"}" > committag.json
|
RUN echo "{\"commitTag\": \"${COMMIT_TAG}\"}" > committag.json
|
||||||
|
|
||||||
|
|
||||||
FROM node:16.17-alpine
|
FROM node:20.9-alpine
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:16.17-alpine
|
FROM node:20.9-alpine
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
146
README.md
146
README.md
@@ -6,7 +6,7 @@
|
|||||||
<a href="https://hub.docker.com/r/fallenbagel/jellyseerr"><img src="https://img.shields.io/docker/pulls/fallenbagel/jellyseerr" alt="Docker pulls"></a>
|
<a href="https://hub.docker.com/r/fallenbagel/jellyseerr"><img src="https://img.shields.io/docker/pulls/fallenbagel/jellyseerr" alt="Docker pulls"></a>
|
||||||
<a href="https://github.com/fallenbagel/jellyseerr/blob/develop/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/fallenbagel/jellyseerr"></a>
|
<a href="https://github.com/fallenbagel/jellyseerr/blob/develop/LICENSE"><img alt="GitHub" src="https://img.shields.io/github/license/fallenbagel/jellyseerr"></a>
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||||
<a href="#contributors-"><img alt="All Contributors" src="https://img.shields.io/badge/all_contributors-98-orange.svg"/></a>
|
<a href="#contributors-"><img alt="All Contributors" src="https://img.shields.io/badge/all_contributors-99-orange.svg"/></a>
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||||
|
|
||||||
**Jellyseerr** is a free and open source software application for managing requests for your media library. It is a a fork of Overseerr built to bring support for Jellyfin & Emby media servers!
|
**Jellyseerr** is a free and open source software application for managing requests for your media library. It is a a fork of Overseerr built to bring support for Jellyfin & Emby media servers!
|
||||||
@@ -146,4 +146,146 @@ You can help improve Jellyseerr too! Check out our [Contribution Guide](https://
|
|||||||
|
|
||||||
## Contributors ✨
|
## Contributors ✨
|
||||||
|
|
||||||
Thanks goes to all wonderful people who contributed directly to Jellyseerr and Overseerr.
|
Thanks goes to these wonderful people from Overseerr ([emoji key](https://allcontributors.org/docs/en/emoji-key)) and all those that contributed directly to Jellyseerr:
|
||||||
|
|
||||||
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
<!-- markdownlint-disable -->
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://sct.dev"><img src="https://avatars1.githubusercontent.com/u/234213?v=4?s=100" width="100px;" alt="sct"/><br /><sub><b>sct</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=sct" title="Code">💻</a> <a href="#design-sct" title="Design">🎨</a> <a href="#ideas-sct" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/azoitos"><img src="https://avatars2.githubusercontent.com/u/26529049?v=4?s=100" width="100px;" alt="Alex Zoitos"/><br /><sub><b>Alex Zoitos</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=azoitos" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/OwsleyJr"><img src="https://avatars3.githubusercontent.com/u/8635678?v=4?s=100" width="100px;" alt="Brandon Cohen"/><br /><sub><b>Brandon Cohen</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=OwsleyJr" title="Code">💻</a> <a href="https://github.com/sct/overseerr/commits?author=OwsleyJr" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ahreluth"><img src="https://avatars2.githubusercontent.com/u/75682440?v=4?s=100" width="100px;" alt="Ahreluth"/><br /><sub><b>Ahreluth</b></sub></a><br /><a href="#translation-Ahreluth" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/KovalevArtem"><img src="https://avatars0.githubusercontent.com/u/36500228?v=4?s=100" width="100px;" alt="KovalevArtem"/><br /><sub><b>KovalevArtem</b></sub></a><br /><a href="#translation-KovalevArtem" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GiyomuWeb"><img src="https://avatars0.githubusercontent.com/u/62489209?v=4?s=100" width="100px;" alt="GiyomuWeb"/><br /><sub><b>GiyomuWeb</b></sub></a><br /><a href="#translation-GiyomuWeb" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/angrycuban13"><img src="https://avatars3.githubusercontent.com/u/39564898?v=4?s=100" width="100px;" alt="Angry Cuban"/><br /><sub><b>Angry Cuban</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=angrycuban13" title="Documentation">📖</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jvennik"><img src="https://avatars3.githubusercontent.com/u/6672637?v=4?s=100" width="100px;" alt="jvennik"/><br /><sub><b>jvennik</b></sub></a><br /><a href="#translation-jvennik" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/darknessgp"><img src="https://avatars0.githubusercontent.com/u/1521243?v=4?s=100" width="100px;" alt="darknessgp"/><br /><sub><b>darknessgp</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=darknessgp" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/saltydk"><img src="https://avatars1.githubusercontent.com/u/6587950?v=4?s=100" width="100px;" alt="salty"/><br /><sub><b>salty</b></sub></a><br /><a href="#infra-saltydk" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Shutruk"><img src="https://avatars2.githubusercontent.com/u/9198633?v=4?s=100" width="100px;" alt="Shutruk"/><br /><sub><b>Shutruk</b></sub></a><br /><a href="#translation-Shutruk" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/krystiancharubin"><img src="https://avatars2.githubusercontent.com/u/17775600?v=4?s=100" width="100px;" alt="Krystian Charubin"/><br /><sub><b>Krystian Charubin</b></sub></a><br /><a href="#design-krystiancharubin" title="Design">🎨</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kieron"><img src="https://avatars2.githubusercontent.com/u/8655212?v=4?s=100" width="100px;" alt="Kieron Boswell"/><br /><sub><b>Kieron Boswell</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=kieron" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/samwiseg0"><img src="https://avatars1.githubusercontent.com/u/2241731?v=4?s=100" width="100px;" alt="samwiseg0"/><br /><sub><b>samwiseg0</b></sub></a><br /><a href="#question-samwiseg0" title="Answering Questions">💬</a> <a href="#infra-samwiseg0" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ecelebi29"><img src="https://avatars2.githubusercontent.com/u/8337120?v=4?s=100" width="100px;" alt="ecelebi29"/><br /><sub><b>ecelebi29</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=ecelebi29" title="Code">💻</a> <a href="https://github.com/sct/overseerr/commits?author=ecelebi29" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mmozeiko"><img src="https://avatars3.githubusercontent.com/u/1665010?v=4?s=100" width="100px;" alt="Mārtiņš Možeiko"/><br /><sub><b>Mārtiņš Možeiko</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=mmozeiko" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mazzetta86"><img src="https://avatars2.githubusercontent.com/u/45591560?v=4?s=100" width="100px;" alt="mazzetta86"/><br /><sub><b>mazzetta86</b></sub></a><br /><a href="#translation-mazzetta86" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Panzer1119"><img src="https://avatars1.githubusercontent.com/u/23016343?v=4?s=100" width="100px;" alt="Paul Hagedorn"/><br /><sub><b>Paul Hagedorn</b></sub></a><br /><a href="#translation-Panzer1119" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Shagon94"><img src="https://avatars3.githubusercontent.com/u/9140783?v=4?s=100" width="100px;" alt="Shagon94"/><br /><sub><b>Shagon94</b></sub></a><br /><a href="#translation-Shagon94" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sebstrgg"><img src="https://avatars3.githubusercontent.com/u/27026694?v=4?s=100" width="100px;" alt="sebstrgg"/><br /><sub><b>sebstrgg</b></sub></a><br /><a href="#translation-sebstrgg" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/danshilm"><img src="https://avatars2.githubusercontent.com/u/20923978?v=4?s=100" width="100px;" alt="Danshil Mungur"/><br /><sub><b>Danshil Mungur</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=danshilm" title="Code">💻</a> <a href="https://github.com/sct/overseerr/commits?author=danshilm" title="Documentation">📖</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/doob187"><img src="https://avatars1.githubusercontent.com/u/60312740?v=4?s=100" width="100px;" alt="doob187"/><br /><sub><b>doob187</b></sub></a><br /><a href="#infra-doob187" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/johnpyp"><img src="https://avatars2.githubusercontent.com/u/20625636?v=4?s=100" width="100px;" alt="johnpyp"/><br /><sub><b>johnpyp</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=johnpyp" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ankarhem"><img src="https://avatars1.githubusercontent.com/u/14110063?v=4?s=100" width="100px;" alt="Jakob Ankarhem"/><br /><sub><b>Jakob Ankarhem</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=ankarhem" title="Documentation">📖</a> <a href="https://github.com/sct/overseerr/commits?author=ankarhem" title="Code">💻</a> <a href="#translation-ankarhem" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jayesh100"><img src="https://avatars1.githubusercontent.com/u/8022175?v=4?s=100" width="100px;" alt="Jayesh"/><br /><sub><b>Jayesh</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=jayesh100" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/flying-sausages"><img src="https://avatars1.githubusercontent.com/u/23618693?v=4?s=100" width="100px;" alt="flying-sausages"/><br /><sub><b>flying-sausages</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=flying-sausages" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hirenshah"><img src="https://avatars2.githubusercontent.com/u/418112?v=4?s=100" width="100px;" alt="hirenshah"/><br /><sub><b>hirenshah</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=hirenshah" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TheCatLady"><img src="https://avatars0.githubusercontent.com/u/52870424?v=4?s=100" width="100px;" alt="TheCatLady"/><br /><sub><b>TheCatLady</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=TheCatLady" title="Code">💻</a> <a href="#translation-TheCatLady" title="Translation">🌍</a> <a href="https://github.com/sct/overseerr/commits?author=TheCatLady" title="Documentation">📖</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chriscpritchard"><img src="https://avatars1.githubusercontent.com/u/1839074?v=4?s=100" width="100px;" alt="Chris Pritchard"/><br /><sub><b>Chris Pritchard</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=chriscpritchard" title="Code">💻</a> <a href="https://github.com/sct/overseerr/commits?author=chriscpritchard" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Tamberlox"><img src="https://avatars3.githubusercontent.com/u/56069014?v=4?s=100" width="100px;" alt="Tamberlox"/><br /><sub><b>Tamberlox</b></sub></a><br /><a href="#translation-Tamberlox" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://hmnd.io"><img src="https://avatars.githubusercontent.com/u/12853597?v=4?s=100" width="100px;" alt="David"/><br /><sub><b>David</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=hmnd" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://www.douglas-parker.com"><img src="https://avatars.githubusercontent.com/u/18235822?v=4?s=100" width="100px;" alt="Douglas Parker"/><br /><sub><b>Douglas Parker</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=douglasparker" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dancarter"><img src="https://avatars.githubusercontent.com/u/4387516?v=4?s=100" width="100px;" alt="Daniel Carter"/><br /><sub><b>Daniel Carter</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=dancarter" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://nuro.dev"><img src="https://avatars.githubusercontent.com/u/4991309?v=4?s=100" width="100px;" alt="nuro"/><br /><sub><b>nuro</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=NuroDev" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/onedr0p"><img src="https://avatars.githubusercontent.com/u/213795?v=4?s=100" width="100px;" alt="ᗪєνιη ᗷυнʟ"/><br /><sub><b>ᗪєνιη ᗷυнʟ</b></sub></a><br /><a href="#infra-onedr0p" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JonnyWong16"><img src="https://avatars.githubusercontent.com/u/9099342?v=4?s=100" width="100px;" alt="JonnyWong16"/><br /><sub><b>JonnyWong16</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=JonnyWong16" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Roxedus"><img src="https://avatars.githubusercontent.com/u/7110194?v=4?s=100" width="100px;" alt="Roxedus"/><br /><sub><b>Roxedus</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Roxedus" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/WoisWoi"><img src="https://avatars.githubusercontent.com/u/75491231?v=4?s=100" width="100px;" alt="WoisWoi"/><br /><sub><b>WoisWoi</b></sub></a><br /><a href="#translation-WoisWoi" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/HubDuck"><img src="https://avatars.githubusercontent.com/u/77843475?v=4?s=100" width="100px;" alt="HubDuck"/><br /><sub><b>HubDuck</b></sub></a><br /><a href="#translation-HubDuck" title="Translation">🌍</a> <a href="https://github.com/sct/overseerr/commits?author=HubDuck" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/costaht"><img src="https://avatars.githubusercontent.com/u/50637431?v=4?s=100" width="100px;" alt="costaht"/><br /><sub><b>costaht</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=costaht" title="Documentation">📖</a> <a href="#translation-costaht" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Shjosan"><img src="https://avatars.githubusercontent.com/u/20847626?v=4?s=100" width="100px;" alt="Shjosan"/><br /><sub><b>Shjosan</b></sub></a><br /><a href="#translation-Shjosan" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kobaubarr"><img src="https://avatars.githubusercontent.com/u/28481522?v=4?s=100" width="100px;" alt="kobaubarr"/><br /><sub><b>kobaubarr</b></sub></a><br /><a href="#translation-kobaubarr" title="Translation">🌍</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/notorius28"><img src="https://avatars.githubusercontent.com/u/1621513?v=4?s=100" width="100px;" alt="Ricardo González"/><br /><sub><b>Ricardo González</b></sub></a><br /><a href="#translation-notorius28" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://torkili.uz"><img src="https://avatars.githubusercontent.com/u/460764?v=4?s=100" width="100px;" alt="Torkil"/><br /><sub><b>Torkil</b></sub></a><br /><a href="#translation-Torkiliuz" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://www.jagandeepbrar.io"><img src="https://avatars.githubusercontent.com/u/3048295?v=4?s=100" width="100px;" alt="Jagandeep Brar"/><br /><sub><b>Jagandeep Brar</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=JagandeepBrar" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://dtalens.com"><img src="https://avatars.githubusercontent.com/u/6631832?v=4?s=100" width="100px;" alt="dtalens"/><br /><sub><b>dtalens</b></sub></a><br /><a href="#translation-dtalens" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/acortelyou"><img src="https://avatars.githubusercontent.com/u/1689668?v=4?s=100" width="100px;" alt="Alex Cortelyou"/><br /><sub><b>Alex Cortelyou</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=acortelyou" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://nz.linkedin.com/in/jonocairns"><img src="https://avatars.githubusercontent.com/u/182836?v=4?s=100" width="100px;" alt="Jono Cairns"/><br /><sub><b>Jono Cairns</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=jonocairns" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://scias.net/"><img src="https://avatars.githubusercontent.com/u/439655?v=4?s=100" width="100px;" alt="DJScias"/><br /><sub><b>DJScias</b></sub></a><br /><a href="#translation-DJScias" title="Translation">🌍</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Dabu-dot"><img src="https://avatars.githubusercontent.com/u/52525576?v=4?s=100" width="100px;" alt="Dabu-dot"/><br /><sub><b>Dabu-dot</b></sub></a><br /><a href="#translation-Dabu-dot" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jabster28"><img src="https://avatars.githubusercontent.com/u/29015942?v=4?s=100" width="100px;" alt="Jabster28"/><br /><sub><b>Jabster28</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Jabster28" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/littlerooster"><img src="https://avatars.githubusercontent.com/u/83890654?v=4?s=100" width="100px;" alt="littlerooster"/><br /><sub><b>littlerooster</b></sub></a><br /><a href="#translation-littlerooster" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dphildebrandt"><img src="https://avatars.githubusercontent.com/u/154459?v=4?s=100" width="100px;" alt="Dustin Hildebrandt"/><br /><sub><b>Dustin Hildebrandt</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=dphildebrandt" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Generator"><img src="https://avatars.githubusercontent.com/u/44146?v=4?s=100" width="100px;" alt="Bruno Guerreiro"/><br /><sub><b>Bruno Guerreiro</b></sub></a><br /><a href="#translation-Generator" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/iceHtwoO"><img src="https://avatars.githubusercontent.com/u/27020492?v=4?s=100" width="100px;" alt="Alexander Neuhäuser"/><br /><sub><b>Alexander Neuhäuser</b></sub></a><br /><a href="#translation-iceHtwoO" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://www.unext.co.jp"><img src="https://avatars.githubusercontent.com/u/37431541?v=4?s=100" width="100px;" alt="Livio"/><br /><sub><b>Livio</b></sub></a><br /><a href="#design-liviokanone" title="Design">🎨</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tangentThought"><img src="https://avatars.githubusercontent.com/u/25516090?v=4?s=100" width="100px;" alt="tangentThought"/><br /><sub><b>tangentThought</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=tangentThought" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nicospz"><img src="https://avatars.githubusercontent.com/u/31373060?v=4?s=100" width="100px;" alt="Nicolás Espinoza"/><br /><sub><b>Nicolás Espinoza</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=nicospz" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sootylunatic"><img src="https://avatars.githubusercontent.com/u/36486087?v=4?s=100" width="100px;" alt="sootylunatic"/><br /><sub><b>sootylunatic</b></sub></a><br /><a href="#translation-sootylunatic" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JoKerIsCraZy"><img src="https://avatars.githubusercontent.com/u/47474211?v=4?s=100" width="100px;" alt="JoKerIsCraZy"/><br /><sub><b>JoKerIsCraZy</b></sub></a><br /><a href="#translation-JoKerIsCraZy" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://daddie.dev"><img src="https://avatars.githubusercontent.com/u/33762262?v=4?s=100" width="100px;" alt="Daddie0"/><br /><sub><b>Daddie0</b></sub></a><br /><a href="#translation-GoByeBye" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://ungaro.me"><img src="https://avatars.githubusercontent.com/u/43807696?v=4?s=100" width="100px;" alt="Simone"/><br /><sub><b>Simone</b></sub></a><br /><a href="#translation-Simoneu01" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/adan89lion"><img src="https://avatars.githubusercontent.com/u/6585644?v=4?s=100" width="100px;" alt="Seohyun Joo"/><br /><sub><b>Seohyun Joo</b></sub></a><br /><a href="#translation-adan89lion" title="Translation">🌍</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ty4ko"><img src="https://avatars.githubusercontent.com/u/21213535?v=4?s=100" width="100px;" alt="Sergey"/><br /><sub><b>Sergey</b></sub></a><br /><a href="#translation-ty4ko" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/skafte1990"><img src="https://avatars.githubusercontent.com/u/31465453?v=4?s=100" width="100px;" alt="Shaaft"/><br /><sub><b>Shaaft</b></sub></a><br /><a href="#translation-skafte1990" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sr093906"><img src="https://avatars.githubusercontent.com/u/8369201?v=4?s=100" width="100px;" alt="sr093906"/><br /><sub><b>sr093906</b></sub></a><br /><a href="#translation-sr093906" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Nackophilz"><img src="https://avatars.githubusercontent.com/u/61667226?v=4?s=100" width="100px;" alt="Nackophilz"/><br /><sub><b>Nackophilz</b></sub></a><br /><a href="#translation-Nackophilz" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/schambers"><img src="https://avatars.githubusercontent.com/u/31563?v=4?s=100" width="100px;" alt="Sean Chambers"/><br /><sub><b>Sean Chambers</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=schambers" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/deniscerri"><img src="https://avatars.githubusercontent.com/u/64997243?v=4?s=100" width="100px;" alt="deniscerri"/><br /><sub><b>deniscerri</b></sub></a><br /><a href="#translation-deniscerri" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tomgacz"><img src="https://avatars.githubusercontent.com/u/14138209?v=4?s=100" width="100px;" alt="tomgacz"/><br /><sub><b>tomgacz</b></sub></a><br /><a href="#translation-tomgacz" title="Translation">🌍</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Andersborrits"><img src="https://avatars.githubusercontent.com/u/29452218?v=4?s=100" width="100px;" alt="Andersborrits"/><br /><sub><b>Andersborrits</b></sub></a><br /><a href="#translation-Andersborrits" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://maxentrouault.fr"><img src="https://avatars.githubusercontent.com/u/67283154?v=4?s=100" width="100px;" alt="Maxent"/><br /><sub><b>Maxent</b></sub></a><br /><a href="#translation-Maxentr" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sambartik"><img src="https://avatars.githubusercontent.com/u/63553146?v=4?s=100" width="100px;" alt="Samuel Bartík"/><br /><sub><b>Samuel Bartík</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=sambartik" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/frank-cywong"><img src="https://avatars.githubusercontent.com/u/90653148?v=4?s=100" width="100px;" alt="Chun Yeung Wong"/><br /><sub><b>Chun Yeung Wong</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=frank-cywong" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TheMeanCanEHdian"><img src="https://avatars.githubusercontent.com/u/16025103?v=4?s=100" width="100px;" alt="TheMeanCanEHdian"/><br /><sub><b>TheMeanCanEHdian</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=TheMeanCanEHdian" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Gylesie"><img src="https://avatars.githubusercontent.com/u/86306812?v=4?s=100" width="100px;" alt="Gylesie"/><br /><sub><b>Gylesie</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Gylesie" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Fhd-pro"><img src="https://avatars.githubusercontent.com/u/82862079?v=4?s=100" width="100px;" alt="Fhd-pro"/><br /><sub><b>Fhd-pro</b></sub></a><br /><a href="#translation-Fhd-pro" title="Translation">🌍</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PovilasID"><img src="https://avatars.githubusercontent.com/u/396243?v=4?s=100" width="100px;" alt="PovilasID"/><br /><sub><b>PovilasID</b></sub></a><br /><a href="#translation-PovilasID" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/byakurau"><img src="https://avatars.githubusercontent.com/u/1811683?v=4?s=100" width="100px;" alt="byakurau"/><br /><sub><b>byakurau</b></sub></a><br /><a href="#translation-byakurau" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/miknii"><img src="https://avatars.githubusercontent.com/u/109232569?v=4?s=100" width="100px;" alt="miknii"/><br /><sub><b>miknii</b></sub></a><br /><a href="#translation-miknii" title="Translation">🌍</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Eclipseop"><img src="https://avatars.githubusercontent.com/u/5846213?v=4?s=100" width="100px;" alt="Mackenzie"/><br /><sub><b>Mackenzie</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Eclipseop" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/s0up4200"><img src="https://avatars.githubusercontent.com/u/18177310?v=4?s=100" width="100px;" alt="soup"/><br /><sub><b>soup</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=s0up4200" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ceptonit"><img src="https://avatars.githubusercontent.com/u/12678743?v=4?s=100" width="100px;" alt="ceptonit"/><br /><sub><b>ceptonit</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=ceptonit" title="Documentation">📖</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aedelbro"><img src="https://avatars.githubusercontent.com/u/36162221?v=4?s=100" width="100px;" alt="aedelbro"/><br /><sub><b>aedelbro</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=aedelbro" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://twitter.com/lunks/"><img src="https://avatars.githubusercontent.com/u/91118?v=4?s=100" width="100px;" alt="Pedro Nascimento"/><br /><sub><b>Pedro Nascimento</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=lunks" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://voke.dev"><img src="https://avatars.githubusercontent.com/u/1899334?v=4?s=100" width="100px;" alt="Owen Voke"/><br /><sub><b>Owen Voke</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=owenvoke" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Nimelrian"><img src="https://avatars.githubusercontent.com/u/8960836?v=4?s=100" width="100px;" alt="Sebastian K"/><br /><sub><b>Sebastian K</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Nimelrian" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jariz"><img src="https://avatars.githubusercontent.com/u/1415847?v=4?s=100" width="100px;" alt="jariz"/><br /><sub><b>jariz</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=jariz" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://arouillard.fr"><img src="https://avatars.githubusercontent.com/u/13947260?v=4?s=100" width="100px;" alt="Alex"/><br /><sub><b>Alex</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Alexays" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Zebebles"><img src="https://avatars.githubusercontent.com/u/11425451?v=4?s=100" width="100px;" alt="Zeb Muller"/><br /><sub><b>Zeb Muller</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Zebebles" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://smoores.dev"><img src="https://avatars.githubusercontent.com/u/5354254?v=4?s=100" width="100px;" alt="Shane Friedman"/><br /><sub><b>Shane Friedman</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=SMores" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://izaacj.me"><img src="https://avatars.githubusercontent.com/u/711323?v=4?s=100" width="100px;" alt="Izaac Brånn"/><br /><sub><b>Izaac Brånn</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=IzaacJ" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SalmanTariq"><img src="https://avatars.githubusercontent.com/u/13284494?v=4?s=100" width="100px;" alt="Salman Tariq"/><br /><sub><b>Salman Tariq</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=SalmanTariq" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andrew-kennedy"><img src="https://avatars.githubusercontent.com/u/2387159?v=4?s=100" width="100px;" alt="Andrew Kennedy"/><br /><sub><b>Andrew Kennedy</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=andrew-kennedy" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Fallenbagel"><img src="https://avatars.githubusercontent.com/u/98979876?v=4?s=100" width="100px;" alt="Fallenbagel"/><br /><sub><b>Fallenbagel</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=Fallenbagel" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://aidoge.xyz"><img src="https://avatars.githubusercontent.com/u/9427639?v=4?s=100" width="100px;" alt="Anton K. (ai Doge)"/><br /><sub><b>Anton K. (ai Doge)</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=scorp200" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://marcofaggian.com"><img src="https://avatars.githubusercontent.com/u/19221001?v=4?s=100" width="100px;" alt="Marco Faggian"/><br /><sub><b>Marco Faggian</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=marcofaggian" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="http://nemchik.com/"><img src="https://avatars.githubusercontent.com/u/725456?v=4?s=100" width="100px;" alt="Eric Nemchik"/><br /><sub><b>Eric Nemchik</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=nemchik" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/RemiRigal"><img src="https://avatars.githubusercontent.com/u/19256051?v=4?s=100" width="100px;" alt="RemiRigal"/><br /><sub><b>RemiRigal</b></sub></a><br /><a href="https://github.com/sct/overseerr/commits?author=RemiRigal" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- markdownlint-restore -->
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
|
|
||||||
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
|||||||
@@ -3,147 +3,147 @@
|
|||||||
"vapidPrivate": "tmnslaO8ZWN6bNbSEv_rolPeBTlNxOwCCAHrM9oZz3M",
|
"vapidPrivate": "tmnslaO8ZWN6bNbSEv_rolPeBTlNxOwCCAHrM9oZz3M",
|
||||||
"vapidPublic": "BK_EpP8NDm9waor2zn6_S28o3ZYv4kCkJOfYpO3pt3W6jnPmxrgTLANUBNbbyaNatPnSQ12De9CeqSYQrqWzHTs",
|
"vapidPublic": "BK_EpP8NDm9waor2zn6_S28o3ZYv4kCkJOfYpO3pt3W6jnPmxrgTLANUBNbbyaNatPnSQ12De9CeqSYQrqWzHTs",
|
||||||
"main": {
|
"main": {
|
||||||
"apiKey": "testkey",
|
"apiKey": "testkey",
|
||||||
"applicationTitle": "Overseerr",
|
"applicationTitle": "Overseerr",
|
||||||
"applicationUrl": "",
|
"applicationUrl": "",
|
||||||
"csrfProtection": false,
|
"csrfProtection": false,
|
||||||
"cacheImages": false,
|
"cacheImages": false,
|
||||||
"defaultPermissions": 32,
|
"defaultPermissions": 32,
|
||||||
"defaultQuotas": {
|
"defaultQuotas": {
|
||||||
"movie": {},
|
"movie": {},
|
||||||
"tv": {}
|
"tv": {}
|
||||||
},
|
},
|
||||||
"hideAvailable": false,
|
"hideAvailable": false,
|
||||||
"localLogin": true,
|
"localLogin": true,
|
||||||
"newPlexLogin": true,
|
"newPlexLogin": true,
|
||||||
"region": "",
|
"region": "",
|
||||||
"originalLanguage": "",
|
"originalLanguage": "",
|
||||||
"trustProxy": false,
|
"trustProxy": false,
|
||||||
"partialRequestsEnabled": true,
|
"partialRequestsEnabled": true,
|
||||||
"locale": "en"
|
"locale": "en"
|
||||||
},
|
},
|
||||||
"plex": {
|
"plex": {
|
||||||
"name": "Seerr",
|
"name": "Seerr",
|
||||||
"ip": "192.168.1.1",
|
"ip": "192.168.1.1",
|
||||||
"port": 32400,
|
"port": 32400,
|
||||||
"useSsl": false,
|
"useSsl": false,
|
||||||
"libraries": [
|
"libraries": [
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"name": "Movies",
|
"name": "Movies",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"type": "movie"
|
"type": "movie"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"machineId": "test"
|
"machineId": "test"
|
||||||
},
|
},
|
||||||
"tautulli": {},
|
"tautulli": {},
|
||||||
"radarr": [],
|
"radarr": [],
|
||||||
"sonarr": [],
|
"sonarr": [],
|
||||||
"public": {
|
"public": {
|
||||||
"initialized": true
|
"initialized": true
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"agents": {
|
"agents": {
|
||||||
"email": {
|
"email": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"options": {
|
"options": {
|
||||||
"emailFrom": "",
|
"emailFrom": "",
|
||||||
"smtpHost": "",
|
"smtpHost": "",
|
||||||
"smtpPort": 587,
|
"smtpPort": 587,
|
||||||
"secure": false,
|
"secure": false,
|
||||||
"ignoreTls": false,
|
"ignoreTls": false,
|
||||||
"requireTls": false,
|
"requireTls": false,
|
||||||
"allowSelfSigned": false,
|
"allowSelfSigned": false,
|
||||||
"senderName": "Overseerr"
|
"senderName": "Overseerr"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"discord": {
|
"discord": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"types": 0,
|
"types": 0,
|
||||||
"options": {
|
"options": {
|
||||||
"webhookUrl": "",
|
"webhookUrl": "",
|
||||||
"enableMentions": true
|
"enableMentions": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lunasea": {
|
"lunasea": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"types": 0,
|
"types": 0,
|
||||||
"options": {
|
"options": {
|
||||||
"webhookUrl": ""
|
"webhookUrl": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"slack": {
|
"slack": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"types": 0,
|
"types": 0,
|
||||||
"options": {
|
"options": {
|
||||||
"webhookUrl": ""
|
"webhookUrl": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"telegram": {
|
"telegram": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"types": 0,
|
"types": 0,
|
||||||
"options": {
|
"options": {
|
||||||
"botAPI": "",
|
"botAPI": "",
|
||||||
"chatId": "",
|
"chatId": "",
|
||||||
"sendSilently": false
|
"sendSilently": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pushbullet": {
|
"pushbullet": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"types": 0,
|
"types": 0,
|
||||||
"options": {
|
"options": {
|
||||||
"accessToken": ""
|
"accessToken": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pushover": {
|
"pushover": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"types": 0,
|
"types": 0,
|
||||||
"options": {
|
"options": {
|
||||||
"accessToken": "",
|
"accessToken": "",
|
||||||
"userToken": ""
|
"userToken": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"webhook": {
|
"webhook": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"types": 0,
|
"types": 0,
|
||||||
"options": {
|
"options": {
|
||||||
"webhookUrl": "",
|
"webhookUrl": "",
|
||||||
"jsonPayload": "IntcbiAgICBcIm5vdGlmaWNhdGlvbl90eXBlXCI6IFwie3tub3RpZmljYXRpb25fdHlwZX19XCIsXG4gICAgXCJldmVudFwiOiBcInt7ZXZlbnR9fVwiLFxuICAgIFwic3ViamVjdFwiOiBcInt7c3ViamVjdH19XCIsXG4gICAgXCJtZXNzYWdlXCI6IFwie3ttZXNzYWdlfX1cIixcbiAgICBcImltYWdlXCI6IFwie3tpbWFnZX19XCIsXG4gICAgXCJ7e21lZGlhfX1cIjoge1xuICAgICAgICBcIm1lZGlhX3R5cGVcIjogXCJ7e21lZGlhX3R5cGV9fVwiLFxuICAgICAgICBcInRtZGJJZFwiOiBcInt7bWVkaWFfdG1kYmlkfX1cIixcbiAgICAgICAgXCJ0dmRiSWRcIjogXCJ7e21lZGlhX3R2ZGJpZH19XCIsXG4gICAgICAgIFwic3RhdHVzXCI6IFwie3ttZWRpYV9zdGF0dXN9fVwiLFxuICAgICAgICBcInN0YXR1czRrXCI6IFwie3ttZWRpYV9zdGF0dXM0a319XCJcbiAgICB9LFxuICAgIFwie3tyZXF1ZXN0fX1cIjoge1xuICAgICAgICBcInJlcXVlc3RfaWRcIjogXCJ7e3JlcXVlc3RfaWR9fVwiLFxuICAgICAgICBcInJlcXVlc3RlZEJ5X2VtYWlsXCI6IFwie3tyZXF1ZXN0ZWRCeV9lbWFpbH19XCIsXG4gICAgICAgIFwicmVxdWVzdGVkQnlfdXNlcm5hbWVcIjogXCJ7e3JlcXVlc3RlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXF1ZXN0ZWRCeV9hdmF0YXJcIjogXCJ7e3JlcXVlc3RlZEJ5X2F2YXRhcn19XCJcbiAgICB9LFxuICAgIFwie3tpc3N1ZX19XCI6IHtcbiAgICAgICAgXCJpc3N1ZV9pZFwiOiBcInt7aXNzdWVfaWR9fVwiLFxuICAgICAgICBcImlzc3VlX3R5cGVcIjogXCJ7e2lzc3VlX3R5cGV9fVwiLFxuICAgICAgICBcImlzc3VlX3N0YXR1c1wiOiBcInt7aXNzdWVfc3RhdHVzfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2VtYWlsXCI6IFwie3tyZXBvcnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X3VzZXJuYW1lXCI6IFwie3tyZXBvcnRlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2F2YXRhclwiOiBcInt7cmVwb3J0ZWRCeV9hdmF0YXJ9fVwiXG4gICAgfSxcbiAgICBcInt7Y29tbWVudH19XCI6IHtcbiAgICAgICAgXCJjb21tZW50X21lc3NhZ2VcIjogXCJ7e2NvbW1lbnRfbWVzc2FnZX19XCIsXG4gICAgICAgIFwiY29tbWVudGVkQnlfZW1haWxcIjogXCJ7e2NvbW1lbnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJjb21tZW50ZWRCeV91c2VybmFtZVwiOiBcInt7Y29tbWVudGVkQnlfdXNlcm5hbWV9fVwiLFxuICAgICAgICBcImNvbW1lbnRlZEJ5X2F2YXRhclwiOiBcInt7Y29tbWVudGVkQnlfYXZhdGFyfX1cIlxuICAgIH0sXG4gICAgXCJ7e2V4dHJhfX1cIjogW11cbn0i"
|
"jsonPayload": "IntcbiAgICBcIm5vdGlmaWNhdGlvbl90eXBlXCI6IFwie3tub3RpZmljYXRpb25fdHlwZX19XCIsXG4gICAgXCJldmVudFwiOiBcInt7ZXZlbnR9fVwiLFxuICAgIFwic3ViamVjdFwiOiBcInt7c3ViamVjdH19XCIsXG4gICAgXCJtZXNzYWdlXCI6IFwie3ttZXNzYWdlfX1cIixcbiAgICBcImltYWdlXCI6IFwie3tpbWFnZX19XCIsXG4gICAgXCJ7e21lZGlhfX1cIjoge1xuICAgICAgICBcIm1lZGlhX3R5cGVcIjogXCJ7e21lZGlhX3R5cGV9fVwiLFxuICAgICAgICBcInRtZGJJZFwiOiBcInt7bWVkaWFfdG1kYmlkfX1cIixcbiAgICAgICAgXCJ0dmRiSWRcIjogXCJ7e21lZGlhX3R2ZGJpZH19XCIsXG4gICAgICAgIFwic3RhdHVzXCI6IFwie3ttZWRpYV9zdGF0dXN9fVwiLFxuICAgICAgICBcInN0YXR1czRrXCI6IFwie3ttZWRpYV9zdGF0dXM0a319XCJcbiAgICB9LFxuICAgIFwie3tyZXF1ZXN0fX1cIjoge1xuICAgICAgICBcInJlcXVlc3RfaWRcIjogXCJ7e3JlcXVlc3RfaWR9fVwiLFxuICAgICAgICBcInJlcXVlc3RlZEJ5X2VtYWlsXCI6IFwie3tyZXF1ZXN0ZWRCeV9lbWFpbH19XCIsXG4gICAgICAgIFwicmVxdWVzdGVkQnlfdXNlcm5hbWVcIjogXCJ7e3JlcXVlc3RlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXF1ZXN0ZWRCeV9hdmF0YXJcIjogXCJ7e3JlcXVlc3RlZEJ5X2F2YXRhcn19XCJcbiAgICB9LFxuICAgIFwie3tpc3N1ZX19XCI6IHtcbiAgICAgICAgXCJpc3N1ZV9pZFwiOiBcInt7aXNzdWVfaWR9fVwiLFxuICAgICAgICBcImlzc3VlX3R5cGVcIjogXCJ7e2lzc3VlX3R5cGV9fVwiLFxuICAgICAgICBcImlzc3VlX3N0YXR1c1wiOiBcInt7aXNzdWVfc3RhdHVzfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2VtYWlsXCI6IFwie3tyZXBvcnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X3VzZXJuYW1lXCI6IFwie3tyZXBvcnRlZEJ5X3VzZXJuYW1lfX1cIixcbiAgICAgICAgXCJyZXBvcnRlZEJ5X2F2YXRhclwiOiBcInt7cmVwb3J0ZWRCeV9hdmF0YXJ9fVwiXG4gICAgfSxcbiAgICBcInt7Y29tbWVudH19XCI6IHtcbiAgICAgICAgXCJjb21tZW50X21lc3NhZ2VcIjogXCJ7e2NvbW1lbnRfbWVzc2FnZX19XCIsXG4gICAgICAgIFwiY29tbWVudGVkQnlfZW1haWxcIjogXCJ7e2NvbW1lbnRlZEJ5X2VtYWlsfX1cIixcbiAgICAgICAgXCJjb21tZW50ZWRCeV91c2VybmFtZVwiOiBcInt7Y29tbWVudGVkQnlfdXNlcm5hbWV9fVwiLFxuICAgICAgICBcImNvbW1lbnRlZEJ5X2F2YXRhclwiOiBcInt7Y29tbWVudGVkQnlfYXZhdGFyfX1cIlxuICAgIH0sXG4gICAgXCJ7e2V4dHJhfX1cIjogW11cbn0i"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"webpush": {
|
"webpush": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"options": {}
|
"options": {}
|
||||||
},
|
},
|
||||||
"gotify": {
|
"gotify": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"types": 0,
|
"types": 0,
|
||||||
"options": {
|
"options": {
|
||||||
"url": "",
|
"url": "",
|
||||||
"token": ""
|
"token": ""
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"jobs": {
|
"jobs": {
|
||||||
"plex-recently-added-scan": {
|
"plex-recently-added-scan": {
|
||||||
"schedule": "0 */5 * * * *"
|
"schedule": "0 */5 * * * *"
|
||||||
},
|
},
|
||||||
"plex-full-scan": {
|
"plex-full-scan": {
|
||||||
"schedule": "0 0 3 * * *"
|
"schedule": "0 0 3 * * *"
|
||||||
},
|
},
|
||||||
"radarr-scan": {
|
"radarr-scan": {
|
||||||
"schedule": "0 0 4 * * *"
|
"schedule": "0 0 4 * * *"
|
||||||
},
|
},
|
||||||
"sonarr-scan": {
|
"sonarr-scan": {
|
||||||
"schedule": "0 30 4 * * *"
|
"schedule": "0 30 4 * * *"
|
||||||
},
|
},
|
||||||
"download-sync": {
|
"download-sync": {
|
||||||
"schedule": "0 * * * * *"
|
"schedule": "0 * * * * *"
|
||||||
},
|
},
|
||||||
"download-sync-reset": {
|
"download-sync-reset": {
|
||||||
"schedule": "0 0 1 * * *"
|
"schedule": "0 0 1 * * *"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1351,6 +1351,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
userToken:
|
userToken:
|
||||||
type: string
|
type: string
|
||||||
|
sound:
|
||||||
|
type: string
|
||||||
GotifySettings:
|
GotifySettings:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -1786,6 +1788,9 @@ components:
|
|||||||
pushoverUserKey:
|
pushoverUserKey:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
pushoverSound:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
telegramEnabled:
|
telegramEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
telegramBotUsername:
|
telegramBotUsername:
|
||||||
@@ -3083,6 +3088,33 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'204':
|
'204':
|
||||||
description: Test notification attempted
|
description: Test notification attempted
|
||||||
|
/settings/notifications/pushover/sounds:
|
||||||
|
get:
|
||||||
|
summary: Get Pushover sounds
|
||||||
|
description: Returns valid Pushover sound options in a JSON array.
|
||||||
|
tags:
|
||||||
|
- settings
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: token
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
nullable: false
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Returned Pushover settings
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
/settings/notifications/gotify:
|
/settings/notifications/gotify:
|
||||||
get:
|
get:
|
||||||
summary: Get Gotify notification settings
|
summary: Get Gotify notification settings
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
color: #6366F1;
|
color: #6366f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<!-- Inline the page's JavaScript file. -->
|
<!-- Inline the page's JavaScript file. -->
|
||||||
<script>
|
<script>
|
||||||
// Manual reload feature.
|
// Manual reload feature.
|
||||||
document.querySelector("button").addEventListener("click", () => {
|
document.querySelector('button').addEventListener('click', () => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
74
public/sw.js
74
public/sw.js
@@ -4,30 +4,30 @@
|
|||||||
// This variable is intentionally declared and unused.
|
// This variable is intentionally declared and unused.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const OFFLINE_VERSION = 3;
|
const OFFLINE_VERSION = 3;
|
||||||
const CACHE_NAME = "offline";
|
const CACHE_NAME = 'offline';
|
||||||
// Customize this with a different URL if needed.
|
// Customize this with a different URL if needed.
|
||||||
const OFFLINE_URL = "/offline.html";
|
const OFFLINE_URL = '/offline.html';
|
||||||
|
|
||||||
self.addEventListener("install", (event) => {
|
self.addEventListener('install', (event) => {
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
(async () => {
|
(async () => {
|
||||||
const cache = await caches.open(CACHE_NAME);
|
const cache = await caches.open(CACHE_NAME);
|
||||||
// Setting {cache: 'reload'} in the new request will ensure that the
|
// Setting {cache: 'reload'} in the new request will ensure that the
|
||||||
// response isn't fulfilled from the HTTP cache; i.e., it will be from
|
// response isn't fulfilled from the HTTP cache; i.e., it will be from
|
||||||
// the network.
|
// the network.
|
||||||
await cache.add(new Request(OFFLINE_URL, { cache: "reload" }));
|
await cache.add(new Request(OFFLINE_URL, { cache: 'reload' }));
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
// Force the waiting service worker to become the active service worker.
|
// Force the waiting service worker to become the active service worker.
|
||||||
self.skipWaiting();
|
self.skipWaiting();
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener("activate", (event) => {
|
self.addEventListener('activate', (event) => {
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
(async () => {
|
(async () => {
|
||||||
// Enable navigation preload if it's supported.
|
// Enable navigation preload if it's supported.
|
||||||
// See https://developers.google.com/web/updates/2017/02/navigation-preload
|
// See https://developers.google.com/web/updates/2017/02/navigation-preload
|
||||||
if ("navigationPreload" in self.registration) {
|
if ('navigationPreload' in self.registration) {
|
||||||
await self.registration.navigationPreload.enable();
|
await self.registration.navigationPreload.enable();
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
@@ -37,10 +37,10 @@ self.addEventListener("activate", (event) => {
|
|||||||
clients.claim();
|
clients.claim();
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener("fetch", (event) => {
|
self.addEventListener('fetch', (event) => {
|
||||||
// We only want to call event.respondWith() if this is a navigation request
|
// We only want to call event.respondWith() if this is a navigation request
|
||||||
// for an HTML page.
|
// for an HTML page.
|
||||||
if (event.request.mode === "navigate") {
|
if (event.request.mode === 'navigate') {
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -59,7 +59,7 @@ self.addEventListener("fetch", (event) => {
|
|||||||
// If fetch() returns a valid HTTP response with a response code in
|
// If fetch() returns a valid HTTP response with a response code in
|
||||||
// the 4xx or 5xx range, the catch() will NOT be called.
|
// the 4xx or 5xx range, the catch() will NOT be called.
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log("Fetch failed; returning offline page instead.", error);
|
console.log('Fetch failed; returning offline page instead.', error);
|
||||||
|
|
||||||
const cache = await caches.open(CACHE_NAME);
|
const cache = await caches.open(CACHE_NAME);
|
||||||
const cachedResponse = await cache.match(OFFLINE_URL);
|
const cachedResponse = await cache.match(OFFLINE_URL);
|
||||||
@@ -85,15 +85,13 @@ self.addEventListener('push', (event) => {
|
|||||||
requestId: payload.requestId,
|
requestId: payload.requestId,
|
||||||
},
|
},
|
||||||
actions: [],
|
actions: [],
|
||||||
}
|
};
|
||||||
|
|
||||||
if (payload.actionUrl){
|
if (payload.actionUrl) {
|
||||||
options.actions.push(
|
options.actions.push({
|
||||||
{
|
action: 'view',
|
||||||
action: 'view',
|
title: payload.actionUrlTitle ?? 'View',
|
||||||
title: payload.actionUrlTitle ?? 'View',
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.notificationType === 'MEDIA_PENDING') {
|
if (payload.notificationType === 'MEDIA_PENDING') {
|
||||||
@@ -109,27 +107,29 @@ self.addEventListener('push', (event) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
event.waitUntil(
|
event.waitUntil(self.registration.showNotification(payload.subject, options));
|
||||||
self.registration.showNotification(payload.subject, options)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('notificationclick', (event) => {
|
self.addEventListener(
|
||||||
const notificationData = event.notification.data;
|
'notificationclick',
|
||||||
|
(event) => {
|
||||||
|
const notificationData = event.notification.data;
|
||||||
|
|
||||||
event.notification.close();
|
event.notification.close();
|
||||||
|
|
||||||
if (event.action === 'approve') {
|
if (event.action === 'approve') {
|
||||||
fetch(`/api/v1/request/${notificationData.requestId}/approve`, {
|
fetch(`/api/v1/request/${notificationData.requestId}/approve`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
});
|
});
|
||||||
} else if (event.action === 'decline') {
|
} else if (event.action === 'decline') {
|
||||||
fetch(`/api/v1/request/${notificationData.requestId}/decline`, {
|
fetch(`/api/v1/request/${notificationData.requestId}/decline`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notificationData.actionUrl) {
|
if (notificationData.actionUrl) {
|
||||||
clients.openWindow(notificationData.actionUrl);
|
clients.openWindow(notificationData.actionUrl);
|
||||||
}
|
}
|
||||||
}, false);
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|||||||
56
server/api/pushover.ts
Normal file
56
server/api/pushover.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import ExternalAPI from './externalapi';
|
||||||
|
|
||||||
|
interface PushoverSoundsResponse {
|
||||||
|
sounds: {
|
||||||
|
[name: string]: string;
|
||||||
|
};
|
||||||
|
status: number;
|
||||||
|
request: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PushoverSound {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapSounds = (sounds: {
|
||||||
|
[name: string]: string;
|
||||||
|
}): PushoverSound[] =>
|
||||||
|
Object.entries(sounds).map(
|
||||||
|
([name, description]) =>
|
||||||
|
({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
} as PushoverSound)
|
||||||
|
);
|
||||||
|
|
||||||
|
class PushoverAPI extends ExternalAPI {
|
||||||
|
constructor() {
|
||||||
|
super(
|
||||||
|
'https://api.pushover.net/1',
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Accept: 'application/json',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getSounds(appToken: string): Promise<PushoverSound[]> {
|
||||||
|
try {
|
||||||
|
const data = await this.get<PushoverSoundsResponse>('/sounds.json', {
|
||||||
|
params: {
|
||||||
|
token: appToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return mapSounds(data.sounds);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`[Pushover] Failed to retrieve sounds: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PushoverAPI;
|
||||||
@@ -51,6 +51,9 @@ export class UserSettings {
|
|||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
public pushoverUserKey?: string;
|
public pushoverUserKey?: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
public pushoverSound?: string;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
public telegramChatId?: string;
|
public telegramChatId?: string;
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ app
|
|||||||
cookie: {
|
cookie: {
|
||||||
maxAge: 1000 * 60 * 60 * 24 * 30,
|
maxAge: 1000 * 60 * 60 * 24 * 30,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
sameSite: true,
|
sameSite: settings.main.csrfProtection ? 'strict' : 'lax',
|
||||||
secure: 'auto',
|
secure: 'auto',
|
||||||
},
|
},
|
||||||
store: new TypeormStore({
|
store: new TypeormStore({
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export interface UserSettingsNotificationsResponse {
|
|||||||
pushbulletAccessToken?: string;
|
pushbulletAccessToken?: string;
|
||||||
pushoverApplicationToken?: string;
|
pushoverApplicationToken?: string;
|
||||||
pushoverUserKey?: string;
|
pushoverUserKey?: string;
|
||||||
|
pushoverSound?: string;
|
||||||
telegramEnabled?: boolean;
|
telegramEnabled?: boolean;
|
||||||
telegramBotUsername?: string;
|
telegramBotUsername?: string;
|
||||||
telegramChatId?: string;
|
telegramChatId?: string;
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ class PushoverAgent
|
|||||||
...notificationPayload,
|
...notificationPayload,
|
||||||
token: settings.options.accessToken,
|
token: settings.options.accessToken,
|
||||||
user: settings.options.userToken,
|
user: settings.options.userToken,
|
||||||
|
sound: settings.options.sound,
|
||||||
} as PushoverPayload);
|
} as PushoverPayload);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Error sending Pushover notification', {
|
logger.error('Error sending Pushover notification', {
|
||||||
@@ -198,6 +199,7 @@ class PushoverAgent
|
|||||||
...notificationPayload,
|
...notificationPayload,
|
||||||
token: payload.notifyUser.settings.pushoverApplicationToken,
|
token: payload.notifyUser.settings.pushoverApplicationToken,
|
||||||
user: payload.notifyUser.settings.pushoverUserKey,
|
user: payload.notifyUser.settings.pushoverUserKey,
|
||||||
|
sound: payload.notifyUser.settings.pushoverSound,
|
||||||
} as PushoverPayload);
|
} as PushoverPayload);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Error sending Pushover notification', {
|
logger.error('Error sending Pushover notification', {
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ export interface NotificationAgentPushover extends NotificationAgentConfig {
|
|||||||
options: {
|
options: {
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
userToken: string;
|
userToken: string;
|
||||||
|
sound: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,6 +399,7 @@ class Settings {
|
|||||||
options: {
|
options: {
|
||||||
accessToken: '',
|
accessToken: '',
|
||||||
userToken: '',
|
userToken: '',
|
||||||
|
sound: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
webhook: {
|
webhook: {
|
||||||
|
|||||||
@@ -80,82 +80,80 @@ class WatchlistSync {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
await Promise.all(
|
for (const mediaItem of unavailableItems) {
|
||||||
unavailableItems.map(async (mediaItem) => {
|
try {
|
||||||
try {
|
logger.info("Creating media request from user's Plex Watchlist", {
|
||||||
logger.info("Creating media request from user's Plex Watchlist", {
|
label: 'Watchlist Sync',
|
||||||
label: 'Watchlist Sync',
|
userId: user.id,
|
||||||
userId: user.id,
|
mediaTitle: mediaItem.title,
|
||||||
mediaTitle: mediaItem.title,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (mediaItem.type === 'show' && !mediaItem.tvdbId) {
|
if (mediaItem.type === 'show' && !mediaItem.tvdbId) {
|
||||||
throw new Error('Missing TVDB ID from Plex Metadata');
|
throw new Error('Missing TVDB ID from Plex Metadata');
|
||||||
}
|
|
||||||
|
|
||||||
// Check if they have auto-request permissons and watchlist sync
|
|
||||||
// enabled for the media type
|
|
||||||
if (
|
|
||||||
((!user.hasPermission(
|
|
||||||
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_MOVIE],
|
|
||||||
{ type: 'or' }
|
|
||||||
) ||
|
|
||||||
!user.settings?.watchlistSyncMovies) &&
|
|
||||||
mediaItem.type === 'movie') ||
|
|
||||||
((!user.hasPermission(
|
|
||||||
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_TV],
|
|
||||||
{ type: 'or' }
|
|
||||||
) ||
|
|
||||||
!user.settings?.watchlistSyncTv) &&
|
|
||||||
mediaItem.type === 'show')
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await MediaRequest.request(
|
|
||||||
{
|
|
||||||
mediaId: mediaItem.tmdbId,
|
|
||||||
mediaType:
|
|
||||||
mediaItem.type === 'show' ? MediaType.TV : MediaType.MOVIE,
|
|
||||||
seasons: mediaItem.type === 'show' ? 'all' : undefined,
|
|
||||||
tvdbId: mediaItem.tvdbId,
|
|
||||||
is4k: false,
|
|
||||||
},
|
|
||||||
user,
|
|
||||||
{ isAutoRequest: true }
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
if (!(e instanceof Error)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (e.constructor) {
|
|
||||||
// During watchlist sync, these errors aren't necessarily
|
|
||||||
// a problem with Overseerr. Since we are auto syncing these constantly, it's
|
|
||||||
// possible they are unexpectedly at their quota limit, for example. So we'll
|
|
||||||
// instead log these as debug messages.
|
|
||||||
case RequestPermissionError:
|
|
||||||
case DuplicateMediaRequestError:
|
|
||||||
case QuotaRestrictedError:
|
|
||||||
case NoSeasonsAvailableError:
|
|
||||||
logger.debug('Failed to create media request from watchlist', {
|
|
||||||
label: 'Watchlist Sync',
|
|
||||||
userId: user.id,
|
|
||||||
mediaTitle: mediaItem.title,
|
|
||||||
errorMessage: e.message,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logger.error('Failed to create media request from watchlist', {
|
|
||||||
label: 'Watchlist Sync',
|
|
||||||
userId: user.id,
|
|
||||||
mediaTitle: mediaItem.title,
|
|
||||||
errorMessage: e.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
);
|
// Check if they have auto-request permissons and watchlist sync
|
||||||
|
// enabled for the media type
|
||||||
|
if (
|
||||||
|
((!user.hasPermission(
|
||||||
|
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_MOVIE],
|
||||||
|
{ type: 'or' }
|
||||||
|
) ||
|
||||||
|
!user.settings?.watchlistSyncMovies) &&
|
||||||
|
mediaItem.type === 'movie') ||
|
||||||
|
((!user.hasPermission(
|
||||||
|
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_TV],
|
||||||
|
{ type: 'or' }
|
||||||
|
) ||
|
||||||
|
!user.settings?.watchlistSyncTv) &&
|
||||||
|
mediaItem.type === 'show')
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await MediaRequest.request(
|
||||||
|
{
|
||||||
|
mediaId: mediaItem.tmdbId,
|
||||||
|
mediaType:
|
||||||
|
mediaItem.type === 'show' ? MediaType.TV : MediaType.MOVIE,
|
||||||
|
seasons: mediaItem.type === 'show' ? 'all' : undefined,
|
||||||
|
tvdbId: mediaItem.tvdbId,
|
||||||
|
is4k: false,
|
||||||
|
},
|
||||||
|
user,
|
||||||
|
{ isAutoRequest: true }
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (!(e instanceof Error)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (e.constructor) {
|
||||||
|
// During watchlist sync, these errors aren't necessarily
|
||||||
|
// a problem with Overseerr. Since we are auto syncing these constantly, it's
|
||||||
|
// possible they are unexpectedly at their quota limit, for example. So we'll
|
||||||
|
// instead log these as debug messages.
|
||||||
|
case RequestPermissionError:
|
||||||
|
case DuplicateMediaRequestError:
|
||||||
|
case QuotaRestrictedError:
|
||||||
|
case NoSeasonsAvailableError:
|
||||||
|
logger.debug('Failed to create media request from watchlist', {
|
||||||
|
label: 'Watchlist Sync',
|
||||||
|
userId: user.id,
|
||||||
|
mediaTitle: mediaItem.title,
|
||||||
|
errorMessage: e.message,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.error('Failed to create media request from watchlist', {
|
||||||
|
label: 'Watchlist Sync',
|
||||||
|
userId: user.id,
|
||||||
|
mediaTitle: mediaItem.title,
|
||||||
|
errorMessage: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
31
server/migration/1697393491630-AddUserPushoverSound.ts
Normal file
31
server/migration/1697393491630-AddUserPushoverSound.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import type { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class AddUserPushoverSound1697393491630 implements MigrationInterface {
|
||||||
|
name = 'AddUserPushoverSound1697393491630';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "temporary_user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, "pushoverSound" varchar, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO "temporary_user_settings"("id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv") SELECT "id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv" FROM "user_settings"`
|
||||||
|
);
|
||||||
|
await queryRunner.query(`DROP TABLE "user_settings"`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "temporary_user_settings" RENAME TO "user_settings"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_settings" RENAME TO "temporary_user_settings"`
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TABLE "user_settings" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "notificationTypes" text, "discordId" varchar, "userId" integer, "region" varchar, "originalLanguage" varchar, "telegramChatId" varchar, "telegramSendSilently" boolean, "pgpKey" varchar, "locale" varchar NOT NULL DEFAULT (''), "pushbulletAccessToken" varchar, "pushoverApplicationToken" varchar, "pushoverUserKey" varchar, "watchlistSyncMovies" boolean, "watchlistSyncTv" boolean, CONSTRAINT "UQ_986a2b6d3c05eb4091bb8066f78" UNIQUE ("userId"), CONSTRAINT "FK_986a2b6d3c05eb4091bb8066f78" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO "user_settings"("id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv") SELECT "id", "notificationTypes", "discordId", "userId", "region", "originalLanguage", "telegramChatId", "telegramSendSilently", "pgpKey", "locale", "pushbulletAccessToken", "pushoverApplicationToken", "pushoverUserKey", "watchlistSyncMovies", "watchlistSyncTv" FROM "temporary_user_settings"`
|
||||||
|
);
|
||||||
|
await queryRunner.query(`DROP TABLE "temporary_user_settings"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import GithubAPI from '@server/api/github';
|
import GithubAPI from '@server/api/github';
|
||||||
|
import PushoverAPI from '@server/api/pushover';
|
||||||
import TheMovieDb from '@server/api/themoviedb';
|
import TheMovieDb from '@server/api/themoviedb';
|
||||||
import type {
|
import type {
|
||||||
TmdbMovieResult,
|
TmdbMovieResult,
|
||||||
@@ -113,6 +114,31 @@ router.get('/settings/discover', isAuthenticated(), async (_req, res) => {
|
|||||||
|
|
||||||
return res.json(sliders);
|
return res.json(sliders);
|
||||||
});
|
});
|
||||||
|
router.get(
|
||||||
|
'/settings/notifications/pushover/sounds',
|
||||||
|
isAuthenticated(),
|
||||||
|
async (req, res, next) => {
|
||||||
|
const pushoverApi = new PushoverAPI();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!req.query.token) {
|
||||||
|
throw new Error('Pushover application token missing from request');
|
||||||
|
}
|
||||||
|
|
||||||
|
const sounds = await pushoverApi.getSounds(req.query.token as string);
|
||||||
|
res.status(200).json(sounds);
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug('Something went wrong retrieving Pushover sounds', {
|
||||||
|
label: 'API',
|
||||||
|
errorMessage: e.message,
|
||||||
|
});
|
||||||
|
return next({
|
||||||
|
status: 500,
|
||||||
|
message: 'Unable to retrieve Pushover sounds.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
router.use('/settings', isAuthenticated(Permission.ADMIN), settingsRoutes);
|
router.use('/settings', isAuthenticated(Permission.ADMIN), settingsRoutes);
|
||||||
router.use('/search', isAuthenticated(), searchRoutes);
|
router.use('/search', isAuthenticated(), searchRoutes);
|
||||||
router.use('/discover', isAuthenticated(), discoverRoutes);
|
router.use('/discover', isAuthenticated(), discoverRoutes);
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ userSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
emailEnabled: settings?.email.enabled,
|
emailEnabled: settings.email.enabled,
|
||||||
pgpKey: user.settings?.pgpKey,
|
pgpKey: user.settings?.pgpKey,
|
||||||
discordEnabled:
|
discordEnabled:
|
||||||
settings?.discord.enabled && settings.discord.options.enableMentions,
|
settings?.discord.enabled && settings.discord.options.enableMentions,
|
||||||
@@ -277,11 +277,12 @@ userSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>(
|
|||||||
pushbulletAccessToken: user.settings?.pushbulletAccessToken,
|
pushbulletAccessToken: user.settings?.pushbulletAccessToken,
|
||||||
pushoverApplicationToken: user.settings?.pushoverApplicationToken,
|
pushoverApplicationToken: user.settings?.pushoverApplicationToken,
|
||||||
pushoverUserKey: user.settings?.pushoverUserKey,
|
pushoverUserKey: user.settings?.pushoverUserKey,
|
||||||
telegramEnabled: settings?.telegram.enabled,
|
pushoverSound: user.settings?.pushoverSound,
|
||||||
telegramBotUsername: settings?.telegram.options.botUsername,
|
telegramEnabled: settings.telegram.enabled,
|
||||||
|
telegramBotUsername: settings.telegram.options.botUsername,
|
||||||
telegramChatId: user.settings?.telegramChatId,
|
telegramChatId: user.settings?.telegramChatId,
|
||||||
telegramSendSilently: user?.settings?.telegramSendSilently,
|
telegramSendSilently: user.settings?.telegramSendSilently,
|
||||||
webPushEnabled: settings?.webpush.enabled,
|
webPushEnabled: settings.webpush.enabled,
|
||||||
notificationTypes: user.settings?.notificationTypes ?? {},
|
notificationTypes: user.settings?.notificationTypes ?? {},
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -332,6 +333,7 @@ userSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>(
|
|||||||
user.settings.pushoverApplicationToken =
|
user.settings.pushoverApplicationToken =
|
||||||
req.body.pushoverApplicationToken;
|
req.body.pushoverApplicationToken;
|
||||||
user.settings.pushoverUserKey = req.body.pushoverUserKey;
|
user.settings.pushoverUserKey = req.body.pushoverUserKey;
|
||||||
|
user.settings.pushoverSound = req.body.pushoverSound;
|
||||||
user.settings.telegramChatId = req.body.telegramChatId;
|
user.settings.telegramChatId = req.body.telegramChatId;
|
||||||
user.settings.telegramSendSilently = req.body.telegramSendSilently;
|
user.settings.telegramSendSilently = req.body.telegramSendSilently;
|
||||||
user.settings.notificationTypes = Object.assign(
|
user.settings.notificationTypes = Object.assign(
|
||||||
@@ -344,13 +346,14 @@ userSettingsRoutes.post<{ id: string }, UserSettingsNotificationsResponse>(
|
|||||||
userRepository.save(user);
|
userRepository.save(user);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
pgpKey: user.settings?.pgpKey,
|
pgpKey: user.settings.pgpKey,
|
||||||
discordId: user.settings?.discordId,
|
discordId: user.settings.discordId,
|
||||||
pushbulletAccessToken: user.settings?.pushbulletAccessToken,
|
pushbulletAccessToken: user.settings.pushbulletAccessToken,
|
||||||
pushoverApplicationToken: user.settings?.pushoverApplicationToken,
|
pushoverApplicationToken: user.settings.pushoverApplicationToken,
|
||||||
pushoverUserKey: user.settings?.pushoverUserKey,
|
pushoverUserKey: user.settings.pushoverUserKey,
|
||||||
telegramChatId: user.settings?.telegramChatId,
|
pushoverSound: user.settings.pushoverSound,
|
||||||
telegramSendSilently: user?.settings?.telegramSendSilently,
|
telegramChatId: user.settings.telegramChatId,
|
||||||
|
telegramSendSilently: user.settings.telegramSendSilently,
|
||||||
notificationTypes: user.settings.notificationTypes,
|
notificationTypes: user.settings.notificationTypes,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ architectures:
|
|||||||
parts:
|
parts:
|
||||||
jellyseerr:
|
jellyseerr:
|
||||||
plugin: nodejs
|
plugin: nodejs
|
||||||
nodejs-version: '16.17.0'
|
nodejs-version: '20.9.0'
|
||||||
nodejs-package-manager: 'yarn'
|
nodejs-package-manager: 'yarn'
|
||||||
nodejs-yarn-version: v1.22.17
|
nodejs-yarn-version: v1.22.17
|
||||||
build-packages:
|
build-packages:
|
||||||
|
|||||||
@@ -76,8 +76,12 @@ const RegionSelector = ({
|
|||||||
}, [value, regions, allRegion]);
|
}, [value, regions, allRegion]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange && regions && selectedRegion) {
|
if (onChange && regions) {
|
||||||
onChange(name, selectedRegion.iso_3166_1);
|
if (selectedRegion) {
|
||||||
|
onChange(name, selectedRegion.iso_3166_1);
|
||||||
|
} else {
|
||||||
|
onChange(name, '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [onChange, selectedRegion, name, regions]);
|
}, [onChange, selectedRegion, name, regions]);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
|||||||
import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
||||||
import globalMessages from '@app/i18n/globalMessages';
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||||
|
import type { PushoverSound } from '@server/api/pushover';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Field, Form, Formik } from 'formik';
|
import { Field, Form, Formik } from 'formik';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -19,6 +20,8 @@ const messages = defineMessages({
|
|||||||
userToken: 'User or Group Key',
|
userToken: 'User or Group Key',
|
||||||
userTokenTip:
|
userTokenTip:
|
||||||
'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',
|
'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',
|
||||||
|
sound: 'Notification Sound',
|
||||||
|
deviceDefault: 'Device Default',
|
||||||
validationAccessTokenRequired: 'You must provide a valid application token',
|
validationAccessTokenRequired: 'You must provide a valid application token',
|
||||||
validationUserTokenRequired: 'You must provide a valid user or group key',
|
validationUserTokenRequired: 'You must provide a valid user or group key',
|
||||||
pushoversettingssaved: 'Pushover notification settings saved successfully!',
|
pushoversettingssaved: 'Pushover notification settings saved successfully!',
|
||||||
@@ -38,6 +41,11 @@ const NotificationsPushover = () => {
|
|||||||
error,
|
error,
|
||||||
mutate: revalidate,
|
mutate: revalidate,
|
||||||
} = useSWR('/api/v1/settings/notifications/pushover');
|
} = useSWR('/api/v1/settings/notifications/pushover');
|
||||||
|
const { data: soundsData } = useSWR<PushoverSound[]>(
|
||||||
|
data?.options.accessToken
|
||||||
|
? `/api/v1/settings/notifications/pushover/sounds?token=${data.options.accessToken}`
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
const NotificationsPushoverSchema = Yup.object().shape({
|
const NotificationsPushoverSchema = Yup.object().shape({
|
||||||
accessToken: Yup.string()
|
accessToken: Yup.string()
|
||||||
@@ -77,6 +85,7 @@ const NotificationsPushover = () => {
|
|||||||
types: data?.types,
|
types: data?.types,
|
||||||
accessToken: data?.options.accessToken,
|
accessToken: data?.options.accessToken,
|
||||||
userToken: data?.options.userToken,
|
userToken: data?.options.userToken,
|
||||||
|
sound: data?.options.sound,
|
||||||
}}
|
}}
|
||||||
validationSchema={NotificationsPushoverSchema}
|
validationSchema={NotificationsPushoverSchema}
|
||||||
onSubmit={async (values) => {
|
onSubmit={async (values) => {
|
||||||
@@ -132,6 +141,7 @@ const NotificationsPushover = () => {
|
|||||||
options: {
|
options: {
|
||||||
accessToken: values.accessToken,
|
accessToken: values.accessToken,
|
||||||
userToken: values.userToken,
|
userToken: values.userToken,
|
||||||
|
sound: values.sound,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -226,6 +236,30 @@ const NotificationsPushover = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="form-row">
|
||||||
|
<label htmlFor="sound" className="text-label">
|
||||||
|
{intl.formatMessage(messages.sound)}
|
||||||
|
</label>
|
||||||
|
<div className="form-input-area">
|
||||||
|
<div className="form-input-field">
|
||||||
|
<Field
|
||||||
|
as="select"
|
||||||
|
id="sound"
|
||||||
|
name="sound"
|
||||||
|
disabled={!soundsData?.length}
|
||||||
|
>
|
||||||
|
<option value="">
|
||||||
|
{intl.formatMessage(messages.deviceDefault)}
|
||||||
|
</option>
|
||||||
|
{soundsData?.map((sound, index) => (
|
||||||
|
<option key={`sound-${index}`} value={sound.name}>
|
||||||
|
{sound.description}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<NotificationTypeSelector
|
<NotificationTypeSelector
|
||||||
currentTypes={values.enabled ? values.types : 0}
|
currentTypes={values.enabled ? values.types : 0}
|
||||||
onUpdate={(newTypes) => {
|
onUpdate={(newTypes) => {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import NotificationTypeSelector from '@app/components/NotificationTypeSelector';
|
|||||||
import useSettings from '@app/hooks/useSettings';
|
import useSettings from '@app/hooks/useSettings';
|
||||||
import { useUser } from '@app/hooks/useUser';
|
import { useUser } from '@app/hooks/useUser';
|
||||||
import globalMessages from '@app/i18n/globalMessages';
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
|
import type { PushoverSound } from '@server/api/pushover';
|
||||||
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Field, Form, Formik } from 'formik';
|
import { Field, Form, Formik } from 'formik';
|
||||||
@@ -22,6 +23,8 @@ const messages = defineMessages({
|
|||||||
pushoverUserKey: 'User or Group Key',
|
pushoverUserKey: 'User or Group Key',
|
||||||
pushoverUserKeyTip:
|
pushoverUserKeyTip:
|
||||||
'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',
|
'Your 30-character <UsersGroupsLink>user or group identifier</UsersGroupsLink>',
|
||||||
|
sound: 'Notification Sound',
|
||||||
|
deviceDefault: 'Device Default',
|
||||||
validationPushoverApplicationToken:
|
validationPushoverApplicationToken:
|
||||||
'You must provide a valid application token',
|
'You must provide a valid application token',
|
||||||
validationPushoverUserKey: 'You must provide a valid user or group key',
|
validationPushoverUserKey: 'You must provide a valid user or group key',
|
||||||
@@ -40,6 +43,11 @@ const UserPushoverSettings = () => {
|
|||||||
} = useSWR<UserSettingsNotificationsResponse>(
|
} = useSWR<UserSettingsNotificationsResponse>(
|
||||||
user ? `/api/v1/user/${user?.id}/settings/notifications` : null
|
user ? `/api/v1/user/${user?.id}/settings/notifications` : null
|
||||||
);
|
);
|
||||||
|
const { data: soundsData } = useSWR<PushoverSound[]>(
|
||||||
|
data?.pushoverApplicationToken
|
||||||
|
? `/api/v1/settings/notifications/pushover/sounds?token=${data.pushoverApplicationToken}`
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
const UserNotificationsPushoverSchema = Yup.object().shape({
|
const UserNotificationsPushoverSchema = Yup.object().shape({
|
||||||
pushoverApplicationToken: Yup.string()
|
pushoverApplicationToken: Yup.string()
|
||||||
@@ -191,6 +199,30 @@ const UserPushoverSettings = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="form-row">
|
||||||
|
<label htmlFor="sound" className="text-label">
|
||||||
|
{intl.formatMessage(messages.sound)}
|
||||||
|
</label>
|
||||||
|
<div className="form-input-area">
|
||||||
|
<div className="form-input-field">
|
||||||
|
<Field
|
||||||
|
as="select"
|
||||||
|
id="sound"
|
||||||
|
name="sound"
|
||||||
|
disabled={!soundsData?.length}
|
||||||
|
>
|
||||||
|
<option value="">
|
||||||
|
{intl.formatMessage(messages.deviceDefault)}
|
||||||
|
</option>
|
||||||
|
{soundsData?.map((sound, index) => (
|
||||||
|
<option key={`sound-${index}`} value={sound.name}>
|
||||||
|
{sound.description}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<NotificationTypeSelector
|
<NotificationTypeSelector
|
||||||
user={user}
|
user={user}
|
||||||
currentTypes={values.types}
|
currentTypes={values.types}
|
||||||
|
|||||||
@@ -584,8 +584,10 @@
|
|||||||
"components.Settings.Notifications.NotificationsPushover.accessToken": "Application API Token",
|
"components.Settings.Notifications.NotificationsPushover.accessToken": "Application API Token",
|
||||||
"components.Settings.Notifications.NotificationsPushover.accessTokenTip": "<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with Jellyseerr",
|
"components.Settings.Notifications.NotificationsPushover.accessTokenTip": "<ApplicationRegistrationLink>Register an application</ApplicationRegistrationLink> for use with Jellyseerr",
|
||||||
"components.Settings.Notifications.NotificationsPushover.agentenabled": "Enable Agent",
|
"components.Settings.Notifications.NotificationsPushover.agentenabled": "Enable Agent",
|
||||||
|
"components.Settings.Notifications.NotificationsPushover.deviceDefault": "Device Default",
|
||||||
"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Pushover notification settings failed to save.",
|
"components.Settings.Notifications.NotificationsPushover.pushoversettingsfailed": "Pushover notification settings failed to save.",
|
||||||
"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Pushover notification settings saved successfully!",
|
"components.Settings.Notifications.NotificationsPushover.pushoversettingssaved": "Pushover notification settings saved successfully!",
|
||||||
|
"components.Settings.Notifications.NotificationsPushover.sound": "Notification Sound",
|
||||||
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed": "Pushover test notification failed to send.",
|
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestFailed": "Pushover test notification failed to send.",
|
||||||
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending": "Sending Pushover test notification…",
|
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSending": "Sending Pushover test notification…",
|
||||||
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess": "Pushover test notification sent!",
|
"components.Settings.Notifications.NotificationsPushover.toastPushoverTestSuccess": "Pushover test notification sent!",
|
||||||
@@ -1163,6 +1165,7 @@
|
|||||||
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Settings saved successfully!",
|
"components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Settings saved successfully!",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.user": "User",
|
"components.UserProfile.UserSettings.UserGeneralSettings.user": "User",
|
||||||
"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId": "You must provide a valid Discord user ID",
|
"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId": "You must provide a valid Discord user ID",
|
||||||
|
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Device Default",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.discordId": "User ID",
|
"components.UserProfile.UserSettings.UserNotificationSettings.discordId": "User ID",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> associated with your user account",
|
"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> associated with your user account",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Discord notification settings failed to save.",
|
"components.UserProfile.UserSettings.UserNotificationSettings.discordsettingsfailed": "Discord notification settings failed to save.",
|
||||||
@@ -1186,6 +1189,7 @@
|
|||||||
"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved": "Pushover notification settings saved successfully!",
|
"components.UserProfile.UserSettings.UserNotificationSettings.pushoversettingssaved": "Pushover notification settings saved successfully!",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Send Silently",
|
"components.UserProfile.UserSettings.UserNotificationSettings.sendSilently": "Send Silently",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Send notifications with no sound",
|
"components.UserProfile.UserSettings.UserNotificationSettings.sendSilentlyDescription": "Send notifications with no sound",
|
||||||
|
"components.UserProfile.UserSettings.UserNotificationSettings.sound": "Notification Sound",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Chat ID",
|
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatId": "Chat ID",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command",
|
"components.UserProfile.UserSettings.UserNotificationSettings.telegramChatIdTipLong": "<TelegramBotLink>Start a chat</TelegramBotLink>, add <GetIdBotLink>@get_id_bot</GetIdBotLink>, and issue the <code>/my_id</code> command",
|
||||||
"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Telegram notification settings failed to save.",
|
"components.UserProfile.UserSettings.UserNotificationSettings.telegramsettingsfailed": "Telegram notification settings failed to save.",
|
||||||
|
|||||||
Reference in New Issue
Block a user